Tiddlywiki internals

download Tiddlywiki internals

of 15

Transcript of Tiddlywiki internals

  • 8/2/2019 Tiddlywiki internals

    1/15

    Tiddlywiki internals 1 of 3: Architectural Concepts

    August 11th, 2008 11 CommentsSoftwareDev

    Welcome to Mahemoff's blog on web development, UX, and software development. I most

    recently worked in developer relations at Google, focusing on Chrome and HTML5, and am nowbusy baking a few apps independently.Follow @mahemoff on Twitter

    (This is part 1 of a 3-part series.Part 1introduces the internals and highlights some of the keypatterns and concepts.Part 2introduces each Javascript file.Part 3focuses on the internals of themore important classes and files.)

    This is the first in a 3-part series on the internal design of Tiddlywiki. The series is more or lessstream of consciousness - I'm a green Tiddlywiki developer, so I've been making these notes as Itrawl through the source and learn it myself. Thanks to various people at Osmosoft for

    explaining some of this, and special thanks toJeremyfor some overviews and reviewing thewriting here,Saqfor a great overview on many feature, andFredfor reviewing the initiallypublished version.

    Overview

    A Tiddlywiki is a collection of "tiddlers", small blocks of content typically a paragaph or so inlength. At any time, a subset of these tiddlers is displayed in the UI (between zero and the totalnumber of stored tiddlers).

    A special property of Tiddlywiki is that the entire application resides in a singleHTML/Javascript/CSS file (it's the quintessential SPA -Single-Page Application). This is whyyou can save a Tiddlywiki locally and run it off a file:// URL and stick it on your iPod or noveltyhamburger USB stick.

    In the file, all the tiddlers are stored inside invisible DIVs, which are read on startup into a"TiddlyWiki" data structure. When you invoke the save feature, for example by hitting the "savechanges" control, the invisible DIVs are refreshed with latest content from memory, and theentire file is written out to the hard drive.

    TiddlyWiki is much more than a specialised wiki - due to its flexible architecture and the

    possibility of plugins, it is more like a platform.Examples of apps built on Tiddlywiki.

    TiddlyWeb, though not discussed specifically here, marks an important step in the future ofTiddlyWiki development. It's a RESTful server of Tiddlers which would allow for greatflexibility in the kinds of UIs you end up with, as well as allowing non-UI clients.

    Anatomy of a Tiddlywiki

    http://softwareas.com/tiddlywiki-internals-1-of-3-architectural-concepts#commentshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-concepts#commentshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-concepts#commentshttp://softwareas.com/category/softwaredevhttp://softwareas.com/category/softwaredevhttp://softwareas.com/category/softwaredevhttp://twitter.com/mahemoffhttp://twitter.com/mahemoffhttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-2-of-3-list-of-javascript-fileshttp://softwareas.com/tiddlywiki-internals-2-of-3-list-of-javascript-fileshttp://softwareas.com/tiddlywiki-internals-2-of-3-list-of-javascript-fileshttp://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-fileshttp://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-fileshttp://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-fileshttp://jermolene.com/http://jermolene.com/http://jermolene.com/http://about.unamesa.org/Imtiazhttp://about.unamesa.org/Imtiazhttp://about.unamesa.org/Imtiazhttp://fnd.lewcid.org/blog/http://fnd.lewcid.org/blog/http://fnd.lewcid.org/blog/http://softwareas.com/code.google.com/p/trimpath/wiki/SinglePageApplicationshttp://softwareas.com/code.google.com/p/trimpath/wiki/SinglePageApplicationshttp://softwareas.com/code.google.com/p/trimpath/wiki/SinglePageApplicationshttp://osmosoft.com/#Productshttp://osmosoft.com/#Productshttp://osmosoft.com/#Productshttp://www.tiddlywiki.org/wiki/TiddlyWebhttp://www.tiddlywiki.org/wiki/TiddlyWebhttp://www.tiddlywiki.org/wiki/TiddlyWebhttp://osmosoft.com/#Productshttp://softwareas.com/code.google.com/p/trimpath/wiki/SinglePageApplicationshttp://fnd.lewcid.org/blog/http://about.unamesa.org/Imtiazhttp://jermolene.com/http://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-fileshttp://softwareas.com/tiddlywiki-internals-2-of-3-list-of-javascript-fileshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://twitter.com/mahemoffhttp://softwareas.com/category/softwaredevhttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-concepts#comments
  • 8/2/2019 Tiddlywiki internals

    2/15

    The image below shows an Tiddlywiki in editable mode. As for the UI, you can see it consists ofa main area with two sidebars. The main area is a "Story" - a story is a sequence of visibletiddlers.

    http://skitch.com/mahemoff/ubw2/tiddlywiki-a-reusable-non-linear-personal-web-notebook
  • 8/2/2019 Tiddlywiki internals

    3/15

    A lot of this is configurable by changing special tiddlers. In particular, the tiddler called"PageTemplate" provides the overall structure, with references to other tiddlers, and "Stylesheet"the CSS styles.

    Object-Oriented Concepts in Tiddlywiki

    There are many ways to deal with classes, objects, and prototypes in Javascript - see"Javascript:The Good Parts"by Doug Crockford and"Pro Javascript Design Patterns"by Ross Harmes andDustin Diaz.

    Tiddlywiki's OO relies on the constructor function pattern, where you create new objects usingthe new keyword.

    PLAIN TEXTJAVASCRIPT:

    1.var tiddler = new Tiddler();

    In Javascript, new Fn() will magically does a couple of things that let us use the familiar (fromC++, Java, etc.) idiom above. It sparks the creation of a blank object, then it conducts a special

    execution of Fn() in which this is superfrajalistically tied to the new-born object. This leads usto an idiom which is called a "constructor function" because it is a function that is both calledand implemented as if it were, for the most part, a constructor in OO languages like C++ and

    Java. The Tiddler constructor function is defined as follows:

    PLAIN TEXTJAVASCRIPT:

    1.function Tiddler(title)2. {3. this.title = title;4. this.text = "";5. ...6. returnthis;7. }

    In addition, the new Tiddler has a number of standard Tiddler methods associated with it, so I

    can call them in typical OO fashion, e.g. tiddler.isTagged("happy"). The implementationsrefer to the specific instance using the this keyword. In Javascript, this can easily be achievedvia prototypes. Therefore, subsequent to the constructor definition, we encounter in Tiddler.js amenagerie of method definitions like:

    http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742/ref=pd_sim_b_1/102-7069230-4404147http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742/ref=pd_sim_b_1/102-7069230-4404147http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742/ref=pd_sim_b_1/102-7069230-4404147http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742/ref=pd_sim_b_1/102-7069230-4404147http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908Xhttp://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908Xhttp://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908Xhttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908Xhttp://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742/ref=pd_sim_b_1/102-7069230-4404147http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742/ref=pd_sim_b_1/102-7069230-4404147
  • 8/2/2019 Tiddlywiki internals

    4/15

    PLAIN TEXTJAVASCRIPT:

    1.Tiddler.prototype.isTagged = function(tag)2.{3.

    returnthis.tags.indexOf(tag) != -1;4.}

    All of the attributes above are public, but Tiddlywiki also uses closures to ensure some attributesare only available externally via declared methods. For example, the tiddlers of a Tiddlywiki is adeclared as a local variable, so there's no direct reference to it outside the methods declared in thesame scope.

    PLAIN TEXT

    JAVASCRIPT:

    1.function TiddlyWiki()2.{3. var tiddlers = {}; // Hashmap by name of tiddlers4. this.tiddlersUpdated = false;5. ...6. this.fetchTiddler = function(title){7. var t = tiddlers[title];8. return t instanceof Tiddler ? t : null;9. };10. }

    The above methods will also be available on each instance created with new, just as with thosedeclared using the prototype assignment. They are used in exactly the same way. The onlydifference is that all these functions are re-created with each new instance, so they will consumemore memory. That's the price we pay for the encapsulation.

    You will also find static methods present (i.e. global functions attached to a constructor purelyfor the sake of namespacing them). For example:

    PLAIN TEXTJAVASCRIPT:

    1.TiddlyWiki.isStandardField = function(name)2.{3. return TiddlyWiki.standardFieldAccess[name] != undefined;4.}

    http://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-concepts
  • 8/2/2019 Tiddlywiki internals

    5/15

    Typically, a class will be contained in a single, dedicated, Javascript file (within the source codefrom which a Tiddlywiki is built). However, the previous example was actually contained inTiddlerFields.js rather than Tiddlywiki.js, so it seems that class definitions may be distributed

    across multiple files in some limited cases.

    And that's how Tiddlywiki handles basic OO.

    You'll also see some parts of TiddlyWiki enhancing built-in Javascript types by extending their

    prototype - for example, BasicTypes.js endows all Arrays with a contains() method and

    Dates.js sticks a getAmPm() method onto each Date that's created. Number, Array, and Datereceive a dozen or so new methods.

    Last but not least, there's also a healthy dose ofinheritancein Tiddlywiki. Javascript inheritanceis a whole new can of worms. We see an example in AdaptorBase, which serves as the base class

    for server adaptor subclasses. AdaptorBase looks very normal, like Tiddler above. FileAdaptor, asubclass, looks like this:

    PLAIN TEXTJAVASCRIPT:

    1.function FileAdaptor(){2.}3.4.FileAdaptor.prototype = new AdaptorBase();

    Basically, Javascript has a concept of prototype chains. The assignment means that any instanceof FileAdaptor will now have all methods present in a new instance of AdaptorBase. FileAdaptorgoes on to define its own methods, using the standard prototype pattern. If so inclined, it canoverride AdaptorBase's methods by defining them on its own prototype method. (This is why wesay "new AdaptorBase()" - if we had assigned FileAdaptor.prototype to AdaptorBase.prototype,anything we set on FileAdaptor would also be set on AdaptorBase.)

    URL Arguments

    Tiddlywiki uses the fragment identifier pattern (described here) to provide flexible loadingstrategies.

    Normally, the "DefaultTiddlers" shadow tiddler is used to specify which tiddlers are shown onstartup. However, this can be overridden via URL params. For example, usehttp://www.tiddlywiki.com/#Examplesto load with just the Examples tiddler showing. Or, formultiple tiddlers, just separate with a space (%20 in URL-5peak)http://www.tiddlywiki.com/#Examples%20Plugins. (An interesting possibility would be for

    http://en.wikipedia.org/wiki/Inheritance_%28computer_science%29http://en.wikipedia.org/wiki/Inheritance_%28computer_science%29http://en.wikipedia.org/wiki/Inheritance_%28computer_science%29http://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://ajaxpatterns.org/Unique_URLshttp://ajaxpatterns.org/Unique_URLshttp://ajaxpatterns.org/Unique_URLshttp://www.tiddlywiki.com/#Exampleshttp://www.tiddlywiki.com/#Exampleshttp://www.tiddlywiki.com/#Examples%20Pluginshttp://www.tiddlywiki.com/#Examples%20Pluginshttp://www.tiddlywiki.com/#Examples%20Pluginshttp://www.tiddlywiki.com/#Exampleshttp://ajaxpatterns.org/Unique_URLshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://en.wikipedia.org/wiki/Inheritance_%28computer_science%29
  • 8/2/2019 Tiddlywiki internals

    6/15

    Tiddlywiki to keep updating the URL to ensure its sync'd with the state of the app, so you couldbookmark it at any time to save that configuration.)

    But maybe you don't want to manually list all the tiddlers - instead, you might want to show alltiddlers matching some criteria. Then you'd want an automated mechanism for auto-selecting

    those criteria (think iTunes Smart Playlist for dramatic effect.) This would make the URLshorter, easier to understand the true purpose of the configuation, and future-proof it against anychanges to the set of tiddlers we're interested in.

    In Tiddlywiki, that mechanism is achieved with a URL "filter" prefix. For example, show all

    tiddlers with "systemConfig" tag - http://tiddlywiki.com/#filter:[tag[systemConfig]] .

    Other things you can do - http://tiddlywiki.com/#newTiddler:tiddlername - create a new tiddler,specifying the name

    The URL is modelled as a map, i.e. key-value pairs. In the case of

    http://www.tiddlywiki.com/#Examples%20Plugins , that's just an alias for the canonical mapform, http://www.tiddlywiki.com/#open:Examples%20open:Plugins . All this is managedby the Paramifiers class.

  • 8/2/2019 Tiddlywiki internals

    7/15

    Tiddlywiki internals 2 of 3: List of Javascript Files

    August 11th, 2008 4 CommentsSoftwareDev

    Welcome to Mahemoff's blog on web development, UX, and software development. I most

    recently worked in developer relations at Google, focusing on Chrome and HTML5, and am nowbusy baking a few apps independently.Follow @mahemoff on Twitter

    (This is part 2 of a 3-part series.Part 1introduces the internals and highlights some of the keypatterns and concepts.Part 2introduces each Javascript file.Part 3focuses on the internals of themore important classes and files.)

    Continuing the series, below is a list of all core Javascript files, organised into functional groups.

    Initialisation

    main.js Runs the initialisation sequence. Paramifiers.js Handles URL params.

    Generic (Non-Animation)

    BasicTypes.js Augments built-in Javascript Number and Array. Crypto.js Crypto functions. (Tiddlers can generate fingerprints.) Dates.js Augments built-in Javascript Date class. Dom.js Supports DOM manipulation. FileSystem.js Strings.js Augments built-in Javascript Number and Array. Http.js Supports XmlHttpRequest based remoting. RGB.js CSS colour manipulation.

    Generic (Specifically Animation)

    See also(2005) TiddlyWiki animation write-up.

    Animator.js Runs the dynamic flow of stepping through an animation, delegating to specificstrategies.

    Morpher.js Morphing animation strategy. Cool smoothly animates between two CSS styles. Scroller.js Scroller animation strategy. Scrolls window to show an element. (The way the page

    smoothly scrolls to show a tiddler when you click its link).

    Slider.js Slider animation strategy. Slides elements opening and closed (e.g. Closing tiddlers orthe Options box on right sidebar.).

    Zoomer.jsZoomer animation strategy (the way a tiddler jumps out from its link).

    http://softwareas.com/tiddlywiki-internals-2-of-3-list-of-javascript-files#commentshttp://softwareas.com/tiddlywiki-internals-2-of-3-list-of-javascript-files#commentshttp://softwareas.com/tiddlywiki-internals-2-of-3-list-of-javascript-files#commentshttp://softwareas.com/category/softwaredevhttp://softwareas.com/category/softwaredevhttp://softwareas.com/category/softwaredevhttp://twitter.com/mahemoffhttp://twitter.com/mahemoffhttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-2-of-3-list-of-javascript-fileshttp://softwareas.com/tiddlywiki-internals-2-of-3-list-of-javascript-fileshttp://softwareas.com/tiddlywiki-internals-2-of-3-list-of-javascript-fileshttp://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-fileshttp://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-fileshttp://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-fileshttp://ajaxpatterns.org/One-Second_Mutation#TiddlyWiki_2http://ajaxpatterns.org/One-Second_Mutation#TiddlyWiki_2http://ajaxpatterns.org/One-Second_Mutation#TiddlyWiki_2http://ajaxpatterns.org/One-Second_Mutation#TiddlyWiki_2http://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-fileshttp://softwareas.com/tiddlywiki-internals-2-of-3-list-of-javascript-fileshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://twitter.com/mahemoffhttp://softwareas.com/category/softwaredevhttp://softwareas.com/tiddlywiki-internals-2-of-3-list-of-javascript-files#comments
  • 8/2/2019 Tiddlywiki internals

    8/15

    Tiddlywiki-Specific Utilities

    FormatterHelpers.jsUtilities specifically for Formatters. Refresh.js Mechanism for notifying and updating elements based on changes, e.g. if stylesheet

    shadow tiddler is updated.

    Utilities.js Miscellaneous TiddlyWiki-specific utility functions.

    Data Structures

    Tiddler.js Data structure representing a tiddler, i.e. a block of text with a title. TiddlerFields.js Augments TiddlyWiki to manage tiddler fields. TiddlyWiki.js Data structure representing a collection of tiddlers.

    Data Import/Export

    AdaptorBase.js Adaptors convert from various wiki formats (e.g. Mediawiki) to TiddlyWiki. Thisis the base class for Adaptors.

    FileAdaptor.js Subclass of AdaptorBase which reads the default/standard Tiddlywiki format. Import.js Macro to import tiddlers from another Tiddlywiki. LoaderSaver.js Converts between HTML and a list of tiddlers. (I think the main purpose is to get

    a clean HTML list of tiddlers.)

    Saving.js Saves the Tiddlywiki main case is serialising everything to DOM elements and savingto local file system.

    SavingRSS.js Serves Tiddlywiki as RSS format (e.g.TiddlyWiki.com RSS feed) showing time-sortedlist of recently updated tiddlers.

    Sync.js Syncs TW21Loader.js Standard implementation of LoaderBase (defined in LoaderSaver.js). TW21Saver.js Standard implementation of SaverBase (defined in LoaderSaver.js).

    Strategies

    This is a broad category of options and control-type functions. The control-type functions arehere because they are designed using flexible mechanisms which make them easily overrideableby plugin developers.

    Config.js General Tiddlywiki config controls capacities, names of shadow tiddlers, whichoptions can be set, other stuff.

    Commands.js Handlers for menus and toolbar. Macros.js Defines built-in macros. Formatter.js Formatters are strategies for locating regexp patterns in the wiki text (wiki words,

    image URLs, etc.) and rendering them.

    Options.js Options are cookie-based preferences. The user can generally set them directly onthe Tiddlywiki UI. This is in contrast to Config.js settings, which are fixed unless the uswer cares

    to dive into the source code.

    Wikifier.js

    http://www.tiddlywiki.com/index.xmlhttp://www.tiddlywiki.com/index.xmlhttp://www.tiddlywiki.com/index.xmlhttp://www.tiddlywiki.com/index.xml
  • 8/2/2019 Tiddlywiki internals

    9/15

    UI Elements

    Backstage.js The backstage space at the top of the page, with access to advanced features andacting as an escape route after over-enthusiastic bouts of customisation.

    ListView.js A table-like list, e.g. shows all options when you hit Backstage|Tweak.

    Manager.js Plugin manager (accessible from Backstage|Plugins) Messages.js Simple status notifications. NewTiddler.jsMacro for a new tiddler, e.g. when user hits New Tiddler menu option, and also

    new journal.

    Popup.js Popup menu (e.g. when you click on the name of a tiddler in the list of shadowtiddlers).

    Search.js Search implementation allows user to search for a term. Sparkline.js Generates CSS basedsparklinesgraphic. Story.js Manages the container of all visible tiddler UI elements. Tabs.js A UI element for handling tabs. Toolbar.js The toolbar shown in the top of a tiddler (with close, close others etc controls

    or done-cancel-delete if open).

    Wizard.js Multi-step wizard UI framework.Miscellaneous

    Deprecated.js Deprecated functions. Guide.js A short readme file. Lingo.js internationalisation-localisation support contains string keys and their English values. Upgrade.js Support for upgrading Tiddlywiki vgersion. Version.js Short file with info about this version of Tiddlywiki.

    http://softwareas.com/en.wikipedia.org/wiki/Sparklinehttp://softwareas.com/en.wikipedia.org/wiki/Sparklinehttp://softwareas.com/en.wikipedia.org/wiki/Sparklinehttp://softwareas.com/en.wikipedia.org/wiki/Sparkline
  • 8/2/2019 Tiddlywiki internals

    10/15

    Tiddlywiki internals 3 of 3: Key Javascript Classes and Files

    August 11th, 2008 4 CommentsSoftwareDev

    Welcome to Mahemoff's blog on web development, UX, and software development. I most

    recently worked in developer relations at Google, focusing on Chrome and HTML5, and am nowbusy baking a few apps independently.Follow @mahemoff on Twitter

    (This is part 3 of a 3-part series.Part 1introduces the internals and highlights some of the keypatterns and concepts.Part 2introduces each Javascript file.Part 3focuses on the internals of themore important classes and files.)

    Concluding this series, below is a list of all core Javascript files, organised into functionalgroups.

    main.js

    main() is the function that runs onload.

    Key functions:

    creates a new tiddlywiki data store (new TiddlyWiki()) - this is the collection of tiddlersusers are exposed to. The store is populated using TiddlyWiki.prototype.loadFromDiv(),which loads all the tiddlers from the "storeArea" div, which is an invisible block on thepage (and rendered back in nice - and visible - manner later on).

    creates a second TiddlyWiki data store to hold "shadow tiddlers" - these are"meta"/config tiddlers holding data such as CSS styling. Populated from invisible"shadowArea" div (which at compile time is defined in the Shadow/ directory).

    creates a new "Story div", a div which will show tiddlers to the user, and themes itaccording to config.options.txtTheme

    sets up Popup.onDocumentClick (removes popup menus when user clicks outside of themenu)

    sets up event propagation - certain tiddlers are notified when certain actions occur. Themappings are defined in refresh.js (e.g. {name: "StyleSheetLayout", notify:refreshStyles})

    sets up and renders backstage

    loads plugins (plugins are evidently supposed to set a global "plugin problem" value if aproblem occurs)

    General:

    calls several lifecycle event handlers as it loads - the wiki config can provide hookfunctions which run upon particular lifetime events

    http://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-files#commentshttp://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-files#commentshttp://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-files#commentshttp://softwareas.com/category/softwaredevhttp://softwareas.com/category/softwaredevhttp://softwareas.com/category/softwaredevhttp://twitter.com/mahemoffhttp://twitter.com/mahemoffhttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-2-of-3-list-of-javascript-fileshttp://softwareas.com/tiddlywiki-internals-2-of-3-list-of-javascript-fileshttp://softwareas.com/tiddlywiki-internals-2-of-3-list-of-javascript-fileshttp://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-fileshttp://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-fileshttp://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-fileshttp://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-fileshttp://softwareas.com/tiddlywiki-internals-2-of-3-list-of-javascript-fileshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://twitter.com/mahemoffhttp://softwareas.com/category/softwaredevhttp://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-files#comments
  • 8/2/2019 Tiddlywiki internals

    11/15

    benchmarks most of the above (the benchmarking was possibly a quick fix - relies onvariables t1,t2...t10 -> this code could be optimised for conciseness using functionwrappers, but maybe startup would be too slow that way).

    After initial setup ensures tiddlywiki data structures and other initialisation/config piecesare in place, it blats and shows the display with restart() and refreshDisplay().

    Plugins

    Tiddlywiki has a strong plugin architecture. Each plugin is included as a regular (non-shadow)tiddler, one that must be tagged "systemConfig". (For all intents and purposes, "systemConfig" issynonymous with "plugin".) There's an example shipping with the default tiddlywiki instance ontiddlywiki.com (and a more detailed example in the source code -association/plugins/SparklinePlugin/SparklinePlugin.js). (Also of interest,the latest plugintemplate at the tiddlywiki.org wiki.)

    PLAIN TEXT

    HTML:

    1.2./***3.|''Name:''|ExamplePlugin|4.|''Description:''|To demonstrate how to write TiddlyWiki

    plugins|

    5.|''Version:''|2.0.3|6.|''Date:''|Sep 22, 2006|7.|''Source:''|http://www.tiddlywiki.com/#ExamplePlugin|8.|''Author:''|JeremyRuston (jeremy (at) osmosoft (dot) com)|9.|''License:''|[[BSD open source license]]|10. |''~CoreVersion:''|2.1.0|11. |''Browser:''|Firefox 1.0.4+; Firefox 1.5;

    InternetExplorer 6.0|

    12. ***/13.14. //{{{15.16. // Uncomment the following line to see how the

    PluginManager deals with errors in plugins17. // deliberateError();18.19. // Log a message20. pluginInfo.log.push("This is a test message from

    " + tiddler.title);

    21.22. //}}}

    http://www.tiddlywiki.org/wiki/Plugin_specs#Templatehttp://www.tiddlywiki.org/wiki/Plugin_specs#Templatehttp://www.tiddlywiki.org/wiki/Plugin_specs#Templatehttp://www.tiddlywiki.org/wiki/Plugin_specs#Templatehttp://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-fileshttp://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-fileshttp://december.com/html/4/element/div.htmlhttp://december.com/html/4/element/div.htmlhttp://december.com/html/4/element/pre.htmlhttp://december.com/html/4/element/pre.htmlhttp://december.com/html/4/element/pre.htmlhttp://december.com/html/4/element/div.htmlhttp://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-fileshttp://www.tiddlywiki.org/wiki/Plugin_specs#Templatehttp://www.tiddlywiki.org/wiki/Plugin_specs#Template
  • 8/2/2019 Tiddlywiki internals

    12/15

    23.

    A plugin is essentially just a Javascript block which gets executed on page load. All the

    biosketch info is optional (although in some cases, it does effect processing, e.g. there is a checkagainst the required TiddlyWiki version). "Just some Javascript" did you say?This post onJQuery pluginsby JQuery daddy John Resig is instructive. His point is that a plugin architectureneeds explicit points for plugins to hook into - i.e. an API - and the existence of a plugincatalogue. Tiddlywiki doesn't have a plugin APIper se, but is structured with plenty of extensionpoints to naturally hook into. As for the catalogue, there's also aplugin wiki area, with a grander-scale plugin repo project in progress.

    Incidentally, note that you don't have to register the Javascript block as you might do in someother frameworks (e.g. runOnInit(myPlugin); ). It executes automatically when plugins areloaded.

    Okay, so about those plugin extension points. I'm still learning that. In the case of sparklines, the

    purpose is to create a new macro (e.g. ), so it definesconfig.macros.sparkline.handler(place,macroName,params) , and its "output" is to

    populate the place element with sparkline content.

    Another popular pasttime for plugin developers is szhushing the global Formatter object to shapehow stuff gets rendered. e.g. if your formatter locates the built-in formatter named "heading", itcould easily overwrite its handler method to MAKE ALL THE HEADINGS SHOUT ATUNSUSPECTING READERS.

    To install a plugin, users usually use the Import dialog, accessible from Backstage. It's alsopossible to manually include pluginsvia cut-and-pasteinto Tiddlywiki.

    There's much more to be said about plugins. The bottom line is that Tiddlywiki's architecture letsyou bend the core product into many things. (By "architecture", I refer to both the pluginmechanism and the flexible nature in which the overall architecture is structured.)

    Tiddlers

    Tiddlers are the atomic content blocks that make up a Tiddlywiki, typically about a paragraph inlength. A Tiddler is simply a block of text, with extra info like a title, a list of tags, and

    timestamp data. There's also a fields hash where you could store any arbitrary properties. (Thisseems suitable for plugins, but the core also makes use of it, and I don't really get that. Even forplugins, why can't they just make new fields dynamically?)

    Tiddler is a Javascript class, so you get a new instance with new Tiddler(). Internally, it usesa publish-subscribe mechanism, where a changed() method is called after any mutation. This

    basically ensures the links property is up to date, as links is a redundant (and presumably therefor performance) collection of links inside the tiddler.

    http://ejohn.org/blog/jquery-plugins-size-and-storage/http://ejohn.org/blog/jquery-plugins-size-and-storage/http://ejohn.org/blog/jquery-plugins-size-and-storage/http://ejohn.org/blog/jquery-plugins-size-and-storage/http://www.tiddlywiki.org/wiki/Pluginshttp://www.tiddlywiki.org/wiki/Pluginshttp://www.tiddlywiki.org/wiki/Pluginshttp://mnteractive.com/archive/how-to-install-a-tiddlywiki-plugin/http://mnteractive.com/archive/how-to-install-a-tiddlywiki-plugin/http://mnteractive.com/archive/how-to-install-a-tiddlywiki-plugin/http://mnteractive.com/archive/how-to-install-a-tiddlywiki-plugin/http://www.tiddlywiki.org/wiki/Pluginshttp://ejohn.org/blog/jquery-plugins-size-and-storage/http://ejohn.org/blog/jquery-plugins-size-and-storage/
  • 8/2/2019 Tiddlywiki internals

    13/15

    A Tiddler also has a collection of "slices", though the collection is managed by TiddlyWikirather than Tiddler. (This relates to the fact that shadow tiddlers are mere text blocks - usingTiddlywiki to extract slices ensures shadow tiddlers can also be sliced up....and slices are a majorfeature of most shadow tiddlers, since they are config-related.)

    There's a string->string map from name to slice. This is similar to the fields hash, insofar as it's afree-form map. In this case, though, it's something that can easily be changed by the user in realtime, as the slice collection is sync'd to the tiddler content. For example: |''slicename:''|''someslice content''|. Slices allow for easily edited meta-data, e.g. a stylesheet tiddler can have a slicecalled "backgroundColour". Users then edit the backgroundColor slice content to set thebackground colour.

    A Tiddler also has a set of notification handlers - this is also managed by TiddlyWiki rather thanthe Tiddlers themselves (again, this ensures the mechanism works for shadow tiddlers). Theseare listeners/observers that are notified each time tiddler is changed.

    A file closely related to Tiddler is TiddlerFields.js. It actually alters the TiddlyWiki definitionrather than the Tiddler definition, but in any event it deals with accessing the Tiddler's fieldsmap.

    Shadow Tiddlers

    Shadow tiddlers are a particular type of tiddler. There's no separate "ShadowTiddler" class, butthey are held in a separate store and treated in special ways. Indeed, shadow tiddlers aren'tactually of class Tiddler (which is slightly confusing). They are simply a title-text pairing; thedata structure is a map from title to text. In contrast, regular Tiddlers are mapped from title toTiddler.

    In particular, TiddlyWiki has a fallback mechanism when asked to return a tiddler - if the tiddlerdoesn't exist, it will attempt to revert to a shadow tiddler of the same name. Shadow tiddlers areimmutable (unless you hack source code), whereas tiddlers are of course easily edited. You canoverride shasow tiddlers with regular tiddlers of the same name, but the original shadow stilllurks (in a good way) in the background.

    To see this, open an editable Tiddlywiki, choose a shadow tiddler from the right sidebar Contentsmenu (e.g. SiteUrl), edit it, and save it. Then re-open it to verify your changes were affected.Then delete it, and notice that it's still in the list of shadow tiddlers. When you open it yet again,you'll see it now contains the original content. (The shadow tiddler itself never changed.)

    Shadow tiddlers are used for config stuff like stylesheets. The fail-safe mechanism ensures youcan easily "restore factory defaults" at any time.

    TiddlyWiki

  • 8/2/2019 Tiddlywiki internals

    14/15

    A Tiddlywiki is essentially a hash of Tiddlers, keyed on their title. More precisely, it's a wrapperaround this hash. Here's a (slightly refactored) look at the relevant code for managing tiddlers,which looks like any other hash wrapper:

    PLAIN TEXT

    JAVASCRIPT:

    1.function TiddlyWiki()2.{3. var tiddlers = {}; // Hashmap by name of tiddlers4. ...5. this.clear = function(){ tiddlers = {}; };6. this.fetchTiddler = function(title){return

    tiddlers[title]; };

    7. this.deleteTiddler = function(title){deletetiddlers[title]; };

    8. this.addTiddler = function(tiddler){tiddlers[tiddler.title] = tiddler; };

    9.}

    There is also a set of similar methods which wrap around these to provide more intelligentbehaviour. e.g. createTiddler() wraps addTiddler() to provide "Add or retrieve if exists"functionality. getTiddler() wraps fetchTiddler() to ensure null is returned if no such tiddler exists.removeTiddler() wraps deleteTiddler() to delete only if the tiddler exists, and also notifies thetiddler's listeners. Most other methods also do "general stuff" with the tiddlers hash. A lot ofthem also run operations on behalf of Tiddlers themselves (this is mostly so it can endow shadowtiddlers - which are just strings - with certain behaviour, as mentioned in the previous section.)

    Story

    Story is the sovereign UI element in TiddlyWiki - its the container of all visible Tiddlers whichyou'll usually see occupying the main, middle, column. Theoretically, there could be more thanone Story instance on the page, but I'm told that there are some hard coding shenanigans that ruleit out in the project's current state. (Specifically, direct references to the "story" instance thatmain.js creates.) So Story is a singleton class in practice.

    One gotcha here with the nomenclature - a "tiddler" inside Story.js is conceptually a DOMelement, whereas in most other places its a data structure. Obviously, the tiddler UI element is arendering of the tiddler data structure. However, the implementation isn't entirely symmetricalbecause the data structure has a dedicated class (Tiddler), while the UI element doesn't; tiddler

    rendering is handled purely by the Story class. In one case (displayTiddler()), either form isvalid as the "tiddler" argument, similar to $() functions that accept either the element or the ID

    (title = (tiddler instanceof Tiddler) ? tiddler.title : tiddler .)

    http://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-fileshttp://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-fileshttp://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-files
  • 8/2/2019 Tiddlywiki internals

    15/15

    Story's key properties are a container ID, which points to the container DOM element, and anidPrefix, the prefix for all tiddler IDs. The container already exists on the page when a Storyobject is created to manage it.

    PLAIN TEXT

    JAVASCRIPT:

    1.function Story(containerId,idPrefix)2.{3. this.container = containerId;4. this.idPrefix = idPrefix;5. ...6.}

    Each tiddler's ID is simplyidPrefix + title

    . You might expect an array of tiddler DOMelements, but Story doesn't need it, as it can use the DOM itself to keep track of them; the directdescendents of the Story container are the Tiddler elements. It simply uses DOM traversaltechniques to iterate through all such elements, when it needs to. (There's a genericforEachTiddler function too; I could imagine there might be some value in othercollectionclosure methods.)

    Story contains the logic to display a tiddler. displayTiddler() decides if the tiddler is alreadybeing shown, and if not, creates a new child element with the tiddler content. It delegates to theanimation engine for display.

    There is also refreshTiddler() - the logic for rendering the tiddler - which is called fromdisplayTiddler(). For flexibility, tiddlers are rendered using a template, a template which isgenerally contained in a shadow tiddler. There's a ViewTemplate shadow tiddler and anEditTemplate shadow tiddler - it depends on whether the tiddler is being edited.

    Furthermore, there is the concept of themes, which means you can use different templates. This

    is handled by switchTheme(). An example of different templates isillustrated here in theTiddlyPedia theme.

    And that concludes the three-part series. Thanks again to those who helped me gather this info(see credits infirst article). I've learned a lot about Tiddlywiki in writing it, but I still have a longway to go. There wil be more.

    http://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-fileshttp://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-fileshttp://martinfowler.com/bliki/CollectionClosureMethod.htmlhttp://martinfowler.com/bliki/CollectionClosureMethod.htmlhttp://martinfowler.com/bliki/CollectionClosureMethod.htmlhttp://martinfowler.com/bliki/CollectionClosureMethod.htmlhttp://tiddlythemes.com/empties/TiddlyPedia.html#ViewTemplate%20EditTemplatehttp://tiddlythemes.com/empties/TiddlyPedia.html#ViewTemplate%20EditTemplatehttp://tiddlythemes.com/empties/TiddlyPedia.html#ViewTemplate%20EditTemplatehttp://tiddlythemes.com/empties/TiddlyPedia.html#ViewTemplate%20EditTemplatehttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://softwareas.com/tiddlywiki-internals-1-of-3-architectural-conceptshttp://tiddlythemes.com/empties/TiddlyPedia.html#ViewTemplate%20EditTemplatehttp://tiddlythemes.com/empties/TiddlyPedia.html#ViewTemplate%20EditTemplatehttp://martinfowler.com/bliki/CollectionClosureMethod.htmlhttp://martinfowler.com/bliki/CollectionClosureMethod.htmlhttp://softwareas.com/tiddlywiki-internals-3-of-3-key-javascript-classes-and-files