Merge remote-tracking branch 'origin/master' into wosch
authorWolfram Schneider <wosch@indexdata.dk>
Fri, 7 Nov 2014 17:34:59 +0000 (18:34 +0100)
committerWolfram Schneider <wosch@indexdata.dk>
Fri, 7 Nov 2014 17:34:59 +0000 (18:34 +0100)
21 files changed:
Makefile
doc/mkws-doc.css
doc/mkws-manual.markdown
examples/htdocs/language.html
examples/htdocs/prettysimple.css [new file with mode: 0644]
examples/htdocs/prettysimple.html [new file with mode: 0644]
examples/htdocs/topic.css
examples/htdocs/topic.html
src/mkws-core.js
src/mkws-widget-main.js
src/templates/facets.handlebars
src/templates/search.handlebars
src/templates/summary.handlebars
test/Makefile
test/bin/bomb.pl
test/spec-dev/async.spec.js [new file with mode: 0644]
test/spec/async.spec.js [deleted file]
test/spec/mkws-pazpar2.js
test/widgets/Makefile
test/widgets/url.koha
tools/htdocs/mkws.css

index cb4d8f6..a105790 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -29,5 +29,5 @@ help:
        @echo "make [ all | setup | clean | distclean ]"
        @echo "     [ check | check-js | phantomjs ]"
        @echo ""
-       @echo "If 'make check' timeout is too short, extend with: make check PHANTOMJS_TIMEOUT=40"
+       @echo "If 'make check' timeout is too short, extend with: make check PHANTOMJS_TIMEOUT=120"
 
index 00e961b..386c46a 100644 (file)
@@ -27,8 +27,10 @@ body > p:last-of-type {
     font-size: small;
 }
 
-table { background: #ddd; border-collapse: collapse; }
+table { border-collapse: collapse; }
 tr.header { color: #fff; background: #888; }
-table, th, td { border: 1px solid #ccc; }
+tr.odd { background: #ddd }
+tr.even { background: #ccc }
+table, th, td { border: 1px solid #bbb; }
 td { vertical-align: top; }
 td, th { padding: 0.3em 0.6em; }
index 0601a79..b0107be 100644 (file)
@@ -41,7 +41,7 @@ flexibility against convenience:
   [Drupal](https://www.drupal.org/)
   sites.
 
-All of these approaches require programming to a greater or lesser
+All but the last of these approaches require programming to a greater or lesser
 extent. Against this backdrop, we introduced
 [MKWS (the MasterKey Widget Set)](http://mkws.indexdata.com/)
 -- a set of simple, very high-level HTML+CSS+JavaScript
@@ -171,22 +171,6 @@ is part of the `aux` team.
 Widgets that do not have a team specified (as in the examples above)
 are placed in the team called `AUTO`.
 
-Old and new-style class-names
------------------------------
-
-**NOTE.** Versions of MKWS before v1.0 used camel-case class-names:
-without hyphens and with second and subsequent words capitalised. So
-instead of `mkws-search`, it used to be `mkwsSearch`. And the classes
-used to specify team names used an `mkwsTeam_` prefix (with an
-underscore). So instead of `mkws-team-foo`, it used to be
-`mkwsTeam_foo`.
-
-The 1.x series of MKWS releases recognise these old-style class-names
-as well as the canonical ones, as a facility for backwards
-compatibility. However, **these old class-names are deprecated, and
-support will be removed in v2.0**. Existing applications that use them
-should be upgraded to the new-style class names as soon as convenient.
-
 Configuring widgets
 ===================
 
@@ -202,18 +186,16 @@ like this:
            lang_options: [ "en", "da" ]
            lang: "da",
            sort_default: "title",
-           query_width: 60
          };
        </script>
        <script type="text/javascript" src="http://mkws.indexdata.com/mkws-complete.js"></script>
 
 This configuration restricts the set of available UI languages English
 and Danish (omitting German), sets the default to Danish (rather than
-the English), initially sorts search results by title rather than
-relevance (though as always this can be changed in the UI) and makes
-the search box a bit wider than the default.
+the English), and initially sorts search results by title rather than
+relevance (though as always this can be changed in the UI).
 
-The full set of supported configuration items is described in the
+The full set of supported configuration settings is described in the
 reference guide below.
 
 Per-widget configuration
@@ -221,7 +203,7 @@ Per-widget configuration
 
 In addition to the global configuration provided by the `mkws_config`
 object, individual widgets' behaviour can be configured by providing
-configuration items as attributed on their HTML elements. For example,
+configuration settings as attributes on their HTML elements. For example,
 a `records` widget might be restricted to displaying no more than
 three records by setting the `numrecs` parameter as follows:
 
@@ -238,11 +220,11 @@ attributes prefixed with `data-mkws-`, so:
 
 For first form is more convenient; the second is more correct.
 
-Because some configuration items take structured values rather than
+Because some configuration settings take structured values rather than
 simple strings, they cannot be directly provided by inline
 attributes. To allow for this, the special attribute
 `data-mkws-config`, if provided, is parsed as JSON and its key-value
-pairs set as configuration items for the widget in question. For
+pairs used as configuration settings for the widget in question. For
 example, the value of `lang_options` is an array of strings specifying
 which of the supported UI languages should be made available. The
 following invocation will limit this list to only English and Danish
@@ -561,7 +543,7 @@ its own User Access record.
 When credential-based authentication is in use (username and
 password), it's necessary to pass these credentials into the Service
 Proxy when establishing the session. This is done 
-by setting the `sp_auth_credentials` configuration item to a string
+by providing the `sp_auth_credentials` configuration setting as a string
 containing the username and password separated by a slash:
 
        mkws_config = { sp_auth_credentials: "mike/swordfish" };
@@ -590,9 +572,10 @@ yourname.com`:
 Step 1: add a rewriting authentication alias to the configuration:
 
        RewriteEngine on
-       RewriteRule /spauth/ http://sp-mkws.indexdata.com/service-proxy/?command=auth&action=check,login&username=U&password=PW [P]
+       RewriteRule /spauth/ http://sp-mkws.indexdata.com/service-proxy/\
+               ?command=auth&action=check,login&username=U&password=PW [P]
 
-Step 2: set the MKWS configuration item `service_proxy_auth` to
+Step 2: set the MKWS configuration setting `service_proxy_auth` to
 `http://yourname.com/spauth/`.
 
 Step 3: protect access to the local path `http://yourname.com/spauth/`
@@ -659,6 +642,9 @@ Name              Description
                   widget be subclassed to store the generated widget
                   definitions in more useful places.
 
+`button`          The search button. Usually generated a `search`
+                  widget.
+
 `categories`      Obtains from the Service Proxy a list of the target
                   categories associated with the library in use, and
                   displays them in a drop-down list. When a category
@@ -668,7 +654,7 @@ Name              Description
 `config`          This widget has no functionality of its own, but its
                   configuration is copied up into its team, allowing
                   it to affect other widgets in the team. This is the
-                  only way to set configuration items at the team
+                  only way to set configuration settings at the team
                   level.
 
 `console-builder` Like the `builder` widget, but emits the generated
@@ -699,154 +685,401 @@ Name              Description
                   be changed by overriding the `done` template using
                   `<script class="mkws-template-done" type="text/x-handlebars-template">`.
 
-`facet`           x
-
-`facets`          x
-
-`google-image`    x
-
-`images`          x
-
-`lang`            x
-
-`log`             x
-
-`lolcat`          x
-
-`motd-container`  x
-
-`motd`            x
-
-`navi`            x
-
-`pager`           x
-
-`per-page`        x
-
-`progress`        x
-
-`query`           x
-
-`ranking`         x
-
-`record`          x
-
-`records`         x
-
-`reference`       x
+`facet`           A facet that displays the frequency with which a set
+                  of terms occur within a specific field. The specific
+                  field whose contents are analysed must be specified
+                  by the widget's `facet` configuration setting, which
+                  may conveniently be done by means of the
+                  `data-mkws-facet` attribute on the HTML
+                  element. The supported facets are "subject",
+                  "author" and "xtargets" -- the latter a special case
+                  which treats the target providing a record as a
+                  facet. Most often, `facet` widgets are generated
+                  by a `facets` widget, which knows which facets are
+                  required, but they can also be placed individually.
+
+`facets`          An area that contains a "Facets" heading and several
+                  `facet` widgets. The set of facet widgets generated
+                  is specified by the `facets` configuration setting,
+                  which may be set globally or at the level of the
+                  widget or the team. The value of this configuration
+                  setting is an array of zero or more strings, each
+                  naming a facet.
+
+`google-image`    A specialisation of the `images` widget which
+                  defaults to the `Google_Images` target.
+
+`images`          A specialisation of the `records` widget which
+                  defaults to the `images` template. Unlike the default
+                  summary template, this displays an image from the
+                  URL specified by the `md-thumburl` field of each
+                  record.
+
+`lang`            Provides a selection between the supported set of
+                  languages (which defaults to English, German and
+                  Danish, but can be configured by the `lang`
+                  configuration setting, whose value is an array of
+                  two-letter language codes).
+
+`log`             Initially empty, this widget accumulates a log of
+                  messages generated by the widget set, similar to
+                  those emitted on the JavaScript console.
+
+`lolcat`          A specialisation of the `google-image` widget which
+                  defaults to the search-term "kitteh" and
+                  auto-executes.
+
+`motd-container`  An empty container which the `motd` widget, if any,
+                  is moved into for initial display. Usually generated
+                  as part of the `results` widget.
+
+`motd`            May be provided, containing content to appear in the
+                  area where records will later appear. It is moved
+                  into this area (the `motd-container` widget) and
+                  initially displayed; then hidden when the first
+                  search is run. It can be used to provide a "message
+                  of the day".
+
+`navi`            Shows a list of the facets that have been selected,
+                  and allows them to be deselected.
+
+`pager`           Shows a list of the available pages of results, and
+                  allows the user to navigate to a selected page.
+
+`per-page`        Provides a dropdown allowing the user to choose how
+                  many records should appear on each page. The
+                  available set of page-sizes can be specified as the
+                  `perpage_options` configuration setting, whose value is
+                  an array of integers. The initial selected value can
+                  be specified by the `perpage_default` configuration setting.
+
+`progress`        Shows a progress bar which indicates how many of the
+                  targets have responded to the search.
+
+`query`           The input area for a query. Usually generated a `search`
+                  widget.
 
-`results`         x
+`ranking`         The result-ranking area, consisting of a `sort`
+                  widget and a `per-page` widget. These may instead
+                  be specified separately if preferred.
+
+`record`          A detailed display of a single record, usually
+                  appearing when the user clicks on a summary
+                  record. This is generated by the `records` widget.
+
+`records`         The area in which summary records appear. (Clicking
+                  on a summary record make it pop up as a detailed
+                  record.)
+
+`reference`       A short summary about a subject specified by the
+                  `autosearch` configuration setting. This is created by
+                  drawing a picture and a paragraph of text from
+                  Wikipedia. To work correctly, this widget must be
+                  used in a library that provides the
+                  `wikimedia_wikipedia_single_result` target.
+
+`results`         A large compound widget used to provide the most
+                  important results-oriented widgets in a pre-packaged
+                  framework: `facets`, `ranking`, `pager`, `navi` and
+                  `records`.
+
+`search-form`     The search form, containing the query area and the
+                  button. Usually generated a `search` widget.
+
+`search`          The search box, consisting of a form containing a
+                  query area and a button.
+
+`sort`            Provides a dropdown allowing the user to choose how
+                  the displayed records should be sorted. The
+                  available set of sort criteria can be specified as the
+                  `sort_options` configuration setting, whose value is
+                  an array of two-element arrays. The first item of
+                  each sub-array is a pazpar2 sort-expression such as
+                  `data:0` and the second is a human-readable label
+                  such as `newest`. The initial selected
+                  value can be specified by the `sort_default` configuration
+                  setting.
+
+`stat`            A summary line stating how many targets remain
+                  active, how many records have been found, and how
+                  many of them have been retrieved for display. For
+                  most purposes, the `progress` widget may be
+                  preferable.
+
+`summary`         A short record, included in the list shown when a
+                  search is run. When clicked, this generally pops up
+                  a detailed `record` widget. This widget is generated
+                  by the toolkit in response to search results.
+
+`switch`          A pair of buttons allowing the user to switch
+                  between viewing the search results (the usual case)
+                  or the target list.
+
+`targets`         A list of all targets in the present library,
+                  showing their ID, the number of records they have
+                  found for the current search, any diagnostics they
+                  have returned, the number of records that have been
+                  returned for display, and the connection state.
+----
 
-`search-form`     x
 
-`search`          x
+Configuration settings
+----------------------
 
-`sort`            x
+Configuration settings may be provided at the level of a indiviual widget, or a team, or globally. Per-widget configuration is
+described above; per-team settings can be placed in a `config` widget belonging to the relevant team, and will be applied to that
+team as a whole; and global settings are provided in the global variable `mkws_config`. This structure is a key-value lookup
+table, and may specify the values of many settings.
 
-`stat`            x
+Some settings apply only to specific widgets; others to the behaviour of the tookit as a whole. When a widget does not itself have
+a value specified for a particular configuration setting, its team is consulted; and if that also does not have a value, the global
+settings are consulted. Only if this, too, is unspecified, is the default value used.
 
-`switch`          x
+The supported configuration settings are described in the table below. For those settings that apply only to particular widgets,
+the relevant widgets are listed. All entries are optional, but if specified must be given values of the specified type. Long
+default values are in footnotes to keep the table reasonably narrow.
 
-`targets`         x
 ----
-
-
-Configuration object
---------------------
-
-The configuration object `mkws_config` may be created before including
-the MKWS JavaScript code to modify default behaviour. This structure
-is a key-value lookup table, whose entries are described in the table
-below. All entries are optional, but if specified must be given values
-of the specified type. If ommitted, each setting takes the indicated
-default value; long default values are in footnotes to keep the table
-reasonably narrow.
-
+Element                   Widget    Type    Default   Description
+--------                  ------    -----   --------- ------------
+autosearch                facet,    string            If provided, this setting contains a query which is immediately run on behalf
+                          facets,                     of the team. Often used with an [indirect setting](#indirect-settings).
+                          record,
+                          records,
+                          results
+
+facet                     facet     string            For a `facet` widget, this setting is mandatory, and indicates which field to
+                                                      list terms for. Three fields are supported: `subject`, `author` and
+                                                      `xtargets` -- the latter a special case which treats the target providing a
+                                                      record as a facet. Any other field may also be used, but the default caption
+                                                      and maximum term-count may not be appropriate, needing to be overridden by
+                                                      `facet_caption_*` and `facet_max_*` settings.
+
+facet_caption_*           facet     string            Specifies what on-screen caption is to be used for the named facet: for
+                                                      example, if a `date` facet is generated, then `facet_caption_date` can be
+                                                      used to set the caption to "Year".
+
+facet_max_*               facet     int               Specifies how many terms are to be displayed for the named facet: for
+                                                      example, if a `publisher` facet is generated, then `facet_max_publisher` can
+                                                      be used to limit the list to the top six.
+
+facets                    _team_    array   *Note 1*  Ordered list of names of facets to display.
+
+lang                      _team_    string            Two-letter ISO code of the default language to display the UI in. Supported
+                                                      language codes are `en` = English, `de` = German, `da` = Danish, and whatever
+                                                      additional languages are configured using `language_*` entries (see below).
+
+lang_options              lang      array   []        A list of the languages to offer as options. If empty (the default), then all
+                                                      configured languages are listed.
+
+language_*                _global_  hash              Support for any number of languages can be added by providing entries whose
+                                                      name is `language_` followed by the code of the language. See the separate
+                                                      section below for details.
+
+limit                     facet,    string            Allows a partial search to be included in the specification of an
+                          facets,                     auto-executing widget. This is ANDed with the submitted query, as though it
+                          record,                     had been selected from a facet. See the Search section in [the Protocol
+                          records,                    chapter of the Pazpar2 manual
+                          results                     ](http://www.indexdata.com/pazpar2/doc/pazpar2_protocol.html)
+
+log_level                 _global_  int     1         Level of debugging output to emit. 0 = none, 1 = messages, 2 = messages with
+                                                      datestamps, 3 = messages with datestamps and stack-traces.
+
+maxrecs                   facet,    int               Limits the metasearching middleware to retrieving no more than the specified
+                          facets,                     number of records from each target.
+                          record,
+                          records,
+                          results
+
+paragraphs                reference int               Limits the number of paragraphs rendered to the specified number. If
+                                                      omitted, there is no limit.
+
+pazpar2_url               _global_  string            If specified, this is the URL used to access the metasearch middleware. This
+                                                      service must be configured to provide search results, facets, etc. It may be
+                                                      either unmediated Pazpar2 or the MasterKey Service Proxy, which mediates
+                                                      access to an underlying Pazpar2 instance. When not specified, the URL is
+                                                      assembled from `pp2_hostname` and `pp2_path`. See the [Assembling Pazpar2
+                                                      URLs](#assembling-pazpar2-urls) section below.
+
+perpage                   facet,    int               Specifies the number of records to show per page in an auto-executing
+                          facets,                     widget. Contrast with `perpage_default`, which is used to prime the dropdown
+                          record,                     with which a user chooses the page-size in an interactive session.
+                          records,
+                          results
+
+perpage_default           _team_    string  20        The initial value for the number of records to show on each page.
+
+perpage_options           ranking   array   *Note 2*  A list of candidate page sizes. Users can choose between these to determine
+                                                      how many records are displayed on each page of results.
+
+pp2_hostname              _global_  string  *Note 3*  Unless overridden by the `pazpar2_url` setting, this is used together with
+                                                      `pp2_path` to construct the URL to the Pazpar2 service (or Service
+                                                      Proxy). Set this to connect to a service on a different host from the
+                                                      default.
+
+pp2_path                  _global_  string  *Note 4*  Unless overridden by the `pazpar2_url` setting, this is used together with
+                                                      `pp2_hostname` to construct the URL to the Pazpar2 service (or Service
+                                                      Proxy). Set this to connect to a service on a different host from the
+                                                      default.
+
+scan_all_nodes            _global_  bool    false     An internal setting that changes how MKWS scans the HTML documen to discover
+                                                      widgets. If set to true, a different approach is used which may be faster
+                                                      under some circumstances.
+
+sentences                 reference int               Limits the number of sentences rendered to the specified number. If
+                                                      omitted, there is no limit.
+
+service_proxy_auth        _global_  url               If defined, this is the URL which, when `use_service_proxy` is true, is
+                                                      fetched once at the beginning of each session to authenticate the user and
+                                                      establish a session that encompasses a defined set of targets to search
+                                                      in. When not defined, the URL is assembled from `sp_auth_hostname` or
+                                                      `pp2_hostname`, `pp2_path` or `sp_auth_path`, `sp_auth_query` and
+                                                      `sp_auth_credentials`. See the [Assembling Pazpar2
+                                                      URLs](#assembling-pazpar2-urls) section below.
+
+service_proxy_auth_domain _global_  domain            When the server used for authentication -- e.g. the one identified by the
+                                                      `service_proxy_auth` URL -- proxies for different server, this can be set to
+                                                      the domain of the server that it proxies for, so that cookies are rewritten
+                                                      to appear to be from this domain.
+
+show_lang                lang       bool    true      Indicates whether or not to display the language menu.
+
+show_perpage             ranking    bool    true      Indicates whether or not to display the perpage menu.
+
+show_sort                ranking    bool    true      Indicates whether or not to display the sort menu.
+
+show_switch              switch     bool    true      Indicates whether or not to display the switch menu.
+
+sort                      facet,    string            Specifies the order in which to sort the records retrieved by an
+                          facets,                     auto-executing widget. Must be one of those in the `sort_options`
+                          record,                     array. Contrast with `sort_default`, which is used to prime the dropdown
+                          records,                    with which a user chooses the sortorder in an interactive session.
+                          results
+
+sort_default              _team_    string  relevance The default sort criterion to use. Must be one of those in the
+                                                      `sort_options` array.
+
+sort_options              ranking   array   *Note 5*  List of supported sort criteria. Each element of the list is itself a
+                                                      two-element list: the first element of each sublist is a pazpar2
+                                                      sort-expression such as `data:0` and the second is a human-readable label
+                                                      such as `newest`.
+
+sp_auth_credentials       _global_  string            If defined, this must be a slash-separated combination of username and
+                                                      password, which is sent as the authentication credentials on session
+                                                      initialisation. See the [Assembling Pazpar2 URLs](#assembling-pazpar2-urls)
+                                                      section below.
+
+sp_auth_hostname          _global_  string            If provided, overrides the `pp2_hostname` setting when constructing the
+                                                      Service Proxy authentication URL. This need only be used when authentication
+                                                      is performed on a different host from the remaining operations (search,
+                                                      retrieve, etc.)
+
+sp_auth_path              _global_  string            Part of the URL used for authentication. See the [Assembling Pazpar2
+                                                      URLs](#assembling-pazpar2-urls) section below.
+
+sp_auth_query             _global_  string  *Note 6*  Part of the URL used for authentication. See the [Assembling Pazpar2
+                                                      URLs](#assembling-pazpar2-urls) section below.
+
+target                    facet,    string            One of three ways to select which targets an auto-searching widgets uses. See
+                          facets,                     the [Choosing targets from the library](#choosing-targets-from-the-library)
+                          record,                     section above.
+                          records,
+                          results
+
+targetfilter              facet,    string            One of three ways to select which targets an auto-searching widgets uses. See
+                          facets,                     the [Choosing targets from the library](#choosing-targets-from-the-library)
+                          record,                     section above.
+                          records,
+                          results
+
+targets                   facet,    string            One of three ways to select which targets an auto-searching widgets uses. See
+                          facets,                     the [Choosing targets from the library](#choosing-targets-from-the-library)
+                          record,                     section above.
+                          records,
+                          results
+
+template                  details,  string            Numerous widgets use Handlebars templates to render HTML. In general, each
+                          done,                       of these by default uses a template with the same name as the widget
+                          facet,                      itself. Individual widgets can be customised to use a template of a
+                          facets,                     different name by means of their `template` setting. The `records` widget
+                          images,                     (and `record`, an equivalent that shows only a single record) use the
+                          lang,                       `summary` template as well as the `records` template.
+                          navi,
+                          pager,
+                          progress,
+                          ranking,
+                          records,
+                          reference,
+                          results,
+                          search,
+                          stat,
+                          switch,
+                          targets
+
+text                      builder   string  "Build!"  Specifies what text to use for the Builder button.
+
+use_service_proxy         _global_  bool    true      If true, then a Service Proxy is used to deliver searching services rather
+                                                      than raw Pazpar2. An authentication phase is run during initialisation.
 ----
-Element                   Type    Default   Description
---------                  -----   --------- ------------
-log_level                 int     1         Level of debugging output to emit. 0 = none, 1 = messages, 2 = messages with
-                                            datestamps, 3 = messages with datestamps and stack-traces.
-
-facets                    array   *Note 1*  Ordered list of names of facets to display. Supported facet names are
-                                            `xtargets`, `subject` and `author`.
-
-lang                      string  en        Code of the default language to display the UI in. Supported language codes are `en` =
-                                            English, `de` = German, `da` = Danish, and whatever additional languages are configured
-                                            using `language_*` entries (see below).
-
-lang_options              array   []        A list of the languages to offer as options. If empty (the default), then all
-                                            configured languages are listed.
-
-language_*                hash              Support for any number of languages can be added by providing entries whose name is
-                                            `language_` followed by the code of the language. See the separate section below for
-                                            details.
 
-pazpar2_url               string  *Note 2*  The URL used to access the metasearch middleware. This service must be configured to
-                                            provide search results, facets, etc. It may be either unmediated or Pazpar2 the
-                                            MasterKey Service Proxy, which mediates access to an underlying Pazpar2 instance. In
-                                            the latter case, `service_proxy_auth` must be provided.
+The `show_lang`, `show_perpage`, `show_sort` and `show_switch` configuration settings are technically redundant, as the relevant
+widgets, like all widgets, are displayed only when they are provided. But they are retained as an easier route to lightly
+customise the display than by providing a full HTML structure.
 
-perpage_default           string  20        The initial value for the number of records to show on each page.
-
-perpage_options           array   *Note 3*  A list of candidate page sizes. Users can choose between these to determine how many
-                                            records are displayed on each page of results.
+### Notes
 
-query_width               int     50        The width of the query box, in characters.
+1. The default for `facets` is `["xtargets", "subject", "author"]`
 
-responsive_design_width   int               If defined, then the facets display moves between two locations as the screen-width
-                                            varies, as described above. The specified number is the threshhold width, in pixels,
-                                            at which the facets move between their two locations.
+2. The default for `perpage_options` is `[10, 20, 30, 50]`
 
-service_proxy_auth        url     *Note 4*  A URL which, when `use_service_proxy` is true, is fetched once at the beginning of each
-                                            session to authenticate the user and establish a session that encompasses a defined set
-                                            of targets to search in.
+3. The default for `pp2_hostname` is `"sp-mkws.indexdata.com"`
 
-service_proxy_auth_domain domain            Can be set to the domain for which `service_proxy_auth` proxies authentication, so
-                                            that cookies are rewritten to appear to be from this domain. In general, this is not
-                                            necessary, as this setting defaults to the domain of `pazpar2_url`.
+4. The default for `pp2_path` is `"service-proxy/"`
 
-show_lang                 bool    true      Indicates whether or not to display the language menu.
+5. The default for `sort_options` is `[["relevance"], ["title:1", "title"], ["date:0", "newest"], ["date:1", "oldest"]]`
 
-show_perpage              bool    true      Indicates whether or not to display the perpage menu.
+6. The default for `sp_auth_query` is `"command=auth&action=perconfig"`
 
-show_sort                 bool    true      Indicates whether or not to display the sort menu.
+### Indirect settings
 
-show_switch               bool    true      Indicates whether or not to display the switch menu, for switching between showing
-                                            retrieved records and target information.
+The values of any setting are generally interpreted literally. However, it is possible to specify a value indirectly -- for
+example, by reference to a query parameter -- and this is often useful in contexts such as specifying an autosearch
+query. Settings of this kind have values beginning with an exclamation mark, and take the form `!`_type_`!`_value_.
 
-sort_default              string  relevance The label of the default sort criterion to use. Must be one of those in the `sort`
-                                            array.
+The currently supported types are:
 
-sort_options              array   *Note 6*  List of supported sort criteria. Each element of the list is itself a two-element list:
-                                            the first element of each sublist is a pazpar2 sort-expression such as `data:0` and
-                                            the second is a human-readable label such as `newest`.
+* `param` -- uses the value of the specified query parameter for the URL. For example
+`<div class="mkws-results" autosearch="!param!term">` will auto-search for the word "sushi" if the page containing that widget is
+invoked from the URL `http://example.com/magic/example.html?term=sushi`
 
-use_service_proxy         bool    true      If true, then a Service Proxy is used to deliver searching services rather than raw
-                                            Pazpar2.
-----
+* `path` -- uses the value of the _n_th component of the URL path, as specified by the value. For example
+`!path!3` will auto-search for the word "dinosaur" if the page containing that widget is
+invoked from the URL `http://example.com/magic/lookup/dinosaur`
 
-Perhaps we should get rid of the `show_lang`, `show_perpage`,
-`show_sort` and `show_switch` configuration items, and simply display the relevant menus
-only when their containers are provided -- e.g. an `mkws-lang` element
-for the language menu. But for now we retain these, as an easier route
-to lightly customise the display than my changing providing a full HTML
-structure.
-
-### Notes
+* `var` -- uses the value of the named JavaScript global variable. This is a very powerful and general mechanism. For example, to
+  search for the reversed value of the query parameter called `reverseTerm`, you might write a JavaScript function to do the
+  extraction and reversing, the use the HTML:
 
-1. ["sources", "subjects", "authors"]
+<!--- Due to a bug in pandoc, we need this comment to force the following code-block to be recognised -->
 
-2. /pazpar2/search.pz2
+               <script>var _reversedParam = extractAndReverse("term");</script>
+               <div class="mkws-results" autosearch="!var!_reversedParam">
 
-3. [10, 20, 30, 50]
+### Assembling Pazpar2 URLs
 
-4. http://sp-mkws.indexdata.com/service-proxy-auth
+Most of MKWS's functionality is achieved by use of the Pazpar2 middleware. This is accessed on an endpoint URL which is usually
+assembled from the two configuration sessings `pp2_hostname` and `pp2_path`. However, if for some reason an unusual Pazpar2
+endpoint must be used, that endpoint can be specified in the `pazpar2_url` setting, and that will be used instead.
 
-5. http://sp-mkws.indexdata.com/service-proxy/
-
-6. [["relevance"], ["title:1", "title"], ["date:0", "newest"], ["date:1", "oldest"]]
+In the common case where Pazpar2 is accessed via the Service Proxy, an authentication call is made during initialisation. The call
+is generally made to the same endpoint as the other requests. However, the hostname used for authentication may if necessary be
+overridden using the `sp_auth_hostname` setting, and the path overridden by `sp_auth_path`. In any case, the value of
+`sp_auth_query` is appended; and if `sp_auth_credentials` is set, then it is used to add username and password parameters.
 
+So in the absence of any configuration added by an application, the Service Proxy authentication URL is made up of `pp2_hostname`
+(sp-mkws.indexdata.com) since `sp_auth_hostname` is undefined; and `pp2_path` (service-proxy/) since `sp_auth_path` is undefined;
+and `sp_auth_query` (command=auth&action=perconfig); and no credentials, since `sp_auth_credentials` is undefined. Therefore the
+URL `http://sp-mkws.indexdata.com/service-proxy/?command=auth&action=perconfig` is generated.
 
 Language specification
 ----------------------
@@ -913,7 +1146,7 @@ from that toolkit. The relevant lines are:
              href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
 
        <div class="mkws-search"></div>
-       <div class="mkws-popup" popup_width="1024" popup_height="650" popup_modal="0" popup_autoOpen="0" popup_button="input.mkwsButton">
+       <div class="mkws-popup" popup_width="1024" popup_height="650" popup_autoOpen="0">
          <div class="mkws-switch"></div>
          <div class="mkws-lang"></div>
          <div class="mkws-results"></div>
@@ -1012,6 +1245,30 @@ and .CLASS indicates an instance of a class.
          span.clients
          span.records
 
+
+Appendix: compatibility roadmap
+===============================
+
+FIXME: more to write here.
+
+
+Old and new-style class-names
+-----------------------------
+
+**NOTE.** Versions of MKWS before v1.0 used camel-case class-names:
+without hyphens and with second and subsequent words capitalised. So
+instead of `mkws-search`, it used to be `mkwsSearch`. And the classes
+used to specify team names used an `mkwsTeam_` prefix (with an
+underscore). So instead of `mkws-team-foo`, it used to be
+`mkwsTeam_foo`.
+
+The 1.x series of MKWS releases recognise these old-style class-names
+as well as the canonical ones, as a facility for backwards
+compatibility. However, **these old class-names are deprecated, and
+support will be removed in v2.0**. Existing applications that use them
+should be upgraded to the new-style class names as soon as convenient.
+
+
 - - -
 
 Copyright (C) 2013-2014 Index Data ApS. <http://indexdata.com>
index 2cbd8be..370429f 100644 (file)
@@ -13,7 +13,6 @@
                use_service_proxy: true,
                show_lang: true,
                sort_default: "relevance",
-               query_width: 50,
                perpage_default: 20,
                language_Arabic: {
                        // Navigation
diff --git a/examples/htdocs/prettysimple.css b/examples/htdocs/prettysimple.css
new file mode 100644 (file)
index 0000000..2984f7c
--- /dev/null
@@ -0,0 +1,386 @@
+/* General styling */
+html {
+  height: 100%;
+  margin: 0;
+}
+body {
+  display: flex;
+  align-content: space-between;
+  align-items: center;
+  flex-wrap: wrap;
+  height: 100%;
+  width: 100%;
+  max-width: 1100px;
+  margin: auto;
+  font-family: "Open Sans", sans-serif;
+}
+a {
+ text-decoration: none;
+ color: black;
+}
+
+/* Top level layout */
+.header {
+  width: 100%;
+  display: flex;
+  margin: .5em;
+  margin-bottom: 1em;
+}
+.mkws-switch {
+  margin-left: auto;
+}
+.main {
+  width: 100%;
+  display: flex;
+  align-items: flex-start;
+  margin: 1em;
+  margin-bottom: auto;
+}
+.forms {
+  width: 100%;
+  margin: 1em;
+}
+.mkws-facets {
+  margin-right: 66px;
+  flex: 1;
+}
+.results {
+  flex: 3;
+}
+
+/* Search form */
+/* heavily inspired by: */
+/* https://github.com/philipwalton/solved-by-flexbox/blob/master/_sass/components/_input-add-on.scss */
+.mkws-search {
+  margin-left: auto;
+  margin-bottom: 0;
+}
+.mkws-search-form {
+  display: flex;
+  margin-left: auto;
+  max-width: 30em;
+}
+.mkws-search-form .mkws-query {
+  flex: 1;
+  border-right: 0 !important;
+  border-radius: 2px 0 0 2px;
+  font-size: 1.1em;
+}
+.mkws-search-form .mkws-button {
+  border-radius: 0 2px 2px 0;
+  background-color: hsla(31, 15%, 50%, 0.1);
+  font: inherit;
+  font-weight: normal;
+}
+.mkws-search-form .mkws-query, .mkws-search-form .mkws-button {
+  border: 1px solid hsla(31, 15%, 50%, 0.25);
+  padding: 0.5em 0.75em;
+  margin: 0;
+}
+.mkws-ranking {
+  font-family: "Open Sans Light", sans-serif;
+  border-top: none;
+  border-bottom-left-radius: 5em 100%;
+  margin-top: 0;
+  margin-left: auto;
+  font-size: .9em;
+  text-align: right;
+  max-width: 25em;
+}
+.mkws-ranking select {
+ font-size: 1.0em;
+ font-family: "Open Sans", sans-serif;
+ border: none;
+ background: none;
+}
+
+/* Misc. elements */
+.mkws-lang {
+  color: gray;
+  font-family: "Open Sans Light", sans-serif;
+}
+.mkws-lang > span {
+  color: black;
+  font-family: "Open Sans", sans-serif;
+}
+.mkws-switch {
+  color: gray;
+  font-family: "Open Sans Light", sans-serif;
+}
+.mkws-switch > a {
+  color: black;
+}
+.mkws-pager {
+  width: 100%;
+}
+.mkws-current-page {
+  background: gray;
+  border-radius: 3em;
+  padding: 0 .5em;
+  color: white;
+}
+.mkws-navi {
+  margin-top: 10px;
+  width: 100%;
+  
+}
+.mkws-removable:after {
+  content: " X";
+  color: DarkRed; 
+}
+.mkws-removable:hover {
+  text-decoration: line-through;
+}
+.mkws-records {
+  width: 100%;
+}
+
+
+/* Facets */
+.mkws-facet {
+  padding-bottom: 1em;
+}
+.mkws-facet-title {
+  border-left: 5px solid #7d8187;
+  padding: .5em 10px;
+  text-transform: uppercase;
+}
+.mkws-facet:nth-child(1)>.mkws-facet-title {
+  border-color: #2980b9;
+}
+.mkws-facet:nth-child(2)>.mkws-facet-title {
+  border-color: #68a863;
+}
+.mkws-facet:nth-child(3)>.mkws-facet-title {
+  border-color: #b45b47;
+}
+
+.mkws-facet:last-child {
+  padding-bottom: initial;
+}
+.mkws-term {
+  display: flex;
+  padding-left: 15px;
+  font-size: .9em;
+}
+.mkws-term a {
+  flex: 1;
+  overflow: hidden; 
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+.mkws-term span {
+  flex: 0 0 min-content;
+  float: right;
+  margin-left: .7em;
+}
+.mkws-stat {
+  font-family: "Open Sans Light", sans-serif;
+  text-align: right;
+  font-size: .9em;
+}
+
+
+/* Result containers */
+.mkws-summary {
+  padding: 40px 20px;
+  min-height: 120px;
+  border-bottom: 1px solid rgba(0, 0, 0, 0.15);
+}
+.mkws-summary:last-child {
+  border: none;
+}
+.mkws-field-data {
+  min-height: 120px;
+  display: flex;
+  flex-direction: column;
+  flex-wrap: wrap;
+  align-items: flex-start;
+  align-content: flex-start;
+  justify-content: space-around;
+}
+
+/* Result fields */
+.mkws-field-data > * {
+  flex 1;
+}
+.mkws-field-date {
+  order: 1;
+  font-size: 14px;
+  color: rgba(0, 0, 0, 0.3);
+}
+.mkws-field-title {
+  order: 2;
+  font-family: "Open Sans Light", sans-serif;
+  font-size: 24px;
+  line-height: 1.2;
+  letter-spacing: -0.02em;
+  margin-bottom: 4px;
+}
+.mkws-field-title-remainder {
+  order: 3;
+  font-family: "Open Sans Light", sans-serif;
+  font-size: 12px;
+  margin-top: -4px;
+  margin-bottom: 4px;
+  overflow: hidden; 
+  text-overflow: ellipsis;
+}
+.mkws-field-description {
+  order: 4;
+  font-family: "Open Sans Light", sans-serif;
+  font-size: 18px;
+  line-height: 1.2;
+  max-height: 44px;
+  overflow: hidden;
+}
+.mkws-field-author {
+  order: 5;
+  font-weight: bold;
+  font-size: 12px;
+  letter-spacing: 0.1em;
+  text-transform: uppercase;
+}
+.mkws-field-thumb {
+  float: left;
+  margin-right: 25px;
+}
+.mkws-field-thumb > img {
+  width: 140px;
+  height: 120px;
+  object-fit: contain;
+}
+.mkws-details {
+  margin-top: 25px;
+}
+.mkws-prev, .mkws-next {
+  text-transform: uppercase;
+  font-size: .75em;
+} 
+
+
+/* Responsive */
+@media screen and (max-width: 1020px) {
+  .mkws-facets {
+    margin-right: 30px;
+  }
+}
+@media screen and (max-width: 900px) {
+  .mkws-pager {
+    margin: 0;
+  }
+  .mkws-pager > div {
+    margin-top: 10px;
+  }
+  .main {
+    flex-wrap: wrap;
+  }
+  .mkws-facets {
+    order: 99;
+    width: 100%;
+    margin-top: 40px;
+    margin-right: 0;
+    flex: none;
+  }
+  .results {
+    width: 100%;
+    order 1;
+    flex: none;
+  }
+  .mkws-ranking {
+    width: 100%;
+  }
+  .mkws-search {
+    width: 100%;
+  }
+  .mkws-summary {
+    min-height: 60px;
+    padding: 20px 10px;
+  }
+  .mkws-field-data {
+    min-height: 60px;
+  }
+  .mkws-field-date {
+    font-size: 12px;
+  }
+  .mkws-field-title {
+    font-size: 18px;
+  }
+  .mkws-field-description {
+    font-size: 14px;
+    max-height: 34px;
+  }
+  .mkws-field-author {
+    font-size: 11px;
+  }
+  .mkws-field-thumb {
+    order: -1;
+    margin-right: 10px;
+  }
+  .mkws-field-thumb > img {
+    width: 70px;
+    height: 60px;
+    object-fit: contain;
+  }
+  .mkws-pager > div {
+    float: none !important;
+  }
+}
+
+/* Font (from mozilla.org) */
+@font-face{
+  font-family:'Open Sans Light';
+  src:url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Light-webfont.eot);
+  src:url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Light-webfont.eot?#iefix) format('embedded-opentype'),url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Light-webfont.woff) format('woff'),url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Light-webfont.ttf) format('truetype'),url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Light-webfont.svg#OpenSansLight) format('svg');
+  font-weight:400;
+  font-style:normal
+}
+
+@font-face{
+  font-family:'Open Sans Light';
+  src:url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.eot);
+  src:url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.eot?#iefix) format('embedded-opentype'),url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.woff) format('woff'),url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.ttf) format('truetype'),url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.svg#OpenSansRegular) format('svg');
+  font-weight:700;
+  font-style:normal
+}
+
+@font-face{
+  font-family:'Open Sans Light';
+  src:url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-LightItalic-webfont.eot);
+  src:url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-LightItalic-webfont.eot?#iefix) format('embedded-opentype'),url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-LightItalic-webfont.woff) format('woff'),url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-LightItalic-webfont.ttf) format('truetype'),url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-LightItalic-webfont.svg#OpenSansRegular) format('svg');
+  font-weight:400;
+  font-style:italic
+}
+
+@font-face{
+  font-family:'Open Sans';
+  src:url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.eot);
+  src:url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.eot?#iefix) format('embedded-opentype'),url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.woff) format('woff'),url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.ttf) format('truetype'),url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Regular-webfont.svg#OpenSansRegular) format('svg');
+  font-weight:400;
+  font-style:normal
+}
+
+@font-face{
+  font-family:'Open Sans';
+  src:url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Semibold-webfont.eot);
+  src:url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Semibold-webfont.eot?#iefix) format('embedded-opentype'),url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Semibold-webfont.woff) format('woff'),url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Semibold-webfont.ttf) format('truetype'),url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Semibold-webfont.svg#OpenSansSemibold) format('svg');
+  font-weight:700;
+  font-style:normal
+}
+
+@font-face{
+  font-family:'Open Sans';
+  src:url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Italic-webfont.eot);
+  src:url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Italic-webfont.eot?#iefix) format('embedded-opentype'),url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Italic-webfont.woff) format('woff'),url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Italic-webfont.ttf) format('truetype'),url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-Italic-webfont.svg#OpenSansItalic) format('svg');
+  font-weight:400;
+  font-style:italic
+}
+
+@font-face{
+  font-family:'Open Sans Extra Bold';
+  src:url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-ExtraBold-webfont.eot);
+  src:url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-ExtraBold-webfont.eot?#iefix) format('embedded-opentype'),url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-ExtraBold-webfont.woff) format('woff'),url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-ExtraBold-webfont.ttf) format('truetype'),url(//mozorg.cdn.mozilla.net/media/fonts/OpenSans-ExtraBold-webfont.svg#OpenSansSemibold) format('svg');
+  font-weight:700;
+  font-style:normal
+}
+
diff --git a/examples/htdocs/prettysimple.html b/examples/htdocs/prettysimple.html
new file mode 100644 (file)
index 0000000..3891f6d
--- /dev/null
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <title>MKWS demo</title>
+    <script type="text/javascript" src="//mkws.indexdata.com/mkws-complete.js"></script>
+    <link rel="stylesheet" href="prettysimple.css" />
+  </head>
+  <body>
+    <div class="header">
+      <div class="mkws-lang"></div>
+      <div class="mkws-switch"></div>
+    </div>
+    <div class="forms">
+      <div class="mkws-search"></div>
+      <div class="mkws-ranking"></div>
+    </div>
+    <div class="main">
+      <div class="mkws-facets"></div>
+      <div class="results">
+        <div class="mkws-pager"></div>
+        <div class="mkws-navi"></div>
+        <div class="mkws-records"></div>
+        <div class="mkws-targets"></div>
+        <div class="mkws-stat"></div>
+      </div>
+    </div>
+  </body>
+</html>
+
+
index 47da435..9e0e181 100644 (file)
@@ -50,8 +50,15 @@ b, strong {
   }
 
 .mkws-summary {
-  padding: .5em 0;
+  margin: .5em 0;
   line-height: 1.35;
+  min-height: 60px;
+}
+.articles .mkws-summary, .alltargets .mkws-summary {
+  min-height: 0;
+}
+.articles .mkws-field-thumb, .alltargets .mkws-field-thumb {
+  display: none;
 }
 .mkws-summary:last-child {
   padding-bottom: 0;
@@ -80,7 +87,7 @@ b, strong {
 }
   .mkws-google-image img {
     max-width: 100%;
-    max-height: 200px;
+    max-height: 180px;
     padding: 1em 0 .5em;
   }
 .list-group-item {
@@ -90,6 +97,25 @@ b, strong {
   box-shadow: none;
   -webkit-box-shadow: none;
 }
+
+/* Fields */
+.mkws-field-thumb {
+  height: 60px;
+  width: 80px;
+  overflow: hidden;
+  margin-right: 1em;
+  float: left;
+}
+.mkws-field-thumb > img {
+  height: 60px;
+  max-width: 80px;
+} 
+.mkws-field-description {
+  overflow: hidden; 
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
 @media screen and (min-width:700px) {
   .multicol {
     column-count: 2;
@@ -100,3 +126,13 @@ b, strong {
     -webkit-column-gap: 20px;
   }
 }
+@media screen and (min-width:900px) {
+  .multicol {
+    column-count: 3;
+    column-gap: 20px;
+    -moz-column-count: 3;
+    -moz-column-gap: 20px;
+    -webkit-column-count: 3;
+    -webkit-column-gap: 20px;
+  }
+}
index 642941b..0c727e1 100644 (file)
@@ -1,10 +1,11 @@
 <!DOCTYPE html>
-<html lang="en">
-<head>
+<html lang="en"><head>
   <meta charset="utf-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1">
-  <title>MKWS demo: Compound reference widget, Bootstrap edition</title>
+  <title>MKWS demo</title>
+
+  <!-- Include Bootstrap. It needs jQuery. -->
   <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> 
   <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
   <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap-theme.min.css">
   <!-- <link href="//maxcdn.bootstrapcdn.com/bootswatch/3.1.1/amelia/bootstrap.min.css" rel="stylesheet"> -->
   <!-- <link href="//maxcdn.bootstrapcdn.com/bootswatch/3.1.1/united/bootstrap.min.css" rel="stylesheet"> -->
   <script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
+
+  <!-- Before including MKWS we can define a configuration object. -->
   <script type="text/javascript">
     var mkws_config = { sp_auth_credentials: "credo/emu" };
   </script>
+
+  <!-- mkws-complete.js includes jQuery and Handlebars. It will co-exist with
+       another copy of jQuery as we have here but you can also use mkws.js
+       if you have included both separately -->
   <script type="text/javascript" src="//mkws.indexdata.com/mkws-complete.js"></script>
-  <!-- <script type="text/javascript" src="//mkws.local/mkws&#45;complete.js"></script> -->
   <link rel="stylesheet" type="text/css" href="topic.css">
+
+  <!-- Handlebars templates can make calls to Javascript functions you
+       define this way. -->
   <script>
-    // The Google Images database returns links like:
-    //      http://images.google.com/url?q=http://eofdreams.com/fish.html&sa=U&ei=RAB-U9XNDo2Dqga1o4L4Bw&ved=0CC4Q9QEwAA&usg=AFQjCNFhRtn6GMevHbpITZ6kfx6rsHV2ow
-    // This Handlebars helper avoids a pointless redirect by transforming
-    // this to the URL of the underling page, in this case
-    //      http://eofdreams.com/fish.html
-    Handlebars.registerHelper('mkws-googleurl', function(obj) {
-      if (!obj) {
-        return "obj undefined";
-      } else if (!obj[0]) {
-        return "obj[0] undefined, JSON=" + $.toJSON(obj);
-      } else {
-        return mkws.getParameterByName('q', obj[0]);
-      }
-    });
     Handlebars.registerHelper('mkws-topicurl', function(topic) {
+      /* Creates a link back to this page with the topic as a parameter */
       return window.location.pathname + "?q=" + encodeURIComponent(topic);
     });
   </script>
+
+  <!-- Here we create replacement templates that incorporate bootstrap. 
+       The prefix "mkws-template-" makes them available to MKWS -->
   <script class="mkws-template-topic-image" type="text/x-handlebars-template">
     {{#each hits}}
       <div class="col-lg-3 col-md-4 col-sm-6 col-xs-12">
-       <a href="{{mkws-googleurl md-electronic-url}}" target="_blank">
+       <a href="{{md-electronic-url}}" target="_blank">
         {{#mkws-first md-thumburl}}
           <img src="{{this}}" alt="{{../md-title}}"/>
         {{/mkws-first}}
     {{/each}}
   </script>
 </head>
+
 <body>
-  <div class='page-header container' autosearch='!param!q'>
+  <div class='page-header container'>
     <div class="row">
-      <!-- reference entry -->
-      <div class="jumbotron panel col-md-8">
+      <!-- mkws-reference - A widget that fetches a Wikipedia entry -->
+      <div class="jumbotron panel col-md-8 col-sm-7">
+        <!-- Note the "autosearch" attribute. It indicates where to get
+             the search term from, in this case a URL parameter.  A URL
+             path component or Javascript variable are also possible. --> 
         <div class="panel-body mkws-reference mkws-team-ref" autosearch="!param!q"
              data-mkws-config='{"paragraphs":1}'></div>
       </div>
-      <!-- related topics -->
-      <div class="col-md-offset-1 col-md-3"><div class="panel panel-default">
+      <!-- Related topics -->
+      <div class="col-md-offset-1 col-md-3 col-sm-5"><div class="panel panel-default">
         <div class="panel-heading title">
           <h3 class="panel-title">Related Topics</h3>
         </div>
+        <!-- This mkws-facet widget is particularly illustrative: 
+             * the data-mkws-facet attribute specifies a particular facet
+             * data-mkws-config allows configuration override; in this case
+               we employ one of the templates we defined above.
+             * having the class mkws-team-main groups this widget with others
+               on the same team. The mkws-records widget at the bottom of
+               the page shares the same team and is thus working from the same
+               result set. -->
         <ul class="panel-body list-group mkws-facet mkws-team-main"
             autosearch="!param!q"
             data-mkws-facet="subject"
@@ -85,6 +96,7 @@
         <div class="panel-heading title">
           <h3 class="panel-title">Images</h3>
         </div>
+        <!-- The "target" config key narrows the search to a list of targets -->
         <div class="panel-body mkws-google-image" autosearch="!param!q"
              data-mkws-config='{ "maxrecs": 4, "template": "topic-image", "target": "google_images_js" }'></div>
       </div></div>
 
     <!-- sources -->
     <div class="row">
-        <div class="col-md-4 col-sm-6"><div class="panel panel-default">
+        <div class="news col-md-4 col-sm-6"><div class="panel panel-default">
           <div class="panel-heading title">
             <h3 class="panel-title">News</h3>
           </div>
+          <!-- The "targetfilter" narrows the search to targets matching some criteria -->
           <div class="panel-body mkws-records mkws-team-news" autosearch="!param!q"
                data-mkws-config='{"targetfilter":"categories=news",
                                   "perpage":7}'></div>
         </div></div>
-        <div class="col-md-4 col-sm-6"><div class="panel panel-default">
+        <div class="articles col-md-4 col-sm-6"><div class="panel panel-default">
           <div class="panel-heading title">
             <h3 class="panel-title">Articles</h3>
           </div>
                data-mkws-config='{"targetfilter":"categories=articles",
                                   "perpage":7}'></div>
         </div></div>
-        <div class="col-md-4 col-sm-6"><div class="panel panel-default">
+        <div class="books col-md-4 col-sm-6"><div class="panel panel-default">
           <div class="panel-heading title">
             <h3 class="panel-title">Books</h3>
           </div>
         </div></div>
     </div>
     <div class="row">
-        <div class="col-md-12"><div class="panel panel-default">
+        <div class="alltargets col-md-12"><div class="panel panel-default">
           <div class="panel-heading title">
             <h3 class="panel-title">Results from all targets</h3>
           </div>
index 6b71bc1..c331bc4 100644 (file)
@@ -155,17 +155,16 @@ mkws.setMkwsConfig = function(overrides) {
     use_service_proxy: true,
     pazpar2_url: undefined,
     pp2_hostname: "sp-mkws.indexdata.com",
-    pp2_path: "service-proxy",
+    pp2_path: "service-proxy/",
     service_proxy_auth: undefined,
-    sp_auth_path: "service-proxy/",
+    sp_auth_path: undefined,
     sp_auth_query: "command=auth&action=perconfig",
-    sp_auth_credentials: "XXX/XXX", // Should be undefined: see bug MKSP-125.
+    sp_auth_credentials: undefined,
     lang: "",
     sort_options: [["relevance"], ["title:1", "title"], ["date:0", "newest"], ["date:1", "oldest"]],
     perpage_options: [10, 20, 30, 50],
     sort_default: "relevance",
     perpage_default: 20,
-    query_width: 50,
     show_lang: true,    /* show/hide language menu */
     show_sort: true,    /* show/hide sort menu */
     show_perpage: true, /* show/hide perpage menu */
@@ -247,7 +246,7 @@ mkws.pazpar2_url = function() {
     mkws.log("using pre-baked pazpar2_url '" + mkws.config.pazpar2_url + "'");
     return mkws.config.pazpar2_url;
   } else {
-    var s = document.location.protocol + "//" + mkws.config.pp2_hostname + "/" + mkws.config.pp2_path + "/";
+    var s = document.location.protocol + "//" + mkws.config.pp2_hostname + "/" + mkws.config.pp2_path;
     mkws.log("generated pazpar2_url '" + s + "'");
     return s;
   }
@@ -462,7 +461,7 @@ mkws.log("Using window.name '" + window.name + "'");
       // This is the old version, which works by telling jQuery to
       // find every node that has a class beginning with "mkws". In
       // theory it should be slower than the class-based selector; but
-      // instrumentation suprisnigly shows this is consistently
+      // instrumentation suprisingly shows this is consistently
       // faster. It also has the advantage that any widgets of
       // non-registered types are logged as warnings rather than
       // silently ignored.
@@ -575,11 +574,6 @@ mkws.log("Using window.name '" + window.name + "'");
 
       log("using language: " + (mkws.config.lang ? mkws.config.lang : "none"));
 
-      if (mkws.config.query_width < 5 || mkws.config.query_width > 150) {
-        log("reset query width to " + mkws.config.query_width);
-        mkws.config.query_width = 50;
-      }
-
       // protocol independent link for pazpar2: "//mkws/sp" -> "https://mkws/sp"
       if (mkws.pazpar2_url().match(/^\/\//)) {
         mkws.config.pazpar2_url = document.location.protocol + mkws.config.pazpar2_url;
@@ -621,8 +615,9 @@ mkws.log("Using window.name '" + window.name + "'");
        return config.service_proxy_auth;
       } else {
        var s = '//';
-       s += config.auth_hostname ? config.auth_hostname : config.pp2_hostname;
-       s += '/' + config.sp_auth_path;
+       s += config.sp_auth_hostname ? config.sp_auth_hostname : config.pp2_hostname;
+       s += '/';
+       s += config.sp_auth_path ? config.sp_auth_path : config.pp2_path;
         var q = config.sp_auth_query;
         if (q) {
           s += '?' + q;
index 8a51a4d..70c45e2 100644 (file)
@@ -56,7 +56,7 @@ mkws.registerWidgetType('pager', function() {
     output.found = data.total;
 
     //client indexes pages from 1 but pz2 from 0
-    var onsides = 6;
+    var onsides = 5;
     var pages = Math.ceil(that.team.totalRecordCount() / that.team.perpage());
     var currentPage = that.team.currentPage();
 
@@ -100,13 +100,11 @@ mkws.registerWidgetType('details', function() {
     });
   }
   this.team.queue("record").subscribe(function(data) {
-    console.log(data);
     if ($.inArray(recid, data.recid) > -1) {
       var template = that.team.loadTemplate(that.config.template || "details");
       that.node.html(template(data));
     }
   });
-  that.autosearch();
 });
 
 mkws.registerWidgetType('records', function() {
@@ -116,7 +114,6 @@ mkws.registerWidgetType('records', function() {
   this.team.queue("records").subscribe(function(data) {
     for (var i = 0; i < data.hits.length; i++) {
       var hit = data.hits[i];
-      that.team.queue("record").publish(hit);
       hit.detailLinkId = team.recordElementId(hit.recid[0]);
       hit.detailClick = "mkws.showDetails('" + team.name() + "', '" + hit.recid[0] + "');return false;";
       hit.containerClass = "mkws-summary mkwsSummary mkws-team-" + team.name();
@@ -223,7 +220,6 @@ mkws.registerWidgetType('switch', function() {
 mkws.registerWidgetType('search', function() {
   var output = {};
   output.team = this.team.name();
-  output.queryWidth = this.config.query_width;
   var template = this.team.loadTemplate(this.config.template || "search");
   this.node.html(template(output));
 });
@@ -289,7 +285,7 @@ mkws.registerWidgetType('lang', function() {
   var list = [];
 
   /* display a list of configured languages, or all */
-  var lang_options = this.config.lang_options || [];
+  var lang_options = this.config.lang_options;
   var toBeIncluded = {};
   for (var i = 0; i < lang_options.length; i++) {
     toBeIncluded[lang_options[i]] = true;
index 8ebc91f..3ca13a6 100644 (file)
@@ -4,8 +4,6 @@ Facets, a container of all configured facets.
 team - the current team
 facets - array of facet names
 }}
-
-<div class="mkws-facets-title mkwsTermlistsTitle">{{mkws-translate "Facets"}}</div>
 {{#each facets}}
   <div class="mkws-facet mkwsFacet mkws-team-{{../team}}" data-mkws-facet="{{this}}"></div>
 {{/each}}
index 82cbd15..446ba16 100644 (file)
@@ -2,10 +2,9 @@
 Search form
 
 team - MKWS team
-queryWidth - configured width for search box
 }}
 <form name="mkws-search-form" class="mkws-search-form mkws-team-{{team}}" action="">
-  <input class="mkws-query mkws-query mkwsQuery mkws-team-{{team}}" type="text" size="{{queryWidth}}">
+  <input class="mkws-query mkws-query mkwsQuery mkws-team-{{team}}" type="text">
   <input class="mkws-button mkws-button mkwsButton mkws-team-{{team}}" type="submit" value="{{{mkws-translate "Search"}}}">
 </form>
 
index aa2ed10..85b371d 100644 (file)
@@ -10,15 +10,34 @@ detailClick - a click event handler for details
 renderedDetails - active record details rendered from the details template
 md-* - metadata fields passed through from backend
 }}
-<a href="#" id="{{detailLinkId}}" onclick="{{detailClick}}">
-  <b>{{md-title}}</b>
-</a>
-{{#if md-title-remainder}}
-  <span>{{md-title-remainder}}</span>
-{{/if}}
-{{#if md-title-responsibility}}
-  <span><i>{{md-title-responsibility}}</i></span>
+{{#if md-thumburl}}
+  <a class="mkws-field-thumb" href="#" onclick="{{detailClick}}">
+    <img src="{{md-thumburl.[0]}}"/>
+  </a>
 {{/if}}
+<div class="mkws-field-data">
+  <span class="mkws-field-title">
+  <a href="#" id="{{detailLinkId}}" onclick="{{detailClick}}">
+    {{md-title}}
+  </a>
+  </span>
+  {{#if md-title-remainder}}
+    <span class="mkws-field-title-remainder">{{md-title-remainder}}</span>
+  {{/if}}
+  {{#if md-author}}
+    <span class="mkws-field-author">{{md-author}}</span>
+  {{else}}
+    {{#if md-title-responsibility}}
+      <span class="mkws-field-author">{{md-title-responsibility}}</span>
+    {{/if}}
+  {{/if}}
+  {{#if md-description}}
+    <div class="mkws-field-description">{{md-description}}</div>
+  {{/if}}
+  {{#if md-date}}
+    <span class="mkws-field-date">{{md-date}}</span>
+  {{/if}}
+</div>
 {{#if renderedDetails}}
   {{{renderedDetails}}}
 {{/if}}
index 1b986b4..e3fa61a 100644 (file)
@@ -105,7 +105,7 @@ node_modules node-modules:
 
 apache-start:
        bin/apache-template-update
-       ${APACHE_HTTPD} -f `pwd`/${TMP_DIR}/jasmine-dev-${APACHE_PORT}.conf
+       umask 002; ${APACHE_HTTPD} -f `pwd`/${TMP_DIR}/jasmine-dev-${APACHE_PORT}.conf
 
 APACHE_PID_FILE=${TMP_DIR}/mkws-jasmine-${APACHE_PORT}.pid
 apache-stop:
@@ -128,7 +128,7 @@ help:
        @echo "Examples: "
        @echo ""
        @echo "make phantomjs PHANTOMJS_PATH=${PHANTOMJS_PATH}"
-       @echo "DEBUG=0 APACHE_PORT=5050 make -s phantomjs PHANTOMJS_TIMEOUT=12 PHANTOMJS_PATH=${PHANTOMJS_PATH}"
+       @echo "DEBUG=0 APACHE_PORT=5050 make -s phantomjs PHANTOMJS_TIMEOUT=16 PHANTOMJS_PATH=${PHANTOMJS_PATH}"
        @echo "DEBUG=2 make phantomjs PHANTOMJS_TIMEOUT=12 PHANTOMJS_URL=${PHANTOMJS_URL}"
        @echo ""
        @echo "make APACHE_PORT=5050 apache-start"
index b91f049..94f5c8d 100755 (executable)
@@ -56,6 +56,9 @@ if ($@) {
 $SIG{ALRM} = sub {
     my $pgid = getpgrp();
 
+    warn "Alarm handler got called after $timeout seconds\n";
+    warn "Kill now the process group...\n\n";
+
     # kill process group
     kill "INT", -$pgid;
 };
@@ -66,7 +69,7 @@ $SIG{INT} = "IGNORE";
 alarm($timeout);
 
 system(@system) == 0
-  or die "system @system failed: $?";
+  or die "system('@system') failed: ?='$?', !='$!', ^E='$^E', ?='$?'";
 
 1;
 
diff --git a/test/spec-dev/async.spec.js b/test/spec-dev/async.spec.js
new file mode 100644 (file)
index 0000000..6de372d
--- /dev/null
@@ -0,0 +1,85 @@
+/* Copyright (c) 2013 Index Data ApS. http://indexdata.com
+ *
+ * async check
+ *
+ */
+describe("Asynchronous check", function () {
+    it("contains spec with an expectation", function () {
+        expect(true).toBe(true);
+    });
+
+    // Asynchronous part
+    it("simple check", function () {
+        var max_time = 1;
+        var timer = 0;
+
+        function found(time, none) {
+            setTimeout(function () {
+                timer = time;
+            }, time * 1000);
+            expect(time >= 0).toBeTruthy();
+        }
+
+        runs(function () {
+            // check hit counter after N seconds
+            found(0, true);
+            found(0.2);
+            found(0.4);
+            found(0.5);
+            found(0.7);
+            found(max_time);
+        });
+
+        waitsFor(function () {
+            // console.log("waits for ... " + timer);
+            return timer == max_time ? true : false;
+        }, "The Value should be N seconds", max_time * 1000);
+
+        runs(function () {
+            expect(timer).toEqual(max_time);
+        });
+    });
+
+
+    it("double async check", function () {
+        var max_time = 0.5;
+        var timer = 0;
+
+        function found(time, none) {
+            setTimeout(function () {
+                timer = time;
+            }, time * 1000);
+            expect(time >= 0).toBeTruthy();
+        }
+
+        runs(function () {
+            found(0);
+            found(0.2);
+            found(max_time - 0.1);
+        });
+
+        waitsFor(function () {
+            return timer == max_time - 0.1 ? true : false;
+        }, "The Value should be N seconds", max_time * 1000);
+
+        runs(function () {
+            expect(timer <= max_time).toBeTruthy();
+        });
+
+        timer = 0;
+        runs(function () {
+            found(0.1);
+            found(max_time);
+        });
+
+        waitsFor(function () {
+            // console.log("waits for ... " + timer);
+            return timer == max_time ? true : false;
+        }, "The Value should be N seconds", max_time * 1000);
+
+        runs(function () {
+            expect(timer <= max_time).toBeTruthy();
+        });
+    });
+
+});
diff --git a/test/spec/async.spec.js b/test/spec/async.spec.js
deleted file mode 100644 (file)
index 6de372d..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/* Copyright (c) 2013 Index Data ApS. http://indexdata.com
- *
- * async check
- *
- */
-describe("Asynchronous check", function () {
-    it("contains spec with an expectation", function () {
-        expect(true).toBe(true);
-    });
-
-    // Asynchronous part
-    it("simple check", function () {
-        var max_time = 1;
-        var timer = 0;
-
-        function found(time, none) {
-            setTimeout(function () {
-                timer = time;
-            }, time * 1000);
-            expect(time >= 0).toBeTruthy();
-        }
-
-        runs(function () {
-            // check hit counter after N seconds
-            found(0, true);
-            found(0.2);
-            found(0.4);
-            found(0.5);
-            found(0.7);
-            found(max_time);
-        });
-
-        waitsFor(function () {
-            // console.log("waits for ... " + timer);
-            return timer == max_time ? true : false;
-        }, "The Value should be N seconds", max_time * 1000);
-
-        runs(function () {
-            expect(timer).toEqual(max_time);
-        });
-    });
-
-
-    it("double async check", function () {
-        var max_time = 0.5;
-        var timer = 0;
-
-        function found(time, none) {
-            setTimeout(function () {
-                timer = time;
-            }, time * 1000);
-            expect(time >= 0).toBeTruthy();
-        }
-
-        runs(function () {
-            found(0);
-            found(0.2);
-            found(max_time - 0.1);
-        });
-
-        waitsFor(function () {
-            return timer == max_time - 0.1 ? true : false;
-        }, "The Value should be N seconds", max_time * 1000);
-
-        runs(function () {
-            expect(timer <= max_time).toBeTruthy();
-        });
-
-        timer = 0;
-        runs(function () {
-            found(0.1);
-            found(max_time);
-        });
-
-        waitsFor(function () {
-            // console.log("waits for ... " + timer);
-            return timer == max_time ? true : false;
-        }, "The Value should be N seconds", max_time * 1000);
-
-        runs(function () {
-            expect(timer <= max_time).toBeTruthy();
-        });
-    });
-
-});
index ccc161e..eca9da5 100644 (file)
@@ -670,11 +670,13 @@ describe("Check SortBy options", function () {
         var waitcount = 0;
         var sort_value = 'title:1';
         var per_page_number = 20;
+
+       // keep current title list
         var title_list_old = title_list("xxx ");
 
         function title_list(prefix) {
             var list = [];
-            var terms = $("div.mkws-records > div.mkws-summary > a");
+            var terms = $("div.mkws-records > div.mkws-summary > div.mkws-field-data span.mkws-field-title");
             for (var i = 0; i < terms.length; i++) {
                 var term = $(terms[i]).text().trim();
                 list.push(term);
@@ -707,7 +709,7 @@ describe("Check SortBy options", function () {
             $("div.mkws-records").unbind("DOMNodeInserted DOMNodeRemoved propertychange");
             debug("unbind by sort");
 
-            var records = $("div.mkws-records > div.mkws-summary > a");
+            var records = $("div.mkws-records > div.mkws-summary");
             debug("Sort by got now " + records.length + " records");
             expect(records.length).toBe(per_page_number);
         });
@@ -740,7 +742,7 @@ describe("Check async widget discovery", function () {
       var numInput = $("div.mkws-search input").length;
       debug("Input elements present: " + numInput);
       expect(numInput).toBe(4);
-      var numRec = $("div.mkws-records > div.mkws-summary > a").length;
+      var numRec = $("div.mkws-records > div.mkws-summary").length;
       debug("Records should still be present. There are: " + numRec);
       expect(numRec).toBeGreaterThan(0);
     });
index e2d3581..f1d13f2 100644 (file)
@@ -28,10 +28,11 @@ test: check
 
 screenshot:
        file=${PREFIX}.$$(echo "${PHANTOMJS_URL}" | perl -npe 's,(\W),-,g; s/-$$//;'); \
-         ${PHANTOMJS} ${PROG} ${PHANTOMJS_URL} ${IMAGES}/tmp.$$file.png ${SCREENSHOT_WIDTH_HEIGHT} ${TIMEOUT}; \
+         ${PHANTOMJS} ${PROG} "${PHANTOMJS_URL}" ${IMAGES}/tmp.$$file.png ${SCREENSHOT_WIDTH_HEIGHT} ${TIMEOUT}; \
          mv -f  ${IMAGES}/tmp.$$file.png  ${IMAGES}/$$file.png
 
 screenshots: clean estimate-time iframe
+       set -e; \
        for t in ${TESTS}; do \
            for i in $$(cat url.$$t); do \
                ${MAKE} PHANTOMJS_URL="$$i" TIMEOUT=4 PREFIX=$$t screenshot; \
index 2ebec85..4000742 100644 (file)
@@ -1,4 +1,5 @@
 http://cph.koha.indexdata.com/cgi-bin/koha/opac-search.pl?q=sushi
 http://demo.koha.indexdata.com/cgi-bin/koha/opac-search.pl?q=sushi
-http://demo.koha.indexdata.com/cgi-bin/koha/opac-search.pl?q=sushi2
+http://demo.koha.indexdata.com/cgi-bin/koha/opac-search.pl?q=sushi3
 http://boston.koha.indexdata.com/cgi-bin/koha/opac-search.pl?q=sushi
+http://cph.koha.indexdata.com/cgi-bin/koha/opac-mkws.pl?q=sushi&t=connect.indexdata.com:9000/flickr_api
index 5964b65..6fb6ec3 100644 (file)
     padding: 3px;
     font-size: 12px;
     background: #f0f8ff;
+    width: 30em;
+    max-width: 100%;
 }
 
 .mkwsTermlistsTitle, .mkws-facets-title {
   display: inline-table /* only for Firefox! */
 }
 
+.mkws-field-description, .mkws-field-date, .mkws-field-thumb {
+  display: none;
+}
+
+