update TiddlyWiki tiddlers
This commit is contained in:
parent
81c46cc5e4
commit
abc41c5a3c
537
docs/index.html
537
docs/index.html
File diff suppressed because one or more lines are too long
@ -8,7 +8,7 @@ type: text/vnd.tiddlywiki
|
||||
|
||||
<$set name="tr-rendering" value="yes">
|
||||
|
||||
<span id="tr-version">1.3.4</span>
|
||||
<span id="tr-version">1.3.5</span>
|
||||
|
||||
{{||$:/plugins/sobjornstad/TiddlyRemember/templates/AnkiDecks}}
|
||||
{{||$:/plugins/sobjornstad/TiddlyRemember/templates/AnkiTags}}
|
||||
|
@ -2,7 +2,7 @@
|
||||
"title": "$:/plugins/sobjornstad/TiddlyRemember",
|
||||
"description": "TiddlyRemember: Embed Anki notes in your TiddlyWiki",
|
||||
"author": "Soren Bjornstad",
|
||||
"version": "1.3.4",
|
||||
"version": "1.3.5",
|
||||
"core-version": ">=5.1.21",
|
||||
"source": "https://github.com/sobjornstad/TiddlyRemember",
|
||||
"list": "readme license",
|
||||
|
@ -4,13 +4,13 @@ type: text/vnd.tiddlywiki
|
||||
|
||||
!! 2.0.1
|
||||
|
||||
[[See GitLab for detailed change history of this release|https://gitlab.com/bimlas/tw5-locator/compare/v2.0.0...v2.0.1]]
|
||||
[[See GitHub for detailed change history of this release|https://github.com/bimlas/tw5-locator/compare/v2.0.0...v2.0.1]]
|
||||
|
||||
* Add MIT license
|
||||
|
||||
!! 2.0.0
|
||||
|
||||
[[See GitLab for detailed change history of this release|https://gitlab.com/bimlas/tw5-locator/compare/v1.5.0...v2.0.0]]
|
||||
[[See GitHub for detailed change history of this release|https://github.com/bimlas/tw5-locator/compare/v1.5.0...v2.0.0]]
|
||||
|
||||
''ALMOST COMPLETE REWRITING, BACKWARDS INCOMPATIBLE CHANGES ARE INTRODUCED''
|
||||
|
||||
@ -28,7 +28,7 @@ type: text/vnd.tiddlywiki
|
||||
|
||||
!! 1.5.0
|
||||
|
||||
[[See GitLab for detailed change history of this release|https://gitlab.com/bimlas/tw5-locator/compare/v1.4.0...v1.5.0]]
|
||||
[[See GitHub for detailed change history of this release|https://github.com/bimlas/tw5-locator/compare/v1.4.0...v1.5.0]]
|
||||
|
||||
* Move tiddler from current context to higher- or subtopic by drag-n-dropping in the Locator sidebar
|
||||
* Assign any tiddler to any of the titles in the Locator sidebar by drag-n-dropping
|
||||
@ -42,7 +42,7 @@ type: text/vnd.tiddlywiki
|
||||
|
||||
!! 1.4.0
|
||||
|
||||
[[See GitLab for detailed change history of this release|https://gitlab.com/bimlas/tw5-locator/compare/v1.3.1...v1.4.0]]
|
||||
[[See GitHub for detailed change history of this release|https://github.com/bimlas/tw5-locator/compare/v1.3.1...v1.4.0]]
|
||||
|
||||
* When there was a space in the search string and "new tiddler" button is used from search, the tiddler title was encapsulated (`[[title with spaces]]`)
|
||||
* When there was a space in any of the breadcrumbs in sidebar and "new tiddler" button is used from it, the tiddler got all of the breadcrumb tags, the title with spaces was encapsulated (literally `[[title with spaces]]` tag)
|
||||
@ -51,27 +51,27 @@ type: text/vnd.tiddlywiki
|
||||
|
||||
!! 1.3.1
|
||||
|
||||
[[See GitLab for detailed change history of this release|https://gitlab.com/bimlas/tw5-locator/compare/v1.3.0...v1.3.1]]
|
||||
[[See GitHub for detailed change history of this release|https://github.com/bimlas/tw5-locator/compare/v1.3.0...v1.3.1]]
|
||||
|
||||
* Add base tag if there is no breadcrumbs when creating new tiddler in current context
|
||||
* Reword documentation
|
||||
|
||||
!! 1.3.0
|
||||
|
||||
[[See GitLab for detailed change history of this release|https://gitlab.com/bimlas/tw5-locator/compare/v1.2.0...v1.3.0]]
|
||||
[[See GitHub for detailed change history of this release|https://github.com/bimlas/tw5-locator/compare/v1.2.0...v1.3.0]]
|
||||
|
||||
* Create new tiddler from search text
|
||||
|
||||
!! 1.2.0
|
||||
|
||||
[[See GitLab for detailed change history of this release|https://gitlab.com/bimlas/tw5-locator/compare/v1.1.0...v1.2.0]]
|
||||
[[See GitHub for detailed change history of this release|https://github.com/bimlas/tw5-locator/compare/v1.1.0...v1.2.0]]
|
||||
|
||||
* Add button to create new tiddler in current context
|
||||
* Ability to use additional filter on tags
|
||||
|
||||
!! 1.1.0
|
||||
|
||||
[[See GitLab for detailed change history of this release|https://gitlab.com/bimlas/tw5-locator/compare/v1.0.0...v1.1.0]]
|
||||
[[See GitHub for detailed change history of this release|https://github.com/bimlas/tw5-locator/compare/v1.0.0...v1.1.0]]
|
||||
|
||||
* ''I realized that most functions work without the `kin` filter''
|
||||
* Use the same "style" for breadcrumb- and list items
|
||||
|
@ -2,7 +2,7 @@ title: $:/plugins/bimlas/locator/README/LICENSE
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) since 2020 BimbaLaszlo <bimbalaszlo@gmail.com> (https://bimlas.gitlab.io/)
|
||||
Copyright (c) since 2020 BimbaLaszlo <bimbalaszlo@gmail.com> (https://bimlas.github.io/)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -6,9 +6,8 @@ type: text/vnd.tiddlywiki
|
||||
|
||||
Locator provides ''a universal interface for navigating between your tiddlers and searching, filtering them'' without the need to write [[filter expressions|https://tiddlywiki.com/#Filters]]. The plugin contains ''a table of contents widget and an enhanced search engine'' that contains a ''visual filter builder to filter results by tags and field values''. You can ''organize the tiddlers to any number of trees, even by custom fields or links in text''. Unlike [[classic Table of Contents|https://tiddlywiki.com/#Table-of-Contents%20Macros%20(Examples)]], [[standard search|$:/core/ui/AdvancedSearch/Standard]], [[filter search|$:/core/ui/AdvancedSearch/Filter]] and [[list of tags|$:/core/ui/MoreSideBar/Tags]], this plugin handles these functions organically.
|
||||
|
||||
* https://bimlas.gitlab.io/tw5-locator (demo + install)
|
||||
* https://gitlab.com/bimlas/tw5-locator (main repository)
|
||||
* https://github.com/bimlas/tw5-locator (mirror, ''please star if you like the plugin'')
|
||||
* https://bimlas.github.io/tw5-locator (demo + install)
|
||||
* https://github.com/bimlas/tw5-locator (''please star if you like the plugin'')
|
||||
|
||||
! Benefits compared to built-in solutions
|
||||
|
||||
@ -23,7 +22,7 @@ Locator provides ''a universal interface for navigating between your tiddlers an
|
||||
|
||||
! Usage
|
||||
|
||||
See the [[demo|https://bimlas.gitlab.io/tw5-locator]] for a complete tutorial
|
||||
See the [[demo|https://bimlas.github.io/tw5-locator]] for a complete tutorial
|
||||
|
||||
! Installation instructions
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
"author": "bimlas",
|
||||
"version": "2.0.1",
|
||||
"core-version": ">=5.1.18",
|
||||
"source": "https://gitlab.com/bimlas/tw5-locator",
|
||||
"source": "https://github.com/bimlas/tw5-locator",
|
||||
"plugin-type": "plugin",
|
||||
"list": "README/README README/macros README/TIPS README/CHANGELOG README/LICENSE",
|
||||
"dependents": ""
|
||||
|
@ -0,0 +1,3 @@
|
||||
title: $:/config/flibbles/relink/attributes/$transclude/$subtiddler
|
||||
|
||||
title
|
@ -0,0 +1,3 @@
|
||||
title: $:/config/flibbles/relink/attributes/$transclude/$tiddler
|
||||
|
||||
title
|
@ -0,0 +1,3 @@
|
||||
title: $:/config/flibbles/relink/exceptions/$:/DefaultTiddlers
|
||||
|
||||
application/x-tiddler-filter
|
@ -0,0 +1,3 @@
|
||||
title: $:/config/flibbles/relink/exceptions/$:/config/FileSystemExtensions
|
||||
|
||||
application/x-tiddler-filter
|
@ -0,0 +1,3 @@
|
||||
title: $:/config/flibbles/relink/exceptions/$:/config/FileSystemPaths
|
||||
|
||||
application/x-tiddler-filter
|
@ -0,0 +1,3 @@
|
||||
title: $:/config/flibbles/relink/macros/translink/title
|
||||
|
||||
title
|
@ -0,0 +1,3 @@
|
||||
title: $:/config/flibbles/relink/messages/tm-new-tiddler
|
||||
|
||||
(.*)
|
@ -2,15 +2,13 @@ tags: $:/tags/EditTemplate
|
||||
title: $:/core/ui/EditTemplate/title
|
||||
|
||||
\whitespace trim
|
||||
<$edit-text field="draft.title" class="tc-titlebar tc-edit-texteditor" focus="true" tabindex={{$:/config/EditTabIndex}}/>
|
||||
|
||||
<$reveal state="!!draft.title" type="nomatch" text={{!!draft.of}} tag="div">
|
||||
<$edit-text field="draft.title" class="tc-titlebar tc-edit-texteditor" focus={{{ [{$:/config/AutoFocus}match[title]then[true]] ~[[false]] }}} tabindex={{$:/config/EditTabIndex}} cancelPopups="yes" dir={{$:/config/DefaultTextDirection}}/>
|
||||
|
||||
<$vars pattern="""[\|\[\]{}]""" bad-chars="""`| [ ] { }`""">
|
||||
|
||||
<$list filter="[all[current]regexp:draft.title<pattern>]" variable="listItem">
|
||||
|
||||
<div class="tc-message-box">
|
||||
<div class="tc-message-box" dir={{$:/config/DefaultTextDirection}}>
|
||||
|
||||
{{$:/core/images/warning}} {{$:/language/EditTemplate/Title/BadCharacterWarning}}
|
||||
|
||||
@ -20,11 +18,13 @@ title: $:/core/ui/EditTemplate/title
|
||||
|
||||
</$vars>
|
||||
|
||||
<$reveal state="!!draft.title" type="nomatch" text={{!!draft.of}} tag="div" dir={{$:/config/DefaultTextDirection}}>
|
||||
|
||||
<$list filter="[{!!draft.title}!is[missing]]" variable="listItem">
|
||||
|
||||
<div class="tc-message-box">
|
||||
|
||||
{{$:/core/images/warning}} {{$:/language/EditTemplate/Title/Exists/Prompt}}
|
||||
{{$:/core/images/warning}} {{$:/language/EditTemplate/Title/Exists/Prompt}}: <$link to={{!!draft.title}} />
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
description: {{$:/plugins/flibbles/relink/language/Filters/Missing}}
|
||||
filter: [all[]!is[system]relink:references[]!is[tiddler]!is[shadow]!prefix[$:/tags/]sort[title]] -[[]]
|
||||
filter: [all[]!is[system]relink:references:hard[]!is[tiddler]!is[shadow]!prefix[$:/tags/]sort[title]] -[[]]
|
||||
tags: $:/tags/Filter
|
||||
title: $:/plugins/flibbles/relink/Filters/Missing
|
@ -36,6 +36,7 @@ function relinkTiddler(fromTitle, toTitle, options) {
|
||||
var failures = [];
|
||||
var indexer = utils.getIndexer(this);
|
||||
var records = indexer.relinkLookup(fromTitle, toTitle, options);
|
||||
var changedTitles = Object.create(null);
|
||||
for (var title in records) {
|
||||
var entries = records[title],
|
||||
changes = Object.create(null),
|
||||
@ -63,11 +64,16 @@ function relinkTiddler(fromTitle, toTitle, options) {
|
||||
this.addTiddler(newTiddler);
|
||||
// If the title changed, we need to perform a nested rename
|
||||
if (newTiddler.fields.title !== title) {
|
||||
this.deleteTiddler(title);
|
||||
this.relinkTiddler(title, newTiddler.fields.title,options);
|
||||
changedTitles[title] = newTiddler.fields.title;
|
||||
}
|
||||
}
|
||||
};
|
||||
// Now that the rename is complete, we must now rename any tiddlers that
|
||||
// changed their titles, and thus repeat the process.
|
||||
for (var title in changedTitles) {
|
||||
this.deleteTiddler(title);
|
||||
this.relinkTiddler(title, changedTitles[title], options);
|
||||
}
|
||||
if (failures.length > 0) {
|
||||
var options = $tw.utils.extend(
|
||||
{ variables: {to: toTitle, from: fromTitle},
|
||||
|
@ -43,6 +43,13 @@ Context.prototype.getMacros = function() {
|
||||
return this.parent.getMacros();
|
||||
};
|
||||
|
||||
/* Exceptions are tiddlers that have text/vnd.tiddlywiki type, but should
|
||||
* not be treated as such.
|
||||
*/
|
||||
Context.prototype.getException = function(tiddlerTitle) {
|
||||
return this.parent.getException(tiddlerTitle);
|
||||
};
|
||||
|
||||
Context.prototype.allowPrettylinks = function() {
|
||||
return this.parent.allowPrettylinks();
|
||||
};
|
||||
@ -54,3 +61,22 @@ Context.prototype.allowWidgets = function() {
|
||||
Context.prototype.hasImports = function(value) {
|
||||
return this.parent.hasImports(value);
|
||||
};
|
||||
|
||||
Context.prototype.getFocus = function() {
|
||||
if (this.parent) {
|
||||
return this.parent.getFocus();
|
||||
}
|
||||
};
|
||||
|
||||
Context.prototype.getPlaceholderList = function() {
|
||||
if (this.parent) {
|
||||
return this.parent.getPlaceholderList();
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
Context.prototype.addParameter = function(parameter) {
|
||||
if(this.parent) {
|
||||
return this.parent.addParameter(parameter);
|
||||
}
|
||||
};
|
||||
|
@ -10,9 +10,12 @@ function ImportContext(wiki, parent, filter) {
|
||||
this.parent = parent;
|
||||
this.wiki = wiki;
|
||||
var importWidget = createImportWidget(filter, this.wiki, this.parent.widget);
|
||||
this._compileList(importWidget.tiddlerList);
|
||||
this._compileList(importWidget.tiddlerList, importWidget.variables);
|
||||
// this.widget is where we ask for macro definitions.
|
||||
// This only works if only one filter is imported
|
||||
this.widget = this.getBottom(importWidget);
|
||||
// We keep this one because it's where we need to test for changes from.
|
||||
this.importWidget = importWidget
|
||||
// Trickle this up, so that any containing tiddlercontext knows that this
|
||||
// tiddler does some importing, and must be checked regularly.
|
||||
parent.hasImports(true);
|
||||
@ -23,7 +26,7 @@ exports.import = ImportContext;
|
||||
ImportContext.prototype = new WidgetContext();
|
||||
|
||||
ImportContext.prototype.changed = function(changes) {
|
||||
return this.widget && this.widget.refresh(changes)
|
||||
return this.importWidget && this.importWidget.refresh(changes)
|
||||
};
|
||||
|
||||
function createImportWidget(filter, wiki, parent) {
|
||||
@ -45,16 +48,20 @@ function createImportWidget(filter, wiki, parent) {
|
||||
return importWidget;
|
||||
};
|
||||
|
||||
ImportContext.prototype._compileList = function(titleList) {
|
||||
ImportContext.prototype._compileList = function(titleList, variables) {
|
||||
for (var i = 0; i < titleList.length; i++) {
|
||||
var parser = this.wiki.parseTiddler(titleList[i]);
|
||||
if (parser) {
|
||||
var parseTreeNode = parser.tree[0];
|
||||
while (parseTreeNode && parseTreeNode.type === "set") {
|
||||
var variable = variables[parseTreeNode.attributes.name.value];
|
||||
if(variable) {
|
||||
variable.tiddler = titleList[i];
|
||||
}
|
||||
if (parseTreeNode.relink) {
|
||||
for (var macroName in parseTreeNode.relink) {
|
||||
var parameters = parseTreeNode.relink[macroName];
|
||||
for (paramName in parameters) {
|
||||
for (var paramName in parameters) {
|
||||
this.addSetting(this.wiki, macroName, paramName, parameters[paramName], titleList[i]);
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,11 @@ exports.tiddler = TiddlerContext;
|
||||
|
||||
TiddlerContext.prototype = new WidgetContext();
|
||||
|
||||
TiddlerContext.prototype.getFocus = function() {
|
||||
// Tiddler Contexts are the last possible focus when not embedded in contexts.
|
||||
return this;
|
||||
};
|
||||
|
||||
TiddlerContext.prototype.changed = function(changes) {
|
||||
return this.widget && this.widget.refresh(changes);
|
||||
};
|
||||
|
@ -7,17 +7,55 @@ This handles the context for variables. Either from $set, $vars, or \define
|
||||
var WidgetContext = require('./widget').widget;
|
||||
|
||||
function VariableContext(parent, setParseTreeNode) {
|
||||
var name = setParseTreeNode.attributes.name.value;
|
||||
this.parent = parent;
|
||||
// Now create a new widget and attach it.
|
||||
var attachPoint = parent.widget;
|
||||
var setWidget = attachPoint.makeChildWidget(setParseTreeNode);
|
||||
attachPoint.children.push(setWidget);
|
||||
setWidget.computeAttributes();
|
||||
setWidget.execute();
|
||||
this.setWidget = attachPoint.makeChildWidget(setParseTreeNode);
|
||||
attachPoint.children.push(this.setWidget);
|
||||
this.setWidget.computeAttributes();
|
||||
this.setWidget.execute();
|
||||
// We get the title of our current parameter focus
|
||||
// (i.e. what \param would affect)
|
||||
// If it's another definition, then title will be null.
|
||||
this.setWidget.variables[name].tiddler = parent.getFocus().title;
|
||||
// point our widget to bottom, where any other contexts would attach to
|
||||
this.widget = this.getBottom(setWidget);
|
||||
this.widget = this.getBottom(this.setWidget);
|
||||
this.parameterFocus = true;
|
||||
if (setParseTreeNode.isMacroDefinition) {
|
||||
this.placeholderList = Object.create(parent.getPlaceholderList());
|
||||
for (var i = 0; i < setParseTreeNode.params.length; i++) {
|
||||
this.placeholderList[setParseTreeNode.params[i].name] = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.variable = VariableContext;
|
||||
|
||||
VariableContext.prototype = new WidgetContext();
|
||||
|
||||
VariableContext.prototype.getFocus = function() {
|
||||
if(this.parameterFocus) {
|
||||
return this;
|
||||
} else {
|
||||
return this.parent.getFocus();
|
||||
}
|
||||
};
|
||||
|
||||
VariableContext.prototype.getPlaceholderList = function() {
|
||||
if (this.placeholderList !== undefined) {
|
||||
return this.placeholderList;
|
||||
} else {
|
||||
return this.parent.getPlaceholderList();
|
||||
}
|
||||
};
|
||||
|
||||
VariableContext.prototype.addParameter = function(parameter) {
|
||||
if(this.parameterFocus) {
|
||||
var name = this.setWidget.setName;
|
||||
var data = this.setWidget.variables[name];
|
||||
data.params.push({name: parameter});
|
||||
} else if (this.parent) {
|
||||
this.parent.addParameter(parameter);
|
||||
}
|
||||
};
|
||||
|
@ -80,6 +80,10 @@ WhitelistContext.prototype.getMacros = function() {
|
||||
return flatten(this.macros);
|
||||
};
|
||||
|
||||
WhitelistContext.prototype.getException = function(tiddlerTitle) {
|
||||
return this.exceptions[tiddlerTitle];
|
||||
};
|
||||
|
||||
WhitelistContext.prototype.changed = function(changedTiddlers) {
|
||||
for (var i = 0; i < WhitelistContext.hotDirectories.length; i++) {
|
||||
var dir = WhitelistContext.hotDirectories[i];
|
||||
|
@ -18,7 +18,23 @@ WidgetContext.prototype = new Context();
|
||||
|
||||
WidgetContext.prototype.getMacroDefinition = function(variableName) {
|
||||
// widget.variables is prototyped, so it looks up into all its parents too
|
||||
return this.widget.variables[variableName] || $tw.macros[variableName];
|
||||
var def = this.widget.variables[variableName];
|
||||
if (!def) {
|
||||
// It might be a javascript macro
|
||||
def = $tw.macros[variableName];
|
||||
if (def && !def.tiddler) {
|
||||
// We haven't assigned associated tiddlers to these macros yet.
|
||||
// That may be important for some installed supplemental plugins.
|
||||
$tw.modules.forEachModuleOfType('macro', function(title, module) {
|
||||
if (module.name) {
|
||||
// For now, we just attach it directly to the definition
|
||||
// It's easier, albeit a little sloppy.
|
||||
$tw.macros[module.name].tiddler = title;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return def;
|
||||
};
|
||||
|
||||
WidgetContext.prototype.addSetting = function(wiki, macroName, parameter, type, sourceTitle) {
|
||||
@ -31,10 +47,6 @@ WidgetContext.prototype.addSetting = function(wiki, macroName, parameter, type,
|
||||
var handler = utils.getType(type);
|
||||
if (handler) {
|
||||
handler.source = sourceTitle;
|
||||
// We attach the fields of the defining tiddler for the benefit
|
||||
// of any 3rd party field types that want access to them.
|
||||
var tiddler = wiki.getTiddler(sourceTitle);
|
||||
handler.fields = tiddler.fields;
|
||||
macro[parameter] = handler;
|
||||
}
|
||||
};
|
||||
@ -71,6 +83,44 @@ WidgetContext.prototype.getMacro = function(macroName) {
|
||||
return theseSettings || parentSettings;
|
||||
};
|
||||
|
||||
WidgetContext.prototype.getAttribute = function(elementName) {
|
||||
if (elementName.charAt(0) == '$' && elementName.indexOf('.') >= 0) {
|
||||
// This is potentially a \widget, look in macros for it.
|
||||
var macroSettings = this.getMacro(elementName);
|
||||
if (macroSettings) {
|
||||
// Make sure that it's actually a widget definition
|
||||
var def = this.getMacroDefinition(elementName);
|
||||
if (def) {
|
||||
// We found a definition, but if it's not a widget, abort all.
|
||||
return (def.isWidgetDefinition)? macroSettings: undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.parent.getAttribute(elementName);
|
||||
};
|
||||
|
||||
WidgetContext.prototype.getOperator = function(name, index) {
|
||||
if (name.indexOf('.') >= 0) {
|
||||
// This is potentially a \function, look in macros for it.
|
||||
var macroSettings = this.getMacro(name);
|
||||
if (macroSettings) {
|
||||
//Make sure that it's actually a macro definition
|
||||
var def = this.getMacroDefinition(name);
|
||||
if (def) {
|
||||
if (def.isFunctionDefinition) {
|
||||
// Minus one because operator indices are 1 indexed,
|
||||
// but parameters as we store them are not.
|
||||
var param = def.params[index - 1];
|
||||
return param && macroSettings[param.name];
|
||||
}
|
||||
// If it's not a filter, abort all.
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.parent.getOperator(name, index);
|
||||
};
|
||||
|
||||
/**Returns the deepest descendant of the given widget.
|
||||
*/
|
||||
WidgetContext.prototype.getBottom = function(widget) {
|
||||
|
@ -51,7 +51,7 @@ exports.relink = function(filter, fromTitle, toTitle, options) {
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
builder = assembleFilterString(parseTree, filter, options);
|
||||
var builder = assembleFilterString(parseTree, filter, options);
|
||||
results.output = builder.results();
|
||||
results.impossible = results.impossible || builder.impossible;
|
||||
return results;
|
||||
@ -116,9 +116,6 @@ function assembleFilterString(parseTree, oldFilter, options) {
|
||||
}
|
||||
relinker.add(wrapped, p, end);
|
||||
wordBarrierRequired = wrapped === text;
|
||||
} else if (options.placeholder) {
|
||||
var ph = options.placeholder.getPlaceholderFor(text);
|
||||
relinker.add('[<' + ph + '>]', p, end);
|
||||
} else {
|
||||
relinker.impossible = true;
|
||||
}
|
||||
@ -156,13 +153,8 @@ function assembleFilterString(parseTree, oldFilter, options) {
|
||||
p = oldFilter.indexOf('[', p);
|
||||
end = oldFilter.indexOf(']', p+1);
|
||||
if (!canBePrettyOperand(operand.text) || (options.inBraces && operand.text.indexOf('}}}') >= 0)) {
|
||||
if (options.placeholder) {
|
||||
var ph = options.placeholder.getPlaceholderFor(operand.text, operand.handler);
|
||||
wrapped = '<' + ph + '>';
|
||||
} else {
|
||||
skip = true;
|
||||
relinker.impossible = true;
|
||||
}
|
||||
skip = true;
|
||||
relinker.impossible = true;
|
||||
} else {
|
||||
wrapped = '[' + operand.text + ']';
|
||||
}
|
||||
|
@ -0,0 +1,65 @@
|
||||
/*\
|
||||
|
||||
Handles reporting of [function[]] operators.
|
||||
|
||||
\*/
|
||||
|
||||
exports.name = "function";
|
||||
|
||||
exports.report = function(filterParseTree, callback, options) {
|
||||
forEachOperand(filterParseTree, options, function(name, operand, handler, index) {
|
||||
handler.report(operand.text, function(title, blurb, style) {
|
||||
callback(title, '[function[' + name + ']' + ','.repeat(index) + '[' + (blurb || '') + ']]', style);
|
||||
}, options);
|
||||
});
|
||||
};
|
||||
|
||||
exports.relink = function(filterParseTree, fromTitle, toTitle, options) {
|
||||
var output = {};
|
||||
forEachOperand(filterParseTree, options, function(name, operand, handler, index) {
|
||||
var entry = handler.relink(operand.text, fromTitle, toTitle, options);
|
||||
if (entry) {
|
||||
if (entry.output) {
|
||||
output.changed = true;
|
||||
operand.text = entry.output;
|
||||
}
|
||||
if (entry.impossible) {
|
||||
output.impossible = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
return output;
|
||||
};
|
||||
|
||||
// Calls the callback for every applicable operand of a function operator
|
||||
function forEachOperand(filterParseTree, options, callback) {
|
||||
for (var i = 0; i < filterParseTree.length; i++) {
|
||||
var run = filterParseTree[i];
|
||||
for (var j = 0; j < run.operators.length; j++) {
|
||||
var operator = run.operators[j];
|
||||
var titleOp = operator.operands[0];
|
||||
if (operator.operator === "function"
|
||||
&& !titleOp.variable && !titleOp.indirect
|
||||
&& titleOp.text) {
|
||||
var funcName = titleOp.text;
|
||||
var managedMacro = options.settings.getMacro(funcName);
|
||||
if (managedMacro) {
|
||||
var def = options.settings.getMacroDefinition(funcName);
|
||||
if (def && def.isFunctionDefinition) {
|
||||
for (var index = 1; index < operator.operands.length; index++) {
|
||||
var operand = operator.operands[index];
|
||||
if (!operand.variable && !operand.indirect
|
||||
&& def.params.length >= index) {
|
||||
var paramName = def.params[index-1].name;
|
||||
var handler = managedMacro[paramName];
|
||||
if (handler) {
|
||||
callback(funcName, operand, handler, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
@ -0,0 +1,3 @@
|
||||
module-type: relinkfilter
|
||||
title: $:/plugins/flibbles/relink/js/fieldtypes/filter/function.js
|
||||
type: application/javascript
|
@ -17,32 +17,38 @@ exports.report = function(filterParseTree, callback, options) {
|
||||
var operator = run.operators[j];
|
||||
for (var index = 1; index <= operator.operands.length; index++) {
|
||||
var operand = operator.operands[index-1];
|
||||
var display = operator.operator === 'title'? '': operator.operator;
|
||||
if (operator.suffix) {
|
||||
display += ':' + operator.suffix;
|
||||
}
|
||||
var display = makeDisplay(operator);
|
||||
// Now add any commas if this is a later operand
|
||||
for (var x = 1; x < index; x++) {
|
||||
display += ',';
|
||||
}
|
||||
if (operand.indirect) {
|
||||
refHandler.report(operand.text, function(title, blurb) {
|
||||
callback(title, (run.prefix || '') + '[' + (operator.prefix || '') + display + '{' + (blurb || '') + '}]');
|
||||
refHandler.report(operand.text, function(title, blurb, style) {
|
||||
callback(title, (run.prefix || '') + '[' + display + '{' + (blurb || '') + '}]', style);
|
||||
}, options);
|
||||
} else if (operand.variable) {
|
||||
var macro = $tw.utils.parseMacroInvocation("<<"+operand.text+">>", 0);
|
||||
macrocall.report(options.settings, macro, function(title, blurb) {
|
||||
callback(title, (run.prefix || '') + '[' + (operator.prefix || '') + display + '<' + blurb + '>]');
|
||||
}, options);
|
||||
if (macro) {
|
||||
macrocall.report(options.settings, macro, function(title, blurb, style) {
|
||||
callback(title, (run.prefix || '') + '[' + display + '<' + blurb + '>]', style);
|
||||
}, options);
|
||||
}
|
||||
continue;
|
||||
} else if (operand.text) {
|
||||
var handler = fieldType(options.settings, operator, index, options)
|
||||
if (handler) {
|
||||
handler.report(operand.text, function(title, blurb) {
|
||||
if (blurb || !standaloneTitleRun(run)) {
|
||||
callback(title, (run.prefix || '') + '[' + (operator.prefix || '') + display + '[' + (blurb || '') + ']]');
|
||||
handler.report(operand.text, function(title, blurb, style) {
|
||||
if (!isTitleRun(operator) || blurb) {
|
||||
callback(title, (run.prefix || '') + '[' + display + '[' + (blurb || '') + ']]', style);
|
||||
} else if (j === run.operators.length-1) {
|
||||
// index will always be 1, meaning single operator run,
|
||||
// unless the user is weird. [title[]] ignores
|
||||
// input, so why would it ever not be 1?
|
||||
callback(title, run.prefix, style);
|
||||
} else {
|
||||
callback(title, run.prefix);
|
||||
// Special case: It's a title operator that's
|
||||
// leading a run
|
||||
callback(title, (run.prefix || '') + '[[]' + makeDisplay(run.operators[j+1]) + '...]', style);
|
||||
}
|
||||
}, options);
|
||||
}
|
||||
@ -69,9 +75,6 @@ exports.relink = function(filterParseTree, fromTitle, toTitle, options) {
|
||||
var handler = fieldType(options.settings, operator, index, options)
|
||||
if (handler) {
|
||||
entry = handler.relink(operand.text, fromTitle, toTitle, options);
|
||||
if (entry && entry.output) {
|
||||
operand.handler = handler.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (entry) {
|
||||
@ -115,32 +118,37 @@ function fieldType(context, operator, index, options) {
|
||||
return rtn;
|
||||
};
|
||||
|
||||
function standaloneTitleRun(run) {
|
||||
if (run.operators.length == 1) {
|
||||
var op = run.operators[0];
|
||||
return op.operator === 'title'
|
||||
&& !op.prefix
|
||||
&& !op.suffix;
|
||||
}
|
||||
return false;
|
||||
function makeDisplay(operator) {
|
||||
return (operator.prefix || '') + (operator.operator === 'title'? '': operator.operator) + (operator.suffix? ':' + operator.suffix: '');
|
||||
};
|
||||
|
||||
function isTitleRun(operator) {
|
||||
return operator.operator === 'title'
|
||||
&& !operator.prefix
|
||||
&& !operator.suffix;
|
||||
};
|
||||
|
||||
// Takes care of relinking a macro, as well as putting it back together.
|
||||
function relinkMacro(context, text, fromTitle, toTitle, options) {
|
||||
text = "<<" + text + ">>";
|
||||
var macro = $tw.utils.parseMacroInvocation(text, 0);
|
||||
var entry = macrocall.relink(context, macro, text, fromTitle, toTitle, false, options);
|
||||
var entry;
|
||||
if (macro) {
|
||||
entry = macrocall.relink(context, macro, text, fromTitle, toTitle, false, options);
|
||||
}
|
||||
if (entry && entry.output) {
|
||||
var string = macrocall.reassemble(entry.output, text, options);
|
||||
// We remove the surrounding brackets.
|
||||
string = string.substring(2, string.length-2);
|
||||
// And we make sure that no brackets remain
|
||||
if (string.indexOf(">") >= 0) {
|
||||
delete entry.output;
|
||||
entry.impossible = true;
|
||||
} else {
|
||||
entry.output = string;
|
||||
var string = macrocall.reassemble(entry, text, options);
|
||||
if (string !== undefined) {
|
||||
// We remove the surrounding brackets.
|
||||
string = string.substring(2, string.length-2);
|
||||
// And we make sure that no brackets remain
|
||||
if (string.indexOf(">") < 0) {
|
||||
entry.output = string;
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
delete entry.output;
|
||||
entry.impossible = true;
|
||||
}
|
||||
return entry;
|
||||
};
|
||||
|
@ -4,12 +4,14 @@ This manages replacing titles that occur within stringLists, like,
|
||||
TiddlerA [[Tiddler with spaces]] [[Another Title]]
|
||||
\*/
|
||||
|
||||
var titleRelinker = require('./title.js');
|
||||
|
||||
exports.name = "list";
|
||||
|
||||
exports.report = function(value, callback, options) {
|
||||
var list = $tw.utils.parseStringArray(value);
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
callback(list[i]);
|
||||
titleRelinker.report(list[i], callback, options);
|
||||
}
|
||||
};
|
||||
|
||||
@ -19,7 +21,9 @@ exports.report = function(value, callback, options) {
|
||||
*/
|
||||
exports.relink = function(value, fromTitle, toTitle, options) {
|
||||
var isModified = false,
|
||||
impossible = false,
|
||||
actualList = false,
|
||||
entry,
|
||||
list;
|
||||
if (typeof value !== "string") {
|
||||
// Not a string. Must be a list.
|
||||
@ -31,25 +35,30 @@ exports.relink = function(value, fromTitle, toTitle, options) {
|
||||
list = $tw.utils.parseStringArray(value || "");
|
||||
}
|
||||
$tw.utils.each(list,function (title,index) {
|
||||
if(title === fromTitle) {
|
||||
list[index] = toTitle;
|
||||
isModified = true;
|
||||
var titleEntry = titleRelinker.relink(title, fromTitle, toTitle, options);
|
||||
if (titleEntry) {
|
||||
if (titleEntry.output) {
|
||||
list[index] = titleEntry.output;
|
||||
isModified = true;
|
||||
}
|
||||
if (titleEntry.impossible) {
|
||||
impossible = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (isModified) {
|
||||
var entry = {name: "list"};
|
||||
if (isModified || impossible) {
|
||||
entry = {name: "list", impossible: impossible};
|
||||
// It doesn't parse correctly alone, it won't
|
||||
// parse correctly in any list.
|
||||
if (!canBeListItem(toTitle)) {
|
||||
entry.impossible = true;
|
||||
} else if (actualList) {
|
||||
entry.output = list;
|
||||
} else {
|
||||
} else if (isModified) {
|
||||
entry.output = $tw.utils.stringifyList(list);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
return undefined;
|
||||
return entry;
|
||||
};
|
||||
|
||||
function canBeListItem(value) {
|
||||
|
@ -4,11 +4,13 @@ This handles the title inside of references.
|
||||
|
||||
\*/
|
||||
|
||||
var titleRelinker = require('../title.js');
|
||||
|
||||
exports.name = 'title';
|
||||
|
||||
exports.report = function(reference, callback, options) {
|
||||
var title = reference.title;
|
||||
if (title) {
|
||||
titleRelinker.report(reference.title, function(title, blurb, style) {
|
||||
if (reference.field) {
|
||||
callback(title, '!!' + reference.field);
|
||||
} else if (reference.index) {
|
||||
@ -16,13 +18,15 @@ exports.report = function(reference, callback, options) {
|
||||
} else {
|
||||
callback(title);
|
||||
}
|
||||
}
|
||||
}, options);
|
||||
};
|
||||
|
||||
exports.relink = function(reference, fromTitle, toTitle, options) {
|
||||
if ($tw.utils.trim(reference.title) === fromTitle) {
|
||||
var entry = titleRelinker.relink($tw.utils.trim(reference.title), fromTitle, toTitle, options);
|
||||
if (entry && entry.output) {
|
||||
// preserve user's whitespace
|
||||
reference.title = reference.title.replace(fromTitle, toTitle);
|
||||
return {output: reference};
|
||||
reference.title = reference.title.replace(fromTitle, entry.output);
|
||||
entry.output = reference;
|
||||
}
|
||||
return entry;
|
||||
};
|
||||
|
@ -8,16 +8,43 @@ simplest kind of field type. One title swaps out for the other.
|
||||
exports.name = 'title';
|
||||
|
||||
exports.report = function(value, callback, options) {
|
||||
callback(value);
|
||||
if (value && !containsPlaceholder(value, options)) {
|
||||
callback(value);
|
||||
}
|
||||
};
|
||||
|
||||
/**Returns undefined if no change was made.
|
||||
*/
|
||||
exports.relink = function(value, fromTitle, toTitle, options) {
|
||||
if (value === fromTitle) {
|
||||
if (value !== fromTitle || containsPlaceholder(value, options)) {
|
||||
return undefined;
|
||||
} else if (containsPlaceholder(toTitle, options)) {
|
||||
return {impossible: true};
|
||||
} else {
|
||||
return {output: toTitle};
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
function containsPlaceholder(value, options) {
|
||||
var dollar = value.indexOf('$');
|
||||
// Quick test. If no dollar signs. No placeholders.
|
||||
if (dollar >= 0 && value.indexOf('$', dollar+1)) {
|
||||
// We potentially have a placeholder
|
||||
var placeholders = options.settings.getPlaceholderList();
|
||||
if (placeholders) {
|
||||
if (value.search(/\$\([^$\)]+\)\$/) >= 0) {
|
||||
// A global placeholder exists
|
||||
return true;
|
||||
}
|
||||
for (var name in placeholders) {
|
||||
if (value.indexOf('$' + name + '$') >= 0) {
|
||||
// Oops. This contains a placeholder.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// This is legacy support for when 'title' was known as 'field'
|
||||
|
@ -78,6 +78,10 @@ WikiWalker.prototype.parseInlineRunUnterminated = function(options) {
|
||||
};
|
||||
|
||||
WikiWalker.prototype.parseInlineRunTerminated = function(terminatorRegExp,options) {
|
||||
return this.parseInlineRunTerminatedExtended(terminatorRegExp,options).tree;
|
||||
};
|
||||
|
||||
WikiWalker.prototype.parseInlineRunTerminatedExtended = function(terminatorRegExp,options) {
|
||||
var entries = [];
|
||||
options = options || {};
|
||||
terminatorRegExp.lastIndex = this.pos;
|
||||
@ -90,7 +94,10 @@ WikiWalker.prototype.parseInlineRunTerminated = function(terminatorRegExp,option
|
||||
if (options.eatTerminator) {
|
||||
this.pos += terminatorMatch[0].length;
|
||||
}
|
||||
return entries;
|
||||
return {
|
||||
match: terminatorMatch,
|
||||
tree: entries
|
||||
};
|
||||
}
|
||||
}
|
||||
if (inlineRuleMatch) {
|
||||
@ -104,7 +111,7 @@ WikiWalker.prototype.parseInlineRunTerminated = function(terminatorRegExp,option
|
||||
}
|
||||
}
|
||||
this.pos = this.sourceLength;
|
||||
return entries;
|
||||
return {tree: entries};
|
||||
|
||||
};
|
||||
|
||||
@ -131,9 +138,6 @@ WikiWalker.prototype.amendRules = function(type, names) {
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if (only !== (names.indexOf("macrodef") >= 0) && this.options.macrodefCanBeDisabled) {
|
||||
this.options.placeholder = undefined
|
||||
}
|
||||
if (only !== (names.indexOf("html") >= 0)) {
|
||||
this.context.allowWidgets = disabled;
|
||||
}
|
||||
@ -179,10 +183,6 @@ exports.report = function(wikitext, callback, options) {
|
||||
function WikiRelinker(type, text, fromTitle, toTitle, options) {
|
||||
this.fromTitle = fromTitle;
|
||||
this.toTitle = toTitle;
|
||||
this.placeholder = options.placeholder;
|
||||
if (this.placeholder) {
|
||||
this.placeholder.parser = this;
|
||||
}
|
||||
WikiWalker.call(this, type, text, options);
|
||||
};
|
||||
|
||||
|
@ -13,7 +13,7 @@ Returns all tiddlers which are not referenced in any way
|
||||
"use strict";
|
||||
|
||||
exports.orphans = function(source,prefix,options) {
|
||||
return options.wiki.getRelinkOrphans();
|
||||
return options.wiki.getRelinkOrphans({ignore: ['$:/StoryList']});
|
||||
};
|
||||
|
||||
})();
|
||||
|
@ -37,6 +37,10 @@ exports.backreferences = function(source,operator,options) {
|
||||
|
||||
exports.references = function(source,operator,options) {
|
||||
var results = new LinkedList();
|
||||
if (operator.suffix === 'hard') {
|
||||
options = Object.create(options);
|
||||
options.hard = true;
|
||||
}
|
||||
source(function(tiddler,title) {
|
||||
var refs = options.wiki.getTiddlerRelinkReferences(title,options);
|
||||
if (refs) {
|
||||
|
@ -17,26 +17,32 @@ var utils = require("$:/plugins/flibbles/relink/js/utils.js");
|
||||
exports.wouldchange = function(source,operator,options) {
|
||||
var from = options.widget && options.widget.getVariable("currentTiddler"),
|
||||
to = operator.operand,
|
||||
indexer = utils.getIndexer(options.wiki),
|
||||
records = indexer.relinkLookup(from, to, options);
|
||||
return Object.keys(records);
|
||||
indexer = utils.getIndexer(options.wiki);
|
||||
if (from !== to) {
|
||||
var records = indexer.relinkLookup(from, to, options);
|
||||
return Object.keys(records);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
exports.impossible = function(source,operator,options) {
|
||||
var from = options.widget && options.widget.getVariable("currentTiddler"),
|
||||
to = operator.operand,
|
||||
results = [],
|
||||
indexer = utils.getIndexer(options.wiki),
|
||||
records = indexer.relinkLookup(from, to, options);
|
||||
source(function(tiddler, title) {
|
||||
var fields = records[title];
|
||||
if (fields) {
|
||||
for (var field in fields) {
|
||||
if (fields[field].impossible) {
|
||||
results.push(title);
|
||||
results = [];
|
||||
if (to && from !== to) {
|
||||
var indexer = utils.getIndexer(options.wiki),
|
||||
records = indexer.relinkLookup(from, to, options);
|
||||
source(function(tiddler, title) {
|
||||
var fields = records[title];
|
||||
if (fields) {
|
||||
for (var field in fields) {
|
||||
if (fields[field].impossible) {
|
||||
results.push(title);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
@ -85,12 +85,26 @@ Indexer.prototype.relinkLookup = function(fromTitle, toTitle, options) {
|
||||
};
|
||||
|
||||
// Returns all tiddlers that don't have anything referencing it.
|
||||
Indexer.prototype.orphans = function() {
|
||||
Indexer.prototype.orphans = function(options) {
|
||||
this._upkeep();
|
||||
var results = [];
|
||||
var ignoreList = (options && options.ignore) || [];
|
||||
var ignoreMap = Object.create(null);
|
||||
for (var i = 0; i < ignoreList.length; i++) {
|
||||
ignoreMap[ignoreList[i]] = true;
|
||||
}
|
||||
for (var title in this.index) {
|
||||
if (!this.backIndex[title]
|
||||
|| Object.keys(this.backIndex[title]).length === 0) {
|
||||
var index = this.backIndex[title];
|
||||
var owned = false;
|
||||
if (index) {
|
||||
for (var key in index) {
|
||||
if (!ignoreMap[key]) {
|
||||
owned = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!owned) {
|
||||
results.push(title);
|
||||
}
|
||||
}
|
||||
|
@ -22,11 +22,11 @@ exports.report = function(tiddler, callback, options) {
|
||||
// they actually point to, but let's not bother with that now
|
||||
return;
|
||||
}
|
||||
handler.report(input, function(title, blurb) {
|
||||
handler.report(input, function(title, blurb, style) {
|
||||
if (blurb) {
|
||||
callback(title, field + ': ' + blurb);
|
||||
callback(title, field + ': ' + blurb, style);
|
||||
} else {
|
||||
callback(title, field);
|
||||
callback(title, field, style);
|
||||
}
|
||||
}, options);
|
||||
}
|
||||
|
@ -9,28 +9,28 @@ relink titles within the body.
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var defaultOperator = "text/vnd.tiddlywiki";
|
||||
var utils = require('$:/plugins/flibbles/relink/js/utils.js');
|
||||
|
||||
exports.name = 'text';
|
||||
|
||||
var textOperators = utils.getModulesByTypeAsHashmap('relinktext', 'type');
|
||||
|
||||
// Set up any aliases, mostly for backward-compatibility
|
||||
$tw.utils.each(Object.keys(textOperators), function(type) {
|
||||
var operator = textOperators[type];
|
||||
if(operator.aliases) {
|
||||
for(var index = 0; index < operator.aliases.length; index++) {
|
||||
textOperators[operator.aliases[index]] = operator;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// These are deprecated. Don't use them.
|
||||
var oldTextOperators = utils.getModulesByTypeAsHashmap('relinktextoperator', 'type');
|
||||
|
||||
// $:/DefaultTiddlers is a tiddler which has type "text/vnd.tiddlywiki",
|
||||
// but it lies. It doesn't contain wikitext. It contains a filter, so
|
||||
// we pretend it has a filter type.
|
||||
// If you want to be able to add more exceptions for your plugin, let me know.
|
||||
var exceptions = {
|
||||
"$:/DefaultTiddlers": "text/x-tiddler-filter"
|
||||
};
|
||||
|
||||
exports.report = function(tiddler, callback, options) {
|
||||
var fields = tiddler.fields;
|
||||
if (fields.text) {
|
||||
var type = exceptions[fields.title] || fields.type || defaultOperator;
|
||||
if (tiddler.fields.text) {
|
||||
var type = getType(tiddler, options);
|
||||
if (textOperators[type]) {
|
||||
textOperators[type].report(tiddler.fields.text, callback, options);
|
||||
} else if (oldTextOperators[type]) {
|
||||
@ -41,9 +41,8 @@ exports.report = function(tiddler, callback, options) {
|
||||
};
|
||||
|
||||
exports.relink = function(tiddler, fromTitle, toTitle, changes, options) {
|
||||
var fields = tiddler.fields;
|
||||
if (fields.text) {
|
||||
var type = exceptions[fields.title] || fields.type || defaultOperator,
|
||||
if (tiddler.fields.text) {
|
||||
var type = getType(tiddler, options),
|
||||
entry;
|
||||
if (textOperators[type]) {
|
||||
entry = textOperators[type].relink(tiddler.fields.text, fromTitle, toTitle, options);
|
||||
@ -56,3 +55,14 @@ exports.relink = function(tiddler, fromTitle, toTitle, changes, options) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* The type of the tiddler is determined based on:
|
||||
* 1. Whether there's an exception specified on it.
|
||||
* 2. The type the tiddler says it is.
|
||||
* 3. Or the default vnd.tiddlywiki type if not specified.
|
||||
*/
|
||||
function getType(tiddler, options) {
|
||||
return options.settings.getException(tiddler.fields.title)
|
||||
|| tiddler.fields.type
|
||||
|| "text/vnd.tiddlywiki";
|
||||
};
|
||||
|
@ -11,7 +11,9 @@ wikitext.
|
||||
|
||||
var filterHandler = require("$:/plugins/flibbles/relink/js/utils").getType('filter');
|
||||
|
||||
exports.type = 'text/x-tiddler-filter';
|
||||
exports.type = 'application/x-tiddler-filter';
|
||||
|
||||
exports.aliases = ['text/x-tiddler-filter'];
|
||||
|
||||
exports.report = filterHandler.report;
|
||||
exports.relink = filterHandler.relink;
|
||||
|
@ -10,7 +10,9 @@ This relinks tiddlers which contain a tiddler list as their body.
|
||||
|
||||
var listHandler = require("$:/plugins/flibbles/relink/js/utils").getType('list');
|
||||
|
||||
exports.type = 'text/x-tiddler-list';
|
||||
exports.type = 'application/x-tiddler-list';
|
||||
|
||||
exports.aliases = ['text/x-tiddler-list'];
|
||||
|
||||
exports.report = listHandler.report;
|
||||
exports.relink = listHandler.relink;
|
||||
|
@ -10,7 +10,9 @@ This relinks tiddlers which contain a tiddler reference as their body.
|
||||
|
||||
var refHandler = require("$:/plugins/flibbles/relink/js/utils").getType('reference');
|
||||
|
||||
exports.type = 'text/x-tiddler-reference';
|
||||
exports.type = 'application/x-tiddler-reference';
|
||||
|
||||
exports.aliases = ['text/x-tiddler-reference'];
|
||||
|
||||
exports.report = refHandler.report;
|
||||
exports.relink = refHandler.relink;
|
||||
|
@ -10,7 +10,9 @@ This relinks tiddlers which contain a single title as their body.
|
||||
|
||||
var titleHandler = require("$:/plugins/flibbles/relink/js/utils").getType('title');
|
||||
|
||||
exports.type = 'text/x-tiddler-title';
|
||||
exports.type = 'application/x-tiddler-title';
|
||||
|
||||
exports.aliases = ['text/x-tiddler-title'];
|
||||
|
||||
exports.report = titleHandler.report;
|
||||
exports.relink = titleHandler.relink;
|
||||
|
@ -9,23 +9,9 @@ and tries to swap it out if it is.
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var Placeholder = require("$:/plugins/flibbles/relink/js/utils/placeholder.js");
|
||||
var wikitextHandler = require('$:/plugins/flibbles/relink/js/utils.js').getType('wikitext');
|
||||
|
||||
exports.type = 'text/vnd.tiddlywiki';
|
||||
|
||||
exports.report = wikitextHandler.report;
|
||||
|
||||
exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
var placeholder = new Placeholder();
|
||||
var currentOptions = Object.create(options);
|
||||
currentOptions.placeholder = placeholder;
|
||||
var entry = wikitextHandler.relink(text, fromTitle, toTitle, currentOptions);
|
||||
if (entry && entry.output) {
|
||||
// If there's output, we've also got to prepend any macros
|
||||
// that the placeholder defined.
|
||||
var preamble = placeholder.getPreamble();
|
||||
entry.output = preamble + entry.output;
|
||||
}
|
||||
return entry;
|
||||
};
|
||||
exports.relink = wikitextHandler.relink;
|
||||
|
@ -0,0 +1,124 @@
|
||||
/*\
|
||||
module-type: relinkwikitextrule
|
||||
|
||||
Handles replacement of conditionals
|
||||
|
||||
<%if Tiddler %>
|
||||
|
||||
<%elseif TiddlerB %>
|
||||
|
||||
\*/
|
||||
|
||||
var utils = require("$:/plugins/flibbles/relink/js/utils.js");
|
||||
var Rebuilder = require("$:/plugins/flibbles/relink/js/utils/rebuilder");
|
||||
var filterRelinker = utils.getType('filter');
|
||||
|
||||
exports.name = "conditional";
|
||||
|
||||
exports.report = function(text, callback, options) {
|
||||
var match = this.match;
|
||||
var keyword = '<%if ';
|
||||
var reEndString = "\\<\\%\\s*(endif)\\s*\\%\\>|\\<\\%\\s*(else)\\s*\\%\\>|\\<\\%\\s*(elseif)\\s+([\\s\\S]+?)\\%\\>";
|
||||
this.parser.pos = this.terminateIfMatch.index + this.terminateIfMatch[0].length;
|
||||
var ex;
|
||||
var filter = this.parser.source.substring(match.index + match[0].length, this.terminateIfMatch.index);
|
||||
while (true) {
|
||||
if (filter) {
|
||||
filterRelinker.report(filter, function(title, blurb, style) {
|
||||
if (blurb) {
|
||||
blurb = keyword + blurb + ' %>';
|
||||
} else {
|
||||
blurb = keyword + '%>';
|
||||
}
|
||||
callback(title, blurb, style);
|
||||
}, options);
|
||||
}
|
||||
var hasLineBreak = doubleLineBreakAtPos(this.parser);
|
||||
// Parse the body looking for else or endif
|
||||
if (hasLineBreak) {
|
||||
ex = this.parser.parseBlocksTerminatedExtended(reEndString);
|
||||
} else {
|
||||
var reEnd = new RegExp(reEndString,"mg");
|
||||
ex = this.parser.parseInlineRunTerminatedExtended(reEnd,{eatTerminator: true});
|
||||
}
|
||||
if (ex.match) {
|
||||
match = ex.match;
|
||||
if (ex.match[3] === "elseif") {
|
||||
keyword = '<%elseif ';
|
||||
filter = ex.match[4];
|
||||
continue;
|
||||
} else if (ex.match[2] === "else") {
|
||||
reEndString = "\\<\\%\\s*(endif)\\s*\\%\\>";
|
||||
filter = null;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
var conditionEntry = {};
|
||||
var builder = new Rebuilder(text, this.match.index);
|
||||
var reEndString = "\\<\\%\\s*(endif)\\s*\\%\\>|\\<\\%\\s*(else)\\s*\\%\\>|\\<\\%\\s*(elseif)\\s+([\\s\\S]+?)\\%\\>";
|
||||
this.parser.pos = this.terminateIfMatch.index + this.terminateIfMatch[0].length;
|
||||
var ex;
|
||||
var filter = this.parser.source.substring(this.match.index + this.match[0].length, this.terminateIfMatch.index);
|
||||
var endOfFilter = this.terminateIfMatch.index;
|
||||
while (true) {
|
||||
if (filter) {
|
||||
var entry = filterRelinker.relink(filter, fromTitle, toTitle, options);
|
||||
if (entry) {
|
||||
if (entry.output) {
|
||||
if (entry.output.indexOf('%>') > 0) {
|
||||
builder.impossible = true;
|
||||
} else {
|
||||
builder.add(entry.output, endOfFilter - filter.length, endOfFilter);
|
||||
}
|
||||
}
|
||||
if (entry.impossible) {
|
||||
builder.impossible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
var hasLineBreak = doubleLineBreakAtPos(this.parser);
|
||||
// Parse the body looking for else or endif
|
||||
if (hasLineBreak) {
|
||||
ex = this.parser.parseBlocksTerminatedExtended(reEndString);
|
||||
} else {
|
||||
var reEnd = new RegExp(reEndString,"mg");
|
||||
ex = this.parser.parseInlineRunTerminatedExtended(reEnd,{eatTerminator: true});
|
||||
}
|
||||
for (var i = 0; i < ex.tree.length; i++) {
|
||||
var child = ex.tree[i];
|
||||
if (child.output) {
|
||||
builder.add(child.output, child.start, child.end);
|
||||
}
|
||||
if (child.impossible) {
|
||||
builder.impossible = true;
|
||||
}
|
||||
}
|
||||
if (ex.match) {
|
||||
if (ex.match[3] === "elseif") {
|
||||
filter = ex.match[4];
|
||||
endOfFilter = ex.match.index + ex.match[0].length - 2;
|
||||
continue;
|
||||
} else if (ex.match[2] === "else") {
|
||||
filter = null;
|
||||
reEndString = "\\<\\%\\s*(endif)\\s*\\%\\>";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (builder.changed() || builder.impossible) {
|
||||
conditionEntry = {
|
||||
output: builder.results(this.parser.pos),
|
||||
impossible: builder.impossible };
|
||||
}
|
||||
return conditionEntry;
|
||||
};
|
||||
|
||||
function doubleLineBreakAtPos(parser) {
|
||||
return !!$tw.utils.parseTokenRegExp(parser.source, parser.pos, /([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/g);
|
||||
};
|
@ -0,0 +1,3 @@
|
||||
module-type: relinkwikitextrule
|
||||
title: $:/plugins/flibbles/relink/js/relinkoperations/text/wikitext/conditional.js
|
||||
type: application/javascript
|
@ -0,0 +1,109 @@
|
||||
/*\
|
||||
module-type: library
|
||||
|
||||
This is a generic def rule that manages both fnprocdef and macrodef.
|
||||
|
||||
\*/
|
||||
|
||||
var utils = require("$:/plugins/flibbles/relink/js/utils");
|
||||
var VariableContext = utils.getContext('variable');
|
||||
var Rebuilder = require("$:/plugins/flibbles/relink/js/utils/rebuilder");
|
||||
var defOperators = utils.getModulesByTypeAsHashmap('relinkdef', 'name');
|
||||
|
||||
exports.report = function(text, callback, options) {
|
||||
// fnprocdef and macrodef have their own implementations of createDefinition
|
||||
// They create a modifiable object from the respective rule matches.
|
||||
var definition = this.createDefinition();
|
||||
var setParseTreeNode = this.parse();
|
||||
var context = this.parser.context = new VariableContext(this.parser.context, setParseTreeNode[0]);
|
||||
// Parse set the pos pointer, but we don't want to skip the macro body.
|
||||
this.parser.pos = this.matchRegExp.lastIndex;
|
||||
var endMatch = getBodyMatch(this.parser.source, this.parser.pos, definition);
|
||||
if (endMatch) {
|
||||
definition.body = endMatch[2];
|
||||
options.settings = context
|
||||
for (var operator in defOperators) {
|
||||
defOperators[operator].report(definition, callback, options);
|
||||
}
|
||||
this.parser.pos = endMatch.index + endMatch[0].length;
|
||||
}
|
||||
context.parameterFocus = false;
|
||||
context.placeholderList = undefined;
|
||||
};
|
||||
|
||||
exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
// fnprocdef and macrodef have their own implementations of createDefinition
|
||||
// They create a modifiable object from the respective rule matches.
|
||||
var definition = this.createDefinition();
|
||||
var setParseTreeNode = this.parse(),
|
||||
entry,
|
||||
context = this.parser.context = new VariableContext(this.parser.context, setParseTreeNode[0]);
|
||||
// Parse set the pos pointer, but we don't want to skip the macro body.
|
||||
this.parser.pos = this.matchRegExp.lastIndex;
|
||||
var endMatch = getBodyMatch(this.parser.source, this.parser.pos, definition);
|
||||
if (endMatch) {
|
||||
definition.body = endMatch[2];
|
||||
options.settings = context;
|
||||
for (var operator in defOperators) {
|
||||
var result = defOperators[operator].relink(definition, fromTitle, toTitle, options);
|
||||
if (result) {
|
||||
entry = entry || {};
|
||||
if (result.output) {
|
||||
entry.output = true;
|
||||
}
|
||||
if (result.impossible) {
|
||||
entry.impossible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.parser.pos = endMatch.index + endMatch[0].length;
|
||||
if (entry && entry.output) {
|
||||
entry.output = reassembleSignature(definition, this.match[0]) + endMatch[1] + definition.body + endMatch[0];
|
||||
}
|
||||
}
|
||||
context.parameterFocus = false;
|
||||
context.placeholderList = undefined;
|
||||
return entry;
|
||||
};
|
||||
|
||||
function reassembleSignature(definition, text) {
|
||||
// Reconstruct the definition. Might be tricky because we need to preserve whitespace within the parameters.
|
||||
var builder = new Rebuilder(text);
|
||||
builder.add(definition.type, 1, text.search(/[^\w\\]/));
|
||||
var pos = builder.index;
|
||||
builder.add(definition.name, skipWhitespace(text, pos), text.indexOf('(', pos));
|
||||
pos = builder.index;
|
||||
if (definition.parameters) {
|
||||
builder.add(definition.parameters, skipWhitespace(text, pos+1), text.indexOf(')'));
|
||||
}
|
||||
return builder.results();
|
||||
};
|
||||
|
||||
function skipWhitespace(text, pos) {
|
||||
return text.substr(pos).search(/\S/)+pos;
|
||||
};
|
||||
|
||||
// Return another match for the body, but tooled uniquely
|
||||
// m[1] = whitespace before body
|
||||
// m[2] = body
|
||||
// m.index + m[0].length -> end of match
|
||||
function getBodyMatch(text, pos, definition) {
|
||||
var whitespace,
|
||||
valueRegExp;
|
||||
if (definition.multiline) {
|
||||
valueRegExp = new RegExp("\\r?\\n[^\\S\\n\\r]*\\\\end[^\\S\\n\\r]*(?:" + $tw.utils.escapeRegExp(definition.name) + ")?(?:\\r?\\n|$)", "mg");
|
||||
whitespace = '';
|
||||
} else {
|
||||
valueRegExp = /(?:\r?\n|$)/mg;
|
||||
var newPos = $tw.utils.skipWhiteSpace(text, pos);
|
||||
whitespace = text.substring(pos, newPos);
|
||||
pos = newPos;
|
||||
}
|
||||
valueRegExp.lastIndex = pos;
|
||||
var match = valueRegExp.exec(text);
|
||||
if (match) {
|
||||
match[1] = whitespace;
|
||||
match[2] = text.substring(pos, match.index);
|
||||
}
|
||||
return match;
|
||||
};
|
@ -0,0 +1,3 @@
|
||||
module-type: library
|
||||
title: $:/plugins/flibbles/relink/js/relinkoperations/text/wikitext/def.js
|
||||
type: application/javascript
|
@ -0,0 +1,60 @@
|
||||
/*\
|
||||
|
||||
Takes care of relinking the bodies of definitions.
|
||||
|
||||
\*/
|
||||
|
||||
var utils = require("$:/plugins/flibbles/relink/js/utils");
|
||||
|
||||
exports.name = "body";
|
||||
|
||||
exports.report = function(definition, callback, options) {
|
||||
var handler = getHandler(definition.type, definition.name);
|
||||
if (handler) {
|
||||
var newOptions = Object.create(options);
|
||||
var entry = handler.report(definition.body, function(title, blurb, style) {
|
||||
var macroStr = '\\' + definition.type + ' ' + definition.name + '()';
|
||||
if (blurb) {
|
||||
macroStr += ' ' + blurb;
|
||||
}
|
||||
callback(title, macroStr, style);
|
||||
}, newOptions);
|
||||
}
|
||||
};
|
||||
|
||||
exports.relink = function(definition, fromTitle, toTitle, options) {
|
||||
var handler = getHandler(definition.type, definition.name);
|
||||
var results;
|
||||
if (handler) {
|
||||
var newOptions = Object.create(options);
|
||||
results = handler.relink(definition.body, fromTitle, toTitle, newOptions);
|
||||
if (results && results.output) {
|
||||
definition.body = results.output;
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
function getHandler(macroType, macroName) {
|
||||
var type;
|
||||
switch (macroType) {
|
||||
case "function":
|
||||
type = "filter";
|
||||
break;
|
||||
case "define":
|
||||
/**This returns the handler to use for a macro
|
||||
* By default, we treat them like wikitext, but Relink used to make
|
||||
* little macros as placeholders. If we find one, we must return
|
||||
* the correct handler for what that placeholder represented.
|
||||
*/
|
||||
var placeholder = /^relink-(?:(\w+)-)?\d+$/.exec(macroName);
|
||||
// normal macro or special placeholder?
|
||||
if (placeholder) {
|
||||
type = placeholder[1] || 'title';
|
||||
break;
|
||||
}
|
||||
default:
|
||||
type = 'wikitext';
|
||||
}
|
||||
return utils.getType(type);
|
||||
};
|
@ -0,0 +1,3 @@
|
||||
module-type: relinkdef
|
||||
title: $:/plugins/flibbles/relink/js/relinkoperations/text/wikitext/def/body.js
|
||||
type: application/javascript
|
@ -0,0 +1,25 @@
|
||||
exports.name = 'substitution';
|
||||
var subHandler = require("$:/plugins/flibbles/relink/js/utils/substitution.js");
|
||||
|
||||
exports.report = function(definition, callback, options) {
|
||||
if (definition.type === 'define') {
|
||||
var options = Object.create(options);
|
||||
options.noFilterSubstitution = true;
|
||||
subHandler.report(definition.body, function(title, blurb, style) {
|
||||
callback(title, '\\define ' + definition.name + '() ' + (blurb || ''), style);
|
||||
}, options);
|
||||
}
|
||||
};
|
||||
|
||||
exports.relink = function(definition, fromTitle, toTitle, options) {
|
||||
var results;
|
||||
if (definition.type === "define") {
|
||||
var options = Object.create(options);
|
||||
options.noFilterSubstitution = true;
|
||||
results = subHandler.relink(definition.body, fromTitle, toTitle, options);
|
||||
if (results && results.output) {
|
||||
definition.body = results.output;
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
@ -0,0 +1,3 @@
|
||||
module-type: relinkdef
|
||||
title: $:/plugins/flibbles/relink/js/relinkoperations/text/wikitext/def/substitution.js
|
||||
type: application/javascript
|
@ -23,9 +23,11 @@ exports.report = function(text, callback, options) {
|
||||
filter = m[1],
|
||||
template = $tw.utils.trim(m[3]),
|
||||
append = template ? '||' + template + '}}}' : '}}}';
|
||||
filterHandler.report(filter, function(title, blurb) {
|
||||
callback(title, '{{{' + blurb + append);
|
||||
}, options);
|
||||
var nestedOptions = Object.create(options);
|
||||
nestedOptions.settings = this.parser.context;
|
||||
filterHandler.report(filter, function(title, blurb, style) {
|
||||
callback(title, '{{{' + blurb + append, style);
|
||||
}, nestedOptions);
|
||||
if (template) {
|
||||
callback(template, '{{{' + $tw.utils.trim(filter).replace(/\r?\n/mg, ' ') + '||}}}');
|
||||
}
|
||||
@ -43,8 +45,9 @@ exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
entry = {};
|
||||
parser.pos = this.matchRegExp.lastIndex;
|
||||
var modified = false;
|
||||
|
||||
var filterEntry = filterHandler.relink(filter, fromTitle, toTitle, options);
|
||||
var nestedOptions = Object.create(options);
|
||||
nestedOptions.settings = this.parser.context;
|
||||
var filterEntry = filterHandler.relink(filter, fromTitle, toTitle, nestedOptions);
|
||||
if (filterEntry !== undefined) {
|
||||
if (filterEntry.output) {
|
||||
filter = filterEntry.output;
|
||||
|
@ -0,0 +1,21 @@
|
||||
/*\
|
||||
module-type: relinkwikitextrule
|
||||
|
||||
Handles pragma function/procedure/widget definitions.
|
||||
|
||||
\*/
|
||||
|
||||
// We inherit from DefRule
|
||||
var DefRule = require('./def.js');
|
||||
$tw.utils.extend(exports, DefRule);
|
||||
|
||||
exports.name = "fnprocdef";
|
||||
|
||||
exports.createDefinition = function() {
|
||||
var m = this.match;
|
||||
return {
|
||||
type: m[1],
|
||||
name: m[2],
|
||||
parameters: m[4],
|
||||
multiline: m[5]};
|
||||
};
|
@ -0,0 +1,3 @@
|
||||
module-type: relinkwikitextrule
|
||||
title: $:/plugins/flibbles/relink/js/relinkoperations/text/wikitext/fnprocdef.js
|
||||
type: application/javascript
|
@ -21,8 +21,8 @@ exports.report = function(text, callback, options) {
|
||||
var nestedOptions = Object.create(options);
|
||||
nestedOptions.settings = this.parser.context;
|
||||
for (var operator in htmlOperators) {
|
||||
htmlOperators[operator].report(this.nextTag, this.parser, function(title, blurb) {
|
||||
callback(title, '<' + blurb + ' />');
|
||||
htmlOperators[operator].report(this.nextTag, this.parser, function(title, blurb, style) {
|
||||
callback(title, '<' + blurb + ' />', style);
|
||||
}, nestedOptions);
|
||||
}
|
||||
this.parse();
|
||||
@ -33,11 +33,12 @@ exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
widgetEntry.attributes = Object.create(null);
|
||||
widgetEntry.element = this.nextTag.tag;
|
||||
var elem = this.nextTag;
|
||||
var originalTag = elem.tag;
|
||||
var changed = false;
|
||||
var nestedOptions = Object.create(options);
|
||||
nestedOptions.settings = this.parser.context;
|
||||
for (var operator in htmlOperators) {
|
||||
var entry = htmlOperators[operator].relink(this.nextTag, this.parser, fromTitle, toTitle, nestedOptions);
|
||||
var entry = htmlOperators[operator].relink(elem, this.parser, fromTitle, toTitle, nestedOptions);
|
||||
if (entry) {
|
||||
if (entry.output) {
|
||||
changed = true;
|
||||
@ -47,6 +48,11 @@ exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// We swap in the original tag in case it changed. We need the old tag
|
||||
// to find the proper closing tag. Parsing must come after the htmlmodules
|
||||
// because those might change the context for the inner body.
|
||||
var newTag = elem.tag;
|
||||
elem.tag = originalTag;
|
||||
var tag = this.parse()[0];
|
||||
if (tag.children) {
|
||||
for (var i = 0; i < tag.children.length; i++) {
|
||||
@ -61,6 +67,7 @@ exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
}
|
||||
if (changed) {
|
||||
var builder = new Rebuilder(text, elem.start);
|
||||
builder.add(newTag, elem.start+1, getEndOfTag(elem, text));
|
||||
for (var attributeName in elem.attributes) {
|
||||
var attr = elem.attributes[attributeName];
|
||||
var quotedValue;
|
||||
@ -72,16 +79,8 @@ exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
var quote = relinkUtils.determineQuote(text, attr);
|
||||
quotedValue = utils.wrapAttributeValue(attr.value, quote)
|
||||
if (quotedValue === undefined) {
|
||||
// The value was unquotable. We need to make
|
||||
// a macro in order to replace it.
|
||||
if (!options.placeholder) {
|
||||
// but we can't...
|
||||
widgetEntry.impossible = true;
|
||||
continue;
|
||||
} else {
|
||||
var value = options.placeholder.getPlaceholderFor(attr.value,attr.handler)
|
||||
quotedValue = "<<"+value+">>";
|
||||
}
|
||||
widgetEntry.impossible = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 'indirect':
|
||||
@ -98,6 +97,18 @@ exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
}
|
||||
// Else If output isn't set, this wasn't ever changed
|
||||
break;
|
||||
case 'substituted':
|
||||
var ticIndex = attr.rawValue.lastIndexOf("`");
|
||||
if (ticIndex < 0) {
|
||||
quotedValue = "`" + attr.rawValue + "`";
|
||||
} else if (ticIndex < attr.rawValue.length-1
|
||||
&& attr.rawValue.indexOf("```") < 0) {
|
||||
quotedValue = "```" + attr.rawValue + "```";
|
||||
} else {
|
||||
// We can't have a tic at the end; can't have triple tic.
|
||||
widgetEntry.impossible = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
var ptr = attr.start;
|
||||
ptr = $tw.utils.skipWhiteSpace(text, ptr);
|
||||
@ -122,6 +133,12 @@ exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
}
|
||||
}
|
||||
}
|
||||
var closingTag = '</' + elem.tag + '>';
|
||||
var startClosingTag = this.parser.pos - closingTag.length;
|
||||
if (text.substring(startClosingTag, this.parser.pos) === closingTag) {
|
||||
// Replace the closing tag in case the tag changed.
|
||||
builder.add(newTag, startClosingTag + 2, this.parser.pos-1);
|
||||
}
|
||||
widgetEntry.output = builder.results(this.parser.pos);
|
||||
}
|
||||
if (widgetEntry.output || widgetEntry.impossible) {
|
||||
@ -129,3 +146,10 @@ exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
function getEndOfTag(element, text) {
|
||||
var regExp = /[^a-zA-Z\-\$\.]/g;
|
||||
regExp.lastIndex = element.start+1;
|
||||
var match = regExp.exec(text);
|
||||
return match.index;
|
||||
};
|
||||
|
@ -4,10 +4,14 @@ Handles all element attribute values. Most widget relinking happens here.
|
||||
|
||||
\*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var relinkUtils = require('$:/plugins/flibbles/relink/js/utils.js');
|
||||
var utils = require('../utils.js');
|
||||
var refHandler = relinkUtils.getType('reference');
|
||||
var filterHandler = relinkUtils.getType('filter');
|
||||
var macrocall = require("$:/plugins/flibbles/relink/js/utils/macrocall.js");
|
||||
var substitution = require("$:/plugins/flibbles/relink/js/utils/substitution.js");
|
||||
var attributeOperators = relinkUtils.getModulesByTypeAsHashmap('relinkhtmlattributes', 'name');
|
||||
|
||||
exports.name = "attributes";
|
||||
@ -22,20 +26,22 @@ exports.report = function(element, parser, callback, options) {
|
||||
if (nextEql < 0 || nextEql > attr.end) {
|
||||
continue;
|
||||
}
|
||||
var entry;
|
||||
switch (attr.type) {
|
||||
case "string":
|
||||
for (var operatorName in attributeOperators) {
|
||||
var operator = attributeOperators[operatorName];
|
||||
var handler = operator.getHandler(element, attr, options);
|
||||
if (handler) {
|
||||
handler.report(attr.value, function(title, blurb) {
|
||||
handler.report(attr.value, function(title, blurb, style) {
|
||||
if (operator.formBlurb) {
|
||||
callback(title, operator.formBlurb(element, attr, blurb, options));
|
||||
if (blurb) {
|
||||
blurb = '"' + blurb + '"';
|
||||
}
|
||||
callback(title, operator.formBlurb(element, attr, blurb, options), style);
|
||||
} else if (blurb) {
|
||||
callback(title, element.tag + ' ' + attributeName + '="' + blurb + '"');
|
||||
callback(title, element.tag + ' ' + attributeName + '="' + blurb + '"', style);
|
||||
} else {
|
||||
callback(title, element.tag + ' ' + attributeName);
|
||||
callback(title, element.tag + ' ' + attributeName, style);
|
||||
}
|
||||
}, options);
|
||||
break;
|
||||
@ -43,21 +49,48 @@ exports.report = function(element, parser, callback, options) {
|
||||
}
|
||||
break;
|
||||
case "indirect":
|
||||
entry = refHandler.report(attr.textReference, function(title, blurb) {
|
||||
callback(title, element.tag + ' ' + attributeName + '={{' + (blurb || '') + '}}');
|
||||
refHandler.report(attr.textReference, function(title, blurb, style) {
|
||||
callback(title, element.tag + ' ' + attributeName + '={{' + (blurb || '') + '}}', style);
|
||||
}, options);
|
||||
break;
|
||||
case "filtered":
|
||||
entry = filterHandler.report(attr.filter, function(title, blurb) {
|
||||
callback(title, element.tag + ' ' + attributeName + '={{{' + blurb + '}}}');
|
||||
filterHandler.report(attr.filter, function(title, blurb, style) {
|
||||
callback(title, element.tag + ' ' + attributeName + '={{{' + blurb + '}}}', style);
|
||||
}, options);
|
||||
break;
|
||||
case "macro":
|
||||
var macro = attr.value;
|
||||
entry = macrocall.report(options.settings, macro, function(title, blurb) {
|
||||
callback(title, element.tag + ' ' + attributeName + '=<<' + blurb + '>>');
|
||||
macrocall.report(options.settings, macro, function(title, blurb, style) {
|
||||
callback(title, element.tag + ' ' + attributeName + '=<<' + blurb + '>>', style);
|
||||
}, options);
|
||||
break;
|
||||
case "substituted":
|
||||
substitution.report(attr.rawValue, function(title, blurb, style) {
|
||||
callback(title, element.tag + ' ' + attributeName + '=`' + blurb + '`', style);
|
||||
}, options);
|
||||
for (var operatorName in attributeOperators) {
|
||||
var operator = attributeOperators[operatorName];
|
||||
var handler = operator.getHandler(element, attr, options);
|
||||
if (handler) {
|
||||
handler.report(attr.rawValue, function(title, blurb, style) {
|
||||
// Only consider titles without substitutions.
|
||||
if (!utils.containsPlaceholders(title)) {
|
||||
blurb = (utils.containsPlaceholders(attr.rawValue) || blurb)? '`' + blurb + '`': '';
|
||||
if (operator.formBlurb) {
|
||||
blurb = operator.formBlurb(element, attr, blurb, options);
|
||||
} else {
|
||||
if (blurb) {
|
||||
blurb = '=' + blurb;
|
||||
}
|
||||
blurb = element.tag + ' ' + attributeName + blurb;
|
||||
}
|
||||
callback(title, blurb, style);
|
||||
}
|
||||
}, options);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -74,8 +107,44 @@ exports.relink = function(element, parser, fromTitle, toTitle, options) {
|
||||
attr.valueless = true;
|
||||
continue;
|
||||
}
|
||||
var entry;
|
||||
var entry = undefined;
|
||||
switch (attr.type) {
|
||||
case 'substituted':
|
||||
if (utils.containsPlaceholders(attr.rawValue)) {
|
||||
var subEntry = substitution.relink(attr.rawValue, fromTitle, toTitle, options);
|
||||
if (subEntry) {
|
||||
if (subEntry.output) {
|
||||
attr.rawValue = subEntry.output;
|
||||
changed = true;
|
||||
}
|
||||
if (subEntry.impossible) {
|
||||
impossible = true;
|
||||
}
|
||||
}
|
||||
if (!utils.containsPlaceholders(fromTitle)) {
|
||||
for (var operatorName in attributeOperators) {
|
||||
var operator = attributeOperators[operatorName];
|
||||
var handler = operator.getHandler(element, attr, options);
|
||||
if (handler) {
|
||||
entry = handler.relink(attr.rawValue, fromTitle, toTitle, options);
|
||||
if (entry && entry.output) {
|
||||
if (utils.containsPlaceholders(toTitle)) {
|
||||
// If we relinked, but the toTitle can't be in
|
||||
// a substitution, then we must fail instead.
|
||||
entry.impossible = true;
|
||||
} else {
|
||||
attr.rawValue = entry.output;
|
||||
attr.handler = handler.name;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
// no break. turn it into a string and try to work with it
|
||||
attr.value = attr.rawValue;
|
||||
case 'string':
|
||||
for (var operatorName in attributeOperators) {
|
||||
var operator = attributeOperators[operatorName];
|
||||
@ -83,11 +152,13 @@ exports.relink = function(element, parser, fromTitle, toTitle, options) {
|
||||
if (handler) {
|
||||
entry = handler.relink(attr.value, fromTitle, toTitle, options);
|
||||
if (entry && entry.output) {
|
||||
attr.oldValue = attr.value;
|
||||
attr.value = entry.output;
|
||||
attr.handler = handler.name;
|
||||
changed = true;
|
||||
// Change it into a string if this was a substitution that had no substitutions
|
||||
attr.type = 'string';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -109,10 +180,11 @@ exports.relink = function(element, parser, fromTitle, toTitle, options) {
|
||||
var macro = attr.value;
|
||||
entry = macrocall.relink(options.settings, macro, parser.source, fromTitle, toTitle, false, options);
|
||||
if (entry && entry.output) {
|
||||
attr.output = macrocall.reassemble(entry.output, parser.source, options);
|
||||
attr.output = macrocall.reassemble(entry, parser.source, options);
|
||||
attr.value = entry.output;
|
||||
changed = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (entry && entry.impossible) {
|
||||
impossible = true;
|
||||
|
@ -20,7 +20,7 @@ exports.formBlurb = function(element, attribute, blurb, options) {
|
||||
var nameAttr = element.attributes["$name"];
|
||||
var newBlurb = '<' + nameAttr.value + ' ' + attribute.name;
|
||||
if (blurb) {
|
||||
newBlurb += '="' + blurb + '"';
|
||||
newBlurb += '=' + blurb;
|
||||
}
|
||||
return newBlurb;
|
||||
};
|
||||
|
@ -0,0 +1,31 @@
|
||||
/*\
|
||||
Handles replacement in $action-sendmessage widgets
|
||||
|
||||
\*/
|
||||
|
||||
exports.name = "sendmessage";
|
||||
|
||||
exports.getHandler = function(element, attribute, options) {
|
||||
if (element.tag === "$action-sendmessage"
|
||||
&& attribute.name[0] !== "$") {
|
||||
var messageAttr = element.attributes['$message'];
|
||||
if (messageAttr) {
|
||||
var regexp = options.settings.getConfig("messages")[messageAttr.value];
|
||||
if (regexp) {
|
||||
var results = regexp.exec(attribute.name);
|
||||
if (results && results[0] === attribute.name) {
|
||||
return options.settings.getFields()[results[1]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.formBlurb = function(element, attribute, blurb, options) {
|
||||
var messageAttr = element.attributes['$message'];
|
||||
var newBlurb = '$action-sendmessage ' + messageAttr.value + ' ' + attribute.name;
|
||||
if (blurb) {
|
||||
newBlurb += '=' + blurb;
|
||||
}
|
||||
return newBlurb;
|
||||
};
|
@ -0,0 +1,3 @@
|
||||
module-type: relinkhtmlattributes
|
||||
title: $:/plugins/flibbles/relink/js/relinkoperations/text/wikitext/html/attributes/sendmessage.js
|
||||
type: application/javascript
|
@ -0,0 +1,39 @@
|
||||
/*\
|
||||
|
||||
Handles replacement in $transclude widgets
|
||||
|
||||
\*/
|
||||
|
||||
exports.name = "transclude";
|
||||
|
||||
exports.getHandler = function(element, attribute, options) {
|
||||
if (element.tag === "$transclude") {
|
||||
var name = attribute.name;
|
||||
if (name[0] === '$') {
|
||||
if (name[1] === '$') {
|
||||
name = name.substr(1);
|
||||
} else {
|
||||
// This is a reserved attribute
|
||||
return;
|
||||
}
|
||||
}
|
||||
var nameAttr = element.attributes["$variable"];
|
||||
if (nameAttr) {
|
||||
var setting = options.settings.getMacro(nameAttr.oldValue || nameAttr.value);
|
||||
return setting && setting[name];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.formBlurb = function(element, attribute, blurb, options) {
|
||||
var nameAttr = element.attributes["$variable"];
|
||||
var name = attribute.name;
|
||||
if (name[0] === '$') {
|
||||
name = name.substr(1);
|
||||
}
|
||||
var newBlurb = '<' + nameAttr.value + ' ' + name;
|
||||
if (blurb) {
|
||||
newBlurb += '=' + blurb;
|
||||
}
|
||||
return newBlurb;
|
||||
};
|
@ -0,0 +1,3 @@
|
||||
module-type: relinkhtmlattributes
|
||||
title: $:/plugins/flibbles/relink/js/relinkoperations/text/wikitext/html/attributes/transclude.js
|
||||
type: application/javascript
|
@ -0,0 +1,36 @@
|
||||
/*\
|
||||
|
||||
Handles replacement in $macrocall widgets
|
||||
|
||||
\*/
|
||||
|
||||
exports.name = "parameters";
|
||||
|
||||
exports.report = function(element, parser, callback, options) {
|
||||
if (element.tag === "$parameters") {
|
||||
processParameters(element, parser, options);
|
||||
}
|
||||
};
|
||||
|
||||
exports.relink = function(element, parser, fromTitle, toTitle, options) {
|
||||
if (element.tag === "$parameters") {
|
||||
processParameters(element, parser, options);
|
||||
}
|
||||
};
|
||||
|
||||
function processParameters(element, parser, options) {
|
||||
var attributes = element.orderedAttributes;
|
||||
var index = 0;
|
||||
for (var i = 0; i < attributes.length; i++) {
|
||||
var attribute = attributes[i].name;
|
||||
if (attribute[0] == '$') {
|
||||
if (attribute[1] == '$') {
|
||||
attribute = attribute.substr(1);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
parser.context.addParameter(attribute);
|
||||
++index;
|
||||
}
|
||||
};
|
@ -0,0 +1,3 @@
|
||||
module-type: relinkhtml
|
||||
title: $:/plugins/flibbles/relink/js/relinkoperations/text/wikitext/html/parameters.js
|
||||
type: application/javascript
|
@ -52,11 +52,11 @@ exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
skipSource = false,
|
||||
imageEntry;
|
||||
if (this.nextImage.attributes.source.value === fromTitle && !canBePretty(toTitle, this.nextImage.attributes.tooltip)) {
|
||||
if (this.parser.context.allowWidgets() && (utils.wrapAttributeValue(toTitle) || options.placeholder)) {
|
||||
if (this.parser.context.allowWidgets() && utils.wrapAttributeValue(toTitle)) {
|
||||
makeWidget = true;
|
||||
builder.add("<$image", ptr, ptr+4);
|
||||
} else {
|
||||
// We won't be able to make a placeholder to replace
|
||||
// We won't be able to make a wdget to replace
|
||||
// the source attribute. We check now so we don't
|
||||
// prematurely convert into a widget.
|
||||
// Keep going in case other attributes need replacing.
|
||||
@ -89,8 +89,7 @@ exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
if (makeWidget) {
|
||||
var quotedValue = utils.wrapAttributeValue(toTitle);
|
||||
if (quotedValue === undefined) {
|
||||
var key = options.placeholder.getPlaceholderFor(toTitle);
|
||||
builder.add("source=<<"+key+">>", ptr, ptr+fromTitle.length);
|
||||
builder.impossible = true;
|
||||
} else {
|
||||
builder.add("source="+quotedValue, ptr, ptr+fromTitle.length);
|
||||
}
|
||||
@ -138,22 +137,22 @@ function reportAttribute(parser, attribute, callback, options) {
|
||||
} else if (attribute.type === "indirect") {
|
||||
ptr = text.indexOf('{{', ptr);
|
||||
var end = ptr + attribute.textReference.length + 4;
|
||||
refHandler.report(attribute.textReference, function(title, blurb) {
|
||||
callback(title, '[img ' + attribute.name + '={{' + (blurb || '') + '}}]');
|
||||
refHandler.report(attribute.textReference, function(title, blurb, style) {
|
||||
callback(title, '[img ' + attribute.name + '={{' + (blurb || '') + '}}]', style);
|
||||
}, options);
|
||||
} else if (attribute.type === "filtered") {
|
||||
ptr = text.indexOf('{{{', ptr);
|
||||
var end = ptr + attribute.filter.length + 6;
|
||||
filterHandler.report(attribute.filter, function(title, blurb) {
|
||||
callback(title, '[img ' + attribute.name + '={{{' + blurb + '}}}]');
|
||||
filterHandler.report(attribute.filter, function(title, blurb, style) {
|
||||
callback(title, '[img ' + attribute.name + '={{{' + blurb + '}}}]', style);
|
||||
}, options);
|
||||
} else if (attribute.type === "macro") {
|
||||
ptr = text.indexOf("<<", ptr);
|
||||
var end = attribute.value.end;
|
||||
var macro = attribute.value;
|
||||
oldValue = attribute.value;
|
||||
macrocall.reportAttribute(parser, macro, function(title, blurb) {
|
||||
callback(title, '[img ' + attribute.name + '=' + blurb + ']');
|
||||
var oldValue = attribute.value;
|
||||
macrocall.reportAttribute(parser, macro, function(title, blurb, style) {
|
||||
callback(title, '[img ' + attribute.name + '=' + blurb + ']', style);
|
||||
}, options);
|
||||
}
|
||||
return end;
|
||||
@ -199,7 +198,7 @@ function relinkAttribute(parser, attribute, builder, fromTitle, toTitle, options
|
||||
ptr = text.indexOf("<<", ptr);
|
||||
var end = attribute.value.end;
|
||||
var macro = attribute.value;
|
||||
oldValue = attribute.value;
|
||||
var oldValue = attribute.value;
|
||||
var macroEntry = macrocall.relinkAttribute(parser, macro, text, fromTitle, toTitle, options);
|
||||
if (macroEntry !== undefined) {
|
||||
if (macroEntry.impossible) {
|
||||
|
@ -16,17 +16,17 @@ exports.report = function(text, callback, options) {
|
||||
// This moves the pos for us
|
||||
var parseTree = this.parse();
|
||||
var filter = parseTree[0].attributes.filter.value || '';
|
||||
filterRelinker.report(filter, function(title, blurb) {
|
||||
filterRelinker.report(filter, function(title, blurb, style) {
|
||||
if (blurb) {
|
||||
blurb = '\\import ' + blurb;
|
||||
} else {
|
||||
blurb = '\\import';
|
||||
}
|
||||
callback(title, blurb);
|
||||
callback(title, blurb, style);
|
||||
}, options);
|
||||
// Before we go, we need to actually import the variables
|
||||
// it's calling for, and any /relink pragma
|
||||
this.parser.context = new ImportContext(options.wiki, this.parser.context, filter);
|
||||
options.settings = this.parser.context = new ImportContext(options.wiki, this.parser.context, filter);
|
||||
};
|
||||
|
||||
exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
@ -44,7 +44,7 @@ exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
|
||||
// Before we go, we need to actually import the variables
|
||||
// it's calling for, and any /relink pragma
|
||||
this.parser.context = new ImportContext(options.wiki, this.parser.context, filter);
|
||||
options.settings = this.parser.context = new ImportContext(options.wiki, this.parser.context, filter);
|
||||
|
||||
return entry;
|
||||
};
|
||||
|
@ -23,22 +23,20 @@ exports.report = function(text, callback, options) {
|
||||
|
||||
exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
var macroInfo = getInfoFromRule(this);
|
||||
var managedMacro = this.parser.context.getMacro(macroInfo.name);
|
||||
this.parser.pos = macroInfo.end;
|
||||
if (!managedMacro) {
|
||||
// We don't manage this macro. Bye.
|
||||
return undefined;
|
||||
}
|
||||
var mayBeWidget = this.parser.context.allowWidgets();
|
||||
var names = getParamNames(this.parser, macroInfo.name, macroInfo.params, options);
|
||||
if (names === undefined) {
|
||||
// Needed the definition, and couldn't find it. So if a single
|
||||
// parameter needs to placeholder, just fail.
|
||||
// parameter doesn't work, just fail.
|
||||
mayBeWidget = false;
|
||||
}
|
||||
var entry = macrocall.relink(this.parser.context, macroInfo, text, fromTitle, toTitle, mayBeWidget, options);
|
||||
if (entry && entry.output) {
|
||||
entry.output = macroToString(entry.output, text, names, options);
|
||||
entry.output = macroToString(entry, text, names, this.parser, options);
|
||||
if (entry.output === undefined) {
|
||||
entry.impossible = true;
|
||||
}
|
||||
}
|
||||
return entry;
|
||||
};
|
||||
@ -51,7 +49,7 @@ exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
exports.relinkAttribute = function(parser, macro, text, fromTitle, toTitle, options) {
|
||||
var entry = macrocall.relink(parser.context, macro, text, fromTitle, toTitle, false, options);
|
||||
if (entry && entry.output) {
|
||||
entry.output = macrocall.reassemble(entry.output, text, options);
|
||||
entry.output = macrocall.reassemble(entry, text, options);
|
||||
}
|
||||
return entry;
|
||||
};
|
||||
@ -60,8 +58,8 @@ exports.relinkAttribute = function(parser, macro, text, fromTitle, toTitle, opti
|
||||
* Kept for backward compatibility reasons
|
||||
*/
|
||||
exports.reportAttribute = function(parser, macro, callback, options) {
|
||||
macrocall.report(parser.context, macro, function(title, blurb) {
|
||||
callback(title, "<<" + blurb + ">>");
|
||||
macrocall.report(parser.context, macro, function(title, blurb, style) {
|
||||
callback(title, "<<" + blurb + ">>", style);
|
||||
}, options);
|
||||
};
|
||||
|
||||
@ -79,12 +77,33 @@ function getInfoFromRule(rule) {
|
||||
};
|
||||
macroInfo.params = parseParams(match[2], offset+macroInfo.start);
|
||||
}
|
||||
// post v5.3.0 changed it so name and param aren't used, but we still use
|
||||
// them. Maybe I should migrate so that I don't either, and that it's
|
||||
// orderedAttributes and $variable that I use.
|
||||
if (macroInfo.name === undefined) {
|
||||
macroInfo.name = macroInfo.attributes["$variable"].value;
|
||||
macroInfo.params = macroInfo.orderedAttributes.slice(1);
|
||||
var index = 0;
|
||||
for (var i = 0; i < macroInfo.params.length; i++) {
|
||||
var param = macroInfo.params[i];
|
||||
if (param.name === index.toString()) {
|
||||
// Swap out the param with one that doesn't have a name.
|
||||
macroInfo.params[i] = {
|
||||
start: param.start,
|
||||
end: param.end,
|
||||
type: param.type,
|
||||
value: param.value
|
||||
};
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return macroInfo;
|
||||
};
|
||||
|
||||
function mustBeAWidget(macro) {
|
||||
for (var i = 0; i < macro.params.length; i++) {
|
||||
if (macro.params[i].type === "macro") {
|
||||
if (macrocall.wrapParameterValue(macro.params[i].value) === undefined) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -95,23 +114,49 @@ function mustBeAWidget(macro) {
|
||||
* it was parsed from, returns a new macro that maintains any syntactic
|
||||
* structuring.
|
||||
*/
|
||||
function macroToString(macro, text, names, options) {
|
||||
if (mustBeAWidget(macro)) {
|
||||
var attrs = [];
|
||||
for (var i = 0; i < macro.params.length; i++) {
|
||||
var p = macro.params[i];
|
||||
var val;
|
||||
if (p.newValue) {
|
||||
val = p.newValue;
|
||||
} else {
|
||||
val = utils.wrapAttributeValue(p.value);
|
||||
}
|
||||
attrs.push(" "+names[i]+"="+val);
|
||||
function macroToString(entry, text, names, parser, options) {
|
||||
var macro = entry.output;
|
||||
if (mustBeAWidget(macro) && parser.context.allowWidgets()) {
|
||||
var widgetString = macroToWidgetString(macro, names);
|
||||
if (widgetString) {
|
||||
// It worked! return it.
|
||||
return widgetString;
|
||||
}
|
||||
return "<$macrocall $name="+utils.wrapAttributeValue(macro.name)+attrs.join('')+"/>";
|
||||
} else {
|
||||
return macrocall.reassemble(macro, text, options);
|
||||
entry.impossible = true;
|
||||
// Otherwise continue on and try macrocall anyways, despite failutes.
|
||||
}
|
||||
return macrocall.reassemble(entry, text, options);
|
||||
};
|
||||
|
||||
function macroToWidgetString(macro, names) {
|
||||
var attrs = [];
|
||||
for (var i = 0; i < macro.params.length; i++) {
|
||||
var p = macro.params[i];
|
||||
var val;
|
||||
if (p.newValue) {
|
||||
val = p.newValue;
|
||||
} else {
|
||||
val = utils.wrapAttributeValue(p.value);
|
||||
}
|
||||
if (val !== undefined) {
|
||||
var name = p.name;
|
||||
if (name === undefined) {
|
||||
if (names === undefined) {
|
||||
// Oops. We've got to give up here. We can't resolve
|
||||
// the name of one of the parameters.
|
||||
return undefined;
|
||||
} else {
|
||||
name = names[i];
|
||||
}
|
||||
}
|
||||
attrs.push(" "+name+"="+val);
|
||||
} else {
|
||||
// Oops. There's an attribute that can't be quoted. We need
|
||||
// to abort.
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
return "<$macrocall $name="+utils.wrapAttributeValue(macro.name)+attrs.join('')+"/>";
|
||||
};
|
||||
|
||||
function getParamNames(parser, macroName, params, options) {
|
||||
|
@ -1,103 +1,24 @@
|
||||
/*\
|
||||
module-type: relinkwikitextrule
|
||||
|
||||
Handles pragma macro definitions. Except we only update placeholder macros
|
||||
that we may have previously install.
|
||||
Handles pragma macro definitions.
|
||||
We may also update placeholder macros that we may have previously installed.
|
||||
|
||||
\define relink-?() Tough title
|
||||
|
||||
\*/
|
||||
|
||||
var utils = require("$:/plugins/flibbles/relink/js/utils");
|
||||
var VariableContext = utils.getContext('variable');
|
||||
// We inherit from DefRule
|
||||
var DefRule = require('./def.js');
|
||||
$tw.utils.extend(exports, DefRule);
|
||||
|
||||
exports.name = "macrodef";
|
||||
|
||||
exports.report = function(text, callback, options) {
|
||||
var setParseTreeNode = this.parse(),
|
||||
m = this.match,
|
||||
name = m[1];
|
||||
this.parser.context = new VariableContext(this.parser.context, setParseTreeNode[0]);
|
||||
// Parse set the pos pointer, but we don't want to skip the macro body.
|
||||
this.parser.pos = this.matchRegExp.lastIndex;
|
||||
var endMatch = getBodyMatch(text, this.parser.pos, m[3]);
|
||||
if (endMatch) {
|
||||
var value = endMatch[2],
|
||||
handler = utils.getType(getActiveType(name, m[2]) || 'wikitext');
|
||||
if (handler) {
|
||||
var entry = handler.report(value, function(title, blurb) {
|
||||
var macroStr = '\\define ' + name + '()';
|
||||
if (blurb) {
|
||||
macroStr += ' ' + blurb;
|
||||
}
|
||||
callback(title, macroStr);
|
||||
}, options);
|
||||
}
|
||||
this.parser.pos = endMatch.index + endMatch[0].length;
|
||||
}
|
||||
};
|
||||
|
||||
exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
var setParseTreeNode = this.parse(),
|
||||
entry,
|
||||
m = this.match,
|
||||
name = m[1],
|
||||
params = m[2],
|
||||
multiline = m[3];
|
||||
this.parser.context = new VariableContext(this.parser.context, setParseTreeNode[0]);
|
||||
// Parse set the pos pointer, but we don't want to skip the macro body.
|
||||
this.parser.pos = this.matchRegExp.lastIndex;
|
||||
var endMatch = getBodyMatch(text, this.parser.pos, multiline);
|
||||
if (endMatch) {
|
||||
var value = endMatch[2],
|
||||
type = getActiveType(name, params),
|
||||
handler = utils.getType(type || 'wikitext');
|
||||
if (handler) {
|
||||
// If this is an active relink placeholder, then let's remember it
|
||||
if (type && options.placeholder) {
|
||||
options.placeholder.registerExisting(name, value);
|
||||
}
|
||||
// Relink the contents
|
||||
entry = handler.relink(value, fromTitle, toTitle, options);
|
||||
if (entry && entry.output) {
|
||||
entry.output = m[0] + endMatch[1] + entry.output + endMatch[0];
|
||||
}
|
||||
}
|
||||
this.parser.pos = endMatch.index + endMatch[0].length;
|
||||
}
|
||||
return entry;
|
||||
};
|
||||
|
||||
// Return another match for the body, but tooled uniquely
|
||||
// m[1] = whitespace before body
|
||||
// m[2] = body
|
||||
// m.index + m[0].length -> end of match
|
||||
function getBodyMatch(text, pos, isMultiline) {
|
||||
var whitespace,
|
||||
valueRegExp;
|
||||
if (isMultiline) {
|
||||
valueRegExp = /\r?\n\\end[^\S\n\r]*(?:\r?\n|$)/mg;
|
||||
whitespace = '';
|
||||
} else {
|
||||
valueRegExp = /(?:\r?\n|$)/mg;
|
||||
var newPos = $tw.utils.skipWhiteSpace(text, pos);
|
||||
whitespace = text.substring(pos, newPos);
|
||||
pos = newPos;
|
||||
}
|
||||
valueRegExp.lastIndex = pos;
|
||||
var match = valueRegExp.exec(text);
|
||||
if (match) {
|
||||
match[1] = whitespace;
|
||||
match[2] = text.substring(pos, match.index);
|
||||
}
|
||||
return match;
|
||||
};
|
||||
|
||||
function getActiveType(macroName, parameters) {
|
||||
var placeholder = /^relink-(?:(\w+)-)?\d+$/.exec(macroName);
|
||||
// normal macro or special placeholder?
|
||||
if (placeholder && parameters === '') {
|
||||
return placeholder[1] || 'title';
|
||||
}
|
||||
return undefined;
|
||||
exports.createDefinition = function() {
|
||||
var m = this.match;
|
||||
return {
|
||||
type: "define",
|
||||
name: m[1],
|
||||
parameters: m[2],
|
||||
multiline: m[3]};
|
||||
};
|
||||
|
@ -0,0 +1,28 @@
|
||||
/*\
|
||||
module-type: relinkwikitextrule
|
||||
|
||||
Handles parameters pragma.
|
||||
|
||||
\parameters(...)
|
||||
|
||||
\*/
|
||||
|
||||
exports.name = "parameters";
|
||||
|
||||
exports.report = function(text, callback, options) {
|
||||
operate(this, options);
|
||||
};
|
||||
|
||||
exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
operate(this, options);
|
||||
};
|
||||
|
||||
function operate(rule, options) {
|
||||
var parser = rule.parser;
|
||||
var parseTreeNode = rule.parse();
|
||||
var attributes = parseTreeNode[0].orderedAttributes;
|
||||
for (var i = 0; i < attributes.length; i++) {
|
||||
var attribute = attributes[i].name;
|
||||
parser.context.addParameter(attribute);
|
||||
}
|
||||
};
|
@ -0,0 +1,3 @@
|
||||
module-type: relinkwikitextrule
|
||||
title: $:/plugins/flibbles/relink/js/relinkoperations/text/wikitext/parameters.js
|
||||
type: application/javascript
|
@ -61,8 +61,8 @@ exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
function reportCite(parser, delimeter) {
|
||||
var callback = parser.callback;
|
||||
try {
|
||||
parser.callback = function(title, blurb) {
|
||||
return callback(title, delimeter + " " + blurb);
|
||||
parser.callback = function(title, blurb, style) {
|
||||
return callback(title, delimeter + " " + blurb, style);
|
||||
};
|
||||
parser.parseInlineRun(/(\r?\n)/mg);
|
||||
} finally {
|
||||
|
@ -10,13 +10,14 @@ It takes care of providing its own relink and report rules.
|
||||
|
||||
var utils = require('$:/plugins/flibbles/relink/js/utils.js');
|
||||
var language = require('$:/plugins/flibbles/relink/js/language.js');
|
||||
var pragmaOperators = utils.getModulesByTypeAsHashmap('relinkpragma', 'name');
|
||||
|
||||
exports.name = "relink";
|
||||
exports.types = {pragma: true};
|
||||
|
||||
exports.init = function(parser) {
|
||||
this.parser = parser;
|
||||
this.matchRegExp = /^\\relink[^\S\n]+([^(\s]+)([^\r\n]*)(\r?\n)?/mg;
|
||||
this.matchRegExp = /^\\relink[^\S\r\n]+([^(\s]+)([^\r\n]*)(\r?\n)?/mg;
|
||||
};
|
||||
|
||||
/**This makes the widget that the macro library will later parse to determine
|
||||
@ -32,7 +33,7 @@ exports.parse = function() {
|
||||
var error = undefined;
|
||||
var rtn = [];
|
||||
var self = this;
|
||||
this.interpretSettings(function(macro, parameter, type) {
|
||||
interpretSettings(this, function(macro, parameter, type) {
|
||||
macroName = macro;
|
||||
if (type && !utils.getType(type)) {
|
||||
error = language.getString("text/plain", "Error/UnrecognizedType",
|
||||
@ -50,6 +51,7 @@ exports.parse = function() {
|
||||
name: {type: "string", value: ""}
|
||||
},
|
||||
children: [],
|
||||
isRelinkDefinition: true,
|
||||
isMacroDefinition: true,
|
||||
relink: relink});
|
||||
}
|
||||
@ -67,22 +69,40 @@ exports.parse = function() {
|
||||
return rtn;
|
||||
};
|
||||
|
||||
exports.report = function(text, callback, options) {
|
||||
operate(this, options);
|
||||
for (var operator in pragmaOperators) {
|
||||
pragmaOperators[operator].report(this, callback, options);
|
||||
}
|
||||
};
|
||||
|
||||
exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
var parser = this.parser;
|
||||
operate(this, options);
|
||||
var entry;
|
||||
for (var operator in pragmaOperators) {
|
||||
// Yes, this only handles one thing for now. I haven't bothered
|
||||
// breaking up \relink into a modifiable type.
|
||||
entry = pragmaOperators[operator].relink(this, fromTitle, toTitle, options);
|
||||
}
|
||||
return entry;
|
||||
};
|
||||
|
||||
function operate(rule, options) {
|
||||
var parser = rule.parser;
|
||||
var currentTiddler = parser.context.widget.variables.currentTiddler.value;
|
||||
parser.pos = this.matchRegExp.lastIndex;
|
||||
this.interpretSettings(function(macro, parameter, type) {
|
||||
parser.pos = rule.matchRegExp.lastIndex;
|
||||
interpretSettings(rule, function(macro, parameter, type) {
|
||||
options.settings.addSetting(parser.wiki, macro, parameter, type, currentTiddler);
|
||||
});
|
||||
// Return nothing, because this rule is ignored by the parser
|
||||
return undefined;
|
||||
};
|
||||
|
||||
exports.interpretSettings = function(block) {
|
||||
var paramString = this.match[2];
|
||||
function interpretSettings(rule, block) {
|
||||
var paramString = rule.match[2];
|
||||
if (paramString !== "") {
|
||||
var macro = this.match[1];
|
||||
var reParam = /\s*([A-Za-z0-9\-_]+)(?:\s*:\s*([^\s]+))?/mg;
|
||||
var macro = rule.match[1];
|
||||
var reParam = /\s*([$A-Za-z0-9\-_]+)(?:\s*:\s*([^\s]+))?/mg;
|
||||
var paramMatch = reParam.exec(paramString);
|
||||
while (paramMatch) {
|
||||
var parameter = paramMatch[1];
|
||||
|
@ -29,8 +29,8 @@ exports.report = function(text, callback, options) {
|
||||
this.parser.pos++;
|
||||
// Parse the caption
|
||||
var oldCallback = this.parser.callback;
|
||||
this.parser.callback = function(title, blurb) {
|
||||
callback(title, '|' + blurb + '|c');
|
||||
this.parser.callback = function(title, blurb, style) {
|
||||
callback(title, '|' + blurb + '|c', style);
|
||||
};
|
||||
try {
|
||||
this.parser.parseInlineRun(rowTermRegExp,{eatTerminator: true});
|
||||
@ -148,8 +148,8 @@ var processRow = function(rowType, callback) {
|
||||
// Parse the cell
|
||||
var oldCallback = this.parser.callback;
|
||||
var reports = [];
|
||||
this.parser.callback = function(title, blurb) {
|
||||
reports.push(title, blurb);
|
||||
this.parser.callback = function(title, blurb, style) {
|
||||
reports.push(title, blurb, style);
|
||||
};
|
||||
try {
|
||||
var output = this.parser.parseInlineRun(cellTermRegExp,{eatTerminator: true});
|
||||
@ -159,8 +159,8 @@ var processRow = function(rowType, callback) {
|
||||
if(this.parser.source.substr(this.parser.pos - 2,1) === " ") { // spaceRight
|
||||
suffix = ' |';
|
||||
}
|
||||
for (var i = 0; i < reports.length; i += 2) {
|
||||
callback(reports[i], prefix + reports[i+1] + suffix + rowType);
|
||||
for (var i = 0; i < reports.length; i += 3) {
|
||||
callback(reports[i], prefix + reports[i+1] + suffix + rowType, reports[i+2]);
|
||||
}
|
||||
} finally {
|
||||
this.parser.callback = oldCallback;
|
||||
|
@ -11,6 +11,7 @@ This renames both the tiddler and the template field.
|
||||
\*/
|
||||
|
||||
var refHandler = require("$:/plugins/flibbles/relink/js/fieldtypes/reference");
|
||||
var titleHandler = require("$:/plugins/flibbles/relink/js/fieldtypes/title");
|
||||
var utils = require("./utils.js");
|
||||
var relinkUtils = require('$:/plugins/flibbles/relink/js/utils.js');
|
||||
var referenceOperators = relinkUtils.getModulesByTypeAsHashmap('relinkreference', 'name');
|
||||
@ -20,20 +21,28 @@ exports.name = ['transcludeinline', 'transcludeblock'];
|
||||
exports.report = function(text, callback, options) {
|
||||
var m = this.match,
|
||||
refString = $tw.utils.trim(m[1]),
|
||||
ref = parseTextReference(refString);
|
||||
template = $tw.utils.trim(m[2]);
|
||||
ref = parseTextReference(refString),
|
||||
template = $tw.utils.trim(m[2]),
|
||||
params = m[3];
|
||||
for (var operator in referenceOperators) {
|
||||
referenceOperators[operator].report(ref, function(title, blurb) {
|
||||
referenceOperators[operator].report(ref, function(title, blurb, style) {
|
||||
blurb = blurb || "";
|
||||
if (template) {
|
||||
blurb += '||' + template;
|
||||
}
|
||||
callback(title, "{{" + blurb + "}}");
|
||||
if (params) {
|
||||
blurb += '|' + params;
|
||||
}
|
||||
callback(title, "{{" + blurb + "}}", style);
|
||||
}, options);
|
||||
}
|
||||
if (template) {
|
||||
callback(template, '{{' + refString + '||}}');
|
||||
}
|
||||
titleHandler.report(template, function(title, blurb, style) {
|
||||
var templateBlurb = refString + '||';
|
||||
if (params) {
|
||||
templateBlurb += '|' + params;
|
||||
}
|
||||
callback(template, '{{' + templateBlurb + '}}', style);
|
||||
}, options);
|
||||
this.parser.pos = this.matchRegExp.lastIndex;
|
||||
};
|
||||
|
||||
@ -41,6 +50,7 @@ exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
var m = this.match,
|
||||
reference = parseTextReference(m[1]),
|
||||
template = m[2],
|
||||
params = m[3],
|
||||
entry = undefined,
|
||||
impossible = false,
|
||||
modified = false;
|
||||
@ -57,12 +67,18 @@ exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($tw.utils.trim(template) === fromTitle) {
|
||||
template = template.replace(fromTitle, toTitle);
|
||||
modified = true;
|
||||
var templateEntry = titleHandler.relink($tw.utils.trim(template), fromTitle, toTitle, options);
|
||||
if (templateEntry) {
|
||||
if (templateEntry.impossible) {
|
||||
impossible = true;
|
||||
}
|
||||
if (templateEntry.output) {
|
||||
template = template.replace(fromTitle, toTitle);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
if (modified) {
|
||||
var output = this.makeTransclude(this.parser, reference, template);
|
||||
var output = this.makeTransclude(this.parser, reference, template, params);
|
||||
if (output) {
|
||||
// Adding any newline that might have existed is
|
||||
// what allows this relink method to work for both
|
||||
@ -82,7 +98,7 @@ exports.relink = function(text, fromTitle, toTitle, options) {
|
||||
// I have my own because the core one is deficient for my needs.
|
||||
function parseTextReference(textRef) {
|
||||
// Separate out the title, field name and/or JSON indices
|
||||
var reTextRef = /^([\w\W]*?)(?:!!(\S[\w\W]*)|##(\S[\w\W]*))?$/g;
|
||||
var reTextRef = /^([\w\W]*?)(?:!!(\S[\w\W]*)|##(\S[\w\W]*))?$/g,
|
||||
match = reTextRef.exec(textRef),
|
||||
result = {};
|
||||
if(match) {
|
||||
@ -100,7 +116,7 @@ function parseTextReference(textRef) {
|
||||
/** This converts a reference and a template into a string representation
|
||||
* of a transclude.
|
||||
*/
|
||||
exports.makeTransclude = function(parser, reference, template) {
|
||||
exports.makeTransclude = function(parser, reference, template, params) {
|
||||
var rtn;
|
||||
if (!canBePrettyTemplate(template)) {
|
||||
var widget = utils.makeWidget(parser, '$transclude', {
|
||||
@ -117,14 +133,14 @@ exports.makeTransclude = function(parser, reference, template) {
|
||||
var transclude;
|
||||
if (canBePrettyField(reference.field)) {
|
||||
var reducedRef = {field: reference.field, index: reference.index};
|
||||
transclude = prettyTransclude(reducedRef, template);
|
||||
transclude = prettyTransclude(reducedRef, template, params);
|
||||
} else {
|
||||
transclude = utils.makeWidget(parser, "$transclude", {tiddler: $tw.utils.trim(reference.title), field: reference.field});
|
||||
}
|
||||
rtn = utils.makeWidget(parser, '$tiddler', {tiddler: $tw.utils.trim(reference.title)}, transclude);
|
||||
} else {
|
||||
// This block takes care of 99% of all cases
|
||||
rtn = prettyTransclude(reference, template);
|
||||
rtn = prettyTransclude(reference, template, params);
|
||||
}
|
||||
return rtn;
|
||||
};
|
||||
@ -141,7 +157,7 @@ function canBePrettyTemplate(value) {
|
||||
return !value || (value.indexOf('}') < 0 && value.indexOf('{') < 0 && value.indexOf('|') < 0);
|
||||
};
|
||||
|
||||
function prettyTransclude(textReference, template) {
|
||||
function prettyTransclude(textReference, template, params) {
|
||||
if (typeof textReference !== "string") {
|
||||
textReference = refHandler.toString(textReference);
|
||||
}
|
||||
@ -149,8 +165,10 @@ function prettyTransclude(textReference, template) {
|
||||
textReference = '';
|
||||
}
|
||||
if (template !== undefined) {
|
||||
return "{{"+textReference+"||"+template+"}}";
|
||||
} else {
|
||||
return "{{"+textReference+"}}";
|
||||
textReference += "||" + template;
|
||||
}
|
||||
if (params) {
|
||||
textReference += "|" + params;
|
||||
}
|
||||
return "{{"+textReference+"}}";
|
||||
};
|
||||
|
@ -15,12 +15,8 @@ exports.makeWidget = function(parser, tag, attributes, body) {
|
||||
if (value !== undefined) {
|
||||
var quoted = exports.wrapAttributeValue(value);
|
||||
if (!quoted) {
|
||||
if (!parser.options.placeholder) {
|
||||
// It's not possible to make this widget
|
||||
return undefined;
|
||||
}
|
||||
var category = getPlaceholderCategory(parser.context, tag, attr);
|
||||
quoted = '<<' + parser.placeholder.getPlaceholderFor(value, category) + '>>';
|
||||
// It's not possible to make this widget
|
||||
return undefined;
|
||||
}
|
||||
string += ' ' + attr + '=' + quoted;
|
||||
}
|
||||
@ -33,23 +29,6 @@ exports.makeWidget = function(parser, tag, attributes, body) {
|
||||
return string;
|
||||
};
|
||||
|
||||
function getPlaceholderCategory(context, tag, attribute) {
|
||||
var element = context.getAttribute(tag);
|
||||
var rule = element && element[attribute];
|
||||
// titles go to relink-\d
|
||||
// plaintext goes to relink-plaintext-\d
|
||||
// because titles are way more common, also legacy
|
||||
if (rule === undefined) {
|
||||
return 'plaintext';
|
||||
} else {
|
||||
rule = rule.fields.text;
|
||||
if (rule === 'title') {
|
||||
rule = undefined;
|
||||
}
|
||||
return rule;
|
||||
}
|
||||
};
|
||||
|
||||
exports.makePrettylink = function(parser, title, caption) {
|
||||
var output;
|
||||
if (parser.context.allowPrettylinks() && canBePrettylink(title, caption)) {
|
||||
@ -65,13 +44,6 @@ exports.makePrettylink = function(parser, title, caption) {
|
||||
}
|
||||
} else if (exports.shorthandPrettylinksSupported(parser.wiki)) {
|
||||
output = exports.makeWidget(parser, '$link', {to: title});
|
||||
} else if (parser.context.allowWidgets() && parser.placeholder) {
|
||||
// If we don't have a caption, we must resort to
|
||||
// placeholders anyway to prevent link/caption desync
|
||||
// from later relinks.
|
||||
// It doesn't matter whether the tiddler is quotable.
|
||||
var ph = parser.placeholder.getPlaceholderFor(title);
|
||||
output = "<$link to=<<"+ph+">>><$text text=<<"+ph+">>/></$link>";
|
||||
}
|
||||
return output;
|
||||
};
|
||||
@ -105,6 +77,29 @@ function sanitizeCaption(parser, caption) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.containsPlaceholders = function(string) {
|
||||
// Does it contain a variable placeholder?
|
||||
if (/\$\(([^\)\$]+)\)\$/.test(string)) {
|
||||
return true;
|
||||
}
|
||||
// Does it contain a filter placeholder?
|
||||
var filterStart = string.indexOf("${");
|
||||
if (filterStart >= 0 && string.indexOf("}$", filterStart+3) >= 0) {
|
||||
return true;
|
||||
}
|
||||
// If no, then it's just a string.
|
||||
return false;
|
||||
};
|
||||
|
||||
var whitelist = ["", "'", '"', '"""'];
|
||||
var choices = {
|
||||
"": function(v) {return !/([\/\s<>"'`=])/.test(v) && v.length > 0; },
|
||||
"'": function(v) {return v.indexOf("'") < 0; },
|
||||
'"': function(v) {return v.indexOf('"') < 0; },
|
||||
'"""': function(v) {return v.indexOf('"""') < 0 && v[v.length-1] != '"';},
|
||||
};
|
||||
var _backticksSupported;
|
||||
|
||||
/**Finds an appropriate quote mark for a given value.
|
||||
*
|
||||
*Tiddlywiki doesn't have escape characters for attribute values. Instead,
|
||||
@ -115,13 +110,16 @@ function sanitizeCaption(parser, caption) {
|
||||
* return: Returns the wrapped value, or undefined if it's impossible to wrap
|
||||
*/
|
||||
exports.wrapAttributeValue = function(value, preference) {
|
||||
var whitelist = ["", "'", '"', '"""'];
|
||||
var choices = {
|
||||
"": function(v) {return !/([\/\s<>"'=])/.test(v) && v.length > 0; },
|
||||
"'": function(v) {return v.indexOf("'") < 0; },
|
||||
'"': function(v) {return v.indexOf('"') < 0; },
|
||||
'"""': function(v) {return v.indexOf('"""') < 0 && v[v.length-1] != '"';}
|
||||
};
|
||||
if (_backticksSupported === undefined) {
|
||||
var test = $tw.wiki.renderText("text/plain", "text/vnd.tiddlywiki", "<$link to=`test`/>");
|
||||
_backticksSupported = (test === "test");
|
||||
if (_backticksSupported) {
|
||||
// add in support for the backtick to the lists
|
||||
whitelist.push('`', '```');
|
||||
choices['`'] = function(v) {return v.indexOf('`') < 0 && !exports.containsPlaceholders(v); };
|
||||
choices['```'] = function(v) {return v.indexOf('```') < 0 && v[v.length-1] != '`' && !exports.containsPlaceholders(v);};
|
||||
}
|
||||
}
|
||||
if (choices[preference] && choices[preference](value)) {
|
||||
return wrap(value, preference);
|
||||
}
|
||||
@ -141,7 +139,9 @@ function wrap(value, wrapper) {
|
||||
"'": function(v) {return "'"+v+"'"; },
|
||||
'"': function(v) {return '"'+v+'"'; },
|
||||
'"""': function(v) {return '"""'+v+'"""'; },
|
||||
"[[": function(v) {return "[["+v+"]]"; }
|
||||
"[[": function(v) {return "[["+v+"]]"; },
|
||||
"`": function(v) {return '`'+v+'`'; },
|
||||
'```': function(v) {return '```'+v+'```'; }
|
||||
};
|
||||
var chosen = wrappers[wrapper];
|
||||
if (chosen) {
|
||||
|
@ -0,0 +1,13 @@
|
||||
/*\
|
||||
module-type: relinkwikitextrule
|
||||
|
||||
Handles whitespace pragma
|
||||
|
||||
\*/
|
||||
|
||||
exports.name = "whitespace";
|
||||
|
||||
// We don't actually do anything, but we can't rely on
|
||||
// the default behavior of moving to parser.pos.
|
||||
// we have to forward past all the whitespace tokens.
|
||||
exports.relink = exports.report = function() { this.parse(); }
|
@ -0,0 +1,3 @@
|
||||
module-type: relinkwikitextrule
|
||||
title: $:/plugins/flibbles/relink/js/relinkoperations/text/wikitext/whitespace.js
|
||||
type: application/javascript
|
@ -12,10 +12,6 @@ exports.generate = function(attributes, tiddler, key) {
|
||||
var data = utils.getType(tiddler.fields.text.trim());
|
||||
if (data) {
|
||||
data.source = tiddler.fields.title;
|
||||
// Secret feature. You can access a config tiddler's
|
||||
// fields from inside the fieldtype handler. Cool
|
||||
// tricks can be done with this.
|
||||
data.fields = tiddler.fields;
|
||||
var elem = root(key);
|
||||
var attr = key.substr(elem.length+1);
|
||||
attributes[elem] = attributes[elem] || Object.create(null);
|
||||
|
@ -0,0 +1,17 @@
|
||||
/*\
|
||||
|
||||
Factory method for specifying system tiddlers which should not be treated
|
||||
as text/vnd.tiddlywiki types, but for whatever reason, they don't specify
|
||||
the type they really are. Sort of like how $:/DefaultTiddlers is actually
|
||||
a filter.
|
||||
|
||||
\*/
|
||||
|
||||
exports.name = "exceptions";
|
||||
|
||||
exports.generate = function(exceptions, tiddler, title) {
|
||||
var tiddlerType = tiddler.fields.text.trim();
|
||||
if (tiddlerType) {
|
||||
exceptions[title] = tiddlerType;
|
||||
}
|
||||
};
|
@ -0,0 +1,4 @@
|
||||
module-type: relinksetting
|
||||
the type they really are. Sort of like how $: /DefaultTiddlers is actually
|
||||
title: $:/plugins/flibbles/relink/js/settings/exceptions.js
|
||||
type: application/javascript
|
@ -12,10 +12,6 @@ exports.generate = function(fields, tiddler, name) {
|
||||
var data = utils.getType(tiddler.fields.text.trim());
|
||||
if (data) {
|
||||
data.source = tiddler.fields.title;
|
||||
// Secret feature. You can access a config tiddler's
|
||||
// fields from inside the fieldtype handler. Cool
|
||||
// tricks can be done with this.
|
||||
data.fields = tiddler.fields;
|
||||
fields[name] = data;
|
||||
}
|
||||
};
|
||||
|
@ -12,10 +12,6 @@ exports.generate = function(macros, tiddler, key) {
|
||||
var data = utils.getType(tiddler.fields.text.trim());
|
||||
if (data) {
|
||||
data.source = tiddler.fields.title;
|
||||
// Secret feature. You can access a config tiddler's
|
||||
// fields from inside the fieldtype handler. Cool
|
||||
// tricks can be done with this.
|
||||
data.fields = tiddler.fields;
|
||||
// We take the last index, not the first, because macro
|
||||
// parameters can't have slashes, but macroNames can.
|
||||
var name = dir(key);
|
||||
@ -33,4 +29,3 @@ function dir(string) {
|
||||
return string.substr(0, index);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,11 @@
|
||||
/*\
|
||||
|
||||
Factory method for creating the message regexp cache.
|
||||
|
||||
\*/
|
||||
|
||||
exports.name = "messages";
|
||||
|
||||
exports.generate = function(messages, tiddler, key) {
|
||||
messages[key] = new RegExp(tiddler.fields.text.trim());
|
||||
};
|
@ -0,0 +1,3 @@
|
||||
module-type: relinksetting
|
||||
title: $:/plugins/flibbles/relink/js/settings/messages.js
|
||||
type: application/javascript
|
@ -12,10 +12,6 @@ exports.generate = function(operators, tiddler, key) {
|
||||
var data = utils.getType(tiddler.fields.text.trim());
|
||||
if (data) {
|
||||
data.source = tiddler.fields.title;
|
||||
// Secret feature. You can access a config tiddler's
|
||||
// fields from inside the fieldtype handler. Cool
|
||||
// tricks can be done with this.
|
||||
data.fields = tiddler.fields;
|
||||
var pair = key.split('/');
|
||||
var name = pair[0];
|
||||
data.key = key;
|
||||
|
@ -5,7 +5,7 @@ Utility methods for relink.
|
||||
|
||||
\*/
|
||||
|
||||
var macroFilter = "[[$:/core/ui/PageMacros]] [all[shadows+tiddlers]tag[$:/tags/Macro]!has[draft.of]]";
|
||||
var macroFilter = "[[$:/core/ui/PageMacros]] [all[shadows+tiddlers]tag[$:/tags/Macro]!has[draft.of]] [all[shadows+tiddlers]tag[$:/tags/Global]!has[draft.of]]";
|
||||
|
||||
/**This works nearly identically to $tw.modules.getModulesByTypeAsHashmap
|
||||
* except that this also takes care of migrating V1 relink modules.
|
||||
@ -25,7 +25,27 @@ exports.getModulesByTypeAsHashmap = function(moduleType, nameField) {
|
||||
}
|
||||
}
|
||||
});
|
||||
return results;
|
||||
// We've got to sort these so that behavior is consistent across different
|
||||
// versions of TiddlyMap, whose module return order depends on version...
|
||||
return sortModules(results);
|
||||
};
|
||||
|
||||
function sortModules(moduleMap) {
|
||||
var keys = Object.keys(moduleMap);
|
||||
var sortedResults = Object.create(null);
|
||||
keys.sort();
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var key = keys[i];
|
||||
if (moduleMap[key].after
|
||||
&& moduleMap[key].after.some(function(requirement) { return !sortedResults[requirement]})) {
|
||||
// Not all requirements have been met yet.
|
||||
$tw.utils.pushTop(keys, key);
|
||||
i--;
|
||||
} else {
|
||||
sortedResults[key] = moduleMap[key];
|
||||
}
|
||||
}
|
||||
return sortedResults;
|
||||
};
|
||||
|
||||
exports.getTiddlerRelinkReferences = function(wiki, title, context) {
|
||||
@ -35,9 +55,9 @@ exports.getTiddlerRelinkReferences = function(wiki, title, context) {
|
||||
if (tiddler) {
|
||||
try {
|
||||
for (var relinker in getRelinkOperators()) {
|
||||
getRelinkOperators()[relinker].report(tiddler, function(title, blurb) {
|
||||
getRelinkOperators()[relinker].report(tiddler, function(title, blurb, style) {
|
||||
references[title] = references[title] || [];
|
||||
references[title].push(blurb || '');
|
||||
references[title].push($tw.utils.extend({blurb: blurb || ''}, style));
|
||||
}, options);
|
||||
}
|
||||
} catch (e) {
|
||||
@ -160,6 +180,18 @@ exports.getDefaultType = function(wiki) {
|
||||
return fieldTypes[defaultType] ? defaultType : "title";
|
||||
};
|
||||
|
||||
exports.abridgeString = function(string, maxLength, truncLength) {
|
||||
if (typeof string === "string") {
|
||||
maxLength = maxLength || 3;
|
||||
if (truncLength === undefined) {
|
||||
truncLength = maxLength-3;
|
||||
}
|
||||
string = string.replace(/\s+/g, " ").trim();
|
||||
return (string.length > maxLength)? string.substr(0, truncLength) + "..." : string;
|
||||
}
|
||||
return string;
|
||||
};
|
||||
|
||||
exports.touchModifyField = function(wiki) {
|
||||
var tiddler = wiki.getTiddler("$:/config/flibbles/relink/touch-modify");
|
||||
return tiddler && tiddler.fields.text.trim() === "yes";
|
||||
|
@ -6,45 +6,13 @@ Methods for reporting and relinking macros. Behaves much like a fieldtype, excep
|
||||
|
||||
var utils = require('$:/plugins/flibbles/relink/js/utils.js');
|
||||
var Rebuilder = require("$:/plugins/flibbles/relink/js/utils/rebuilder");
|
||||
|
||||
// Error thrown when a macro's definition is needed, but can't be found.
|
||||
function CannotFindMacroDef() {};
|
||||
CannotFindMacroDef.prototype.impossible = true;
|
||||
CannotFindMacroDef.prototype.name = "macroparam";
|
||||
// Failed relinks due to missing definitions aren't reported for now.
|
||||
// I may want to do something special later on.
|
||||
CannotFindMacroDef.prototype.report = function() { return []; };
|
||||
var macrocallOperators = utils.getModulesByTypeAsHashmap('relinkmacrocall', 'name');
|
||||
|
||||
/** As in, report a macrocall invocation that is an html attribute.
|
||||
* macro: must be a macro object.*/
|
||||
exports.report = function(context, macro, callback, options) {
|
||||
var managedMacro = context.getMacro(macro.name);
|
||||
if (!managedMacro) {
|
||||
// We don't manage this macro. Bye.
|
||||
return undefined;
|
||||
}
|
||||
for (var managedArg in managedMacro) {
|
||||
var index;
|
||||
try {
|
||||
index = getParamIndexWithinMacrocall(context, macro.name, managedArg, macro.params, options);
|
||||
} catch (e) {
|
||||
continue;
|
||||
}
|
||||
if (index < 0) {
|
||||
// The argument was not supplied. Move on to next.
|
||||
continue;
|
||||
}
|
||||
var param = macro.params[index];
|
||||
var handler = managedMacro[managedArg];
|
||||
var nestedOptions = Object.create(options);
|
||||
nestedOptions.settings = context;
|
||||
var entry = handler.report(param.value, function(title, blurb) {
|
||||
var rtn = managedArg;
|
||||
if (blurb) {
|
||||
rtn += ': "' + blurb + '"';
|
||||
}
|
||||
callback(title, macro.name + ' ' + rtn);
|
||||
}, nestedOptions);
|
||||
for (var operator in macrocallOperators) {
|
||||
macrocallOperators[operator].report(context, macro, callback, options);
|
||||
}
|
||||
};
|
||||
|
||||
@ -57,171 +25,59 @@ exports.report = function(context, macro, callback, options) {
|
||||
* to be converted.
|
||||
*/
|
||||
exports.relink = function(context, macro, text, fromTitle, toTitle, mayBeWidget, options) {
|
||||
var managedMacro = context.getMacro(macro.name);
|
||||
var modified = false;
|
||||
if (!managedMacro) {
|
||||
// We don't manage this macro. Bye.
|
||||
return undefined;
|
||||
}
|
||||
var outMacro = $tw.utils.extend({}, macro);
|
||||
var macroEntry = {};
|
||||
outMacro.params = macro.params.slice();
|
||||
for (var managedArg in managedMacro) {
|
||||
var index;
|
||||
try {
|
||||
index = getParamIndexWithinMacrocall(context, macro.name, managedArg, macro.params, options);
|
||||
} catch (e) {
|
||||
if (e instanceof CannotFindMacroDef) {
|
||||
macroEntry.impossible = true;
|
||||
continue;
|
||||
var entry;
|
||||
for (var operator in macrocallOperators) {
|
||||
var results = macrocallOperators[operator].relink(context, macro, text, fromTitle, toTitle, options);
|
||||
if (results) {
|
||||
entry = entry || {};
|
||||
if (results.impossible) {
|
||||
entry.impossible = true;
|
||||
}
|
||||
if (results.output) {
|
||||
macro = results.output;
|
||||
entry.output = macro;
|
||||
}
|
||||
}
|
||||
if (index < 0) {
|
||||
// this arg either was not supplied, or we can't find
|
||||
// the definition, so we can't tie it to an anonymous
|
||||
// argument. Either way, move on to the next.
|
||||
continue;
|
||||
}
|
||||
var param = macro.params[index];
|
||||
var handler = managedMacro[managedArg];
|
||||
var nestedOptions = Object.create(options);
|
||||
nestedOptions.settings = context;
|
||||
var entry = handler.relink(param.value, fromTitle, toTitle, nestedOptions);
|
||||
if (entry === undefined) {
|
||||
continue;
|
||||
}
|
||||
// Macro parameters can only be string parameters, not
|
||||
// indirect, or macro, or filtered
|
||||
if (entry.impossible) {
|
||||
macroEntry.impossible = true;
|
||||
}
|
||||
if (!entry.output) {
|
||||
continue;
|
||||
}
|
||||
var quote = utils.determineQuote(text, param);
|
||||
var quoted = wrapParameterValue(entry.output, quote);
|
||||
var newParam = $tw.utils.extend({}, param);
|
||||
if (quoted === undefined) {
|
||||
if (!mayBeWidget || !options.placeholder) {
|
||||
macroEntry.impossible = true;
|
||||
continue;
|
||||
}
|
||||
var ph = options.placeholder.getPlaceholderFor(entry.output,handler.name);
|
||||
newParam.newValue = "<<"+ph+">>";
|
||||
newParam.type = "macro";
|
||||
} else {
|
||||
newParam.start = newParam.end - (newParam.value.length + (quote.length*2));
|
||||
newParam.value = entry.output;
|
||||
newParam.newValue = quoted;
|
||||
}
|
||||
outMacro.params[index] = newParam;
|
||||
modified = true;
|
||||
}
|
||||
if (modified || macroEntry.impossible) {
|
||||
if (modified) {
|
||||
macroEntry.output = outMacro;
|
||||
}
|
||||
return macroEntry;
|
||||
}
|
||||
return undefined;
|
||||
return entry;
|
||||
};
|
||||
|
||||
/**Converts the macro object into a string, includes the <<..>>.
|
||||
* The text is the old text the macro was formed from. It's used to preserve
|
||||
* whitespace.
|
||||
*/
|
||||
exports.reassemble = function(macro, text, options) {
|
||||
exports.reassemble = function(entry, text, options) {
|
||||
var macro = entry.output;
|
||||
var builder = new Rebuilder(text, macro.start);
|
||||
var varAttribute = macro.attributes && macro.attributes['$variable'];
|
||||
if (varAttribute && varAttribute.value !== macro.name) {
|
||||
// The name of the macro changed. Update it.
|
||||
builder.add(varAttribute.value, macro.start + 2, macro.start + 2 + macro.name.length);
|
||||
}
|
||||
for (var i = 0; i < macro.params.length; i++) {
|
||||
var param = macro.params[i];
|
||||
if (param.newValue) {
|
||||
builder.add(param.newValue, param.start, param.end);
|
||||
if (param.modified) {
|
||||
var newValue = exports.wrapParameterValue(param.value, param.quote);
|
||||
if (newValue === undefined) {
|
||||
entry.impossible = true;
|
||||
} else {
|
||||
builder.add(newValue, param.start, param.end);
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder.results(macro.end);
|
||||
};
|
||||
|
||||
|
||||
/** Returns -1 if param definitely isn't in macrocall.
|
||||
*/
|
||||
function getParamIndexWithinMacrocall(context, macroName, param, params, options) {
|
||||
var index, i, anonsExist = false;
|
||||
for (i = 0; i < params.length; i++) {
|
||||
var name = params[i].name;
|
||||
if (name === param) {
|
||||
return i;
|
||||
}
|
||||
if (name === undefined) {
|
||||
anonsExist = true;
|
||||
}
|
||||
}
|
||||
if (!anonsExist) {
|
||||
// If no anonymous parameters are present, and we didn't find
|
||||
// it among the named ones, it must not be there.
|
||||
return -1;
|
||||
}
|
||||
var expectedIndex = indexOfParameterDef(context, macroName, param, options);
|
||||
// We've got to skip over all the named parameter instances.
|
||||
if (expectedIndex >= 0) {
|
||||
var anonI = 0;
|
||||
for (i = 0; i < params.length; i++) {
|
||||
if (params[i].name === undefined) {
|
||||
if (anonI === expectedIndex) {
|
||||
return i;
|
||||
}
|
||||
anonI++;
|
||||
} else {
|
||||
var indexOfOther = indexOfParameterDef(context, macroName, params[i].name, options);
|
||||
if (indexOfOther < expectedIndex) {
|
||||
anonI++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
// Looks up the definition of a macro, and figures out what the expected index
|
||||
// is for the given parameter.
|
||||
function indexOfParameterDef(context, macroName, paramName, options) {
|
||||
var def = context.getMacroDefinition(macroName);
|
||||
if (def === undefined) {
|
||||
throw new CannotFindMacroDef();
|
||||
}
|
||||
var params = def.params || [];
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
if (params[i].name === paramName) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
// Looks up the definition of a macro, and figures out what the expected index
|
||||
// is for the given parameter.
|
||||
function indexOfParameterDef(context, macroName, paramName, options) {
|
||||
var def = context.getMacroDefinition(macroName);
|
||||
if (def === undefined) {
|
||||
throw new CannotFindMacroDef();
|
||||
}
|
||||
var params = def.params || [];
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
if (params[i].name === paramName) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
/**Like wrapAttribute value, except for macro parameters, not attributes.
|
||||
*
|
||||
* These are more permissive. Allows brackets,
|
||||
* and slashes and '<' in unquoted values.
|
||||
*/
|
||||
function wrapParameterValue(value, preference) {
|
||||
exports.wrapParameterValue = function(value, preference) {
|
||||
var whitelist = ["", "'", '"', '[[', '"""'];
|
||||
var choices = {
|
||||
"": function(v) {return !/([\s>"'=])/.test(v); },
|
||||
"": function(v) {return !/([\s>"':])/.test(v); },
|
||||
"'": function(v) {return v.indexOf("'") < 0; },
|
||||
'"': function(v) {return v.indexOf('"') < 0; },
|
||||
"[[": canBePrettyOperand,
|
||||
|
@ -0,0 +1,158 @@
|
||||
var utils = require('$:/plugins/flibbles/relink/js/utils.js');
|
||||
|
||||
exports.name = "parameters";
|
||||
|
||||
// Error thrown when a macro's definition is needed, but can't be found.
|
||||
function CannotFindMacroDef() {};
|
||||
CannotFindMacroDef.prototype.impossible = true;
|
||||
CannotFindMacroDef.prototype.name = "macroparam";
|
||||
// Failed relinks due to missing definitions aren't reported for now.
|
||||
// I may want to do something special later on.
|
||||
CannotFindMacroDef.prototype.report = function() { return []; };
|
||||
|
||||
exports.report = function(context, macro, callback, options) {
|
||||
var managedMacro = context.getMacro(macro.name);
|
||||
if (!managedMacro) {
|
||||
// We don't manage this macro. Bye.
|
||||
return undefined;
|
||||
}
|
||||
for (var managedArg in managedMacro) {
|
||||
var index;
|
||||
try {
|
||||
index = getParamIndexWithinMacrocall(context, macro.name, managedArg, macro.params, options);
|
||||
} catch (e) {
|
||||
continue;
|
||||
}
|
||||
if (index < 0) {
|
||||
// The argument was not supplied. Move on to next.
|
||||
continue;
|
||||
}
|
||||
var param = macro.params[index];
|
||||
var handler = managedMacro[managedArg];
|
||||
var nestedOptions = Object.create(options);
|
||||
nestedOptions.settings = context;
|
||||
var entry = handler.report(param.value, function(title, blurb, style) {
|
||||
var rtn = managedArg;
|
||||
if (blurb) {
|
||||
rtn += ': "' + blurb + '"';
|
||||
}
|
||||
callback(title, macro.name + ' ' + rtn, style);
|
||||
}, nestedOptions);
|
||||
}
|
||||
};
|
||||
|
||||
exports.relink = function(context, macro, text, fromTitle, toTitle, options) {
|
||||
var managedMacro = context.getMacro(macro.name);
|
||||
var modified = false;
|
||||
if (!managedMacro) {
|
||||
// We don't manage this macro. Bye.
|
||||
return undefined;
|
||||
}
|
||||
var outMacro = $tw.utils.extend({}, macro);
|
||||
var macroEntry = {};
|
||||
outMacro.params = macro.params.slice();
|
||||
for (var managedArg in managedMacro) {
|
||||
var index;
|
||||
try {
|
||||
index = getParamIndexWithinMacrocall(context, macro.name, managedArg, macro.params, options);
|
||||
} catch (e) {
|
||||
if (e instanceof CannotFindMacroDef) {
|
||||
macroEntry.impossible = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (index < 0) {
|
||||
// this arg either was not supplied, or we can't find
|
||||
// the definition, so we can't tie it to an anonymous
|
||||
// argument. Either way, move on to the next.
|
||||
continue;
|
||||
}
|
||||
var param = macro.params[index];
|
||||
var handler = managedMacro[managedArg];
|
||||
var nestedOptions = Object.create(options);
|
||||
nestedOptions.settings = context;
|
||||
var entry = handler.relink(param.value, fromTitle, toTitle, nestedOptions);
|
||||
if (entry === undefined) {
|
||||
continue;
|
||||
}
|
||||
// Macro parameters can only be string parameters, not
|
||||
// indirect, or macro, or filtered
|
||||
if (entry.impossible) {
|
||||
macroEntry.impossible = true;
|
||||
}
|
||||
if (!entry.output) {
|
||||
continue;
|
||||
}
|
||||
var quote = utils.determineQuote(text, param);
|
||||
var newParam = $tw.utils.extend({}, param);
|
||||
newParam.start = newParam.end - (newParam.value.length + (quote.length*2));
|
||||
newParam.value = entry.output;
|
||||
newParam.quote = quote;
|
||||
newParam.modified = true;
|
||||
outMacro.params[index] = newParam;
|
||||
modified = true;
|
||||
}
|
||||
if (modified || macroEntry.impossible) {
|
||||
if (modified) {
|
||||
macroEntry.output = outMacro;
|
||||
}
|
||||
return macroEntry;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
/** Returns -1 if param definitely isn't in macrocall.
|
||||
*/
|
||||
function getParamIndexWithinMacrocall(context, macroName, param, params, options) {
|
||||
var index, i, anonsExist = false;
|
||||
for (i = 0; i < params.length; i++) {
|
||||
var name = params[i].name;
|
||||
if (name === param) {
|
||||
return i;
|
||||
}
|
||||
if (name === undefined) {
|
||||
anonsExist = true;
|
||||
}
|
||||
}
|
||||
if (!anonsExist) {
|
||||
// If no anonymous parameters are present, and we didn't find
|
||||
// it among the named ones, it must not be there.
|
||||
return -1;
|
||||
}
|
||||
var expectedIndex = indexOfParameterDef(context, macroName, param, options);
|
||||
// We've got to skip over all the named parameter instances.
|
||||
if (expectedIndex >= 0) {
|
||||
var anonI = 0;
|
||||
for (i = 0; i < params.length; i++) {
|
||||
if (params[i].name === undefined) {
|
||||
if (anonI === expectedIndex) {
|
||||
return i;
|
||||
}
|
||||
anonI++;
|
||||
} else {
|
||||
var indexOfOther = indexOfParameterDef(context, macroName, params[i].name, options);
|
||||
if (indexOfOther < expectedIndex) {
|
||||
anonI++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
// Looks up the definition of a macro, and figures out what the expected index
|
||||
// is for the given parameter.
|
||||
function indexOfParameterDef(context, macroName, paramName, options) {
|
||||
var def = context.getMacroDefinition(macroName);
|
||||
if (def === undefined) {
|
||||
throw new CannotFindMacroDef();
|
||||
}
|
||||
var params = def.params || [];
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
if (params[i].name === paramName) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
@ -0,0 +1,3 @@
|
||||
module-type: relinkmacrocall
|
||||
title: $:/plugins/flibbles/relink/js/utils/macrocall/parameters.js
|
||||
type: application/javascript
|
@ -1,61 +0,0 @@
|
||||
/*\
|
||||
|
||||
A method which doles out placeholders when requested, and constructs
|
||||
the necessary supporting pragma when requested.
|
||||
|
||||
\*/
|
||||
|
||||
var utils = require('../utils');
|
||||
|
||||
function Placeholder() {
|
||||
this.placeholders = Object.create(null);
|
||||
this.reverseMap = {};
|
||||
this.used = Object.create(null);
|
||||
};
|
||||
|
||||
module.exports = Placeholder;
|
||||
|
||||
Placeholder.prototype.getPlaceholderFor = function(value, category) {
|
||||
this.reverseMap[category] = this.reverseMap[category] || Object.create(null);
|
||||
var placeholder = this.reverseMap[category][value];
|
||||
if (placeholder) {
|
||||
return placeholder;
|
||||
}
|
||||
var config = (this.parser && this.parser.context) || utils.getWikiContext(this.parser.wiki);
|
||||
var number = 0;
|
||||
var prefix = "relink-"
|
||||
if (category && category !== "title") {
|
||||
// I don't like "relink-title-1". "relink-1" should be for
|
||||
// titles. lists, and filters can have descriptors though.
|
||||
prefix += category + "-";
|
||||
}
|
||||
do {
|
||||
number += 1;
|
||||
placeholder = prefix + number;
|
||||
} while (config.getMacroDefinition(placeholder) || this.used[placeholder]);
|
||||
this.placeholders[placeholder] = value;
|
||||
this.reverseMap[category][value] = placeholder;
|
||||
this.used[placeholder] = true;
|
||||
return placeholder;
|
||||
};
|
||||
|
||||
// For registering placeholders that already existed
|
||||
Placeholder.prototype.registerExisting = function(key, value) {
|
||||
this.reverseMap[value] = key;
|
||||
this.used[key] = true;
|
||||
};
|
||||
|
||||
Placeholder.prototype.getPreamble = function() {
|
||||
var results = [];
|
||||
var keys = Object.keys(this.placeholders);
|
||||
if (keys.length > 0) {
|
||||
keys.sort();
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var name = keys[i];
|
||||
var val = this.placeholders[name];
|
||||
results.push("\\define "+name+"() "+val+"\n");
|
||||
}
|
||||
}
|
||||
return results.join('');
|
||||
};
|
||||
|
@ -1,3 +0,0 @@
|
||||
module-type: library
|
||||
title: $:/plugins/flibbles/relink/js/utils/placeholder.js
|
||||
type: application/javascript
|
@ -0,0 +1,76 @@
|
||||
/*\
|
||||
|
||||
Handles relinking substitution text, like strings containing $(this)$.
|
||||
|
||||
\*/
|
||||
|
||||
var utils = require('$:/plugins/flibbles/relink/js/utils.js');
|
||||
var filterHandler = utils.getType('filter');
|
||||
var macrocallHandler = require("./macrocall.js");
|
||||
|
||||
exports.report = function(string, callback, options) {
|
||||
if (!options.noFilterSubstitution) {
|
||||
var filterRegex = /\$\{([\S\s]+?)\}\$/g, filter;
|
||||
while (filter = filterRegex.exec(string)) {
|
||||
filterHandler.report(filter[1], function(title, blurb, style) {
|
||||
callback(title, '${' + blurb + '}$', style);
|
||||
}, options);
|
||||
}
|
||||
}
|
||||
var varRegex = /\$\(([^\)\$]+)\)\$/g, varMatch;
|
||||
while (varMatch = varRegex.exec(string)) {
|
||||
macrocallHandler.report(options.settings, {name: varMatch[1], params: []}, function(title, blurb, style) {
|
||||
callback(title, '$(' + blurb + ')$', style);
|
||||
}, options);
|
||||
}
|
||||
};
|
||||
|
||||
exports.relink = function(string, fromTitle, toTitle, options) {
|
||||
var entry;
|
||||
var changed = false;
|
||||
var newValue = string;
|
||||
if (!options.noFilterSubstitution) {
|
||||
newValue = newValue.replace(/\$\{([\S\s]+?)\}\$/g, function(match, filter) {
|
||||
var filterEntry = filterHandler.relink(filter, fromTitle, toTitle, options);
|
||||
if (filterEntry) {
|
||||
entry = entry || {};
|
||||
if (filterEntry.output) {
|
||||
// The only }$ should be the one at the very end
|
||||
if (filterEntry.output.indexOf("}$") < 0) {
|
||||
changed = true;
|
||||
match = '${' + filterEntry.output + '}$';
|
||||
} else {
|
||||
entry.impossible = true;
|
||||
}
|
||||
}
|
||||
if (filterEntry.impossible) {
|
||||
entry.impossible = true;
|
||||
}
|
||||
}
|
||||
return match;
|
||||
});
|
||||
}
|
||||
newValue = newValue.replace(/\$\(([^\)\$]+)\)\$/g, function(match, varname) {
|
||||
var macroEntry = macrocallHandler.relink(options.settings, {name: varname, params: []}, string, fromTitle, toTitle, false, options);
|
||||
if (macroEntry) {
|
||||
entry = entry || {};
|
||||
if (macroEntry.output) {
|
||||
var newTitle = macroEntry.output.attributes.$variable.value;
|
||||
if (newTitle.indexOf('$') >= 0 || newTitle.indexOf(')') >= 0) {
|
||||
entry.impossible = true;
|
||||
} else {
|
||||
changed = true;
|
||||
match = '$(' + newTitle + ')$';
|
||||
}
|
||||
}
|
||||
if (macroEntry.impossible) {
|
||||
entry.impossible = true;
|
||||
}
|
||||
}
|
||||
return match;
|
||||
});
|
||||
if (changed) {
|
||||
entry.output = newValue;
|
||||
}
|
||||
return entry;
|
||||
};
|
@ -0,0 +1,3 @@
|
||||
module-type: library
|
||||
title: $:/plugins/flibbles/relink/js/utils/substitution.js
|
||||
type: application/javascript
|
@ -7,12 +7,16 @@ Introduces some utility methods used by Relink.
|
||||
|
||||
var utils = require("./utils.js");
|
||||
|
||||
exports.getTiddlerRelinkReferences = function(title) {
|
||||
return utils.getIndexer(this).lookup(title);
|
||||
exports.getTiddlerRelinkReferences = function(title, options) {
|
||||
var refs = utils.getIndexer(this).lookup(title);
|
||||
return refs && blurbs(refs, options && options.hard);
|
||||
};
|
||||
|
||||
exports.getTiddlerRelinkBackreferences = function(title) {
|
||||
return utils.getIndexer(this).reverseLookup(title);
|
||||
var refs = utils.getIndexer(this).reverseLookup(title);
|
||||
// For now, I don't have the equivalent "hard" option because I'm not
|
||||
// sure it has any value. May change this later.
|
||||
return blurbs(refs);
|
||||
};
|
||||
|
||||
exports.getRelinkableTitles = function() {
|
||||
@ -28,6 +32,20 @@ exports.getRelinkableTitles = function() {
|
||||
})();
|
||||
};
|
||||
|
||||
exports.getRelinkOrphans = function() {
|
||||
return utils.getIndexer(this).orphans();
|
||||
exports.getRelinkOrphans = function(options) {
|
||||
return utils.getIndexer(this).orphans(options);
|
||||
};
|
||||
|
||||
function blurbs(refs, hardOnly) {
|
||||
var blurbsOnly = Object.create(null);
|
||||
for (var title in refs) {
|
||||
for (var i = 0; i < refs[title].length; i++) {
|
||||
var record = refs[title][i];
|
||||
if (!hardOnly || !record.soft) {
|
||||
blurbsOnly[title] = blurbsOnly[title] || [];
|
||||
blurbsOnly[title].push(record.blurb);
|
||||
}
|
||||
}
|
||||
}
|
||||
return blurbsOnly;
|
||||
};
|
||||
|
@ -10,6 +10,8 @@ title: $:/plugins/flibbles/relink/ui/TiddlerInfo/References
|
||||
</$list>
|
||||
<table class="tc-relink-references-table">
|
||||
<tbody>
|
||||
<$vars toTitle='' >
|
||||
<$list filter=<<filter>> emptyMessage=<<lingo References/Empty>> variable="listItem" template="$:/plugins/flibbles/relink/ui/TiddlerInfo/ReferencesTemplate" />
|
||||
</$vars>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -2,14 +2,19 @@ title: $:/plugins/flibbles/relink/ui/TiddlerInfo/ReferencesTemplate
|
||||
|
||||
\whitespace trim
|
||||
<tr class="tc-relink-references">
|
||||
<td class="tc-relink-references-title">
|
||||
<$link to=<<listItem>>/>
|
||||
<td class={{{ tc-relink-references-title [<toTitle>!match[]then<listItem>relink:impossible<toTitle>then[tc-relink-impossible]] +[join[ ]] }}} >
|
||||
<$list
|
||||
variable=whitelist
|
||||
filter="[<listItem>removeprefix[$:/config/flibbles/relink/]split[/]first[]titlecase[]addprefix[$:/plugins/flibbles/relink/ui/configuration/]]"
|
||||
emptyMessage="<$link to=<<listItem>>/>" >
|
||||
<$link to=<<whitelist>>>
|
||||
''//Relink// whitelist''
|
||||
</$link>
|
||||
</$list>
|
||||
</td>
|
||||
<td class="tc-relink-references-report">
|
||||
<$list filter="[<listItem>relink:report<currentTiddler>]">
|
||||
<$list filter="[<listItem>relink:report<currentTiddler>]">
|
||||
|
||||
<$text text=<<currentTiddler>> />
|
||||
</$list>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<$text text=<<currentTiddler>> />
|
||||
</$list>
|
||||
</td></tr>
|
||||
|
@ -4,7 +4,7 @@ title: $:/plugins/flibbles/relink/ui/components/tables
|
||||
\whitespace trim
|
||||
|
||||
<$list variable="render" filter="[relink:signatures<__plugin__>prefix<__category__>first[]]">
|
||||
<$set name="table-state" value=<<qualify """$:/state/flibbles/relink/tables/$title$""">>>
|
||||
<$vars table-state=<<qualify """$:/state/flibbles/relink/tables/$plugin$""">>>
|
||||
<tr><th class="tc-relink-header-plugin" colspan=<<column-count>> >
|
||||
<$reveal type="nomatch" state=<<table-state>> text="yes" default="""$default-table-state$""">
|
||||
<$button class="tc-btn-invisible tc-btn-dropdown" set=<<table-state>> setTo="yes">
|
||||
@ -30,7 +30,7 @@ title: $:/plugins/flibbles/relink/ui/components/tables
|
||||
</$tiddler>
|
||||
</$vars>
|
||||
</$list>
|
||||
</$set>
|
||||
</$vars>
|
||||
</$list>
|
||||
\end
|
||||
|
||||
@ -48,7 +48,10 @@ title: $:/plugins/flibbles/relink/ui/components/tables
|
||||
|
||||
<$list
|
||||
filter="[plugin-type[plugin]![$:/core]![$:/plugins/flibbles/relink]]">
|
||||
<$set name="subtitle" filter="[all[current]has[description]]" value="''{{!!name}}'': <$text text={{!!description}}/>" emptyValue="''{{!!name}}''" >
|
||||
<$set name="subtitle"
|
||||
filter="[all[current]has[description]]"
|
||||
value="''{{!!name}}'': <$text text={{!!description}}/>"
|
||||
emptyValue="''{{!!name}}''" >
|
||||
<$macrocall $name=".make-table" title=<<subtitle>> plugin=<<currentTiddler>> />
|
||||
</$set>
|
||||
</$list>
|
||||
|
@ -62,11 +62,14 @@ title: $:/plugins/flibbles/relink/ui/configuration/Attributes
|
||||
<$text text={{$(lingo-base)$NewAttribute/Caption}}/>
|
||||
</$button>
|
||||
</$reveal>
|
||||
|
||||
@@.tc-control-panel
|
||||
<$macrocall
|
||||
$name=tables
|
||||
category="attributes"
|
||||
header-list="[[Widget/HTML Element]] Attribute Type"
|
||||
list-row-macro="row" />
|
||||
@@
|
||||
\end
|
||||
|
||||
{{$:/plugins/flibbles/relink/language/Help/Attributes}}
|
||||
|
@ -39,11 +39,14 @@ title: $:/plugins/flibbles/relink/ui/configuration/Fields
|
||||
<$text text={{$(lingo-base)$NewField/Caption}}/>
|
||||
</$button>
|
||||
</$reveal>
|
||||
|
||||
@@.tc-control-panel
|
||||
<$macrocall
|
||||
$name=tables
|
||||
category="fields"
|
||||
header-list="[[Field Name]] [[Field Type]]"
|
||||
list-row-macro="row" />
|
||||
@@
|
||||
\end
|
||||
|
||||
{{$:/plugins/flibbles/relink/language/Help/Fields}}
|
||||
|
@ -63,11 +63,14 @@ title: $:/plugins/flibbles/relink/ui/configuration/Macros
|
||||
<$text text={{$(lingo-base)$NewParameter/Caption}}/>
|
||||
</$button>
|
||||
</$reveal>
|
||||
|
||||
@@.tc-control-panel
|
||||
<$macrocall
|
||||
$name=tables
|
||||
category="macros"
|
||||
header-list="Macro Parameter Type"
|
||||
list-row-macro="row" />
|
||||
@@
|
||||
\end
|
||||
|
||||
{{$:/plugins/flibbles/relink/language/Help/Macros}}
|
||||
|
@ -39,11 +39,14 @@ title: $:/plugins/flibbles/relink/ui/configuration/Operators
|
||||
<$text text={{$(lingo-base)$NewOperator/Caption}}/>
|
||||
</$button>
|
||||
</$reveal>
|
||||
|
||||
@@.tc-control-panel
|
||||
<$macrocall
|
||||
$name=tables
|
||||
category="operators"
|
||||
header-list="[[Filter Operator]] [[Operand Type]]"
|
||||
list-row-macro="row" />
|
||||
@@
|
||||
\end
|
||||
|
||||
{{$:/plugins/flibbles/relink/language/Help/Operators}}
|
||||
|
@ -20,6 +20,8 @@ title: $:/plugins/flibbles/relink/ui/stylesheet.css
|
||||
.tc-relink-references-title {
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
|
||||
.tc-relink-references-occurrence {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user