diff --git a/core/modules/parsers/wikiparser/rules/prettylink.js b/core/modules/parsers/wikiparser/rules/prettylink.js index 12683b3eb..33841f116 100644 --- a/core/modules/parsers/wikiparser/rules/prettylink.js +++ b/core/modules/parsers/wikiparser/rules/prettylink.js @@ -27,18 +27,13 @@ exports.init = function(parser) { this.matchRegExp = /\[\[(.*?)(?:\|(.*?))?\]\]/mg; }; -var isLinkExternal = function(to) { - var externalRegExp = /(?:file|http|https|mailto|ftp|irc|news|data|skype):[^\s<>{}\[\]`|'"\\^~]+(?:\/|\b)/i; - return externalRegExp.test(to); -}; - exports.parse = function() { // Move past the match this.parser.pos = this.matchRegExp.lastIndex; // Process the link var text = this.match[1], link = this.match[2] || text; - if(isLinkExternal(link)) { + if($tw.utils.isLinkExternal(link)) { return [{ type: "element", tag: "a", diff --git a/core/modules/utils/utils.js b/core/modules/utils/utils.js index b0aead3e6..4f8676c18 100644 --- a/core/modules/utils/utils.js +++ b/core/modules/utils/utils.js @@ -439,6 +439,12 @@ exports.escapeRegExp = function(s) { return s.replace(/[\-\/\\\^\$\*\+\?\.\(\)\|\[\]\{\}]/g, '\\$&'); }; +// Checks whether a link target is external, i.e. not a tiddler title +exports.isLinkExternal = function(to) { + var externalRegExp = /(?:file|http|https|mailto|ftp|irc|news|data|skype):[^\s<>{}\[\]`|'"\\^~]+(?:\/|\b)/i; + return externalRegExp.test(to); +}; + exports.nextTick = function(fn) { /*global window: false */ if(typeof process === "undefined") { diff --git a/core/modules/widgets/link.js b/core/modules/widgets/link.js index 4943a2ea9..eac53a050 100755 --- a/core/modules/widgets/link.js +++ b/core/modules/widgets/link.js @@ -106,8 +106,8 @@ LinkWidget.prototype.renderLink = function(parent,nextSibling) { this.domNodes.push(domNode); }; -LinkWidget.prototype.handleClickEvent = function (event) { - // Send the click on it's way as a navigate event +LinkWidget.prototype.handleClickEvent = function(event) { + // Send the click on its way as a navigate event var bounds = this.domNodes[0].getBoundingClientRect(); this.dispatchEvent({ type: "tm-navigate", diff --git a/core/modules/widgets/list.js b/core/modules/widgets/list.js index 0138e0837..2b3666eec 100755 --- a/core/modules/widgets/list.js +++ b/core/modules/widgets/list.js @@ -60,16 +60,18 @@ ListWidget.prototype.execute = function() { this.variableName = this.getAttribute("variable","currentTiddler"); this.storyViewName = this.getAttribute("storyview"); this.historyTitle = this.getAttribute("history"); + this.iterator = this.getAttribute("iterator","iterator"); // Compose the list elements this.list = this.getTiddlerList(); var members = [], - self = this; + self = this, + count = self.list.length; // Check for an empty list - if(this.list.length === 0) { + if(0 === count) { members = this.getEmptyMessage(); } else { $tw.utils.each(this.list,function(title,index) { - members.push(self.makeItemTemplate(title)); + members.push(self.makeItemTemplate(title,index,count,self.iterator)); }); } // Construct the child widgets @@ -96,7 +98,7 @@ ListWidget.prototype.getEmptyMessage = function() { /* Compose the template for a list item */ -ListWidget.prototype.makeItemTemplate = function(title) { +ListWidget.prototype.makeItemTemplate = function(title,index,count,iterator) { // Check if the tiddler is a draft var tiddler = this.wiki.getTiddler(title), isDraft = tiddler && tiddler.hasField("draft.of"), @@ -119,7 +121,15 @@ ListWidget.prototype.makeItemTemplate = function(title) { } } // Return the list item - return {type: "listitem", itemTitle: title, variableName: this.variableName, children: templateTree}; + return { + type: "listitem", + itemTitle: title, + variableName: this.variableName, + children: templateTree, + index: index, + count: count, + iterator: iterator + }; }; /* @@ -291,8 +301,12 @@ ListItemWidget.prototype.render = function(parent,nextSibling) { Compute the internal state of the widget */ ListItemWidget.prototype.execute = function() { + var item = this.parseTreeNode; // Set the current list item title - this.setVariable(this.parseTreeNode.variableName,this.parseTreeNode.itemTitle); + this.setVariable(item.variableName,item.itemTitle); + this.setVariable(item.iterator,(item.index + 1).toString()); + this.setVariable(item.iterator + "-even",item.index % 2 == 1 ? "true" : "false"); + this.setVariable(item.iterator + "-last",item.index + 1 == item.count ? "true" : "false"); // Construct the child widgets this.makeChildWidgets(); }; diff --git a/core/wiki/macros/toc.tid b/core/wiki/macros/toc.tid index 240b0a978..1be085ee9 100644 --- a/core/wiki/macros/toc.tid +++ b/core/wiki/macros/toc.tid @@ -167,7 +167,7 @@ tags: $:/tags/Macro
<$reveal state="""$selectedTiddler$""" type="nomatch" text=""> <$transclude mode="block" tiddler="$template$"> -

<$transclude field="caption"><$view field="title"/>

+

<>

<$transclude mode="block">$missingText$ diff --git a/editions/fr-FR/tiddlers/TableOfContentsMacro Expandable Example.tid b/editions/fr-FR/tiddlers/TableOfContentsMacro Expandable Example.tid new file mode 100644 index 000000000..8965ddaec --- /dev/null +++ b/editions/fr-FR/tiddlers/TableOfContentsMacro Expandable Example.tid @@ -0,0 +1,14 @@ +caption: Développable +created: 20150104182842728 +modified: 20150104183013132 +tags: table-of-contents-example +title: TableOfContentsMacro Expandable Example +type: text/vnd.tiddlywiki + +!! Table des matières développable + +<$macrocall $name='wikitext-example-without-html' +src='
+<> +
+'/> diff --git a/editions/fr-FR/tiddlers/TableOfContentsMacro Selective Expandable Example.tid b/editions/fr-FR/tiddlers/TableOfContentsMacro Selective Expandable Example.tid new file mode 100644 index 000000000..8a17847fb --- /dev/null +++ b/editions/fr-FR/tiddlers/TableOfContentsMacro Selective Expandable Example.tid @@ -0,0 +1,14 @@ +caption: Développable sélectivement +created: 20150104182559211 +modified: 20150104183032161 +tags: table-of-contents-example +title: TableOfContentsMacro Selective Expandable Example +type: text/vnd.tiddlywiki + +!! Table des matières développable sélectivement + +<$macrocall $name='wikitext-example-without-html' +src='
+<> +
+'/> diff --git a/editions/fr-FR/tiddlers/TableOfContentsMacro Simple Example.tid b/editions/fr-FR/tiddlers/TableOfContentsMacro Simple Example.tid new file mode 100644 index 000000000..f0bbcf429 --- /dev/null +++ b/editions/fr-FR/tiddlers/TableOfContentsMacro Simple Example.tid @@ -0,0 +1,14 @@ +caption: Simple +created: 20150104182258371 +modified: 20150104182323524 +tags: table-of-contents-example +title: TableOfContentsMacro Simple Example +type: text/vnd.tiddlywiki + +!! Table des matières simple + +<$macrocall $name='wikitext-example-without-html' +src='
+<> +
+'/> diff --git a/editions/fr-FR/tiddlers/TableOfContentsMacro Sorted Expandable Example.tid b/editions/fr-FR/tiddlers/TableOfContentsMacro Sorted Expandable Example.tid new file mode 100644 index 000000000..c88a07c34 --- /dev/null +++ b/editions/fr-FR/tiddlers/TableOfContentsMacro Sorted Expandable Example.tid @@ -0,0 +1,14 @@ +caption: Développable triée +created: 20150104182748334 +modified: 20150104182956846 +tags: table-of-contents-example +title: TableOfContentsMacro Sorted Expandable Example +type: text/vnd.tiddlywiki + +!! Table des matières développable triée + +<$macrocall $name='wikitext-example-without-html' +src='
+<> +
+'/> diff --git a/editions/fr-FR/tiddlers/TableOfContentsMacro Tabbed Example.tid b/editions/fr-FR/tiddlers/TableOfContentsMacro Tabbed Example.tid new file mode 100644 index 000000000..721d42924 --- /dev/null +++ b/editions/fr-FR/tiddlers/TableOfContentsMacro Tabbed Example.tid @@ -0,0 +1,45 @@ +caption: Tabbed +created: 20150104183128274 +modified: 20150104222928663 +tags: table-of-contents-example +title: TableOfContentsMacro Tabbed Example +type: text/vnd.tiddlywiki + +!! Table des matières tabulée + +La variante tabulée de la macro table des matières affiche une table des matières développable sélectivement à côté d'un panneau qui affiche le tiddler en cours de sélection. + +!!! Paramètres + +|!Position |!Nom |!Description |!Défaut | +|1^^re^^ |tag |Tag à utiliser pour construire la table des matières | | +|2^^e^^ |sort |Sous-filtre de tri optionnel (par exemple `sort[title]`) | | +|3^^e^^ |selectedTiddler |Titre du tiddler contenant le titre du tiddler en cours d'affichage |"$:/temp/toc/selectedTiddler" | +|4^^e^^ |unselectedText |Texte à afficher lorsqu'aucun tiddler n'est sélectionné | | +|5^^e^^ |missingText |Texte à afficher quand le tiddler sélectionné est manquant | | +|6^^e^^ |template |Titre optionnel d'un tiddler à utiliser comme template pour le rendu du tiddler sélectionné | | + +!!! Navigation interne + +Cet exemple montre comment construire une table des matières tabulée avec navigation interne, de sorte que cliquer sur les liens du tiddler en cours d'affichage remplacera le tiddler en question. + +``` +<> +``` + +!!! Navigation externe + +Cet exemple montre comment construire une table des matières tabulée avec navigation externe, de sorte que cliquer sur les liens du tiddler en cours d'affichage ouvrira les tiddlers référencés dans le déroulé principal, selon la manière habituelle. + +``` +<> +``` + +!! Exemple + +Type<<:>> <$select tiddler="TabbedExampleType"> + + + + +<$macrocall $name={{TabbedExampleType}} tag="TableOfContents" selectedTiddler="$:/temp/toc/selectedTiddler" unselectedText="

Choisissez un sujet dans la table des matières. Cliquez sur la flèche pour développer un sujet.

" missingText="

Tiddler manquant.

"/> diff --git a/editions/fr-FR/tiddlers/TableOfContentsMacro.tid b/editions/fr-FR/tiddlers/TableOfContentsMacro.tid new file mode 100644 index 000000000..cc9c16db1 --- /dev/null +++ b/editions/fr-FR/tiddlers/TableOfContentsMacro.tid @@ -0,0 +1,51 @@ +caption: toc +created: 20140919155729620 +modified: 20150105102807522 +tags: Macros +title: TableOfContentsMacro +type: text/vnd.tiddlywiki + +La macro //~TableOfContents// (Table des Matières) produit une arborescence hiérarchique de tiddlers, en se basant sur leurs tags. + +Les entrées de premier niveau de la table des matières sont définies par un tag racine. Les sous-entrées de chacune de ces entrées sont taguées avec le titre de l'entrée. Les entrées peuvent être triées à l'aide du champ `list` du tiddler de tag correspondant, comme décrit dans [[Tagging]]. + +Le libellé utilisé pour chaque entrée est tiré du champ ''caption'' s'il est présent<<;>> dans le cas contraire, c'est le titre (champ ''title'') qui est utilisé. + +Les entrées sont affichées sous forme de liens vers le tiddler correspondant, à moins que le tiddler contienne un champ ''toc-link'' avec la valeur ''no''. Dans les exemples ci-dessous, l'entrée SecondThree est configurée ainsi, de manière à ne pas apparaître comme un lien. + +Il existe plusieurs variantes de cette macro<<:>> + +* `<>` produit une arborescence hiérarchique de liens simple +* `<>` produit une arborescence de liens développable +* `<>` produit une arborescence de liens développable où les boutons développer / contracter ne sont affichés que pour les entrées qui possèdent des nœuds fils + +Les macros génèrent des listes HTML ordonnées. Les éléments `
    ` bénéficient de la classe `tc-toc`, ceux de la variante //expandable// bénéficiant également de la classe `tc-toc-expandable` tandis que ceux de la variante //selective expandable// bénéficient de la classe `tc-toc-selective-expandable`. + +! Paramètres + +|!Position |!Nom |!Description |!Défaut | +|1^^re^^ |tag |Le tag racine qui identifie le premier niveau de la hiérachie | | +|2^^e^^ |sort |Sous-fitre optionnel de tri (par exemple `sort[title]`) | | + +Les paramètres ''tag'' et ''sort'' sont combinés pour construire une expression de filtre de la forme<<:>> + +``` +[tag[$tag$]$sort$] +``` + +! Exemples + +Dans les exemples suivants, les entrées de premier niveau de la table des matières sont définies par leur tag racine ''Contents''. Les sous-entrées sous chacune de ces entrées sont taguées avec le titre de leur parent, ici ''First'', ''Second'', ''Third'', et ''Fourth''. Au niveau du dessous, seul ''~SecondThree'' comporte des sous-entrées. + +Voici la structure des tags, affichée à l'aide de pastilles de tag cliquables<<:>> + +{{Contents||$:/core/ui/TagTemplate}} +*{{First||$:/core/ui/TagTemplate}} +*{{Second||$:/core/ui/TagTemplate}} +**{{SecondThree||$:/core/ui/TagTemplate}} +*{{Third||$:/core/ui/TagTemplate}} +*{{Fourtth||$:/core/ui/TagTemplate}} + +Pour des instructions sur la manière d'ajouter une table des matières dans la barre latérale, voyez<<:>> [[Comment ajouter un nouvel onglet dans la barre latérale|How to add a new tab to the sidebar]]. + +<> diff --git a/editions/tw5.com/tiddlers/about/Tiddler Titles.tid b/editions/tw5.com/tiddlers/about/Tiddler Titles.tid index 9d381b0ad..ea93dd761 100644 --- a/editions/tw5.com/tiddlers/about/Tiddler Titles.tid +++ b/editions/tw5.com/tiddlers/about/Tiddler Titles.tid @@ -4,7 +4,7 @@ tags: documenting Each of the main words of a tiddler title begins with a capital letter, but minor words such as "and", "or", "the", "to" and "with" do not. Avoid starting a tiddler with the word "the". -[[Reference Tiddlers]] have ~CamelCase nouns as their titles, e.g. ''~RevealWidget'', ''~CamelCase'', ''CSS''. The title is plural if it denotes a category, e.g. ''~KeyboardShorcuts'', ''~TiddlerFields''. Such categories are used to tag more specific tiddlers within the category. +[[Reference Tiddlers]] have ~CamelCase nouns as their titles, e.g. ''~RevealWidget'', ''~CamelCase'', ''CSS''. The title is plural if it denotes a category, e.g. ''~KeyboardShortcuts'', ''~TiddlerFields''. Such categories are used to tag more specific tiddlers within the category. Other tags usually consist of a single lowercase word. Avoid spaces in tags. diff --git a/editions/tw5.com/tiddlers/community/resources/Taskgraph by Felix Kuppers.tid b/editions/tw5.com/tiddlers/community/resources/TiddlyMap by Felix Kuppers.tid similarity index 60% rename from editions/tw5.com/tiddlers/community/resources/Taskgraph by Felix Kuppers.tid rename to editions/tw5.com/tiddlers/community/resources/TiddlyMap by Felix Kuppers.tid index 57740c454..0d4e499d6 100644 --- a/editions/tw5.com/tiddlers/community/resources/Taskgraph by Felix Kuppers.tid +++ b/editions/tw5.com/tiddlers/community/resources/TiddlyMap by Felix Kuppers.tid @@ -1,16 +1,14 @@ created: 20141122093837330 modified: 20141122093837330 tags: Resources -title: "Taskgraph Plugin" by Felix Küppers +title: TiddlyMap Plugin by Felix Küppers type: text/vnd.tiddlywiki -url: http://wkpr.de/hosting/tmp/tw5/taskgraph/ +url: http://bit.ly/tiddlymap -An interactive network visualisation plugin based on [[Vis.js|http://visjs.org]]. - -{{!!url}} +An interactive network visualisation plugin based on [[Vis.js|http://visjs.org]]. A demo can be found here: {{!!url}}. <<< -TW-Taskgraph is a TiddlyWiki plugin that allows you to link your wiki-topics (tiddlers) in order to create clickable graphs. By creating relations between your topics you can easily do the following: +~TiddlyMap is a TiddlyWiki plugin that allows you to link your wiki-topics (tiddlers) in order to create clickable graphs. By creating relations between your topics you can easily do the following: * Create mindmaps and quickly manifest your ideas in tiddlers (wiki entries). * Create task-dependency graphs to organize and describe your tasks. diff --git a/editions/tw5.com/tiddlers/concepts/RailroadDiagrams.tid b/editions/tw5.com/tiddlers/concepts/RailroadDiagrams.tid new file mode 100644 index 000000000..f10dc9a73 --- /dev/null +++ b/editions/tw5.com/tiddlers/concepts/RailroadDiagrams.tid @@ -0,0 +1,15 @@ +created: 20150105133800000 +modified: 20150105134300000 +title: RailroadDiagrams + +Railroad diagrams, sometimes called syntax diagrams, are a visual way of explaining the syntax rules of a computer language. Reading one is like reading a public transport map. + +Each diagram starts on the left and ends on the right. Simply follow any line from the startpoint to the endpoint. All the alternative lines are equally valid. A line will sometimes jump over an item that is optional, or loop back to indicate that an item can be repeated. + +<$railroad text=""" +start [:optional] {repeated +","} end +"""/> + +Characters in round boxes are literal, i.e. they denote themselves. A name in a rectangular box denotes a further railroad diagram. + +The railroad diagrams on this site are generated using the [[Railroad Plugin]]. diff --git a/editions/tw5.com/tiddlers/filters/Introduction to Filters.tid b/editions/tw5.com/tiddlers/filters/Introduction to Filters.tid index 2b42e738a..d118293b5 100644 --- a/editions/tw5.com/tiddlers/filters/Introduction to Filters.tid +++ b/editions/tw5.com/tiddlers/filters/Introduction to Filters.tid @@ -4,21 +4,21 @@ tags: Learning title: Introduction to Filters type: text/vnd.tiddlywiki -A step by step introduction to how [[Filters]] are used. +This is a step-by-step introduction to how [[Filters]] are used. [[Filter Syntax]] presents a more technical summary of this information. ! Using Filters -Filters are a special language within WikiText for expressing lists of tiddlers. +Filters are a special notation for expressing lists of tiddlers within WikiText. Filters are used in the ListMacro, TabsMacro, ListWidget, CountWidget, and many other areas of TiddlyWiki. -For example, this is how the ListMacro would be used to display the first example below: +For example, this is how the ListMacro would be used to display the first example below: ``` <> ``` -The easiest way to experiment with tiddler filters is by typing them into the "Filter" tab of the [[advanced search panel|$:/AdvancedSearch]]. +The easiest way to experiment with tiddler filters is by typing them into the ''Filter'' tab of the [[advanced search panel|$:/AdvancedSearch]]. ! Simple Filters @@ -32,13 +32,13 @@ The titles must be separated by one or more spaces and/or linebreaks. ! Filter Operators -Filter operators are used to select tiddlers based on some criteria. For example, this filter consists of a single operation that selects all tiddlers tagged "introduction": +Filter operators are used to select tiddlers in particular ways. For example, this filter consists of a single step that selects all tiddlers tagged ''introduction'': ``` [tag[introduction]] ``` -The word "tag" is the ''operator'' and "introduction" is the ''operand''. +The word `tag` is the ''operator'' and `introduction` is the ''parameter'' (sometimes called the ''operand''). See [[Filters]] for a complete list of the available operators. @@ -46,9 +46,9 @@ See [[Filters]] for a complete list of the available operators. The operator defaults to `title` if omitted, so `[[HelloThere]]` is equivalent to `[title[HelloThere]]`. If there are no spaces in the title, then the double square brackets can also be omitted: `HelloThere`. -! Negating Filter Operators +! Negating Filter Steps -Filter operations can be negated by preceding the operator with an exclamation mark (!). This example selects all tiddlers that are not tagged "introduction": +A filter step can be negated by preceding the operator with an exclamation mark (`!`). This example selects all tiddlers that are not tagged ''introduction'': ``` [!tag[introduction]] @@ -56,7 +56,7 @@ Filter operations can be negated by preceding the operator with an exclamation m ! Operator Suffixes -Some filter operators can take an optional suffix that provides further information for the operation. For example, the "field" operator takes a suffix indicating the field to be compared. The following filter returns all tiddlers that have "JeremyRuston" in the "modifier" field: +Some filter operators can take an optional suffix that provides further information. For example, the `field` operator takes a suffix indicating the field to be compared. The following filter returns all tiddlers that have ''JeremyRuston'' in the `modifier` field: ``` [field:modifier[JeremyRuston]] @@ -64,70 +64,72 @@ Some filter operators can take an optional suffix that provides further informat ! Field Operator Shortcut -If an unknown operator is used then it is instead interpreted as the suffix of the "field" operator. Thus, these two filters both return all the tiddlers that contain the string "create" in their "caption" field: +If an operator is not recognised, then it is instead interpreted as the suffix of the `field` operator. Thus, these two filters both return all the tiddlers that contain the string ''create'' in their `caption` field: ``` [caption[create]] [field:caption[create]] ``` -! Indirect Operands +! Indirect Parameters -If a filter operator is written with curly brackets around the operand then it is taken to be a TextReference to the actual value. For example, this filter selects all tiddlers containing the string contained in the tiddler titled "$:/temp/search" +If a filter step has curly brackets around its parameter, then it is taken to be a TextReference to the actual value. For example, this filter selects all tiddlers containing the string contained in the ''$:/temp/search'' tiddler: ``` [search{$:/temp/search}] ``` -! Variable Operands +! Variable Parameters -If a filter operator is written with angle brackets around the operand then it is taken to be the name of a variable containing the actual value. For example, this filter selects all tiddlers containing the title of the current tiddler: +If a filter step has angle brackets around its parameter, then it is taken to be the name of a variable containing the actual value. For example, this filter selects all tiddlers containing the title of the current tiddler: ``` [search] ``` -(Note that the `currentTiddler` variable is used to track the current tiddler). +(The built-in `currentTiddler` variable keeps track of which tiddler is the current one.) -! ORing Multiple Filter Operators +! ORing Multiple Filter Steps -You can use multiple filter operations at once. This example selects all tiddlers that are either tagged "introduction" or "demo": +You can use multiple filter steps at once. If you write the steps separately, the overall result is the set of tiddlers that match //any// of the steps. Each step is processed separately, adding its tiddlers to the overall result. + +This example selects all tiddlers that are either tagged ''introduction'' or ''demo'': ``` [tag[introduction]] [tag[demo]] ``` -Each separate operator is processed in turn, accumulating the tiddlers that they select. - -Here's an example that returns tiddlers tagged ''alpha'' or ''beta'' that are also tagged ''task'' and not tagged ''done'': +Here's an example that returns tiddlers tagged ''alpha'' or ''beta'' that are also tagged ''task'' but not tagged ''done'': ``` [tag[alpha]] [tag[beta]] +[tag[task]!tag[done]] ``` -! ANDing Multiple Filter Operators +! ANDing Multiple Filter Steps -A sequence of operators can be logically ANDed together by bashing them together and merging the outer square brackets. This is called a "run" of operations. For example, here we select tiddlers that are tagged "introduction" and also tagged "demo": +A sequence of steps can also be combined by bashing them together and merging the outer square brackets. This is called a "run". The result is the set of tiddlers that match //all// of the steps in the run. + +For example, here we select tiddlers that are tagged ''introduction'' and also tagged ''demo'': ``` [tag[introduction]tag[demo]] ``` -Here's another example that selects all tiddlers tagged "introduction" that are not tagged "demo": +Here's another example that selects all tiddlers tagged ''introduction'' that are //not// tagged ''demo'': ``` [tag[introduction]!tag[demo]] ``` -! Negating Runs of Filter Operators +! Negating Runs -Ordinarily, each run of filter operations adds to the accumulated results. Prefixing a run with `-` causes the list of tiddlers to instead be removed from the results. For example, this example returns all the tiddlers tagged "introduction" apart from `HelloThere` and `Title with Spaces`: +Ordinarily, each run //adds// to the accumulated results. Prefixing a run with `-` instead causes the list of tiddlers selected to be //removed// from the results. For example, this example returns all the tiddlers tagged ''introduction'', apart from `HelloThere` and `Title with Spaces`: ``` [tag[introduction]] -HelloThere -[[Title with Spaces]] ``` -This example returns all tiddlers tagged "introduction" that are not also tagged "demo": +This example returns all tiddlers tagged ''introduction'' that are not also tagged ''demo'': ``` [tag[introduction]] -[tag[demo]] @@ -135,9 +137,9 @@ This example returns all tiddlers tagged "introduction" that are not also tagged ! Working with Filter Results -Usually, each run of filter operations takes as its source the entire store of available tiddlers. Prefixing a run with `+` causes the accumulated results to be used as the source instead. +Usually, each run takes the entire store of available tiddlers as its source. Prefixing a run with `+` causes the results so far accumulated to be used as the source instead. -For example, this filter selects tiddlers tagged "introduction" or "demo" and then sorts the resulting list by the "title" field: +For example, this filter selects tiddlers tagged ''introduction'' or ''demo'', and then sorts the resulting list by the `title` field: ``` [tag[introduction]] [tag[demo]] +[sort[title]] diff --git a/editions/tw5.com/tiddlers/plugins/Railroad Plugin.tid b/editions/tw5.com/tiddlers/plugins/Railroad Plugin.tid new file mode 100644 index 000000000..3d3d948b2 --- /dev/null +++ b/editions/tw5.com/tiddlers/plugins/Railroad Plugin.tid @@ -0,0 +1,7 @@ +title: Railroad Plugin +modified: 20150105134500000 +tags: Plugins + +{{$:/plugins/tiddlywiki/railroad/readme}} + +{{$:/plugins/tiddlywiki/railroad/syntax}} \ No newline at end of file diff --git a/plugins/tiddlywiki/railroad/components.js b/plugins/tiddlywiki/railroad/components.js index 3001f448c..959db3840 100644 --- a/plugins/tiddlywiki/railroad/components.js +++ b/plugins/tiddlywiki/railroad/components.js @@ -89,13 +89,13 @@ Component.prototype.debug = function(output,indent) { Component.prototype.debugArray = function(array,output,indent) { for(var i=0; i) +({ [[digit|GettingStarted]] } | "#" <'escape sequence'>) [{("@" name-char | :"--" )}] \ No newline at end of file diff --git a/plugins/tiddlywiki/railroad/doc/example.tid b/plugins/tiddlywiki/railroad/doc/example.tid index 6b4df3071..b64199a44 100644 --- a/plugins/tiddlywiki/railroad/doc/example.tid +++ b/plugins/tiddlywiki/railroad/doc/example.tid @@ -8,7 +8,7 @@ title: $:/plugins/tiddlywiki/railroad/example ``` <$railroad text=""" ["+"] -({digit} | "#" <'escape sequence'>) +({ [[digit|GettingStarted]] } | "#" <'escape sequence'>) [{("@" name-char | :"--" )}] """/> ``` diff --git a/plugins/tiddlywiki/railroad/doc/readme.tid b/plugins/tiddlywiki/railroad/doc/readme.tid index a7507a305..04536dae9 100644 --- a/plugins/tiddlywiki/railroad/doc/readme.tid +++ b/plugins/tiddlywiki/railroad/doc/readme.tid @@ -2,7 +2,7 @@ created: 20150102163222184 modified: 20150102172016663 title: $:/plugins/tiddlywiki/railroad/readme -This plugin provides a `<$railroad>` widget for generating railroad syntax diagrams as SVG images. It is based on [[a library by Tab Atkins|https://github.com/tabatkins/railroad-diagrams]]. +This plugin provides a `<$railroad>` widget for generating railroad syntax diagrams as SVG images. It is based on [[a library by Tab Atkins|https://github.com/tabatkins/railroad-diagrams]], and has been extended to allow components of a diagram to function as links. The content of the `<$railroad>` widget is ignored. @@ -10,8 +10,10 @@ The content of the `<$railroad>` widget is ignored. |text |Text in a special syntax that defines the diagram's layout | |mode |If set to `debug`, the diagram will display its internal tree structure. The default mode is `svg` | -The `text` can be transcluded from another tiddler: +The entire `text` can be transcluded from another tiddler: ``` <$railroad tiddler={{diagram}}> -``` \ No newline at end of file +``` + +Alternatively, the diagram syntax allows specific parts of the `text` to be transcluded from other tiddlers. \ No newline at end of file diff --git a/plugins/tiddlywiki/railroad/doc/syntax.tid b/plugins/tiddlywiki/railroad/doc/syntax.tid index a658c734f..d99e3bb80 100644 --- a/plugins/tiddlywiki/railroad/doc/syntax.tid +++ b/plugins/tiddlywiki/railroad/doc/syntax.tid @@ -2,10 +2,12 @@ created: 20150103184022184 modified: 20150103184022184 title: $:/plugins/tiddlywiki/railroad/syntax -The railroad widget constructs a diagram from the components defined below. +The railroad widget uses a special ''diagram syntax'' to construct the components defined below. `x` and `y` here stand for any component. +Names (as opposed to quoted strings) are available when a value starts with a letter and contains only letters, digits, underscores, dots and hyphens. + --- ; sequence @@ -52,7 +54,6 @@ The railroad widget constructs a diagram from the components defined below. ; nonterminal : <$railroad text=""" (name | "<" string ">") """/> * A nonterminal component, i.e. the name of another diagram -* The simple `name` option is available when the text starts with a letter and contains only letters, digits, underscores, dots and hyphens --- @@ -64,4 +65,16 @@ The railroad widget constructs a diagram from the components defined below. ; dummy : <$railroad text=""" "-" """/> -* The absence of a component \ No newline at end of file +* The absence of a component + +--- + +; link +: <$railroad text=""" "[[" x "|" (name|string) "]]" """/> +* A link to the tiddler title or URI given by the string or name + +--- + +; transclusion +: <$railroad text=""" "{{" (name|string) "}}" """/> +* Treats the content of another tiddler as diagram syntax and transcludes it into the current diagram diff --git a/plugins/tiddlywiki/railroad/files/railroad-diagrams.js b/plugins/tiddlywiki/railroad/files/railroad-diagrams.js index bccaa7747..b5bae739b 100644 --- a/plugins/tiddlywiki/railroad/files/railroad-diagrams.js +++ b/plugins/tiddlywiki/railroad/files/railroad-diagrams.js @@ -467,15 +467,16 @@ var temp = (function(options) { } /* TiddlyWiki: added linking ability */ - function Link(target, item) { - if(!(this instanceof Link)) return new Link(target, item); - FakeSVG.call(this, 'a', {'xlink:href': target}); + function Link(item,options) { + if(!(this instanceof Link)) return new Link(item,options); + FakeSVG.call(this,'a',options); this.item = item; this.width = item.width; this.up = item.up; this.down = item.down; } subclassOf(Link, FakeSVG); + Link.prototype.needsSpace = true; Link.prototype.format = function(x, y, width) { this.item.format(x,y,width).addTo(this); return this; diff --git a/plugins/tiddlywiki/railroad/parser.js b/plugins/tiddlywiki/railroad/parser.js index 1c8116e02..1dfd50d29 100644 --- a/plugins/tiddlywiki/railroad/parser.js +++ b/plugins/tiddlywiki/railroad/parser.js @@ -21,13 +21,11 @@ x y z sequence <"x"> nonterminal /"blah"/ comment - dummy +[[x|"tiddler"]] link +{{"tiddler"}} transclusion "x" can also be written 'x' or """x""" -Future extensions: -[[x|tiddler]] link -{{tiddler}} transclusion - \*/ (function(){ @@ -37,12 +35,14 @@ Future extensions: var components = require("$:/plugins/tiddlywiki/railroad/components.js").components; -var Parser = function(source) { +var Parser = function(widget,source) { + this.widget = widget; this.source = source; this.tokens = this.tokenise(source); this.tokenPos = 0; this.advance(); - this.root = new components.Root(this.parseContent()); + this.content = this.parseContent(); + this.root = new components.Root(this.content); this.checkFinished(); }; @@ -66,8 +66,8 @@ Parser.prototype.parseComponent = function() { if(this.token) { if(this.at("string")) { component = this.parseTerminal(); - } else if(this.at("identifier")) { - component = this.parseIdentifier(); + } else if(this.at("name")) { + component = this.parseName(); } else { switch(this.token.value) { case "[": @@ -85,6 +85,12 @@ Parser.prototype.parseComponent = function() { case "/": component = this.parseComment(); break; + case "[[": + component = this.parseLink(); + break; + case "{{": + component = this.parseTransclusion(); + break; case "<-": component = this.parseSequence(); break; @@ -112,25 +118,21 @@ Parser.prototype.parseChoice = function() { // Parse the next branch content.push(this.parseContent()); } while(this.eat("|")); - // Create a component - var component = new components.Choice(content,colon === -1 ? 0 : colon); // Consume the closing bracket this.close(")"); - return component; + // Create a component + return new components.Choice(content,colon === -1 ? 0 : colon); }; Parser.prototype.parseComment = function() { // Consume the / this.advance(); // The comment's content should be in a string literal - this.expectStringLiteral("/"); - // Create a component - var component = new components.Comment(this.token.value); - // Consume the string literal - this.advance(); + var content = this.expectString("after /"); // Consume the closing / this.close("/"); - return component; + // Create a component + return new components.Comment(content); }; Parser.prototype.parseDummy = function() { @@ -140,27 +142,43 @@ Parser.prototype.parseDummy = function() { return new components.Dummy(); }; -Parser.prototype.parseIdentifier = function() { +Parser.prototype.parseLink = function() { + // Consume the [[ + this.advance(); + // Parse the content + var content = this.parseContent(); + // Consume the | + this.expect("|"); + // Consume the target + var target = this.expectNameOrString("as link target"); + // Prepare some attributes for the SVG "a" element to carry + var options = {"data-tw-target": target}; + if($tw.utils.isLinkExternal(target)) { + options["data-tw-external"] = true; + } + // Consume the closing ]] + this.close("]]"); + // Create a component + return new components.Link(content,options); +}; + +Parser.prototype.parseName = function() { // Create a component var component = new components.Nonterminal(this.token.value); - // Consume the identifier + // Consume the name this.advance(); return component; }; - Parser.prototype.parseNonterminal = function() { // Consume the < this.advance(); // The nonterminal's name should be in a string literal - this.expectStringLiteral("<"); - // Create a component - var component = new components.Nonterminal(this.token.value); - // Consume the string literal - this.advance(); + var content = this.expectString("after <"); // Consume the closing bracket this.close(">"); - return component; + // Create a component + return new components.Nonterminal(content); }; Parser.prototype.parseOptional = function() { @@ -177,14 +195,13 @@ Parser.prototype.parseOptional = function() { if(repeated && this.eat("+")) { separator = this.parseContent(); } - // Create a component - var component = repeated ? new components.OptionalRepeated(content,separator,normal) : new components.Optional(content,normal); // Consume the closing brackets if(repeated) { this.close("}"); } this.close("]"); - return component; + // Create a component + return repeated ? new components.OptionalRepeated(content,separator,normal) : new components.Optional(content,normal); }; Parser.prototype.parseRepeated = function() { @@ -197,23 +214,21 @@ Parser.prototype.parseRepeated = function() { if(this.eat("+")) { separator = this.parseContent(); } - // Create a component - var component = new components.Repeated(content,separator); // Consume the closing bracket this.close("}"); - return component; + // Create a component + return new components.Repeated(content,separator); }; Parser.prototype.parseSequence = function() { - // Consume the ~ + // Consume the <- this.advance(); // Parse the content var content = this.parseContent(); - // Create a component - var component = new components.Sequence(content); - // Consume the closing ~ + // Consume the closing -> this.close("->"); - return component; + // Create a component + return new components.Sequence(content); }; Parser.prototype.parseTerminal = function() { @@ -223,6 +238,21 @@ Parser.prototype.parseTerminal = function() { return component; }; +Parser.prototype.parseTransclusion = function() { + // Consume the {{ + this.advance(); + // Consume the text reference + var textRef = this.expectNameOrString("as transclusion source"); + // Consume the closing }} + this.close("}}"); + // Retrieve the content of the text reference + var source = this.widget.wiki.getTextReference(textRef,"",this.widget.getVariable("currentTiddler")); + // Parse the content + var content = new Parser(this.widget,source).content; + // Create a component + return new components.Transclusion(content); +}; + /////////////////////////// Token manipulation Parser.prototype.advance = function() { @@ -244,10 +274,10 @@ Parser.prototype.eat = function(token) { return at; }; -Parser.prototype.expectStringLiteral = function(preamble) { - if(!this.at("string")) { - throw "String expected after " + preamble; - } +Parser.prototype.tokenValue = function() { + var output = this.token.value; + this.advance(); + return output; }; Parser.prototype.close = function(token) { @@ -262,6 +292,27 @@ Parser.prototype.checkFinished = function() { } }; +Parser.prototype.expect = function(token) { + if(!this.eat(token)) { + throw token + " expected"; + } +}; + +Parser.prototype.expectString = function(context,token) { + if(!this.at("string")) { + token = token || "String"; + throw token + " expected " + context; + } + return this.tokenValue(); +}; + +Parser.prototype.expectNameOrString = function(context) { + if(this.at("name")) { + return this.tokenValue(); + } + return this.expectString(context,"Name or string"); +}; + /////////////////////////// Tokenisation Parser.prototype.tokenise = function(source) { @@ -294,12 +345,12 @@ Parser.prototype.tokenise = function(source) { } else if(c === "-") { // - or -> s = source.charAt(pos+1) === ">" ? "->" : "-"; - } else if("()>+|/:".indexOf(c) !== -1) { + } else if("()>+/:|".indexOf(c) !== -1) { // Single character s = c; } else if(c.match(/[a-zA-Z]/)) { - // Identifier - token = this.readIdentifier(source,pos); + // Name + token = this.readName(source,pos); } else { throw "Syntax error at " + c; } @@ -316,14 +367,14 @@ Parser.prototype.tokenise = function(source) { return tokens; }; -Parser.prototype.readIdentifier = function(source,pos) { +Parser.prototype.readName = function(source,pos) { var re = /([a-zA-Z0-9_.-]+)/g; re.lastIndex = pos; var match = re.exec(source); if(match && match.index === pos) { - return {type: "identifier", value: match[1], start: pos, end: pos + match[1].length}; + return {type: "name", value: match[1], start: pos, end: pos+match[1].length}; } else { - throw "Invalid identifier"; + throw "Invalid name"; } }; diff --git a/plugins/tiddlywiki/railroad/wrapper.js b/plugins/tiddlywiki/railroad/wrapper.js index fec71ba76..cb1b9a0bd 100644 --- a/plugins/tiddlywiki/railroad/wrapper.js +++ b/plugins/tiddlywiki/railroad/wrapper.js @@ -38,24 +38,73 @@ RailroadWidget.prototype.render = function(parent,nextSibling) { var div = this.document.createElement("div"); try { // Parse the source - var parser = new Parser(source); + var parser = new Parser(this,source); + // Generate content into the div if(this.getAttribute("mode","svg") === "debug") { - var output = ["
    "];
    -			parser.root.debug(output, "");
    -			output.push("
    "); - div.innerHTML = output.join(""); + this.renderDebug(parser,div); } else { - div.innerHTML = parser.root.toSvg(); + this.renderSvg(parser,div); } } catch(ex) { div.className = "tc-error"; div.textContent = ex; } - // Insert it into the DOM + // Insert the div into the DOM parent.insertBefore(div,nextSibling); this.domNodes.push(div); }; +RailroadWidget.prototype.renderDebug = function(parser,div) { + var output = ["
    "];
    +	parser.root.debug(output, "");
    +	output.push("
    "); + div.innerHTML = output.join(""); +}; + +RailroadWidget.prototype.renderSvg = function(parser,div) { + // Generate a model of the diagram + var fakeSvg = parser.root.toSvg(); + // Render the model into a tree of SVG DOM nodes + var svg = fakeSvg.toSVG(); + // Fill in the remaining attributes of any link nodes + this.patchLinks(svg); + // Insert the SVG tree into the div + div.appendChild(svg); +}; + +RailroadWidget.prototype.patchLinks = function(node) { + var self = this; + if(node.hasChildNodes()) { + var children = node.childNodes; + for(var i=0; i