diff --git a/core/language/en-GB/Filters.multids b/core/language/en-GB/Filters.multids index 652b78f3c..45f8991fc 100644 --- a/core/language/en-GB/Filters.multids +++ b/core/language/en-GB/Filters.multids @@ -11,3 +11,4 @@ SystemTiddlers: System tiddlers ShadowTiddlers: Shadow tiddlers OverriddenShadowTiddlers: Overridden shadow tiddlers SystemTags: System tags +TypedTiddlers: Non wiki-text tiddlers \ No newline at end of file diff --git a/core/language/en-GB/Misc.multids b/core/language/en-GB/Misc.multids index 9fc58aa59..819d77ec4 100644 --- a/core/language/en-GB/Misc.multids +++ b/core/language/en-GB/Misc.multids @@ -9,7 +9,7 @@ ConfirmDeleteTiddler: Do you wish to delete the tiddler "<$text text=<>/> ConfirmOverwriteTiddler: Do you wish to overwrite the tiddler "<$text text=<<title>>/>"? ConfirmEditShadowTiddler: You are about to edit a ShadowTiddler. Any changes will override the default system making future upgrades non-trivial. Are you sure you want to edit "<$text text=<<title>>/>"? DefaultNewTiddlerTitle: New Tiddler -DropMessage: Drop here (or click escape to cancel) +DropMessage: Drop here (or use the 'Escape' key to cancel) Encryption/ConfirmClearPassword: Do you wish to clear the password? This will remove the encryption applied when saving this wiki Encryption/PromptSetPassword: Set a new password for this TiddlyWiki InvalidFieldName: Illegal characters in field name "<$text text=<<fieldName>>/>". Fields can only contain lowercase letters, digits and the characters underscore (`_`), hyphen (`-`) and period (`.`) diff --git a/core/modules/filters.js b/core/modules/filters.js index 15dde5f75..8fbcac587 100644 --- a/core/modules/filters.js +++ b/core/modules/filters.js @@ -13,8 +13,8 @@ Adds tiddler filtering methods to the $tw.Wiki object. "use strict"; /* -Parses an operation within a filter string - results: Array of array of operator nodes into which results should be inserted +Parses an operation (i.e. a run) within a filter string + operators: Array of array of operator nodes into which results should be inserted filterString: filter string p: start position within the string Returns the new start position, after the parsed operation @@ -108,7 +108,7 @@ exports.parseFilter = function(filterString) { p = 0, // Current position in the filter string match; var whitespaceRegExp = /(\s+)/mg, - operandRegExp = /((?:\+|\-)?)(?:(\[)|("(?:[^"])*")|('(?:[^'])*')|([^\s\[\]]+))/mg; + operandRegExp = /((?:\+|\-)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg; while(p < filterString.length) { // Skip any whitespace whitespaceRegExp.lastIndex = p; @@ -202,6 +202,7 @@ exports.compileFilter = function(filterString) { if(operator.variable) { operand = widget.getVariable(operator.operand,{defaultValue: ""}); } + // Invoke the appropriate filteroperator module results = operatorFunction(accumulator,{ operator: operator.operator, operand: operand, diff --git a/core/modules/wiki.js b/core/modules/wiki.js index ec56d97b7..bfc0f146a 100755 --- a/core/modules/wiki.js +++ b/core/modules/wiki.js @@ -524,7 +524,7 @@ exports.sortByList = function(array,listTitle) { if(!array || array.length === 0) { return []; } else { - var titles = [], t, title; + var t, title, titles = [], unlisted = []; // First place any entries that are present in the list for(t=0; t<list.length; t++) { title = list[t]; @@ -532,13 +532,17 @@ exports.sortByList = function(array,listTitle) { titles.push(title); } } - // Then place any remaining entries + // Add remaining entries to unlisted for(t=0; t<array.length; t++) { title = array[t]; if(list.indexOf(title) === -1) { - titles.push(title); + unlisted.push(title); } } + //sort unlisted + $tw.wiki.sortTiddlers(unlisted,"title",false,false); + //concat listed with unlisted + titles = titles.concat(unlisted); // Finally obey the list-before and list-after fields of each tiddler in turn var sortedTitles = titles.slice(0); for(t=0; t<sortedTitles.length; t++) { diff --git a/core/ui/Filters/TypedTiddlers b/core/ui/Filters/TypedTiddlers new file mode 100644 index 000000000..e31bfd278 --- /dev/null +++ b/core/ui/Filters/TypedTiddlers @@ -0,0 +1,5 @@ +title: $:/core/Filters/TypedTiddlers +tags: $:/tags/Filter +filter: [!is[system]has[type]each[type]sort[type]] -[type[text/vnd.tiddlywiki]] +description: {{$:/language/Filters/TypedTiddlers}} + diff --git a/core/ui/MoreSideBar/All.tid b/core/ui/MoreSideBar/All.tid index 404620e3c..1f6f3e451 100644 --- a/core/ui/MoreSideBar/All.tid +++ b/core/ui/MoreSideBar/All.tid @@ -2,4 +2,4 @@ title: $:/core/ui/MoreSideBar/All tags: $:/tags/MoreSideBar caption: {{$:/language/SideBar/All/Caption}} -<$list filter="[!is[system]sort[title]]" template="$:/core/ui/ListItemTemplate"/> +<$list filter={{$:/core/Filters/AllTiddlers!!filter}} template="$:/core/ui/ListItemTemplate"/> diff --git a/core/ui/MoreSideBar/Drafts.tid b/core/ui/MoreSideBar/Drafts.tid index 736445868..30e4ec222 100644 --- a/core/ui/MoreSideBar/Drafts.tid +++ b/core/ui/MoreSideBar/Drafts.tid @@ -2,4 +2,4 @@ title: $:/core/ui/MoreSideBar/Drafts tags: $:/tags/MoreSideBar caption: {{$:/language/SideBar/Drafts/Caption}} -<$list filter="[has[draft.of]sort[title]]" template="$:/core/ui/ListItemTemplate"/> +<$list filter={{$:/core/Filters/Drafts!!filter}} template="$:/core/ui/ListItemTemplate"/> diff --git a/core/ui/MoreSideBar/Missing.tid b/core/ui/MoreSideBar/Missing.tid index b8382da6a..f04d5250c 100644 --- a/core/ui/MoreSideBar/Missing.tid +++ b/core/ui/MoreSideBar/Missing.tid @@ -2,4 +2,4 @@ title: $:/core/ui/MoreSideBar/Missing tags: $:/tags/MoreSideBar caption: {{$:/language/SideBar/Missing/Caption}} -<$list filter="[all[missing]sort[title]]" template="$:/core/ui/MissingTemplate"/> +<$list filter={{$:/core/Filters/Missing!!filter}} template="$:/core/ui/MissingTemplate"/> diff --git a/core/ui/MoreSideBar/Orphans.tid b/core/ui/MoreSideBar/Orphans.tid index 9485e887f..28660471d 100644 --- a/core/ui/MoreSideBar/Orphans.tid +++ b/core/ui/MoreSideBar/Orphans.tid @@ -2,4 +2,4 @@ title: $:/core/ui/MoreSideBar/Orphans tags: $:/tags/MoreSideBar caption: {{$:/language/SideBar/Orphans/Caption}} -<$list filter="[all[orphans]sort[title]]" template="$:/core/ui/ListItemTemplate"/> +<$list filter={{$:/core/Filters/Orphans!!filter}} template="$:/core/ui/ListItemTemplate"/> diff --git a/core/ui/MoreSideBar/Shadows.tid b/core/ui/MoreSideBar/Shadows.tid index d7ca78493..f403c7f4c 100644 --- a/core/ui/MoreSideBar/Shadows.tid +++ b/core/ui/MoreSideBar/Shadows.tid @@ -2,4 +2,4 @@ title: $:/core/ui/MoreSideBar/Shadows tags: $:/tags/MoreSideBar caption: {{$:/language/SideBar/Shadows/Caption}} -<$list filter="[all[shadows]sort[title]]" template="$:/core/ui/ListItemTemplate"/> +<$list filter={{$:/core/Filters/ShadowTiddlers!!filter}} template="$:/core/ui/ListItemTemplate"/> diff --git a/core/ui/MoreSideBar/System.tid b/core/ui/MoreSideBar/System.tid index 8ad930887..932e68085 100644 --- a/core/ui/MoreSideBar/System.tid +++ b/core/ui/MoreSideBar/System.tid @@ -2,4 +2,4 @@ title: $:/core/ui/MoreSideBar/System tags: $:/tags/MoreSideBar caption: {{$:/language/SideBar/System/Caption}} -<$list filter="[is[system]sort[title]]" template="$:/core/ui/ListItemTemplate"/> +<$list filter={{$:/core/Filters/SystemTiddlers!!filter}} template="$:/core/ui/ListItemTemplate"/> diff --git a/core/ui/MoreSideBar/Tags.tid b/core/ui/MoreSideBar/Tags.tid index b3499b527..268bca137 100644 --- a/core/ui/MoreSideBar/Tags.tid +++ b/core/ui/MoreSideBar/Tags.tid @@ -16,7 +16,7 @@ caption: {{$:/language/SideBar/Tags/Caption}} </$set> -<$list filter="[tags[]!is[system]sort[title]]"> +<$list filter={{$:/core/Filters/AllTags!!filter}}> <$transclude tiddler="$:/core/ui/TagTemplate"/> <small class="tc-menu-list-count"><$count filter="[all[current]tagging[]]"/></small> diff --git a/core/ui/MoreSideBar/Types.tid b/core/ui/MoreSideBar/Types.tid index deb52e17f..a23d729bb 100644 --- a/core/ui/MoreSideBar/Types.tid +++ b/core/ui/MoreSideBar/Types.tid @@ -2,7 +2,7 @@ title: $:/core/ui/MoreSideBar/Types tags: $:/tags/MoreSideBar caption: {{$:/language/SideBar/Types/Caption}} -<$list filter="[!is[system]has[type]each[type]sort[type]] -[type[text/vnd.tiddlywiki]]"> +<$list filter={{$:/core/Filters/TypedTiddlers!!filter}}> <div class="tc-menu-list-item"> <$view field="type"/> <$list filter="[type{!!type}!is[system]sort[title]]"> diff --git a/editions/tw5.com/tiddlers/nodejs/Installing TiddlyWiki on Node.js.tid b/editions/tw5.com/tiddlers/nodejs/Installing TiddlyWiki on Node.js.tid index dbb024e8a..376424405 100644 --- a/editions/tw5.com/tiddlers/nodejs/Installing TiddlyWiki on Node.js.tid +++ b/editions/tw5.com/tiddlers/nodejs/Installing TiddlyWiki on Node.js.tid @@ -12,7 +12,7 @@ type: text/vnd.tiddlywiki #> `sudo npm install -g tiddlywiki` (Mac/Linux) # Check TiddlyWiki is installed by typing: #> `tiddlywiki --version` -# In response, you should see TiddlyWiki report its current version (eg `5.0.8-beta`; you may also see other debugging information reported) +# In response, you should see TiddlyWiki report its current version (eg `<<version>>`; you may also see other debugging information reported) # Try it out: ## `tiddlywiki mynewwiki --init server` to create a folder for a new wiki that includes server-related components ## `tiddlywiki mynewwiki --server` to start TiddlyWiki diff --git a/editions/tw5.com/tiddlers/releasenotes/Releases.tid b/editions/tw5.com/tiddlers/releasenotes/Releases.tid index 223f2b915..a97472da8 100644 --- a/editions/tw5.com/tiddlers/releasenotes/Releases.tid +++ b/editions/tw5.com/tiddlers/releasenotes/Releases.tid @@ -8,4 +8,6 @@ Here are the details of recent releases of TiddlyWiki5. See [[TiddlyWiki5 Versio (BetaReleases and AlphaReleases are listed separately). -<<tabs "[tag[ReleaseNotes]!sort[created]]" "Release 5.1.7" "$:/state/tab2" "tc-vertical" "ReleaseTemplate">> +<$list filter="[tag[ReleaseNotes]!sort[created]limit[1]]"> + <$macrocall $name="tabs" tabsList="[tag[ReleaseNotes]!sort[created]]"default={{!!title}} class="tc-vertical" template="ReleaseTemplate" /> +</$list> diff --git a/editions/tw5.com/tiddlywiki.info b/editions/tw5.com/tiddlywiki.info index cf5dc2a3e..9340dba75 100644 --- a/editions/tw5.com/tiddlywiki.info +++ b/editions/tw5.com/tiddlywiki.info @@ -5,7 +5,7 @@ "tiddlywiki/nodewebkitsaver", "tiddlywiki/github-fork-ribbon", "tiddlywiki/browser-sniff", - "tiddlywiki/railroad" + "tiddlywiki/railroad" ], "themes": [ "tiddlywiki/vanilla", diff --git a/licenses/cla-individual.md b/licenses/cla-individual.md index 5599a4bc0..000a63641 100644 --- a/licenses/cla-individual.md +++ b/licenses/cla-individual.md @@ -210,3 +210,5 @@ David P Dannemiller, @dpdannemiller, 2015/01/10 Ben Williams, @Mathobal, 2015/01/26 Neil Griffin, @ng110, 2015/01/20 + +Alex Hough, @alexhough 2015/01/26 diff --git a/plugins/tiddlywiki/railroad/components.js b/plugins/tiddlywiki/railroad/components.js index 959db3840..85d0d16e2 100644 --- a/plugins/tiddlywiki/railroad/components.js +++ b/plugins/tiddlywiki/railroad/components.js @@ -177,10 +177,11 @@ Optional.prototype.toSvg = function() { return railroad.Optional(this.child.toSvg(), this.normal ? undefined : "skip"); } -var OptionalRepeated = function(content,separator,normal) { +var OptionalRepeated = function(content,separator,normal,wantArrow) { this.initialiseWithChild("OptionalRepeated",content); this.separator = toSingleChild(separator); this.normal = normal; + this.wantArrow = wantArrow; }; OptionalRepeated.prototype = new Component(); @@ -189,12 +190,13 @@ OptionalRepeated.prototype.toSvg = function() { // Call ZeroOrMore(component,separator,"skip") var separatorSvg = this.separator ? this.separator.toSvg() : null; var skip = this.normal ? undefined : "skip"; - return railroad.ZeroOrMore(this.child.toSvg(),separatorSvg,skip); + return railroad.ZeroOrMore(this.child.toSvg(),separatorSvg,skip,this.wantArrow); } -var Repeated = function(content,separator) { +var Repeated = function(content,separator,wantArrow) { this.initialiseWithChild("Repeated",content); this.separator = toSingleChild(separator); + this.wantArrow = wantArrow; }; Repeated.prototype = new Component(); @@ -202,7 +204,7 @@ Repeated.prototype = new Component(); Repeated.prototype.toSvg = function() { // Call OneOrMore(component,separator) var separatorSvg = this.separator ? this.separator.toSvg() : null; - return railroad.OneOrMore(this.child.toSvg(),separatorSvg); + return railroad.OneOrMore(this.child.toSvg(),separatorSvg,this.wantArrow); } var Link = function(content,options) { @@ -234,9 +236,11 @@ var Root = function(content) { Root.prototype = new Component(); -Root.prototype.toSvg = function() { - // Call Diagram(component1,component2,...) - return railroad.Diagram.apply(null, this.getSvgOfChildren()); +Root.prototype.toSvg = function(options) { + var args = this.getSvgOfChildren(); + args.unshift(options); + // Call Diagram(options,component1,component2,...) + return railroad.Diagram.apply(null,args); } var Sequence = function(content) { @@ -247,7 +251,7 @@ Sequence.prototype = new Component(); Sequence.prototype.toSvg = function() { // Call Sequence(component1,component2,...) - return railroad.Sequence.apply(null, this.getSvgOfChildren()); + return railroad.Sequence.apply(null,this.getSvgOfChildren()); } var Choice = function(content,normal) { @@ -264,7 +268,7 @@ Choice.prototype.toSvg = function() { // Call Choice(normal,component1,component2,...) var args = this.getSvgOfChildren(); args.unshift(this.normal); - return railroad.Choice.apply(null, args); + return railroad.Choice.apply(null,args); } /////////////////////////// Exports diff --git a/plugins/tiddlywiki/railroad/doc/example-source.tid b/plugins/tiddlywiki/railroad/doc/example-source.tid index dcca701db..8efc6b536 100644 --- a/plugins/tiddlywiki/railroad/doc/example-source.tid +++ b/plugins/tiddlywiki/railroad/doc/example-source.tid @@ -1,9 +1,9 @@ created: 20150103184022184 -modified: 20150103185522184 +modified: 20150119214125000 tags: title: $:/plugins/tiddlywiki/railroad/example-source -type: text/plain +type: text/vnd.tiddlywiki.railroad ["+"] ({ [[digit|GettingStarted]] } | "#" <'escape sequence'>) -[{("@" name-char | :"--" )}] \ No newline at end of file +[{("@" name-char | :"--" )}] diff --git a/plugins/tiddlywiki/railroad/doc/example.tid b/plugins/tiddlywiki/railroad/doc/example.tid index b64199a44..87161d708 100644 --- a/plugins/tiddlywiki/railroad/doc/example.tid +++ b/plugins/tiddlywiki/railroad/doc/example.tid @@ -1,16 +1,16 @@ created: 20150102165032410 -modified: 20150102172010663 +modified: 20150120090735000 tags: title: $:/plugins/tiddlywiki/railroad/example -<$railroad text={{$:/plugins/tiddlywiki/railroad/example-source}}/> +Notation: -``` -<$railroad text=""" -["+"] -({ [[digit|GettingStarted]] } | "#" <'escape sequence'>) -[{("@" name-char | :"--" )}] -"""/> -``` +<pre><code><$text text={{$:/plugins/tiddlywiki/railroad/example-source}}/></code></pre> -<$railroad mode="debug" text={{$:/plugins/tiddlywiki/railroad/example-source}}/> \ No newline at end of file +Diagram: + +{{$:/plugins/tiddlywiki/railroad/example-source}} + +Debug mode: + +<$railroad debug="yes" text={{$:/plugins/tiddlywiki/railroad/example-source}}/> diff --git a/plugins/tiddlywiki/railroad/doc/readme.tid b/plugins/tiddlywiki/railroad/doc/readme.tid index 04536dae9..05a22aeb4 100644 --- a/plugins/tiddlywiki/railroad/doc/readme.tid +++ b/plugins/tiddlywiki/railroad/doc/readme.tid @@ -1,19 +1,27 @@ created: 20150102163222184 -modified: 20150102172016663 +modified: 20150119231005000 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]], and has been extended to allow components of a diagram to function as links. +This plugin provides a `<$railroad>` widget for generating railroad diagrams as SVG images. + +Alternatively, the [[diagram notation|$:/plugins/tiddlywiki/railroad/syntax]] can be stored in a dedicated tiddler with its `type` field set to `text/vnd.tiddlywiki.railroad`, and that tiddler can simply be transcluded to wherever it is needed. + +The plugin is based on [[a library by Tab Atkins|https://github.com/tabatkins/railroad-diagrams]], and has been extended to make it more flexible, including allowing components of a diagram to function as links or be transcluded from other tiddlers. The content of the `<$railroad>` widget is ignored. -|!Attribute |!Description | -|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` | +|!Attribute |!Description |!Default | +|text |Text in a special notation that defines the diagram's layout |-- | +|arrow |If set to `no`, repeat paths do not have an arrow on them |`yes` | +|start |Style of the startpoint: `single`, `double`, `none` |`single` | +|end |Style of the endpoint: `single`, `double`, `none` |`single` | +|debug |If set to `yes`, the diagram displays its parse tree |`no` | -The entire `text` can be transcluded from another tiddler: +These options can also be specified via pragmas in the diagram notation, or globally via a dictionary tiddler called `$:/config/railroad`: ``` -<$railroad tiddler={{diagram}}> +arrow: yes +start: single +end: single +debug: no ``` - -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 d99e3bb80..fc0d8d87f 100644 --- a/plugins/tiddlywiki/railroad/doc/syntax.tid +++ b/plugins/tiddlywiki/railroad/doc/syntax.tid @@ -1,8 +1,8 @@ created: 20150103184022184 -modified: 20150103184022184 +modified: 20150119220342000 title: $:/plugins/tiddlywiki/railroad/syntax -The railroad widget uses a special ''diagram syntax'' to construct the components defined below. +The railroad widget uses a special notation to construct the components defined below. `x` and `y` here stand for any component. @@ -78,3 +78,22 @@ Names (as opposed to quoted strings) are available when a value starts with a le ; transclusion : <$railroad text=""" "{{" (name|string) "}}" """/> * Treats the content of another tiddler as diagram syntax and transcludes it into the current diagram + +--- + +; arrow pragma +: <$railroad text=""" "\arrow" ("yes" | "no") """/> +* Controls whether repeat paths have an arrow on them +* Can be toggled on and off in mid-diagram, if desired + +--- + +; debug pragma +: <$railroad text=""" "\debug" """/> +* Causes the diagram to display its parse tree + +--- + +; start/end pragma +: <$railroad text=""" ("\start" |: "\end") ("none" |: "single" | "double") """/> +* Controls the style of the diagram's startpoint or endpoint diff --git a/plugins/tiddlywiki/railroad/files/railroad-diagrams.css b/plugins/tiddlywiki/railroad/files/railroad-diagrams.css index 4f9ba13b3..20c720a50 100644 --- a/plugins/tiddlywiki/railroad/files/railroad-diagrams.css +++ b/plugins/tiddlywiki/railroad/files/railroad-diagrams.css @@ -1,23 +1,32 @@ +/* CSS modified for TiddlyWiki */ svg.railroad-diagram { - background-color: hsl(30,20%,95%); + background-color: hsl(30,20%,98%); + border-radius: 5px; +} +svg.railroad-diagram:hover { + background-color: hsl(30,20%,96%); +} +svg.railroad-diagram path, +svg.railroad-diagram rect { + stroke-width: 2; + stroke: #333; } svg.railroad-diagram path { - stroke-width: 3; - stroke: black; - fill: rgba(0,0,0,0); -} -svg.railroad-diagram text { - font: bold 14px monospace; - text-anchor: middle; -} -svg.railroad-diagram text.label { - text-anchor: start; -} -svg.railroad-diagram text.comment { - font: italic 12px monospace; + fill: rgba(0,0,0,0); } svg.railroad-diagram rect { - stroke-width: 3; - stroke: black; - fill: hsl(120,100%,90%); + fill: hsl(120,100%,90%); +} +svg.railroad-diagram text { + font: 14px monospace; + text-anchor: middle; +} +svg.railroad-diagram text.label { + text-anchor: start; +} +svg.railroad-diagram text.comment { + font: italic 12px monospace; +} +svg.railroad-diagram path.arrow { + stroke-width: 2; } \ No newline at end of file diff --git a/plugins/tiddlywiki/railroad/files/railroad-diagrams.js b/plugins/tiddlywiki/railroad/files/railroad-diagrams.js index b5bae739b..dfdcbe7ff 100644 --- a/plugins/tiddlywiki/railroad/files/railroad-diagrams.js +++ b/plugins/tiddlywiki/railroad/files/railroad-diagrams.js @@ -111,9 +111,9 @@ var temp = (function(options) { return str; } - function Path(x,y) { - if(!(this instanceof Path)) return new Path(x,y); - FakeSVG.call(this, 'path'); + function Path(x,y,attrs) { + if(!(this instanceof Path)) return new Path(x,y,attrs); + FakeSVG.call(this, 'path', attrs); this.attrs.d = "M"+x+' '+y; } subclassOf(Path, FakeSVG); @@ -156,17 +156,23 @@ var temp = (function(options) { this.attrs.d += 'h.5'; return this; } +/* TiddlyWiki: added support for arbitrary straight lines */ + Path.prototype.line = function(dx,dy) { + this.attrs.d += "l"+dx+" "+dy; + return this; + } - function Diagram(items) { - if(!(this instanceof Diagram)) return new Diagram([].slice.call(arguments)); +/* TiddlyWiki: added twOptions parameter, passing it to Start() and End() */ + function Diagram(twOptions, items) { + if(!(this instanceof Diagram)) return new Diagram(twOptions, [].slice.call(arguments,1)); FakeSVG.call(this, 'svg', {class: Diagram.DIAGRAM_CLASS}); this.items = items.map(wrapString); - this.items.unshift(new Start); - this.items.push(new End); + this.items.unshift(new Start(twOptions.start)); + this.items.push(new End(twOptions.end)); this.width = this.items.reduce(function(sofar, el) { return sofar + el.width + (el.needsSpace?20:0)}, 0)+1; this.up = Math.max.apply(null, this.items.map(function (x) { return x.up; })); this.down = Math.max.apply(null, this.items.map(function (x) { return x.down; })); - this.formatted = false; + this.formatted = false; } subclassOf(Diagram, FakeSVG); for(var option in options) { @@ -325,15 +331,23 @@ var temp = (function(options) { throw "Unknown value for Optional()'s 'skip' argument."; } - function OneOrMore(item, rep) { - if(!(this instanceof OneOrMore)) return new OneOrMore(item, rep); +/* TiddlyWiki: added wantArrow */ + function OneOrMore(item, rep, wantArrow) { + if(!(this instanceof OneOrMore)) return new OneOrMore(item, rep, wantArrow); FakeSVG.call(this, 'g'); + +/* TiddlyWiki: code added */ + this.wantArrow = wantArrow; + rep = rep || (new Skip); this.item = wrapString(item); this.rep = wrapString(rep); this.width = Math.max(this.item.width, this.rep.width) + Diagram.ARC_RADIUS*2; this.up = this.item.up; this.down = Math.max(Diagram.ARC_RADIUS*2, this.item.down + Diagram.VERTICAL_SEPARATION + this.rep.up + this.rep.down); + +/* TiddlyWiki: moved calculation of distanceFromY (of the repeat arc) to here */ + this.distanceFromY = Math.max(Diagram.ARC_RADIUS*2, this.item.down+Diagram.VERTICAL_SEPARATION+this.rep.up); } subclassOf(OneOrMore, FakeSVG); OneOrMore.prototype.needsSpace = true; @@ -350,41 +364,70 @@ var temp = (function(options) { Path(x+this.width-Diagram.ARC_RADIUS,y).right(Diagram.ARC_RADIUS).addTo(this); // Draw repeat arc - var distanceFromY = Math.max(Diagram.ARC_RADIUS*2, this.item.down+Diagram.VERTICAL_SEPARATION+this.rep.up); +/* TiddlyWiki: moved calculation of distanceFromY from here to constructor */ + var distanceFromY = this.distanceFromY; + Path(x+Diagram.ARC_RADIUS,y).arc('nw').down(distanceFromY-Diagram.ARC_RADIUS*2).arc('ws').addTo(this); this.rep.format(x+Diagram.ARC_RADIUS, y+distanceFromY, this.width - Diagram.ARC_RADIUS*2).addTo(this); Path(x+this.width-Diagram.ARC_RADIUS, y+distanceFromY).arc('se').up(distanceFromY-Diagram.ARC_RADIUS*2).arc('en').addTo(this); + +/* TiddlyWiki: code added */ + if(this.wantArrow) { + var arrowSize = Diagram.ARC_RADIUS/2; + // Compensate for the illusion that makes the arrow look unbalanced if it's too close to the curve below it + var multiplier = (distanceFromY < arrowSize*5) ? 1.2 : 1; + Path(x-arrowSize, y+distanceFromY/2 + arrowSize/2, {class:"arrow"}). + line(arrowSize, -arrowSize).line(arrowSize*multiplier, arrowSize).addTo(this); + } return this; } - function ZeroOrMore(item, rep, skip) { - return Optional(OneOrMore(item, rep), skip); + function ZeroOrMore(item, rep, skip, wantArrow) { + return Optional(OneOrMore(item, rep, wantArrow), skip); } - function Start() { - if(!(this instanceof Start)) return new Start(); +/* TiddlyWiki: added type parameter */ + function Start(type) { + if(!(this instanceof Start)) return new Start(type); FakeSVG.call(this, 'path'); - this.width = 20; + this.type = type || 'single' + this.width = (this.type === 'double') ? 20 : 10; this.up = 10; this.down = 10; } subclassOf(Start, FakeSVG); Start.prototype.format = function(x,y) { - this.attrs.d = 'M '+x+' '+(y-10)+' v 20 m 10 -20 v 20 m -10 -10 h 20.5'; +/* TiddlyWiki: added types */ + if(this.type === 'single') { + this.attrs.d = 'M '+x+' '+(y-10)+' v 20 m 0 -10 h 10.5'; + } else if(this.type === 'double') { + this.attrs.d = 'M '+x+' '+(y-10)+' v 20 m 10 -20 v 20 m -10 -10 h 20.5'; + } else { // 'none' + this.attrs.d = 'M '+x+' '+y+' h 10.5'; + } return this; } - function End() { - if(!(this instanceof End)) return new End(); +/* TiddlyWiki: added type parameter */ + function End(type) { + if(!(this instanceof End)) return new End(type); FakeSVG.call(this, 'path'); - this.width = 20; + this.type = type || 'double'; + this.width = (this.type === 'double') ? 20 : 10; this.up = 10; this.down = 10; } subclassOf(End, FakeSVG); End.prototype.format = function(x,y) { - this.attrs.d = 'M '+x+' '+y+' h 20 m -10 -10 v 20 m 10 -20 v 20'; +/* TiddlyWiki: added types */ + if(this.type === 'single') { + this.attrs.d = 'M '+x+' '+y+' h 10 m 0 -10 v 20'; + } else if(this.type === 'double') { + this.attrs.d = 'M '+x+' '+y+' h 20 m -10 -10 v 20 m 10 -20 v 20'; + } else { // 'none' + this.attrs.d = 'M '+x+' '+y+' h 10'; + } return this; } diff --git a/plugins/tiddlywiki/railroad/parser.js b/plugins/tiddlywiki/railroad/parser.js index 1dfd50d29..bb55b57b8 100644 --- a/plugins/tiddlywiki/railroad/parser.js +++ b/plugins/tiddlywiki/railroad/parser.js @@ -26,6 +26,12 @@ x y z sequence "x" can also be written 'x' or """x""" +pragmas: + \arrow yes|no + \debug yes|no + \start single|double|none + \end single|double|none + \*/ (function(){ @@ -35,9 +41,10 @@ x y z sequence var components = require("$:/plugins/tiddlywiki/railroad/components.js").components; -var Parser = function(widget,source) { +var Parser = function(widget,source,options) { this.widget = widget; this.source = source; + this.options = options; this.tokens = this.tokenise(source); this.tokenPos = 0; this.advance(); @@ -56,7 +63,9 @@ Parser.prototype.parseContent = function() { if(!component) { break; } - content.push(component); + if(!component.isPragma) { + content.push(component); + } } return content; }; @@ -68,6 +77,8 @@ Parser.prototype.parseComponent = function() { component = this.parseTerminal(); } else if(this.at("name")) { component = this.parseName(); + } else if(this.at("pragma")) { + component = this.parsePragma(); } else { switch(this.token.value) { case "[": @@ -182,6 +193,7 @@ Parser.prototype.parseNonterminal = function() { }; Parser.prototype.parseOptional = function() { + var wantArrow = this.options.arrow; // Consume the [ this.advance(); // Consume the { if there is one @@ -201,10 +213,12 @@ Parser.prototype.parseOptional = function() { } this.close("]"); // Create a component - return repeated ? new components.OptionalRepeated(content,separator,normal) : new components.Optional(content,normal); + return repeated ? new components.OptionalRepeated(content,separator,normal,wantArrow) + : new components.Optional(content,normal); }; Parser.prototype.parseRepeated = function() { + var wantArrow = this.options.arrow; // Consume the { this.advance(); // Parse the content @@ -217,7 +231,7 @@ Parser.prototype.parseRepeated = function() { // Consume the closing bracket this.close("}"); // Create a component - return new components.Repeated(content,separator); + return new components.Repeated(content,separator,wantArrow); }; Parser.prototype.parseSequence = function() { @@ -253,6 +267,44 @@ Parser.prototype.parseTransclusion = function() { return new components.Transclusion(content); }; +/////////////////////////// Pragmas + +Parser.prototype.parsePragma = function() { + // Create a dummy component + var component = { isPragma: true }; + // Consume the pragma + var pragma = this.token.value; + this.advance(); + // Apply the setting + if(pragma === "arrow") { + this.options.arrow = this.parseYesNo(pragma); + } else if(pragma === "debug") { + this.options.debug = true; + } else if(pragma === "start") { + this.options.start = this.parseTerminusStyle(pragma); + } else if(pragma === "end") { + this.options.end = this.parseTerminusStyle(pragma); + } else { + throw "Invalid pragma"; + } + return component; +}; + +Parser.prototype.parseYesNo = function(pragma) { + return this.parseSetting(["yes","no"],pragma) === "yes"; +} + +Parser.prototype.parseTerminusStyle = function(pragma) { + return this.parseSetting(["single","double","none"],pragma); +} + +Parser.prototype.parseSetting = function(options,pragma) { + if(this.at("name") && options.indexOf(this.token.value) !== -1) { + return this.tokenValueEaten(); + } + throw options.join(" or ") + " expected after \\" + pragma; +} + /////////////////////////// Token manipulation Parser.prototype.advance = function() { @@ -274,7 +326,7 @@ Parser.prototype.eat = function(token) { return at; }; -Parser.prototype.tokenValue = function() { +Parser.prototype.tokenValueEaten = function() { var output = this.token.value; this.advance(); return output; @@ -303,12 +355,12 @@ Parser.prototype.expectString = function(context,token) { token = token || "String"; throw token + " expected " + context; } - return this.tokenValue(); + return this.tokenValueEaten(); }; Parser.prototype.expectNameOrString = function(context) { if(this.at("name")) { - return this.tokenValue(); + return this.tokenValueEaten(); } return this.expectString(context,"Name or string"); }; @@ -351,6 +403,9 @@ Parser.prototype.tokenise = function(source) { } else if(c.match(/[a-zA-Z]/)) { // Name token = this.readName(source,pos); + } else if(c.match(/\\/)) { + // Pragma + token = this.readPragma(source,pos); } else { throw "Syntax error at " + c; } @@ -378,6 +433,18 @@ Parser.prototype.readName = function(source,pos) { } }; +Parser.prototype.readPragma = function(source,pos) { + var re = /([a-z]+)/g; + pos++; + re.lastIndex = pos; + var match = re.exec(source); + if(match && match.index === pos) { + return {type: "pragma", value: match[1], start: pos, end: pos+match[1].length}; + } else { + throw "Invalid pragma"; + } +}; + /////////////////////////// Exports exports.parser = Parser; diff --git a/plugins/tiddlywiki/railroad/typed-parser.js b/plugins/tiddlywiki/railroad/typed-parser.js new file mode 100644 index 000000000..c956ff09b --- /dev/null +++ b/plugins/tiddlywiki/railroad/typed-parser.js @@ -0,0 +1,28 @@ +/*\ +title: $:/plugins/tiddlywiki/railroad/typed-parser.js +type: application/javascript +module-type: parser + +This parser wraps unadorned railroad syntax into a railroad widget + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +var RailroadParser = function(type,text,options) { + var element = { + type: "railroad", + tag: "$railroad", + text: text + }; + this.tree = [element]; +console.log(text); +}; + +exports["text/vnd.tiddlywiki.railroad"] = RailroadParser; + +})(); + diff --git a/plugins/tiddlywiki/railroad/wrapper.js b/plugins/tiddlywiki/railroad/wrapper.js index a4e8c7032..ca1c18e6b 100644 --- a/plugins/tiddlywiki/railroad/wrapper.js +++ b/plugins/tiddlywiki/railroad/wrapper.js @@ -19,6 +19,8 @@ var RailroadWidget = function(parseTreeNode,options) { this.initialise(parseTreeNode,options); }; +var RAILROAD_OPTIONS = "$:/config/railroad"; + /* Inherit from the base widget class */ @@ -37,10 +39,18 @@ RailroadWidget.prototype.render = function(parent,nextSibling) { // Create a div to contain the SVG or error message var div = this.document.createElement("div"); try { + // Initialise options from the config tiddler or widget attributes + var config = $tw.wiki.getTiddlerData(RAILROAD_OPTIONS,{}); + var options = { + arrow: this.getAttribute("arrow", config.arrow || "yes") === "yes", + debug: this.getAttribute("debug", config.debug || "no") === "yes", + start: this.getAttribute("start", config.start || "single"), + end: this.getAttribute("end", config.end || "single") + }; // Parse the source - var parser = new Parser(this,source); + var parser = new Parser(this,source,options); // Generate content into the div - if(this.getAttribute("mode","svg") === "debug") { + if(parser.options.debug) { this.renderDebug(parser,div); } else { this.renderSvg(parser,div); @@ -63,7 +73,7 @@ RailroadWidget.prototype.renderDebug = function(parser,div) { RailroadWidget.prototype.renderSvg = function(parser,div) { // Generate a model of the diagram - var fakeSvg = parser.root.toSvg(); + var fakeSvg = parser.root.toSvg(parser.options); // Render the model into a tree of SVG DOM nodes var svg = fakeSvg.toSVG(); // Fill in the remaining attributes of any link nodes @@ -107,7 +117,7 @@ RailroadWidget.prototype.patchLinks = function(node) { RailroadWidget.prototype.refresh = function(changedTiddlers) { var changedAttributes = this.computeAttributes(); - if(changedAttributes.text) { + if(changedAttributes.text || changedTiddlers[RAILROAD_OPTIONS]) { this.refreshSelf(); return true; }