Resolve
authorMike Taylor <mike@indexdata.com>
Thu, 14 Aug 2014 14:03:03 +0000 (15:03 +0100)
committerMike Taylor <mike@indexdata.com>
Thu, 14 Aug 2014 14:03:03 +0000 (15:03 +0100)
12 files changed:
doc/.gitignore
doc/Makefile
doc/mkws-developer.markdown [new file with mode: 0644]
doc/mkws-developer.txt [deleted file]
doc/mkws-doc.css
doc/mkws-manual.markdown
examples/htdocs/mike.html
src/mkws-widget-builder.js
src/mkws-widget.js
tools/htdocs/.gitignore
tools/service-proxy/.gitignore [new file with mode: 0644]
tools/service-proxy/Makefile [new file with mode: 0644]

index 5d3ccd7..653ed0c 100644 (file)
@@ -4,3 +4,6 @@ README.pdf
 mkws-manual.html
 mkws-manual.odt
 mkws-manual.pdf
+mkws-developer.html
+mkws-developer.odt
+mkws-developer.pdf
index 19b9dfb..2a6b99b 100644 (file)
@@ -1,9 +1,10 @@
 # Copyright (c) 2013-2014 IndexData ApS. http://indexdata.com
 
 DOCS = README.html README.odt README.pdf \
-       mkws-manual.html mkws-manual.odt mkws-manual.pdf
+       mkws-manual.html mkws-manual.odt mkws-manual.pdf \
+       mkws-developer.html mkws-developer.odt mkws-developer.pdf
 
-INSTALLABLE = README.html mkws-manual.html mkws-doc.css
+INSTALLABLE = README.html mkws-manual.html mkws-developer.html mkws-doc.css
 INSTALLED = $(INSTALLABLE:%=../tools/htdocs/%)
 
 install: $(INSTALLED)
diff --git a/doc/mkws-developer.markdown b/doc/mkws-developer.markdown
new file mode 100644 (file)
index 0000000..00a5b59
--- /dev/null
@@ -0,0 +1,261 @@
+% The MasterKey Widget Set developer's guide
+% Mike Taylor
+% 11 August 2014
+
+
+Overview
+========
+
+Core concepts
+-------------
+
+Development with MKWS consists primarily of defining new types of
+widgets. These can interact with the core functionality is several
+defined ways.
+
+You create a new widget type by calling the `mkws.registerWidgetType`
+function, passing in the widget name and a function. The name is used
+to recognise HTML elements as being widgets of this type -- for
+example, if you register a `Foo` widget, elements like
+`<div class="mkwsFoo">` will be widgets of this type.
+
+The function promotes a bare widget object (passed as `this`) into a
+widget of the appropriate type. MKWS doesn't use classes or explicit
+prototypes: it just makes objects that have the necessary
+behaviours. There are _no_ behaviours that Widgets are obliged to
+provide: you can make a doesn't-do-anything-at-all widget if you like:
+
+       mkws.registerWidgetType('Sluggard', function() {});
+
+More commonly, widgets will subscribe to one or more events, so that
+they're notified when something interesting happens. For example, the
+`Log` widget asks to be notified when a `log` event happens, and
+appends the logged message to its node, as follows:
+
+       mkws.registerWidgetType('Log', function() {
+         var that = this;
+
+         this.team.queue("log").subscribe(function(teamName, timestamp, message) {
+           $(that.node).append(teamName + ": " + timestamp + message + "<br/>");
+         });
+       });
+
+This simple widget illustrates several important points:
+
+* The base widget object (`this`) has several baked-in properties and
+  methods that are available to individual widgets. These include
+  `this.team` (the team that this widget is a part of) and `this.node`
+  (the DOM element of the widget). See below for a full list.
+
+* The team object (`this.team`) also has baked-in properties and
+  methods. These include the `queue` function, which takes an event-name
+  as its argument. See below for a full list.
+
+* You can add functionality to a widget by subscribing it to an
+  event's queue using `this.team.queue("EVENT").subscribe`. The
+  argument is a function which is called whenever the event is
+  published. The arguments to the function are different for different
+  events.
+
+* As with so much JavaScript programming, the value of the special
+  variable `this` is lost inside the `subscribez` callback function,
+  so it must be saved if it's to be used inside that callback
+  (typically as a local variable named `that`).
+
+
+Widget specialisation (inheritance)
+-----------------------------------
+
+Many widgets are simple specialisations of existing widgets. For
+example, the `Record` widget is the same as the `Records` widget
+except that it defaults to displaying a single record. It's defined as
+follows:
+
+       mkws.registerWidgetType('Record', function() {
+         mkws.promotionFunction('Records').call(this);
+         if (!this.config.maxrecs) this.config.maxrecs = 1;
+       });
+
+Remember that when a promotion function is called, it's passed a base
+widget object that's not specialised for any particular task. To make
+a specialised widget, you first promote that base widget into the type
+that you want to specialise from -- in this case, `Records` -- using
+the promotion function that's been registered for that type.
+
+Once this has been done, the specialisations can be introduced. In
+this case, it's a very simple matter of changing the `maxrecs`
+configuration setting to 1 unless it's already been given an explicit
+value. (That would occur if the HTML used an element like `<div
+class="mkwsRecord" maxrecs="2">`, though it's not obvious why anyone
+would do that.)
+
+
+Reference Guide
+===============
+
+
+Widget properties and methods
+-----------------------------
+
+The following properties and methods exist in the bare widget object
+that is passed into `registerWidgetType`'s callback function, and can
+be used by the derived widget.
+
+* `String this.type` --
+       A string containing the type of the widget.
+
+* `Team this.team` --
+       The team object to which this widget belongs. The team has
+       several additional important properties and methods, described
+       below.
+
+* `DOMElement this.node` --
+       The DOM element of the widget
+
+* `Hash this.config` --
+       A table of configuration values for the widget. This table
+       inherits missing values from the team's configuration, which
+       in turn inherits from the top-level MKWS configuration, which
+       inherits from the default configuration. Instances of widgets
+       in HTML can set configuration items as HTML attributes: for
+       example, the HTML element
+       `<div class="mkwsRecords" maxrecs="10">`.
+       creates a widget for which `this.config.maxrecs` is set to 10.
+
+* `String this.toString()` --
+       A function returning a string that briefly names this
+       widget. Can be useful in logging.
+
+* `Void this.log(string)` --
+       A function to log a string for debugging purposes. The string
+       is written on the browser console, and also published to any
+       subcribers to the `log` event.
+
+* `String this.value()` --
+       A function returning the value of the widget's HTML element.
+
+* `VOID autosearch()` --
+       Registers that this kind of widget is one that requires an
+       automatic search to be run for it if an `autosearch` attribute
+       is provided on the HTML element. This is appropriate for
+       widgets such as `Records` and `Facet` that display some part
+       of a search result.
+
+* `VOID hideWhenNarrow()` --
+       Registers that this widget should hide itself when the page
+       becomes "narrow" -- that is, fewer pixels in width that the
+       threshhold value specified by the top-level configuration item
+       `responsive_design_width`. Should be used for "unimportant"
+       widgets that can be omitted from the mobile version of a site.
+
+* `expandValue()` --
+       TODO: either document this or remove it from the API.
+
+* `subwidget(type, overrides, defaults)` --
+       Returns the HTML of a subwidget of the specified type, which
+       can then be inserted into the widget using the
+       `this.node.html` function. The subwidget is given the same
+       attributes at the parent widget that invokes this function,
+       except where overrides are passed in. If defaults are also
+       provided, then these are used when the parent widget provides
+       no values. Both the `overrides` and `defaults` arguments are
+       hashes: the latter is optional.
+  
+       See for example the `Credo` widget defined in the example
+       area's `mkws-widget-credo.js` file. This uses several
+       invocations of `subwidget` to create a complex compound widget
+       with numerous text, facet and image panes. TODO: rename this
+       widget and everything related to it.
+
+In addition to these properties and methods of the bare widget object,
+some kinds of specific widget add other properties of their own. For
+example, the `Builder` widget uses a `callback` property as the
+function that it use to publish the widget definition that it
+constructs. This defaults to the builtin function `alert`, but can be
+overridden by derived widgets such as `ConsoleBuilder`.
+
+
+Team methods
+------------
+
+Since the team object is supposed to be opaque to widgets, all access
+is via the following API methods rather than direct access to
+properties.
+
+* `String team.name()`
+* `Bool team.submitted()`
+* `Num team.perpage()`
+* `Num team.totalRecordCount()`
+* `Num team.currentPage();`
+* `String team.currentRecordId()`
+* `String team.currentRecordData()`
+
+These are all simple accessor functions that provide the ability to
+read properties of the team.
+
+* `Array team.filters()` --
+       Another accessor function, providing access to the array of
+       prevailing filters (which narrow the search results by means
+       of Pazpar2 filters and limits). This is really too complicated
+       an object for the widgets to be given access to, but it's
+       convenient to do it this way. If you must insist on using
+       this, see the `Navi` widget, which is the only place it's used.
+
+* `Bool team.targetFiltered(targetId)` --
+       Indicates whether the specified target has been filtered by
+       selection as a facet. This is used only by the `Facet` widget,
+       and there is probably no reason for you to use it.
+
+* `Hash team.config()` --
+       Access to the team's configuration settings. There is almost
+       certainly no reason to use this: the settings that haven't
+       been overridden are accessible via `this.config`.
+
+* `Void team.set_sortOrder(string)`, `Void team.set_perpage(number)` --
+       "Setter" functions for the team's sortOrder and perpage
+       functions. Unlikely to be needed outside of the `Sort` and
+       `Perpage` widgets.
+
+* `Queue team.queue(eventName)` --
+       Returns the queue associated with the named event: this can be
+       used to subscribe to the event (or more rarely to publish it).
+
+* `Void team.newSearch(query, sortOrder, maxrecs, perpage, limit, targets, targetfilter)` --
+       Starts a new search with the specified parameters. All but the
+       query may be omitted, in which case the prevailing defaults
+       are used.
+
+* `Void team.reShow()` --
+       Using the existing search, re-shows the result records after a
+       change in sort-order, per-page count, etc.
+
+* `String team.recordElementId(recordId)` --
+       Utility function for converting a record identifer (returned
+       from Pazpar2) into a version suitable for use as an HTML
+       element ID.
+
+* `String team.renderDetails(recordData)` --
+       Utility function returns an HTML rendering of the record
+       represented by the specified data.
+
+* `Template team.loadTemplate(templateName)` --
+       Loads (or retrieves from cache) the named Handlebars template,
+       and returns it in a form that can be invoked as a function,
+       passed a data-set.
+
+Some of these methods either (A) are really too low-level and should
+not be exposed, or (B) should be widget-level methods. The present
+infelicities reflect the fact that some code that rightly belongs in
+widgets is still in the team. When we finish migrating it, the widget
+API should get simpler.
+
+
+Events
+------
+
+TODO: list of events that can be usefully subscribed to.
+
+
+- - -
+
+Copyright (C) 2013-2014 by IndexData ApS, <http://www.indexdata.com>
diff --git a/doc/mkws-developer.txt b/doc/mkws-developer.txt
deleted file mode 100644 (file)
index 693df63..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-INTRODUCTION
-============
-
-Development with MKWS consists primarily of defining new types of
-widgets. These can interact with the core functionality is several
-defined ways.
-
-You create a new widget type by calling the mkws.registerWidgetType
-function, passing in the widget name and a function. The name is used
-to recognise HTML elements as being widgets of this type -- for
-example, if you register a "Foo" widget, elements like <div
-class="mkwsFoo"> will be widgets of this type.
-
-The function promotes a bare widget object (passed as `this') into a
-widget of the appropriate type. MKWS doesn't use classes or explicit
-prototypes: it just makes objects that have the necessary
-behaviours. Widgets have *no* behaviours that they have to provide:
-you can make a doesn't-do-anything-at-all widget if you like:
-
-       mkws.registerWidgetType('Sluggard', function() {});
-
-More commonly, widgets will subscribe to one or more events, so that
-they're notified when something interesting happens. For example, the
-"Log" widget asks to be notified when a "log" event happens, and
-appends the logged message to its node, as follows:
-
-       mkws.registerWidgetType('Log', function() {
-           var that = this;
-
-           this.team.queue("log").subscribe(function(teamName, timestamp, message) {
-               $(that.node).append(teamName + ": " + timestamp + message + "<br/>");
-           });
-       });
-
-This simple widget illustrates several important points:
-
-* The base widget object (`this') has several baked-in properties and
-  methods that are available to individual widgets. These include
-  this.team (the team that this widget is a part of) and this.node
-  (the DOM element of the widget).
-
-* The team object (`this.team') also has baked-in properties and
-  methods. These include the queue function, which takes an event-name
-  as its argument. It's possible to subscribe to an event's queue
-  using this.team.queue("EVENT").subscribe. The argument is a function
-  which is called whenever the event is published. The arguments to
-  the function are different for different events.
-
-* The value of `this' is lost inside the subscribe callback, so it
-  must be saved if it's to be used inside that callback (typically as
-  a local variable named `that').
-
-
-SPECIALISATION (INHERITANCE)
-============================
-
-Many widgets are simple specialisations of existing widgets. For
-example, the "Record" widget is the same as the "Records" widget
-except that it defaults to displaying a single record. It's defined as
-follows:
-
-       mkws.registerWidgetType('Record', function() {
-           mkws.promotionFunction('Records').call(this);
-           if (!this.config.maxrecs) this.config.maxrecs = 1;
-       });
-
-Remember that when a promotion function is called, it's passed a base
-widget object that's not specialised for any particular task. To make
-a specialised widget, first promote that base widget into the type
-that you want to specialise from -- in this case, "Records" -- using
-the promotion function that's been registered for that type.
-
-Once this has been done, the specialisations can be introduced. In
-this case, it's a very simple matter of changing the "maxrecs"
-configuration setting to 1 unless it's already been given an explicit
-value. (That would occur if the HTML used an element like <div
-class="mkwsRecord" maxrecs="2">, though it's not obvious why anyone
-would do that.)
-
-
-WIDGET PROPERTIES AND METHODS
-=============================
-
-String this.type
-       A string containing the type of the widget.
-
-Team this.team
-       The team object to which this widget belongs. The team has
-       several additional important properties and methods, described
-       below.
-
-DOMElement this.node
-       The DOM element of the widget
-
-Hash this.config
-       A table of configuration values for the widget. This table
-       inherits missing values from the team's configuration, which
-       in turn inherits from the top-level MKWS configuration, which
-       inherits from the default configuration. Instances of widgets
-       in HTML can set configuration items as HTML attributes, as in
-       <div class="mkwsRecords" maxrecs="2">.
-
-String this.toString()
-       A function returning a string that briefly names this
-       widget. Can be useful in logging.
-
-Void this.log(string)
-       A function to log a string for debugging purposes. The string
-       is written on the browser console, and also published to any
-       "log" subcribers.
-
-String this.value()
-       A function returning the value of the widget's HTML element.
-
-
-TEAM METHODS
-============
-
-Since the team object is supposed to be opaque to widgets, all access
-is via the following API methods rather than direct access to
-properties.
-
-String team.name()
-Bool team.submitted()
-Num team.perpage()
-Num team.totalRecordCount()
-Num team.currentPage();
-String team.currentRecordId()
-String team.currentRecordData()
-       Simple accessor functions that provide the ability to read
-       properties of the team.
-
-Array team.filters()
-       Another accessor function, providing access to the array of
-       prevailing filters (which narrow the search results by means
-       of Pazpar2 filters and limits). This is really too complicated
-       an object for the widgets to be given access to, but it's
-       convenient to do it this way. See the "Navi" widget, which is
-       the only place it's used.
-
-Hash team.config()
-       Access to the team's configuration settings. There is almost
-       certainly no reason to use this: the settings that haven't
-       been overridden are accessible via this.config.
-
-Void team.set_sortOrder(string)
-Void team.set_perpage(number)
-       "Setter" functions for the team's sortOrder and perpage
-       functions. Unlikely to be needed outside of the "Sort" and
-       "Perpage" widgets.
-
-Queue team.queue(eventName)
-       Returns the queue associated with the named event: this can be
-       used to subscribe to the event (or more rarely to publish it).
-
-Bool team.targetFiltered(targetId)
-       Indicates whether the specified target has been filtered by
-       selection as a facet.
-
-Void team.newSearch(query, sortOrder, maxrecs, perpage, limit, targets, targetfilter)
-       Starts a new search with the specified parameters. All but the
-       query may be omitted, in which case the prevailing defaults
-       are used.
-
-Void team.reShow()
-       Using the existing search, re-shows the result records after a
-       change in sort-order, per-page count, etc.
-
-String team.recordElementId(recordId)
-       Utility function for converting a record identifer (returned
-       from Pazpar2) into a version suitable for use as an HTML
-       element ID.
-
-String team.renderDetails(recordData)
-       Utility function returns an HTML rendering of the record
-       represented by the specified data.
-
-Template team.loadTemplate(templateName)
-       Loads (or retrieves from cache) the named Handlebars template,
-       and returns it in a form that can be invoked as a function,
-       passed a data-set.
-
-Some of these methods either (A) are really too low-level and should
-not be exposed, or (B) should be widget-level methods. The present
-infelicities reflect the fact that some code that rightly belongs in
-widgets is still in the team. When we finish migrating it, the widget
-API should get simpler.
-
index 603999a..0eb4a34 100644 (file)
@@ -69,13 +69,3 @@ table tr:nth-child(odd) {
 table tr:nth-child(even) {
     background: #bfdcf8;
 }
-
-/*
- * Works with the HTML emitted by pandoc. It would better if pandoc
- * were to emit class names that we can use. But it doesn't.
- */  
-body > p:last-of-type {
-    font-size: small;
-    max-width: none;
-    text-align: right;
-}
index 2247868..79b396e 100644 (file)
@@ -701,19 +701,19 @@ from that toolkit. The relevant lines are:
     </div>
 
 ----
-Element    Type    Default           Description
---------   -----   ---------         ------------
-popup_width     string     880       Width of the popup window (if used), in
-                                     pixels.
+Element         Type    Default             Description
+--------        -----   -------             ------------
+popup_width     string  880                 Width of the popup window (if used), in
+                                            pixels.
 
-popup_height    string     760       Height of the popup window (if used), in
-                                     pixels.
+popup_height    string  760                 Height of the popup window (if used), in
+                                            pixels.
 
-popup_button    string      input.mkwsButton  (Never change this.)
+popup_button    string  `input.mkwsButton`  (Never change this.)
 
-popup_modal     string      0       Modal confirmation mode. Valid values are 0 or 1
+popup_modal     string  0                   Modal confirmation mode. Valid values are 0 or 1
 
-popup_autoOpen  string      1       Open popup window on load. Valid values are 0 or 1
+popup_autoOpen  string  1                   Open popup window on load. Valid values are 0 or 1
 
 ----
 
index 90caf92..e48a0be 100644 (file)
@@ -5,13 +5,17 @@
     <link rel="stylesheet" type="text/css" href="tools/htdocs/mkws.css" />
     <script type="text/javascript">
       var mkws_config = {
-       pazpar2_url:        "//sp-mkws.indexdata.com/service-proxy/",
         // For now, we have to provide known-bad credentials to skip user/pw login: see bug MKSP-125
-       service_proxy_auth: "//sp-mkws.indexdata.com/service-proxy/?command=auth&action=perconfig&username=XXX&password=XXX"
-        // For explicit credential-based authentication, add: &username=orex&password=orexmkc
+        service_proxy_auth: undefined,
+        // Was: //sp-mkws.indexdata.com/service-proxy/?command=auth&action=perconfig&username=XXX&password=XXX
+        pp2_hostname: "x.sp-mkws.indexdata.com:8585",
+        sp_path: "service-proxy/",
+        credentials: "XXX/XXX",
+        // ### This should automatically follow pp2_hostname
+       pazpar2_url:        "//x.sp-mkws.indexdata.com:8585/service-proxy/",
       };
     </script>
-    <script type="text/javascript" src="//code.jquery.com/jquery-1.10.0.min.js"></script>
+    <script type="text/javascript" src="tools/htdocs/jquery-1.10.0.min.js"></script>
     <script type="text/javascript" src="tools/htdocs/jquery.json-2.4.js"></script>
     <script type="text/javascript" src="tools/htdocs/handlebars-v1.1.2.js"></script>
     <script type="text/javascript" src="tools/htdocs/pz2.js"></script>
index 60ee37b..6468e86 100644 (file)
@@ -2,12 +2,12 @@ mkws.registerWidgetType('Builder', function() {
   var that = this;
   var team = this.team;
 
-  this.button = mkws.$('<button/>', {
+  var button = mkws.$('<button/>', {
     type: 'button',
     text: this.config.text || "Build!"
   });
-  this.node.append(this.button);
-  this.button.click(function() {
+  this.node.append(button);
+  button.click(function() {
     var   query = team.widget('Query').value();
     var    sort = team.widget('Sort').value();
     var perpage = team.widget('Perpage').value();
index 722db5e..9a3a7f7 100644 (file)
@@ -66,6 +66,7 @@ function widget($, team, type, node) {
     return s.join('');
   };
 
+  // ### why is this a member function? It's never called from outside this file.
   that.expandValue = function(val) {
     if (val.match(/^!param!/)) {
       var param = val.replace(/^!param!/, '');
index 9c724ae..b31bd88 100644 (file)
@@ -12,3 +12,4 @@ mkws.js
 mkws.min.js
 pz2.js
 mkws-manual.html
+mkws-developer.html
diff --git a/tools/service-proxy/.gitignore b/tools/service-proxy/.gitignore
new file mode 100644 (file)
index 0000000..ab91c1c
--- /dev/null
@@ -0,0 +1 @@
+service-proxy-mike-mac.properties
diff --git a/tools/service-proxy/Makefile b/tools/service-proxy/Makefile
new file mode 100644 (file)
index 0000000..da127e4
--- /dev/null
@@ -0,0 +1,10 @@
+MIKE = service-proxy-mike-mac.properties
+
+$(MIKE): service-proxy.properties Makefile
+       rm -f $@
+       sed 's/mkc-admin.indexdata.com/x.&:8181/g;s/,constraint,/,/' $< > $@
+       chmod 444 $@
+
+clean:
+       rm -f $(MIKE)
+