MarkDown formatting about 1/3-1/2 done.
[mkws-moved-to-github.git] / doc / mkws-developer.markdown
1 % The MasterKey Widget Set developer's guide
2 % Mike Taylor
3 % 11 August 2014
4
5
6 Introduction
7 ============
8
9 Development with MKWS consists primarily of defining new types of
10 widgets. These can interact with the core functionality is several
11 defined ways.
12
13 You create a new widget type by calling the `mkws.registerWidgetType`
14 function, passing in the widget name and a function. The name is used
15 to recognise HTML elements as being widgets of this type -- for
16 example, if you register a `Foo` widget, elements like
17 `<div class="mkwsFoo">` will be widgets of this type.
18
19 The function promotes a bare widget object (passed as `this`) into a
20 widget of the appropriate type. MKWS doesn't use classes or explicit
21 prototypes: it just makes objects that have the necessary
22 behaviours. There are _no_ behaviours that Widgets are obliged to
23 provide: you can make a doesn't-do-anything-at-all widget if you like:
24
25         mkws.registerWidgetType('Sluggard', function() {});
26
27 More commonly, widgets will subscribe to one or more events, so that
28 they're notified when something interesting happens. For example, the
29 `Log` widget asks to be notified when a `log` event happens, and
30 appends the logged message to its node, as follows:
31
32         mkws.registerWidgetType('Log', function() {
33           var that = this;
34
35           this.team.queue("log").subscribe(function(teamName, timestamp, message) {
36             $(that.node).append(teamName + ": " + timestamp + message + "<br/>");
37           });
38         });
39
40 This simple widget illustrates several important points:
41
42 * The base widget object (`this`) has several baked-in properties and
43   methods that are available to individual widgets. These include
44   `this.team` (the team that this widget is a part of) and `this.node`
45   (the DOM element of the widget). See below for a full list.
46
47 * The team object (`this.team`) also has baked-in properties and
48   methods. These include the `queue` function, which takes an event-name
49   as its argument. See below for a full list.
50
51 * You can add functionality to a widget by subscribing it to an
52   event's queue using `this.team.queue("EVENT").subscribe`. The
53   argument is a function which is called whenever the event is
54   published. The arguments to the function are different for different
55   events.
56
57 * As with so much JavaScript programming, the value of the special
58   variable `this` is lost inside the `subscribez` callback function,
59   so it must be saved if it's to be used inside that callback
60   (typically as a local variable named `that`).
61
62
63 Widget specialisation (inheritance)
64 ===================================
65
66 Many widgets are simple specialisations of existing widgets. For
67 example, the `Record` widget is the same as the `Records` widget
68 except that it defaults to displaying a single record. It's defined as
69 follows:
70
71         mkws.registerWidgetType('Record', function() {
72           mkws.promotionFunction('Records').call(this);
73           if (!this.config.maxrecs) this.config.maxrecs = 1;
74         });
75
76 Remember that when a promotion function is called, it's passed a base
77 widget object that's not specialised for any particular task. To make
78 a specialised widget, first promote that base widget into the type
79 that you want to specialise from -- in this case, "Records" -- using
80 the promotion function that's been registered for that type.
81
82 Once this has been done, the specialisations can be introduced. In
83 this case, it's a very simple matter of changing the "maxrecs"
84 configuration setting to 1 unless it's already been given an explicit
85 value. (That would occur if the HTML used an element like <div
86 class="mkwsRecord" maxrecs="2">, though it's not obvious why anyone
87 would do that.)
88
89
90 Widget Properties and Methods
91 =============================
92
93 String this.type
94         A string containing the type of the widget.
95
96 Team this.team
97         The team object to which this widget belongs. The team has
98         several additional important properties and methods, described
99         below.
100
101 DOMElement this.node
102         The DOM element of the widget
103
104 Hash this.config
105         A table of configuration values for the widget. This table
106         inherits missing values from the team's configuration, which
107         in turn inherits from the top-level MKWS configuration, which
108         inherits from the default configuration. Instances of widgets
109         in HTML can set configuration items as HTML attributes, as in
110         <div class="mkwsRecords" maxrecs="2">.
111
112 String this.toString()
113         A function returning a string that briefly names this
114         widget. Can be useful in logging.
115
116 Void this.log(string)
117         A function to log a string for debugging purposes. The string
118         is written on the browser console, and also published to any
119         "log" subcribers.
120
121 String this.value()
122         A function returning the value of the widget's HTML element.
123
124
125 Team methods
126 ============
127
128 Since the team object is supposed to be opaque to widgets, all access
129 is via the following API methods rather than direct access to
130 properties.
131
132 String team.name()
133 Bool team.submitted()
134 Num team.perpage()
135 Num team.totalRecordCount()
136 Num team.currentPage();
137 String team.currentRecordId()
138 String team.currentRecordData()
139         Simple accessor functions that provide the ability to read
140         properties of the team.
141
142 Array team.filters()
143         Another accessor function, providing access to the array of
144         prevailing filters (which narrow the search results by means
145         of Pazpar2 filters and limits). This is really too complicated
146         an object for the widgets to be given access to, but it's
147         convenient to do it this way. See the "Navi" widget, which is
148         the only place it's used.
149
150 Hash team.config()
151         Access to the team's configuration settings. There is almost
152         certainly no reason to use this: the settings that haven't
153         been overridden are accessible via this.config.
154
155 Void team.set_sortOrder(string)
156 Void team.set_perpage(number)
157         "Setter" functions for the team's sortOrder and perpage
158         functions. Unlikely to be needed outside of the "Sort" and
159         "Perpage" widgets.
160
161 Queue team.queue(eventName)
162         Returns the queue associated with the named event: this can be
163         used to subscribe to the event (or more rarely to publish it).
164
165 Bool team.targetFiltered(targetId)
166         Indicates whether the specified target has been filtered by
167         selection as a facet.
168
169 Void team.newSearch(query, sortOrder, maxrecs, perpage, limit, targets, targetfilter)
170         Starts a new search with the specified parameters. All but the
171         query may be omitted, in which case the prevailing defaults
172         are used.
173
174 Void team.reShow()
175         Using the existing search, re-shows the result records after a
176         change in sort-order, per-page count, etc.
177
178 String team.recordElementId(recordId)
179         Utility function for converting a record identifer (returned
180         from Pazpar2) into a version suitable for use as an HTML
181         element ID.
182
183 String team.renderDetails(recordData)
184         Utility function returns an HTML rendering of the record
185         represented by the specified data.
186
187 Template team.loadTemplate(templateName)
188         Loads (or retrieves from cache) the named Handlebars template,
189         and returns it in a form that can be invoked as a function,
190         passed a data-set.
191
192 Some of these methods either (A) are really too low-level and should
193 not be exposed, or (B) should be widget-level methods. The present
194 infelicities reflect the fact that some code that rightly belongs in
195 widgets is still in the team. When we finish migrating it, the widget
196 API should get simpler.
197
198 - - -
199
200 Copyright (C) 2013-2014 by IndexData ApS, <http://www.indexdata.com>