Merge branch 'master' into templateallthemarkup
authorJason Skomorowski <jason@indexdata.com>
Mon, 4 Aug 2014 15:15:46 +0000 (11:15 -0400)
committerJason Skomorowski <jason@indexdata.com>
Mon, 4 Aug 2014 15:15:46 +0000 (11:15 -0400)
Conflicts:
examples/htdocs/jasmine-local-popup.html
tools/htdocs/Makefile

40 files changed:
Makefile
doc/.gitignore
doc/Makefile
doc/README.markdown
doc/library-configuration.txt [deleted file]
doc/mkws-doc.css
doc/mkws-manual.markdown [new file with mode: 0644]
doc/whitepaper.markdown [deleted file]
examples/htdocs/README
examples/htdocs/index.html
examples/htdocs/jasmine-cors-popup.html
examples/htdocs/jasmine-local-popup.html
examples/htdocs/jasmine-popup.html
examples/htdocs/jasmine-pp2.html
examples/htdocs/jasmine.html
examples/htdocs/mike.html
examples/htdocs/popup-dev.html [new file with mode: 0644]
examples/htdocs/popup.html
examples/htdocs/simple.html [new file with mode: 0644]
examples/htdocs/surlyauto.html [new file with mode: 0644]
examples/htdocs/wolfram.html
notes/developers.txt
src/Makefile [new file with mode: 0644]
src/mkws-core.js
src/mkws-handlebars.js
src/mkws-jquery.js [deleted file]
src/mkws-popup.js [new file with mode: 0644]
src/mkws-team.js
src/mkws-widget-main.js
src/mkws-widget.js
test/Makefile
test/js/mkws-jasmine-run.js
test/spec/mkws-pazpar2.js
tools/apache2/jasmine-dev.template
tools/apache2/mkws-live
tools/htdocs/.gitignore
tools/htdocs/Makefile
tools/htdocs/index.html
tools/service-proxy/service-proxy.properties [new file with mode: 0644]
tools/sp-htdocs/index.html

index 32309e5..e80e8e3 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@ clean distclean:
 check-js:
        ${MAKE} -C./test check
 
-phantomjs p:
+phantomjs p p-all phantomjs-all jsb:
        ${MAKE} -C./test $@
 
 # must be called once after GIT checkout
index e727760..5d3ccd7 100644 (file)
@@ -1,6 +1,6 @@
 README.html
 README.odt
 README.pdf
-whitepaper.html
-whitepaper.odt
-whitepaper.pdf
+mkws-manual.html
+mkws-manual.odt
+mkws-manual.pdf
index 34dc62e..19b9dfb 100644 (file)
@@ -1,9 +1,9 @@
 # Copyright (c) 2013-2014 IndexData ApS. http://indexdata.com
 
 DOCS = README.html README.odt README.pdf \
-       whitepaper.html whitepaper.odt whitepaper.pdf
+       mkws-manual.html mkws-manual.odt mkws-manual.pdf
 
-INSTALLABLE = README.html whitepaper.html mkws-doc.css
+INSTALLABLE = README.html mkws-manual.html mkws-doc.css
 INSTALLED = $(INSTALLABLE:%=../tools/htdocs/%)
 
 install: $(INSTALLED)
@@ -22,7 +22,7 @@ all: $(DOCS)
 # http://johnmacfarlane.net/pandoc/demo/example9/pandocs-markdown.html -->
 
 # for older pandoc (<1.9) run first:
-# perl -i.bak -npe 's/"(Authors|Subjects)": "(.*?)"/"$1": "test"/' tools/htdocs/whitepaper.markdown
+# perl -i.bak -npe 's/"(Authors|Subjects)": "(.*?)"/"$1": "test"/' tools/htdocs/mkws-manual.markdown
 #
 %.html: %.markdown
        rm -f $@
@@ -34,7 +34,7 @@ all: $(DOCS)
        pandoc --standalone $< -o $@
        chmod ugo-w $@
 
-# ### In order to compile the whitepaper, which has tables, to PDF,
+# ### In order to compile the manual, which has tables, to PDF,
 # you will need to install the Debian package
 #      texlive-latex-recommended
 %.pdf: %.markdown
index 667cf4f..ff9f4bb 100644 (file)
@@ -1,27 +1,31 @@
 % The MasterKey Widget Set
 % Mike Taylor; Wolfram Schneider
-% 10 July 2013
+% 28 July 2014
 
 
 Introduction
 ------------
 
-This is the MasterKey Widget Set. The initial version was based on the
-"jsdemo" application distributed with pazpar2, but it is now far
-removed from those beginnnings.
+This is the MasterKey Widget Set. It provides a way to insert
+searching and other information-related functionality into existing
+web pages as small snippets of HTML.
 
 As much of the searching functionality as possible is hosted on
        <http://mkws.indexdata.com/>
-so that very simple websites such as
-       <http://example.indexdata.com/>
+so that very simple applications such as
+       <http://example.indexdata.com/simple.html>
 can have MasterKey searching with minimal effort.
 
 The following files are hosted on `mkws.indexdata.com`:
 
-* `mkws.js`
+* `mkws.js` (and its compressed version `mkws.min.js`)
 * `/pazpar2/js/pz2.js`
-* `mkws-complete.js` -- a single file consisting of `mkws.js`,
-  jQuery (which it uses), Handlebars (ditto) and `pz2.js`
+* `mkws-complete.js` (and its compressed version `mkws-complete.min.js`)
+  -- a single file consisting of `mkws.js` together with the files it
+  uses: `pz2.js` jQuery, jQuery-JSON and Handlebars.
+* Local copy of `jquery-1.10.0.min.js`
+* Local copy of `jquery.json-2.4.js`
+* Local copy of `handlebars-v1.1.2.js`
 * `mkws.css`
 
 
@@ -65,39 +69,23 @@ will be filled in by MKWS:
 * `<div id="mkwsStat"></div>` -- summary statistics
 
 You can configure and control the client by creating an `mkws_config`
-object _before_ loading the widget-set.  Here is an example of all
-possible options:
+object before loading the widget-set. Here is an example showing how
+to use options to offer a choice between English and German UI
+languages, and to default to sorting by title ascending:
 
 ~~~
     <script type="text/javascript">
       var mkws_config = {
-        use_service_proxy: true,    /* true, flase: use service proxy instead pazpar2 */
-        show_lang: true,            /* true, false: show/hide language menu */
-        show_sort: true,            /* true, false: show/hide sort menu */
-        show_perpage: true,         /* true, false: show/hide perpage menu */
-        show_switch: true,          /* true, false: show/hide switch menu */
-        lang_options: ["en", "de", "da"],
-                                    /* display languages links for given languages, [] for all */
-        facets: ["xtargets", "subject", "author"],
-                                    /* display facets, in this order, [] for none */
-        sort_default: "relevance",  /* "relevance", "title:1", "date:0", "date:1" */
-        query_width: 50,            /* 5..50 */
-        perpage_default: 20,        /* 10, 20, 30, 50 */
-        lang: "en",                 /* "en", "de", "da" */
-        debug_level: 0,             /* debug level for development: 0..2 */
-
-        responsive_design_wodth: 600,    /* page reflows for devices < 600 pixels wide */
-        pazpar2_url: "/service-proxy/",            /* URL */
-        service_proxy_auth: "/service-proxy-auth", /* URL */
-        // TODO: language_*, perpage_options, sort_options
+        lang_options: ["en", "de" ],
+        sort_default: "title:1"
       };
     </script>
 ~~~
 
-For much more detail, see
-[the MKWS whitepaper](whitepaper.html).
+For much more detail, see:
+[Embedded metasearching with the MasterKey Widget Set](mkws-manual.html)
 
 
 - - -
 
-Copyright 2013 IndexData ApS. <http://indexdata.com>
+Copyright 2014 IndexData ApS. <http://indexdata.com>
diff --git a/doc/library-configuration.txt b/doc/library-configuration.txt
deleted file mode 100644 (file)
index 5132887..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-MKWS Target Selection
-=====================
-
-
-MKWS accesses targets using the Pazpar2 metasearching engine, almost
-always fronted by the Service Proxy to manage target selection. This
-document assumes the SP is used, and so that a library of targets is
-available, maintained using an instance of MKAdmin (often
-http://mkc-admin.indexdata.com/console/)
-
-
-1. Selecting targets within the library
----------------------------------------
-
-MKWS applications can choose what subset of the library's targets to
-use, by means of several alternative settings on individual widgets or
-in the mkws_config structure:
-
-* targets -- contains a Pazpar2 targets string, typically of the form
-  "pz:id=" or "pz:id~" followed by a pipe-separated list of low-level
-  target IDs.
-
-  At present, these IDs can take one of two forms, depending on the
-  configuration of the Service Proxy being used: they may be based on
-  ZURLs, so a typical value would be something like:
-       pz:id=josiah.brown.edu:210/innopac|lui.indexdata.com:8080/solr4/select?fq=database:4902
-  Or they may be UDBs, so a typical value would be something like:
-       pz:id=brown|artstor
-
-* targetfilter -- contains a CQL query which is used to find relevant
-  targets from the relvant library. For example,
-       udb==Google_Images
-  Or
-       categories=news
-
-* target -- contains a single UDB, that of the sole target to be
-  used. For example
-       Google_Images
-  This is merely syntactic sugar for "targetfilter" with the query
-       udb==NAME
-
-
-2. Authenticating onto the library
-----------------------------------
-
-Some MKWS applications will be content to use the default library with
-its selection of targets. Most, though, will want to define their own
-library providing a different range of available targets. An important
-case is that of applications that authenticate onto subscription
-resources by means of credentials stored in MKAdmin: precautions must
-be taken so that such library accounts do not allow unauthorised
-access.
-
-Setting up such a library is a two, three or four-stage process.
-
-Stage A: create the library
-
-Use MKAdmin to create the library:
-       - Make a new library on http://mkc-admin.indexdata.com/console/
-       - Select relevant targets
-       - Add authentication credentials to the targets as necessary
-       - Create an end-user account
-       - Depending on what authentication method it be used, set the
-         end-user account's username and password, or IP-address
-         range, or referring URL, or hostname.
-
-Stage B: tell the application to use the library
-
-In the HTML of the application, tell MKWS to authenticate on to the
-Service Proxy. When IP-based, referer-based or hostname-based
-authentication is used, this is very simple:
-
-       <script type="text/javascript">
-         var mkws_config = { service_proxy_auth:
-         "http://mkws.indexdata.com/service-proxy/?command=auth&action=check,login" };
-        </script>
-
-And ensure that access to the MWKS application is from the correct
-IP-range, referer or hostname.
-
-Stage C (optional): embed credentials for access to the library
-
-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 can most simply be done just
-by setting the service_proxy_auth configuration item to a URL such as
-       http://mkws.indexdata.com/service-proxy/?command=auth&action=check,login&username=MIKE&password=SWORDFISH
-
-Stage D (optional): conceal credentials from HTML source
-
-Using a Service-Proxy authentication URL such as the one above reveals
-the the credentials to public view -- to anyone who does View Source
-on the MKWS application. This may be acceptable for some libraries,
-but is intolerable for those which provide authenticated access to
-subscription resources.
-
-In these circumstances, a more elaborate approach is necessary. The
-idea is to make a local URL that is used for authentication onto the
-Service Proxy, hiding the credentials, and to use local mechanisms to
-limit access to that local authentication URL. Here is one way to do
-it when Apache2 is the application's web-server, which we will call
-example.com:
-
-       - Add a rewriting authentication alias to the configuration:
-               RewriteEngine on
-               RewriteRule /spauth/ http://mkws.indexdata.com/service-proxy/?command=auth&action=check,login&username=U&password=PW [P]
-       - Set thwe MKWS configuration item "service_proxy_auth" to:
-               http://example.com/spauth/
-       - Protect access to the local path http://example.com/spauth/
-               (e.g. using a .htaccess file).
-
-Once such a library has been set up, and access to it established,
-target selection within the set that it makes available can be done
-using the mechanisms above.
-
index a58c10f..603999a 100644 (file)
@@ -1,5 +1,5 @@
 body {
-    font-family: Times, "Times Roman", "Times New Roman";
+    font-family: Baskerville, "Baskervald ADF Std", "Times New Roman", "Times Roman", Times;
 }
 
 h1, h2, h3, h4 {
@@ -8,7 +8,7 @@ h1, h2, h3, h4 {
     font-family: Gill Sans, "Gillius ADF", Gillius, GilliusADF, Verdana, Sans-Serif;
 }
 
-h2 a, h3 a, h4 a, div#TOC a {
+h1 a, h2 a, h3 a, h4 a, div#TOC a {
     color: #68a;
     text-decoration: none;
 }
@@ -18,7 +18,7 @@ h2, h3 {
     margin-bottom: -0.5em;
 }
 
-h1 {
+h1.title {
     background: #e0e8f8;
     padding: 0.2em;
     font-weight: normal;
@@ -34,10 +34,15 @@ h3.date {
     color: black
 }
 
-body > p, ul, ol, pre, table, h4 {
+body > p, ul, ol, pre, table, h4, blockquote {
     margin-left: 10%;
 }
 
+blockquote {
+    padding-left: 4em;
+    padding-right: 4em;
+}
+
 p, ul {
     max-width: 40em;
 }
diff --git a/doc/mkws-manual.markdown b/doc/mkws-manual.markdown
new file mode 100644 (file)
index 0000000..c4ddeb7
--- /dev/null
@@ -0,0 +1,784 @@
+% Embedded metasearching with the MasterKey Widget Set
+% Mike Taylor
+% 30 July 2014
+
+
+Introduction
+============
+
+There are lots of practical problems in building resource discovery
+solutions. One of the biggest, and most ubiquitous is incorporating
+metasearching functionality into existing web-sites -- for example,
+content-management systems, library catalogues or intranets. In
+general, even when access to core metasearching functionality is
+provided by simple web-services such as
+[Pazpar2](http://www.indexdata.com/pazpar2), integration work is seen
+as a major part of most projects.
+
+Index Data provides several different toolkits for communicating with
+its metasearching middleware, trading off varying degrees of
+flexibility against convenience:
+
+* pz2.js -- a low-level JavaScript library for interrogating the
+  Service Proxy and Pazpar2. It allows the HTML/JavaScript programmer
+  to create JavaScript applications display facets, records, etc. that
+  are fetched from the metasearching middleware.
+
+* masterkey-ui-core -- a higher-level, complex JavaScript library that
+  uses pz2.js to provide the pieces needed for building a
+  full-featured JavaScript application.
+
+* MasterKey Demo UI -- an example of a searching application built on
+  top of masterkey-ui-core. Available as a public demo at
+  http://mk2.indexdata.com/
+
+* MKDru -- a toolkit for embedding MasterKey-like searching into
+  Drupal sites.
+
+All of these approaches require programming to a greater or lesser
+extent. Against this backdrop, we introduced MKWS (the MasterKey
+Widget Set) -- a set of simple, very high-level HTML+CSS+JavaScript
+components that can be incorporated into any web-site to provide
+MasterKey searching facilities. By placing `<div>`s with well-known
+identifiers in any HTML page, the various components of an application
+can be embedded: search-boxes, results areas, target information, etc.
+
+
+Simple Example
+==============
+
+The following is a complete MKWS-based searching application:
+
+    <html>
+      <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+        <title>MKWS demo client</title>
+        <script type="text/javascript" src="http://mkws.indexdata.com/mkws-complete.js"></script>
+        <link rel="stylesheet" href="http://mkws.indexdata.com/mkws.css" />
+      </head>
+      <body>
+        <div id="mkwsSearch"></div>
+        <div id="mkwsResults"></div>
+      </body>
+    </html>
+
+Go ahead, try it! You don't even need a web-server. Just copy and
+paste this HTML into a file on your computer -- `/tmp/magic.html`,
+say -- and point your web-browser at it:
+`file:///tmp/magic.html`. Just like that, you have working
+metasearching.
+
+
+How the example works
+---------------------
+
+If you know any HTML, the structure of the file will be familar to
+you: the `<html>` element at the top level contains a `<head>` and a
+`<body>`. In addition to whatever else you might want to put on your
+page, you can add MKWS elements.
+
+These fall into two categories. First, the prerequisites in the HTML
+header, which are loaded from the tool site mkws.indexdata.com:
+
+* `mkws-complete.js`
+  contains all the JavaScript needed by the widget-set.
+
+* `mkws.css`
+  provides the default CSS styling
+
+Second, within the HTML body, `<div>` elements with special IDs that
+begin `mkws` can be provided. These are filled in by the MKWS code,
+and provide the components of the searching UI. The very simple
+application above has only two such components: a search box and a
+results area. But more are supported. The main `<div>`s are:
+
+* `mkwsSearch` -- provides the search box and button.
+
+* `mkwsResults` -- provides the results area, including a list of
+   brief records (which open out into full versions when clicked),
+   paging for large results sets, facets for refining a search,
+   sorting facilities, etc.
+
+* `mkwsLang` -- provides links to switch between one of several
+   different UI languages. By default, English, Danish and German are
+   provided.
+
+* `mkwsSwitch` -- provides links to switch between a view of the
+   result records and of the targets that provide them. Only
+   meaningful when `mkwsTargets` is also provided.
+
+* `mkwsTargets` -- the area where per-target information will appear
+   when selected by the link in the `mkwsSwitch` area. Of interest
+   mostly for fault diagnosis rather than for end-users.
+
+* `mkwsStat` --provides a status line summarising the statistics of
+   the various targets.
+
+To see all of these working together, just put them all into the HTML
+`<body>` like so:
+
+        <div id="mkwsSwitch"></div>
+        <div id="mkwsLang"></div>
+        <div id="mkwsSearch"></div>
+        <div id="mkwsResults"></div>
+        <div id="mkwsTargets"></div>
+        <div id="mkwsStat"></div>
+
+
+Configuration
+=============
+
+Many aspects of the behaviour of MKWS can be modified by setting
+parameters into the `mkws_config` object. **This must be done *before*
+including the MKWS JavaScript** so that when that code is executed it
+can refer to the configuration values. So the HTML header looks like
+this:
+
+        <script type="text/javascript">
+          var mkws_config = {
+            lang: "da",
+            sort_default: "title",
+            query_width: 60
+          };
+        </script>
+        <script type="text/javascript" src="http://mkws.indexdata.com/mkws-complete.js"></script>
+
+This configuration sets the UI language to Danish (rather than the
+default of 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 full set of supported configuration items is described in the
+reference guide below.
+
+
+Control over HTML and CSS
+=========================
+
+More sophisticated applications will not simply place the `<div>`s
+together, but position them carefully within an existing page
+framework -- such as a Drupal template, an OPAC or a SharePoint page.
+
+While it's convenient for simple applications to use a monolithic
+`mkwsResults` area which contains record, facets, sorting options,
+etc., customised layouts may wish to treat each of these components
+separately. In this case, `mkwsResults` can be omitted, and the
+following lower-level components provided instead:
+
+* `mkwsTermlists` -- provides the facets
+
+* `mkwsRanking` -- provides the options for how records are sorted and
+   how many are included on each page of results.
+
+* `mkwsPager` -- provides the links for navigating back and forth
+   through the pages of records.
+
+* `mkwsNavi` -- when a search result has been narrowed by one or more
+   facets, this area shows the names of those facets, and allows the
+   selected values to be clicked in order to remove them.
+
+* `mkwsRecords` -- lists the actual result records.
+
+Customisation of MKWS searching widgets can also be achieved by
+overriding the styles set in the toolkit's CSS stylesheet. The default
+styles can be inspected in `mkws.css` and overridden in any
+styles that appears later in the HTML than that file. At the simplest
+level, this might just mean changing fonts, sizes and colours, but
+more fundamental changes are also possible.
+
+To properly apply styles, it's necessary to understand how the HTML is
+structured, e.g. which elements are nested within which
+containers. The structures used by the widget-set are described in the
+reference guide below.
+
+
+Refinements
+===========
+
+
+Message of the day
+------------------
+
+Some applications might like to open with content in the area that
+will subsequently be filled with result-records -- a message of the
+day, a welcome message or a help page. This can be done by placing an
+`mkwsMOTD` division anywhere on the page. It will be moved into the
+`mkwsResults` area and initially displayed, but will be hidden when a
+search is made.
+
+
+Customised display using Handlebars templates
+---------------------------------------------
+
+Certain aspects of the widget-set's display can be customised by
+providing Handlebars templates with well-known classes that begin with
+the string `mkwsTemplate_`. At present, the supported templates are:
+
+* `mkwsTemplate_Summary` -- used for each summary record in a list of
+  results.
+
+* `mkwsTemplate_Record` -- used when displaying a full record.
+
+For both of these the metadata record is passed in, and its fields can
+be referenced in the template. As well as the metadata fields
+(`md-*`), two special fields are provided to the `mkwsTemplate_Summary`
+template, for creating popup links for full records. These are `_id`,
+which must be provided as the `id` attribute of a link tag, and
+`_onclick`, which must be provided as the `onclick` attribute.
+
+For example, an application can install a simple author+title summary
+record in place of the usual one providing the following template:
+
+        <script class="mkwsTemplate_Summary" type="text/x-handlebars-template">
+          {{#if md-author}}
+            <span>{{md-author}}</span>
+          {{/if}}
+          <a href="#" id="{{_id}}" onclick="{{_onclick}}">
+            <b>{{md-title}}</b>
+          </a>
+        </script>
+
+For details of Handlebars template syntax, see
+[the online documentation](http://handlebarsjs.com/).
+
+
+Responsive design
+-----------------
+
+Metasearching applications may need to appear differently on
+small-screened mobile devices, or change their appearance when
+screen-width changes (as when a small device is rotated). To achieve
+this, MKWS supports responsive design which will move the termlists to
+the bottom on narrow screens and to the sidebar on wide screens.
+
+To turn on this behaviour, set the `responsive_design_width` to the desired
+threshhold width in pixels. For example:
+
+        <script type="text/javascript">
+            var mkws_config = {
+                responsive_design_width: 990
+            };
+        </script>
+
+If individual result-related components are in use in place of the
+all-in-one mkwsResults, then the redesigned application needs to
+specify the locations where the termlists should appear in both
+cases. In this case, wrap the wide-screen `mkwsTermlists` element in a
+`mkwsTermlists-Container-wide` element; and provide an
+`mkwsTermlists-Container-narrow` element in the place where the narrow-screen
+termlists should appear.
+
+
+Popup results with jQuery UI
+----------------------------
+
+The [jQuery UI library](http://en.wikipedia.org/wiki/JQuery_UI)
+can be used to construct MKWS applications in which the only component
+generally visible on the page is a search box, and the results appear
+in a popup. The key part of such an application is this invocation of
+the MKWS jQuery plugin:
+
+        <div class="mkwsSearch"></div>
+        <div class="mkwsPopup" popup_width="1024" popup_height="650" popup_modal="0" popup_autoOpen="0" popup_button="input.mkwsButton">
+          <div class="mkwsSwitch"></div>
+          <div class="mkwsLang"></div>
+          <div class="mkwsResults"></div>
+          <div class="mkwsTargets"></div>
+          <div class="mkwsStat"></div>
+        </div>
+
+The necessary scaffolding can be seen in an example application,
+http://example.indexdata.com/index-popup.html
+
+
+Authentication and target configuration
+---------------------------------------
+
+By default, MKWS configures itself to use a demonstration account on a
+service hosted by mkws.indexdata.com. This account (username `demo`,
+password `demo`) provides access to about a dozen free data
+sources. Authentication onto this service is via an authentication URL
+on the same MKWS server, so no explicit configuration is needed.
+
+In order to search in a customised set of targets, including
+subscription resources, it's necessary to create an account with
+Index Data's hosted service proxy, and protect that account with
+authentication tokens (to prevent unauthorised use of subscription
+resources). For information on how to do this, see the next section.
+
+
+MKWS Target Selection
+=====================
+
+MKWS accesses targets using the Pazpar2 metasearching engine. Although
+Pazpar2 can be used directly, using a statically configured set of
+targets, this usage is unusual. More often, Pazpar2 is fronted by the
+Service Proxy (SP), which manages authentication, sessions, target
+selection, etc.
+
+This document assumes the SP is used, and explains how to go about
+making a set of targets (a "library") available, how to connect your
+MKWS application to that library, and how to choose which of the
+available targets to use.
+
+
+Maintaining the library
+-----------------------
+
+The service proxy accesses sets of targets that are known as
+"libraries". In general, each customer will have their own library,
+though some standard libraries may be shared between many customers --
+for example, a library containing all open-access academic journals.
+A library can also contain other configuration information, including
+the set of categories by which targets are classified for the library.
+
+Libraries are maintained using MKAdmin (MasterKey
+Admin). Specifically, those used by MKWS are generally maintained on
+the "MKX Admin" installation at
+<http://mkx-admin.indexdata.com/console/>
+
+In general, Index Data will create a library for each customer, then
+give the customer a username/password pair that they can use to enter
+MKAdmin and administrate that library.
+
+Once logged in, customers can select which targets to include (from
+the list of several thousand that MKAdmin knows about), and make
+customer-specific modifications -- e.g. overriding the titles of the
+targets.
+
+Most importantly, customers' administrators can add authentication
+credentials that the Service Proxy will used on their behalf when
+accessing subscription resources -- username/password pairs or proxies
+to use for IP-based authentication. Note that **it is then crucial to
+secure the library from use by unauthorised clients**, otherwise the
+customer's paid subscriptions will be exploited.
+
+Access to libraries is managed by creating one or more "User Access"
+records in MKAdmin, under the tab of that name. Each of these records
+provides a combination of credentials and other data that allow an
+incoming MKWS client to be identified as having legitimate access to
+the library. The authentication process, described below, works by
+searching for a matching User Access record.
+
+
+Authenticating your MWKS application onto the library
+-----------------------------------------------------
+
+Some MKWS applications will be content to use the default library with
+its selection of targets. Most, though, will want to define their own
+library providing a different range of available targets. An important
+case is that of applications that authenticate onto subscription
+resources by means of backe-end site credentials stored in MKAdmin:
+precautions must be taken so that such library accounts do not allow
+unauthorised access.
+
+Setting up such a library is a process of several stages.
+
+### Create the User Access account
+
+
+Log in to MKAdmin administrate your library:
+
+* Go to <http://mkx-admin.indexdata.com/console/>
+* Enter the adminstrative username/password
+* Go to the User Access tab
+* Create an end-user account
+* Depending on what authentication method it be used, set the
+  User Access account's username and password, or IP-address range, or
+  referring URL, or hostname.
+
+If your MWKS application runs at a well-known, permanent address --
+<http://yourname.com/app.html>, say -- you can set the User Access
+record so that this originating URL is recognised by setting it into
+the "Referring URL" field.
+
+If your application accesses the Service Proxy by a unique virtual
+hostname -- yourname.sp-mkws.indexdata.com, say -- you can tie the use
+of this hostname to your library by setting the User Access record's
+"Host Name" field to name of the host where the SP is accessed. **Note
+that this is not secure, as other applications can use this virtual
+hostname to gain access to your library.**
+
+> TODO Authentication by IP address does not yet work correctly -- see
+> bug MKWS-234 ("Improve SP configuration/proxying for better
+> authentication").
+
+Alternatively, your application can authenticate by username and
+password credentials. This is a useful approach in several situations,
+including when you need to specify the use of a different library from
+usual one. To arrange for this, set the username and password as a
+single string separated by a slash -- e.g. "mike/swordfish" -- into
+the User Access record's Authentication field.
+
+You can create multiple User Access records: for example, one that
+uses Referring URL, and another that uses a username/password pair to
+be used when running an application from a different URL.
+
+### Tell the application to use the library
+
+In the HTML of the application, tell MKWS to authenticate on to the
+Service Proxy. When IP-based, referer-based or hostname-based
+authentication is used, this is very simple:
+
+       <script type="text/javascript">
+         var mkws_config = { service_proxy_auth:
+         "//sp-mkws.indexdata.com/service-proxy/?command=auth&action=perconfig" };
+       </script>
+
+> TODO This should be the default setting
+
+And ensure that access to the MWKS application is from the correct
+Referrer URL or IP-range.
+
+### (Optional): access by a different virtual hostname
+
+When hostname-based authentication is in use, it's necessary to access
+the Service Proxy as the correctly named virtual host. This can be
+done by setting the `service_proxy_auth` configuration item to a
+URL containing that hostname, such as
+<//yourname.sp-mkws.indexdata.com/service-proxy/?command=auth&action=perconfig>
+
+> TODO It should be possible to change just the hostname without
+> needing to repeat the rest of the URL (protocol, path, query)
+
+> TODO When changing the SP authentication URL, the Pazpar2 URL should
+> in general change along with it.
+
+### (Optional): embed credentials for access to the library
+
+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 can most simply be done just
+by setting the `service_proxy_auth` configuration item to a URL such as
+<//sp-mkws.indexdata.com/service-proxy/?command=auth&action=perconfig&username=mike&password=swordfish>
+
+> TODO It should be possible to add the username and password to the
+> configuration without needing to repeat the rest of the URL.
+
+### (Optional): conceal credentials from HTML source
+
+Using a credential-based Service-Proxy authentication URL such as the
+one above reveals the the credentials to public view -- to anyone who
+does View Source on the MKWS application. This may be acceptable for
+some libraries, but is intolerable for those which provide
+authenticated access to subscription resources.
+
+In these circumstances, a more elaborate approach is necessary. The
+idea is to make a URL local to the customer that is used for
+authentication onto the Service Proxy, hiding the credentials in a
+local rewrite rule. Then local mechanisms can be used to limit access
+to that local authentication URL. Here is one way to do it when
+Apache2 is the application's web-server, which we will call
+yourname.com:
+
+- Add a rewriting authentication alias to the configuration:
+
+       RewriteEngine on
+       RewriteRule /spauth/ http://mkws.indexdata.com/service-proxy/?command=auth&action=check,login&username=U&password=PW [P]
+
+- Set the MKWS configuration item `service_proxy_auth` to
+  <http://yourname.com/spauth/>
+- Protect access to the local path <http://yourname.com/spauth/>
+  (e.g. using a .htaccess file).
+
+
+Choosing targets from the library
+---------------------------------
+
+MKWS applications can choose what subset of the library's targets to
+use, by means of several alternative settings on individual widgets or
+in the `mkws_config` structure:
+
+* `targets` -- contains a Pazpar2 targets string, typically of the form
+  "pz:id=" or "pz:id~" followed by a pipe-separated list of low-level
+  target IDs.
+  At present, these IDs can take one of two forms, depending on the
+  configuration of the Service Proxy being used: they may be based on
+  ZURLs (so a typical value would be something like
+  `pz:id=josiah.brown.edu:210/innopac|lui.indexdata.com:8080/solr4/select?fq=database:4902`)
+  or they may be UDBs (so a typical value would be something like
+  `pz:id=brown|artstor`)
+
+* `targetfilter` -- contains a CQL query which is used to find relevant
+  targets from the relvant library. For example,
+  `udb==Google_Images`
+  or
+  `categories=news`
+
+* `target` -- contains a single UDB, that of the sole target to be
+  used. For example,
+  `Google_Images`.
+  This is merely syntactic sugar for "targetfilter" with the query
+  `udb==NAME`
+
+For example, a `Records` widget can be limited to searching only in
+targets that have been categorised as news sources by providing an
+attribute as follows:
+
+       <div class="mkwsRecords" targetfilter='categories=news'/>
+
+
+Reference Guide
+===============
+
+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                   Type    Default   Description
+--------                  -----   --------- ------------
+debug_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.
+
+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.
+
+query_width               int     50        The width of the query box, in characters.
+
+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.
+
+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.
+
+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`.
+
+show_lang                 bool    true      Indicates whether or not to display the language menu.
+
+show_perpage              bool    true      Indicates whether or not to display the perpage menu.
+
+show_sort                 bool    true      Indicates whether or not to display the sort menu.
+
+show_switch               bool    true      Indicates whether or not to display the switch menu, for switching between showing
+                                            retrieved records and target information.
+
+sort_default              string  relevance The label of the default sort criterion to use. Must be one of those in the `sort`
+                                            array.
+
+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`.
+
+use_service_proxy         bool    true      If true, then a Service Proxy is used to deliver searching services rather than raw
+                                            Pazpar2.
+----
+
+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 `mkwsLang` 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
+
+1. ["sources", "subjects", "authors"]
+
+2. /pazpar2/search.pz2
+
+3. [10, 20, 30, 50]
+
+4. http://mkws.indexdata.com/service-proxy-auth
+
+5. http://mkws.indexdata.com/service-proxy/
+
+6. [["relevance"], ["title:1", "title"], ["date:0", "newest"], ["date:1", "oldest"]]
+
+
+Language specification
+----------------------
+
+Support for another UI language can be added by providing an entry in
+the `mkws_config` object whose name is `language_` followed by the
+name of the language: for example, `language_French` to support
+French. Then value of this entry must be a key-value lookup table,
+mapping the English-language strings of the UI into their equivalents
+in the specified language. For example:
+
+            var mkws_config = {
+              language_French: {
+                "Authors": "Auteurs",
+                "Subjects": "Sujets",
+                // ... and others ...
+              }
+            }
+
+The following strings occurring in the UI can be translated:
+`Displaying`,
+`Next`,
+`Prev`,
+`Records`,
+`Search`,
+`Sort by`,
+`Targets`,
+`Termlists`,
+`and show`,
+`found`,
+`of`,
+`per page`
+and
+`to`.
+
+In addition, facet names can be translated:
+`Authors`,
+`Sources`
+and
+`Subjects`.
+
+Finally, the names of fields in the full-record display can be
+translated. These include, but may not be limited to:
+`Author`,
+`Date`,
+`Location`,
+`Subject`
+and
+`Title`.
+
+
+
+jQuery UI popup invocation
+--------------------------
+
+The MasterKey Widget Set can be invoked in a popup window on top of the page.
+
+Note that when using the `popup` layout, facilities from the jQuery UI
+toolkit are used, so it's necessary to include both CSS and JavaScript
+from that toolkit. The relevant lines are:
+
+    <script src="http://code.jquery.com/ui/1.10.3/jquery-ui.min.js"></script>
+    <link rel="stylesheet" type="text/css"
+          href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
+
+    <div class="mkwsSearch"></div>
+    <div class="mkwsPopup" popup_width="1024" popup_height="650" popup_modal="0" popup_autoOpen="0" popup_button="input.mkwsButton">
+      <div class="mkwsSwitch"></div>
+      <div class="mkwsLang"></div>
+      <div class="mkwsResults"></div>
+      <div class="mkwsTargets"></div>
+      <div class="mkwsStat"></div>
+    </div>
+
+----
+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_button    string      input.mkwsButton  (Never change this.)
+
+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
+
+----
+
+
+The structure of the HTML generated by the MKWS widgets
+-------------------------------------------------------
+
+In order to override the default CSS styles provided by the MasterKey Widget
+Set, it's necessary to understand that structure of the HTML elements that are
+generated within the components. This knowledge make it possible, for example,
+to style each `<div>` with class `term` but only when it occurs inside an
+element with ID `#mkwsTermlists`, so as to avoid inadvertently styling other
+elements using the same class in the non-MKWS parts of the page.
+
+The HTML structure is as follows. As in CSS, #ID indicates a unique identifier
+and .CLASS indicates an instance of a class.
+
+    #mkwsSwitch
+      a*
+
+    #mkwsLang
+      ( a | span )*
+
+    #mkwsSearch
+      form
+        input#mkwsQuery type=text
+        input#mkwsButton type=submit
+
+    #mkwsBlanket
+      (no contents -- used only for masking)
+
+    #mkwsResults
+      table
+        tbody
+          tr
+            td
+              #mkwsTermlists
+                div.title
+                div.facet*
+                  div.termtitle
+                  ( a span br )*
+            td
+              div#mkwsRanking
+                form#mkwsSelect
+                  select#mkwsSort
+                  select#mkwsPerpage
+              #mkwsPager
+              #mkwsNavi
+              #mkwsRecords
+                div.record*
+                  span (for sequence number)
+                  a (for title)
+                  span (for other information such as author)
+                  div.details (sometimes)
+                    table
+                      tbody
+                        tr*
+                          th
+                          td
+    #mkwsTargets
+      #mkwsBytarget
+        table
+          thead
+            tr*
+              td*
+          tbody
+            tr*
+              td*
+
+    #mkwsStat
+      span.head
+      span.clients
+      span.records
+
+- - -
+
+Copyright (C) 2013-2014 by IndexData ApS, <http://www.indexdata.com>
diff --git a/doc/whitepaper.markdown b/doc/whitepaper.markdown
deleted file mode 100644 (file)
index 55c56ec..0000000
+++ /dev/null
@@ -1,598 +0,0 @@
-% Embedded metasearching with the MasterKey Widget Set
-% Mike Taylor
-% July-September 2013
-
-
-Introduction
-------------
-
-There are lots of practical problems in building resource discovery
-solutions. One of the biggest, and most ubiquitous is incorporating
-metasearching functionality into existing web-sites -- for example,
-content-management systems, library catalogues or intranets. In
-general, even when access to core metasearching functionality is
-provided by simple web-services such as
-[Pazpar2](http://www.indexdata.com/pazpar2), integration work is seen
-as a major part of most projects.
-
-Index Data provides several different toolkits for communicating with
-its metasearching middleware, trading off varying degrees of
-flexibility against convenience:
-
-* pz2.js -- a low-level JavaScript library for interrogating the
-  Service Proxy and Pazpar2. It allows the HTML/JavaScript programmer
-  to create JavaScript applications display facets, records, etc. that
-  are fetched from the metasearching middleware.
-
-* masterkey-ui-core -- a higher-level, complex JavaScript library that
-  uses pz2.js to provide the pieces needed for building a
-  full-featured JavaScript application.
-
-* MasterKey Demo UI -- an example of a searching application built on
-  top of masterkey-ui-core. Available as a public demo at
-  http://mk2.indexdata.com/
-
-* MKDru -- a toolkit for embedding MasterKey-like searching into
-  Drupal sites.
-
-All of these approaches require programming to a greater or lesser
-extent. Against this backdrop, we introduced MKWS (the MasterKey
-Widget Set) -- a set of simple, very high-level HTML+CSS+JavaScript
-components that can be incorporated into any web-site to provide
-MasterKey searching facilities. By placing `<div>`s with well-known
-identifiers in any HTML page, the various components of an application
-can be embedded: search-boxes, results areas, target information, etc.
-
-
-Simple Example
---------------
-
-The following is a complete MKWS-based searching application:
-
-    <html>
-      <head>
-        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-        <title>MKWS demo client</title>
-        <script type="text/javascript" src="http://mkws.indexdata.com/mkws-complete.js"></script>
-        <link rel="stylesheet" href="http://mkws.indexdata.com/mkws.css" />
-      </head>
-      <body>
-        <div id="mkwsSearch"></div>
-        <div id="mkwsResults"></div>
-      </body>
-    </html>
-
-Go ahead, try it! You don't even need a web-server. Just copy and
-paste this HTML into a file on your computer -- `/tmp/magic.html`,
-say -- and point your web-browser at it:
-`file:///tmp/magic.html`. Just like that, you have working
-metasearching.
-
-
-How the example works
----------------------
-
-If you know any HTML, the structure of the file will be familar to
-you: the `<html>` element at the top level contains a `<head>` and a
-`<body>`. In addition to whatever else you might want to put on your
-page, you can add MKWS elements.
-
-These fall into two categories. First, the prerequisites in the HTML
-header, which are loaded from the tool site mkws.indexdata.com:
-
-* `mkws-complete.js`
-  contains all the JavaScript needed by the widget-set.
-
-* `mkws.css`
-  provides the default CSS styling 
-
-Second, within the HTML body, `<div>` elements with special IDs that
-begin `mkws` can be provided. These are filled in by the MKWS code,
-and provide the components of the searching UI. The very simple
-application above has only two such components: a search box and a
-results area. But more are supported. The main `<div>`s are:
-
-* `mkwsSearch` -- provides the search box and button.
-
-* `mkwsResults` -- provides the results area, including a list of
-   brief records (which open out into full versions when clicked),
-   paging for large results sets, facets for refining a search,
-   sorting facilities, etc.
-
-* `mkwsLang` -- provides links to switch between one of several
-   different UI languages. By default, English, Danish and German are
-   provided.
-
-* `mkwsSwitch` -- provides links to switch between a view of the
-   result records and of the targets that provide them. Only
-   meaningful when `mkwsTargets` is also provided.
-
-* `mkwsTargets` -- the area where per-target information will appear
-   when selected by the link in the `mkwsSwitch` area. Of interest
-   mostly for fault diagnosis rather than for end-users.
-
-* `mkwsStat` --provides a status line summarising the statistics of
-   the various targets.
-
-To see all of these working together, just put them all into the HTML
-`<body>` like so:
-
-        <div id="mkwsSwitch"></div>
-        <div id="mkwsLang"></div>
-        <div id="mkwsSearch"></div>
-        <div id="mkwsResults"></div>
-        <div id="mkwsTargets"></div>
-        <div id="mkwsStat"></div>
-
-Configuration
--------------
-
-Many aspects of the behaviour of MKWS can be modified by setting
-parameters into the `mkws_config` object. **This must be done *before*
-including the MKWS JavaScript** so that when that code is executed it
-can refer to the configuration values. So the HTML header looks like
-this:
-
-        <script type="text/javascript">
-          var mkws_config = {
-            lang: "da",
-            sort_default: "title",
-            query_width: 60
-          };
-        </script>
-        <script type="text/javascript" src="http://mkws.indexdata.com/mkws-complete.js"></script>
-
-This configuration sets the UI language to Danish (rather than the
-default of 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 full set of supported configuration items is described in the
-reference guide below.
-
-
-Control over HTML and CSS
--------------------------
-
-More sophisticated applications will not simply place the `<div>`s
-together, but position them carefully within an existing page
-framework -- such as a Drupal template, an OPAC or a SharePoint page.
-
-While it's convenient for simple applications to use a monolithic
-`mkwsResults` area which contains record, facets, sorting options,
-etc., customised layouts may wish to treat each of these components
-separately. In this case, `mkwsResults` can be omitted, and the
-following lower-level components provided instead:
-
-* `mkwsTermlists` -- provides the facets
-
-* `mkwsRanking` -- provides the options for how records are sorted and
-   how many are included on each page of results.
-
-* `mkwsPager` -- provides the links for navigating back and forth
-   through the pages of records.
-
-* `mkwsNavi` -- when a search result has been narrowed by one or more
-   facets, this area shows the names of those facets, and allows the
-   selected values to be clicked in order to remove them.
-
-* `mkwsRecords` -- lists the actual result records.
-
-Customisation of MKWS searching widgets can also be achieved by
-overriding the styles set in the toolkit's CSS stylesheet. The default
-styles can be inspected in `mkws.css` and overridden in any
-styles that appears later in the HTML than that file. At the simplest
-level, this might just mean changing fonts, sizes and colours, but
-more fundamental changes are also possible.
-
-To properly apply styles, it's necessary to understand how the HTML is
-structured, e.g. which elements are nested within which
-containers. The structures used by the widget-set are described in the
-reference guide below.
-
-
-Refinements
------------
-
-
-### Message of the day
-
-Some applications might like to open with content in the area that
-will subsequently be filled with result-records -- a message of the
-day, a welcome message or a help page. This can be done by placing an
-`mkwsMOTD` division anywhere on the page. It will be moved into the
-`mkwsResults` area and initially displayed, but will be hidden when a
-search is made.
-
-
-### Customised display using Handlebars templates
-
-Certain aspects of the widget-set's display can be customised by
-providing Handlebars templates with well-known classes that begin with
-the string `mkwsTemplate_`. At present, the supported templates are:
-
-* `mkwsTemplate_Summary` -- used for each summary record in a list of
-  results.
-
-* `mkwsTemplate_Record` -- used when displaying a full record.
-
-For both of these the metadata record is passed in, and its fields can
-be referenced in the template. As well as the metadata fields
-(`md-*`), two special fields are provided to the `mkwsTemplate_Summary`
-template, for creating popup links for full records. These are `_id`,
-which must be provided as the `id` attribute of a link tag, and
-`_onclick`, which must be provided as the `onclick` attribute.
-
-For example, an application can install a simple author+title summary
-record in place of the usual one providing the following template:
-
-        <script class="mkwsTemplate_Summary" type="text/x-handlebars-template">
-          {{#if md-author}}
-            <span>{{md-author}}</span>
-          {{/if}}
-          <a href="#" id="{{_id}}" onclick="{{_onclick}}">
-            <b>{{md-title}}</b>
-          </a>
-        </script>
-
-For details of Handlebars template syntax, see
-[the online documentation](http://handlebarsjs.com/).
-
-
-### Responsive design
-
-Metasearching applications may need to appear differently on
-small-screened mobile devices, or change their appearance when
-screen-width changes (as when a small device is rotated). To achieve
-this, MKWS supports responsive design which will move the termlists to
-the bottom on narrow screens and to the sidebar on wide screens.
-
-To turn on this behaviour, set the `responsive_design_width` to the desired
-threshhold width in pixels. For example:
-
-        <script type="text/javascript">
-            var mkws_config = {
-                responsive_design_width: 990
-            };
-        </script>
-
-If individual result-related components are in use in place of the
-all-in-one mkwsResults, then the redesigned application needs to
-specify the locations where the termlists should appear in both
-cases. In this case, wrap the wide-screen `mkwsTermlists` element in a
-`mkwsTermlists-Container-wide` element; and provide an
-`mkwsTermlists-Container-narrow` element in the place where the narrow-screen
-termlists should appear.
-
-
-### Popup results with jQuery UI
-
-The [jQuery UI library](http://en.wikipedia.org/wiki/JQuery_UI)
-can be used to construct MKWS applications in which the only component
-generally visible on the page is a search box, and the results appear
-in a popup. The key part of such an application is this invocation of
-the MKWS jQuery plugin:
-
-        <script type="text/javascript">
-          jQuery.pazpar2({ "layout":"popup", width:800, height:500 });
-        </script>
-
-The necessary scaffolding can be seen in an example application,
-http://example.indexdata.com/index-popup.html
-
-
-### Authentication and target configuration
-
-By default, MKWS configures itself to use a demonstration account on a
-service hosted by mkws.indexdata.com. This account (username `demo`,
-password `demo`) provides access to about a dozen free data
-sources. Authentication onto this service is via an authentication URL
-on the same MKWS server, so no explicit configuration is needed.
-
-In order to search in a customised set of targets, including
-subscription resources, it's necessary to create an account with
-Index Data's hosted service proxy, and protect that account with
-authentication tokens (to prevent unauthorised use of subscription
-resources). But in order to gain access to those resources, the
-authentication tokens have to be available to the widgets in some way,
-and simple embedding them in the JavaScript configuration is not
-acceptable because they are easy to read from there.
-
-The solution to this problem is in three steps.
-
-<b>First</b>
-the application's web-server creates a rewriting rule that takes an
-innocuous URL like
-http://example.indexdata.com/service-proxy-auth/
-and rewrites it as an access to Index Data's authentication service
-with authentication credentials embedded. This can be done using
-Apache2 directives such as
-
-    RewriteEngine on
-    RewriteRule /service-proxy-auth/
-        http://mkws.indexdata.com/service-proxy/?command=auth&action=login&username=U&password=PW [P]
-
-Because the credentials appear only in the application's web-server
-configuration, they are not visible to malicious users.
-
-<b>Second</b>, the broader application that includes MKWS widgets must
-protect access to the authentication URL on its own web-server. This
-can be done using IP authentication, a local username/password scheme,
-Kerberos or any other means.
-
-<b>Third</b>, the MKWS application must be configured to use the
-application-hosted authentication URL instead of the default one. This
-is done by means of the `service_proxy_auth` configuration element,
-which should be set to the authentication URL.
-
-Once these three steps are taken, the MKWS application will
-authenticate by means of a special URL on the application's web
-server, which the application prevents unauthorised access to, and the
-underlying credentials are hidden.
-
-
-Reference Guide
----------------
-
-### 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                   Type    Default   Description
---------                  -----   --------- ------------
-debug_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.
-
-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.
-
-query_width               int     50        The width of the query box, in characters.
-
-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.
-
-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.
-
-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`.
-
-show_lang                 bool    true      Indicates whether or not to display the language menu.
-
-show_perpage              bool    true      Indicates whether or not to display the perpage menu.
-
-show_sort                 bool    true      Indicates whether or not to display the sort menu.
-
-show_switch               bool    true      Indicates whether or not to display the switch menu, for switching between showing
-                                            retrieved records and target information.
-
-sort_default              string  relevance The label of the default sort criterion to use. Must be one of those in the `sort`
-                                            array.
-
-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`.
-
-use_service_proxy         bool    true      If true, then a Service Proxy is used to deliver searching services rather than raw
-                                            Pazpar2.
----
-
-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 `mkwsLang` 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
-
-1. ["sources", "subjects", "authors"]
-
-2. /pazpar2/search.pz2
-
-3. [10, 20, 30, 50]
-
-4. http://mkws.indexdata.com/service-proxy-auth
-
-5. http://mkws.indexdata.com/service-proxy/
-
-6. [["relevance"], ["title:1", "title"], ["date:0", "newest"], ["date:1", "oldest"]]
-
-
-### Language specification
-
-Support for another UI language can be added by providing an entry in
-the `mkws_config` object whose name is `language_` followed by the
-name of the language: for example, `language_French` to support
-French. Then value of this entry must be a key-value lookup table,
-mapping the English-language strings of the UI into their equivalents
-in the specified language. For example:
-
-            var mkws_config = {
-              language_French: {
-                "Authors": "Auteurs",
-                "Subjects": "Sujets",
-                // ... and others ...
-              }
-            }
-
-The following strings occurring in the UI can be translated:
-`Displaying`,
-`Next`,
-`Prev`,
-`Records`,
-`Search`,
-`Sort by`,
-`Targets`,
-`Termlists`,
-`and show`,
-`found`,
-`of`,
-`per page`
-and
-`to`.
-
-In addition, facet names can be translated:
-`Authors`,
-`Sources`
-and
-`Subjects`.
-
-Finally, the names of fields in the full-record display can be
-translated. These include, but may not be limited to:
-`Author`,
-`Date`,
-`Location`,
-`Subject`
-and
-`Title`.
-
-
-
-### jQuery plugin invocation
-
-The MasterKey Widget Set can be invoked as a jQuery plugin rather than
-by providing an HTML skeleton explicitly. When this approach is used,
-the invocation is a single line of JavaScript:
-
-        <script>jQuery.pazpar2();</script>
-
-This code should be inserted in the page at the position where the
-metasearch should occur.
-
-When invoking this plugin, a key-value lookup table of named options
-may be passed in to modify the default behaviour, as in the exaple
-above. The available options are as follows:
-
----
-Element    Type    Default           Description
---------   -----   ---------         ------------
-layout     string  popup             Specifies how the user interface should
-                                     appear. Options are `table` (the default,
-                                     with facets at the bottom), `div` (with
-                                     facets at the side) and `popup` (to
-                                     obtain a popup window).
-
-width      int     880               Width of the popup window (if used), in
-                                     pixels.
-
-height     int     760               Height of the popup window (if used), in
-                                     pixels.
-
-id_button  string  input#mkwsButton  (Never change this.)
-
-id_popup   string  #mkwsPopup        (Never change this.)
----
-
-Note that when using the `popup` layout, facilities from the jQuery UI
-toolkit are used, so it's necessary to include both CSS and JavaScript
-from that toolkit. The relevant lines are:
-
-    <script src="http://code.jquery.com/ui/1.10.3/jquery-ui.min.js"></script>
-    <link rel="stylesheet" type="text/css"
-          href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
-
-
-### The structure of the HTML generated by the MKWS widgets
-
-In order to override the default CSS styles provided by the MasterKey Widget
-Set, it's necessary to understand that structure of the HTML elements that are
-generated within the components. This knowledge make it possible, for example,
-to style each `<div>` with class `term` but only when it occurs inside an
-element with ID `#mkwsTermlists`, so as to avoid inadvertently styling other
-elements using the same class in the non-MKWS parts of the page.
-
-The HTML structure is as follows. As in CSS, #ID indicates a unique identifier
-and .CLASS indicates an instance of a class.
-
-    #mkwsSwitch
-      a*
-
-    #mkwsLang
-      ( a | span )*
-
-    #mkwsSearch
-      form
-        input#mkwsQuery type=text
-        input#mkwsButton type=submit
-
-    #mkwsBlanket
-      (no contents -- used only for masking)
-
-    #mkwsResults
-      table
-        tbody
-          tr
-            td
-              #mkwsTermlists
-                div.title
-                div.facet*
-                  div.termtitle
-                  ( a span br )*
-            td
-              div#mkwsRanking
-                form#mkwsSelect
-                  select#mkwsSort
-                  select#mkwsPerpage
-              #mkwsPager
-              #mkwsNavi
-              #mkwsRecords
-                div.record*
-                  span (for sequence number)
-                  a (for title)
-                  span (for other information such as author)
-                  div.details (sometimes)
-                    table
-                      tbody
-                        tr*
-                          th
-                          td
-    #mkwsTargets
-      #mkwsBytarget
-        table
-          thead
-            tr*
-              td*
-          tbody
-            tr*
-              td*
-
-    #mkwsStat
-      span.head
-      span.clients
-      span.records
-
-- - -
-
-Copyright (C) 2013 by IndexData ApS, <http://www.indexdata.com>
index a1f96b1..d1e1c2b 100644 (file)
@@ -1,17 +1,3 @@
-Development
-===========================================
-
-please run first in this directory: 
-$ make jasmine-links
-
-
-jasmine.html      - jasmine test with standard HTML page. 
-
-jasmine-popup.html - jasmine test with MKWS popup. No HTML, only JavaScript.
-                    Returns better readable test results as jasmine.html, 
-                    but it is less flexible.
-
-
 Public demo pages
 -----------------
 auto.html
@@ -27,8 +13,9 @@ popup.html
 
 Jasmine test pages
 ------------------
-jasmine-popup.html     - jasmine test with jquery popup, best for JS/HTML testing
 jasmine-local-popup.html  jasmine test with local SP and jquery popup, best for development
 jasmine-pp2.html       - running with local pazpar2 instead SP
-jasmine.html           - standard jasmine test
-
+jasmine.html      - jasmine test with standard HTML page. 
+jasmine-popup.html - jasmine test with MKWS popup. No HTML, only JavaScript.
+                    Returns better readable test results as jasmine.html, 
+                    but it is less flexible.
index 2f2788c..e54fe2c 100644 (file)
@@ -1,18 +1,9 @@
-<html>
-  <head>
-    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-    <title>MKWS demo client</title>
-    <link rel="stylesheet" type="text/css" href="//mkws.indexdata.com/mkws.css" />
-    <script type="text/javascript" src="//mkws.indexdata.com/mkws-complete.js"></script>
-  </head>
-  <body>
-    <div class="mkwsSwitch"></div>
-    <div class="mkwsLang"></div>
-    <div class="mkwsProgress"></div>
-    <div class="mkwsSearch"></div>
-    <div class="mkwsResults"></div>
-    <div class="mkwsTargets"></div>
-    <div class="mkwsStat"></div>
-    <div class="mkwsBuilder"></div>
-  </body>
-</html>
+<h1>MKWS examples</h1>
+<p>
+  List to follow ...
+</p>
+<p>
+  In the mean time see the links from
+  <a href="http://mkws.indexdata.com/"
+                 >mkws.indexdata.com</a>
+</p>
index d7d1a7a..a910bee 100644 (file)
     </script>
 
     <script type="text/javascript" src="//mkws.indexdata.com/mkws-complete.js"></script>
-    <link rel="stylesheet" type="text/css" href="//mkws.indexdata.com/mkws.css" />
-
+    <script>var _jquery = jQuery; $ = jQuery = mkws.$; </script>
     <script type="text/javascript" src="//code.jquery.com/ui/1.10.3/jquery-ui.min.js"></script>
+    <script>jQuery = $ = _jquery; </script>
+
+    <link rel="stylesheet" type="text/css" href="//mkws.indexdata.com/mkws.css" />
     <link rel="stylesheet" type="text/css" href="//code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
 
     <link rel="shortcut icon" type="image/png" href="jasmine/lib/jasmine-1.3.1/jasmine_favicon.png">
     <link rel="stylesheet" type="text/css" href="jasmine/lib/jasmine-1.3.1/jasmine.css">
+
     <script type="text/javascript" src="jasmine/lib/jasmine-1.3.1/jasmine.js"></script>
     <script type="text/javascript" src="jasmine/lib/jasmine-1.3.1/jasmine-html.js"></script>
 
@@ -27,7 +30,6 @@
     <script type="text/javascript" src="test/spec/mkws-pazpar2.js"></script>
 
     <script type="text/javascript" src="test/js/mkws-jasmine-run.js"></script>
-    <script type="text/javascript"> mkws_jasmine_init(500); </script>
 
     <style type="text/css">
       body > div > form > input.ui-state-default { background: none; }
@@ -47,6 +49,7 @@
 
     <script type="text/javascript">
     var mkws_config = {
+      service_proxy_auth: "//mkws.indexdata.com/service-proxy-testauth",
       perpage_default: 10
     };
 
 
     <h2>MKWS Jasmine regression tests</h2>
 
+    <div class="mkwsSearch"></div>
+    <div class="mkwsPopup" popup_width="990" popup_height="760" popup_modal="0" popup_autoOpen="0" popup_button="input.mkwsButton">
       <div class="mkwsSwitch"></div>
       <div class="mkwsLang"></div>
       <div class="mkwsProgress"></div>
-      <div class="mkwsSearch"></div>
       <div class="mkwsResults"></div>
       <div class="mkwsTargets"></div>
       <div class="mkwsStat"></div>
       <div class="mkwsBuilder"></div>
+    </div>
 
       <!-- include jquery again -->
       <script type="text/javascript" src="//code.jquery.com/jquery-1.10.0.js"></script>
index e5792e0..cde7ac2 100644 (file)
     <script type="text/javascript" src="tools/htdocs/pz2.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="src/mkws-handlebars.js"></script>
     <script type="text/javascript" src="src/mkws-core.js"></script>
     <script type="text/javascript" src="src/mkws-team.js"></script>
     <script type="text/javascript" src="src/mkws-filter.js"></script>
+    <script type="text/javascript" src="src/mkws-popup.js"></script>
     <script type="text/javascript" src="src/mkws-widget.js"></script>
     <script type="text/javascript" src="src/mkws-widget-main.js"></script>
     <script type="text/javascript" src="src/mkws-widget-termlists.js"></script>
     <script type="text/javascript" src="src/mkws-widget-authname.js"></script>
+    <script type="text/javascript" src="src/mkws-widget-categories.js"></script>
     <script type="text/javascript" src="src/mkws-widget-log.js"></script>
     <script type="text/javascript" src="src/mkws-widget-record.js"></script>
     <script type="text/javascript" src="src/mkws-templates.js"></script>
-
-    <script type="text/javascript" src="src/mkws-jquery.js"></script>
+    <script type="text/javascript" src="src/mkws-widget-reference.js"></script>
+    <script type="text/javascript" src="src/mkws-widget-builder.js"></script>
 
     <link rel="shortcut icon" type="image/png" href="jasmine/lib/jasmine-1.3.1/jasmine_favicon.png">
     <link rel="stylesheet" type="text/css" href="jasmine/lib/jasmine-1.3.1/jasmine.css">
@@ -35,7 +38,6 @@
     <script type="text/javascript" src="test/spec/mkws-pazpar2.js"></script>
 
     <script type="text/javascript" src="test/js/mkws-jasmine-run.js"></script>
-    <script type="text/javascript"> mkws_jasmine_init(500); </script>
 
     <style type="text/css">
       body > div > form > input.ui-state-default { background: none; }
       show_record_url: true
     };
 
-    jQuery.pazpar2({
-        "layout": "popup",               /* "table" [default], "div", "popup" */
-        "width": 990,                    /* popup width, should be at least 800 */
-        "height": 760                    /* popup height, should be at least 600 */
-    });
     </script>
 
 <h2>MKWS Jasmine regression tests</h2>
-<p/>
+
+    <div class="mkwsSearch"></div>
+    <div class="mkwsPopup" popup_width="990" popup_height="760" popup_modal="0" popup_autoOpen="0" popup_button="input.mkwsButton">
+      <div class="mkwsSwitch"></div>
+      <div class="mkwsLang"></div>
+      <div class="mkwsResults"></div>
+      <div class="mkwsTargets"></div>
+      <div class="mkwsStat"></div>
+    </div>
 
   </body>
 </html>
index c27e0f4..b2c7450 100644 (file)
     <script type="text/javascript" src="tools/htdocs/pz2.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="src/mkws-handlebars.js"></script>
     <script type="text/javascript" src="src/mkws-core.js"></script>
     <script type="text/javascript" src="src/mkws-team.js"></script>
     <script type="text/javascript" src="src/mkws-filter.js"></script>
+    <script type="text/javascript" src="src/mkws-popup.js"></script>
     <script type="text/javascript" src="src/mkws-widget.js"></script>
     <script type="text/javascript" src="src/mkws-widget-main.js"></script>
     <script type="text/javascript" src="src/mkws-widget-termlists.js"></script>
     <script type="text/javascript" src="src/mkws-widget-authname.js"></script>
+    <script type="text/javascript" src="src/mkws-widget-categories.js"></script>
     <script type="text/javascript" src="src/mkws-widget-log.js"></script>
     <script type="text/javascript" src="src/mkws-widget-record.js"></script>
-
-    <script type="text/javascript" src="src/mkws-jquery.js"></script>
+    <script type="text/javascript" src="src/mkws-widget-reference.js"></script>
+    <script type="text/javascript" src="src/mkws-widget-builder.js"></script>
 
     <link rel="shortcut icon" type="image/png" href="jasmine/lib/jasmine-1.3.1/jasmine_favicon.png">
     <link rel="stylesheet" type="text/css" href="jasmine/lib/jasmine-1.3.1/jasmine.css">
@@ -34,9 +37,7 @@
     <script type="text/javascript" src="test/spec/mkws-pazpar2.js"></script>
 
     <script type="text/javascript" src="test/js/mkws-jasmine-run.js"></script>
-    <script type="text/javascript"> mkws_jasmine_init(500); </script>
-
-    <!-- jquery null test 
+    <!-- jquery null test
     <script type="text/javascript">$ = undefined;</script>
        -->
 
       check_motd: false,
       show_record_url: true
     };
-
-    jQuery.pazpar2({
-        "layout": "popup",               /* "table" [default], "div", "popup" */
-        "width": 990,                    /* popup width, should be at least 800 */
-        "height": 760                    /* popup height, should be at least 600 */
-    });
     </script>
 
 <h2>MKWS Jasmine regression tests</h2>
-<p/>
+    <div class="mkwsSearch"></div>
+    <div class="mkwsPopup" popup_width="990" popup_height="760" popup_modal="0" popup_autoOpen="0" popup_button="input.mkwsButton">
+      <div class="mkwsSwitch"></div>
+      <div class="mkwsLang"></div>
+      <div class="mkwsResults"></div>
+      <div class="mkwsTargets"></div>
+      <div class="mkwsStat"></div>
+    </div>
+
 
   </body>
 </html>
index 0e106bb..3fea281 100644 (file)
@@ -45,9 +45,6 @@
 
     <!-- init and run jasmine -->
     <script type="text/javascript" src="test/js/mkws-jasmine-run.js"></script>
-    <script type="text/javascript">
-      mkws_jasmine_init(500);
-    </script>
   <!-- EOF jasmine -->
 
   </head>
index e47e374..afbe943 100644 (file)
@@ -39,9 +39,6 @@
 
     <!-- init and run jasmine -->
     <script type="text/javascript" src="test/js/mkws-jasmine-run.js"></script>
-    <script type="text/javascript">
-      mkws_jasmine_init(500);
-    </script>
   <!-- EOF jasmine -->
 
   </head>
index 2ea8c21..86b5852 100644 (file)
@@ -6,7 +6,7 @@
     <script type="text/javascript">
       var mkws_config = {
        pazpar2_url:        "//sp-mkws.indexdata.com/service-proxy/",
-       service_proxy_auth: "//sp-mkws.indexdata.com/service-proxy/?command=auth&action=check,login&username=orex&password=orexmkc"
+       service_proxy_auth: "//sp-mkws.indexdata.com/service-proxy/?command=auth&action=perconfig&username=Xorex&password=orexmkc"
       };
     </script>
     <script type="text/javascript" src="//code.jquery.com/jquery-1.10.0.min.js"></script>
diff --git a/examples/htdocs/popup-dev.html b/examples/htdocs/popup-dev.html
new file mode 100644 (file)
index 0000000..174fc37
--- /dev/null
@@ -0,0 +1,61 @@
+<html>
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    <title>MKWS demo: Reference widget with popup window</title>
+    <link rel="stylesheet" type="text/css" href="tools/htdocs/mkws.css" />
+    <link rel="stylesheet" type="text/css" href="//code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
+    <link rel="stylesheet" type="text/css" href="mkws-widget-reference.css" />
+    <link rel="stylesheet" type="text/css" href="mkws-widget-credo.css" />
+
+    <script type="text/javascript">
+      var mkws_config = {
+         service_proxy_auth: "//mkws.indexdata.com/service-proxy-credoauth"
+      };
+    </script>
+
+    <script type="text/javascript" src="tools/htdocs/jquery-1.10.0.min.js"></script>
+    <script type="text/javascript" src="//code.jquery.com/ui/1.10.3/jquery-ui.min.js"></script>
+
+    <script type="text/javascript" src="tools/htdocs/pz2.js"></script>
+    <script type="text/javascript" src="tools/htdocs/handlebars-v1.1.2.js"></script>
+    <script type="text/javascript" src="tools/htdocs/jquery.json-2.4.js"></script>
+
+    <script type="text/javascript" src="src/mkws-handlebars.js"></script>
+    <script type="text/javascript" src="src/mkws-core.js"></script>
+    <script type="text/javascript" src="src/mkws-team.js"></script>
+    <script type="text/javascript" src="src/mkws-filter.js"></script>
+    <script type="text/javascript" src="src/mkws-popup.js"></script>
+    <script type="text/javascript" src="src/mkws-widget.js"></script>
+    <script type="text/javascript" src="src/mkws-widget-main.js"></script>
+    <script type="text/javascript" src="src/mkws-widget-termlists.js"></script>
+    <script type="text/javascript" src="src/mkws-widget-authname.js"></script>
+    <script type="text/javascript" src="src/mkws-widget-categories.js"></script>
+    <script type="text/javascript" src="src/mkws-widget-log.js"></script>
+    <script type="text/javascript" src="src/mkws-widget-record.js"></script>
+    <script type="text/javascript" src="src/mkws-widget-reference.js"></script>
+    <script type="text/javascript" src="src/mkws-widget-builder.js"></script>
+
+    <script type="text/javascript" src="mkws-widget-credo.js"></script>
+  </head>
+  <body>
+    <h3>MKWS widgets in a popup window</h3>
+
+    <div class="mkwsSearch"></div>
+    <div class="mkwsPopup" popup_width="1024" popup_height="650" popup_modal="0" popup_autoOpen="0" popup_button="input.mkwsButton">
+      <div class="mkwsSwitch"></div>
+      <div class="mkwsLang"></div>
+      <div class="mkwsResults"></div>
+      <div class="mkwsTargets"></div>
+      <div class="mkwsStat"></div>
+    </div>
+
+    <div class="mkwsPopup" popup_width="1024" popup_height="800" popup_autoOpen="1">
+      <div class="mkwsCredo mkwsTeam_credo" autosearch="!param!q">mkwsCredo result will appear here</div>
+    </div>
+
+    <div class="mkwsPopup" popup_width="700" popup_height="600" popup_autoOpen="1">
+      <div class="mkwsReference mkwsTeam_credo" sentences="1" autosearch="!param!q">mkwsReference result will appear here</div>
+    </div>
+
+  </body>
+</html>
index 60529bb..9a1a35e 100644 (file)
@@ -1,81 +1,51 @@
 <html>
   <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-    <title>MKWS demo: popup search box</title>
-
-    <link rel="stylesheet" type="text/css" href="//code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
+    <title>MKWS demo: Reference widget with popup window</title>
     <link rel="stylesheet" type="text/css" href="//mkws.indexdata.com/mkws.css" />
+    <link rel="stylesheet" type="text/css" href="//code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
+    <link rel="stylesheet" type="text/css" href="//example.indexdata.com/mkws-widget-reference.css" />
+    <link rel="stylesheet" type="text/css" href="//example.indexdata.com/mkws-widget-credo.css" />
 
     <script type="text/javascript">
-      mkws_config = {
-       show_lang: false,
-       perpage_default: 10,
-       query_width: 50,
-        service_proxy_auth: "http://mkws.indexdata.com/service-proxy-auth"
-     };
+      var mkws_config = {
+         service_proxy_auth: "//mkws.indexdata.com/service-proxy-credoauth"
+      };
     </script>
 
+    <!--
+    <script type="text/javascript" src="tools/htdocs/mkws-complete.js"></script>
+    <script>jQuery = mkws.$</script>
+    <script type="text/javascript" src="//code.jquery.com/ui/1.10.3/jquery-ui.min.js"></script>
+    -->
     <script type="text/javascript" src="//code.jquery.com/jquery-1.10.0.min.js"></script>
     <script type="text/javascript" src="//jquery-json.googlecode.com/files/jquery.json-2.4.js"></script>
-    <!-- legacy libs for testing
-    <script type="text/javascript" src="//code.jquery.com/jquery-1.6.4.min.js"></script>
-    <script src="//code.jquery.com/ui/1.8.0/jquery-ui.min.js"></script>
-    -->
-
-    <script type="text/javascript" src="//mkws.indexdata.com/pazpar2/js/pz2.js"></script>
-    <script type="text/javascript" src="//mkws.indexdata.com/handlebars-v1.1.2.js"></script>
+    <script type="text/javascript" src="//code.jquery.com/ui/1.10.3/jquery-ui.min.js"></script>
+    <script type="text/javascript" src="//git.indexdata.com/?p=pazpar2.git;a=blob_plain;f=js/pz2.js;hb=HEAD"></script>
+    <script type="text/javascript" src="//builds.handlebarsjs.com.s3.amazonaws.com/handlebars-v1.1.2.js"></script>
     <script type="text/javascript" src="//mkws.indexdata.com/mkws.js"></script>
-    <script type="text/javascript" src="//mkws.indexdata.com/mkws-jquery.js"></script>
+   
+    <script type="text/javascript" src="//example.indexdata.com/mkws-widget-credo.js"></script>
   </head>
   <body>
-    <script type="text/javascript">
-     jQuery.pazpar2({ "layout":"popup", width: 800, height: 500 } );
-    </script>
-
-    <pre>
-      An embryonic MasterKey Widget Set
-=================================
-
-This directory contains an embryonic MasterKey Widget Set, based
-initially on "jsdemo" though now far removed from those beginnnings.
-
-
-How this works
---------------
-
-The goal is to make it that as much of the searching functionality as
-possible is hosted on
-        http://mkws.indexdata.com/
-so that very simple websites such as
-        http://example.indexdata.com/
-can have MasterKey searching with minimal effort.
-
-The following files must be hosted on mkws.indexdata.com:
-        mkws.js
-        mkws.css
-        /pazpar2/js/pz2.js (*)
-
-The following files make up the application:
-        index.html
-        favicon.ico [optional]
-        robots.txt [optional]
-
-(At present, the client application's configuruation also needs an
-Alias for /service-proxy/, to avoid cross-site scripting issues. We
-will fix this.)
+    <h3>MKWS widgets in a popup window</h3>
 
-(*) if you don't have already installed pazpar2 on the machine, you can
-do it by installing a debian package or check it out from GIT:
-$ git clone ssh://git.indexdata.com:222/home/git/pub/pazpar2
+    <div class="mkwsSearch"></div>
+    <div class="mkwsPopup" popup_width="1024" popup_height="650" popup_modal="0" popup_autoOpen="0" popup_button="input.mkwsButton">
+      <div class="mkwsSwitch"></div>
+      <div class="mkwsLang"></div>
+      <div class="mkwsResults"></div>
+      <div class="mkwsTargets"></div>
+      <div class="mkwsStat"></div>
+    </div>
 
-Configuring a client
---------------------
+    <div class="mkwsPopup" popup_width="1024" popup_height="800" popup_autoOpen="1">
+      <div class="mkwsCredo mkwsTeam_credo" autosearch="!param!q">mkwsCredo result will appear here</div>
+    </div>
 
-The application's HTML must contains the following elements as well as
-whatever makes up the application itself:
+    <div class="mkwsPopup" popup_width="700" popup_height="600" popup_autoOpen="1">
+      <div class="mkwsReference mkwsTeam_credo" sentences="1" autosearch="!param!q">mkwsReference result will appear here</div>
+    </div>
 
-[...]
-    </pre>
-    <script src="//code.jquery.com/ui/1.10.3/jquery-ui.min.js"></script>
   </body>
 </html>
diff --git a/examples/htdocs/simple.html b/examples/htdocs/simple.html
new file mode 100644 (file)
index 0000000..2f2788c
--- /dev/null
@@ -0,0 +1,18 @@
+<html>
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    <title>MKWS demo client</title>
+    <link rel="stylesheet" type="text/css" href="//mkws.indexdata.com/mkws.css" />
+    <script type="text/javascript" src="//mkws.indexdata.com/mkws-complete.js"></script>
+  </head>
+  <body>
+    <div class="mkwsSwitch"></div>
+    <div class="mkwsLang"></div>
+    <div class="mkwsProgress"></div>
+    <div class="mkwsSearch"></div>
+    <div class="mkwsResults"></div>
+    <div class="mkwsTargets"></div>
+    <div class="mkwsStat"></div>
+    <div class="mkwsBuilder"></div>
+  </body>
+</html>
diff --git a/examples/htdocs/surlyauto.html b/examples/htdocs/surlyauto.html
new file mode 100644 (file)
index 0000000..ef9c436
--- /dev/null
@@ -0,0 +1,18 @@
+<html>
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    <title>MKWS demo: Multiple autosearching widgets get their own teams</title>
+    <link rel="stylesheet" type="text/css" href="mkws-widget-reference.css" />
+    <script type="text/javascript">
+      var mkws_config = { service_proxy_auth: "//mkws.indexdata.com/service-proxy-testauth" };
+    </script>
+    <!-- <script type="text/javascript" src="//mkws.local/mkws&#45;complete.js"></script> -->
+    <script type="text/javascript" src="//mkws.indexdata.com/mkws-complete.js"></script>
+  </head>
+  <body>
+    <div class='mkwsReference' autosearch='one' sentences='1'>result will appear here</div>
+    <div class='mkwsReference' autosearch='two' sentences='1'>result will appear here</div>
+    <div class='mkwsReference' autosearch='three' sentences='1'>result will appear here</div>
+    <div class='mkwsReference' sentences='1'>result will appear here</div>
+  </body>
+</html>
index a15f554..f2653aa 100644 (file)
     <script type="text/javascript" src="src/mkws-widget-main.js"></script>
     <script type="text/javascript" src="src/mkws-widget-termlists.js"></script>
     <script type="text/javascript" src="src/mkws-widget-authname.js"></script>
+    <script type="text/javascript" src="src/mkws-widget-categories.js"></script>
     <script type="text/javascript" src="src/mkws-widget-log.js"></script>
     <script type="text/javascript" src="src/mkws-widget-record.js"></script>
+    <script type="text/javascript" src="src/mkws-widget-reference.js"></script>
+    <script type="text/javascript" src="src/mkws-widget-builder.js"></script>
 
     <style type="text/css">
       .mkwsTermlists div.facet {
index 02fb7bd..a95e4bf 100644 (file)
@@ -45,7 +45,7 @@ test page, wait 3 seconds for success and shutdown windows.
 Include files
 -------------
 
-The whitepaper says to include mkws-complete.js. This file is made by concatenating
+The manual says to include mkws-complete.js. This file is made by concatenating
 a number of files (see Makefile). For us developers, it is easier to include the
 raw files, as in
 
diff --git a/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..d44c596
--- /dev/null
@@ -0,0 +1,6 @@
+**default**:
+       make -C ../tools/htdocs
+
+clean:
+       make -C ../tools/htdocs clean
+
index ce71fda..4d6550c 100644 (file)
@@ -9,7 +9,9 @@
 // Set up global mkws object. Contains truly global state such as SP
 // authentication, and a hash of team objects, indexed by team-name.
 //
-var mkws = {
+// We set it as a property of window to make the global explicit as
+// some things complain about an implicit global.
+window.mkws = {
   $: $, // Our own local copy of the jQuery object
   authenticated: false,
   log_level: 1, // Will be overridden from mkws.config, but
@@ -275,7 +277,26 @@ mkws.pagerNext = function(tname) {
       }
     }
 
-    if (!teamName) teamName = "AUTO";
+    // Widgets without a team are on team "AUTO"
+    if (!teamName) {
+      teamName = "AUTO";
+      // Autosearch widgets don't join team AUTO if there is already an
+      // autosearch on the team or the team has otherwise gotten a query
+      if (node.hasAttribute("autosearch")) {
+        if (mkws.autoHasAuto ||
+            mkws.teams["AUTO"] && mkws.teams["AUTO"].config["query"]) {
+          log("AUTO team already has a query, using unique team");
+          teamName = "UNIQUE";
+        }
+        mkws.autoHasAuto = true;
+      }
+    }
+
+    // Widgets on team "UNIQUE" get a random team
+    if (teamName === "UNIQUE") {
+      teamName = Math.floor(Math.random() * 100000000).toString();
+    }
+
     callback.call(node, teamName, type);
   }
 
@@ -419,6 +440,7 @@ mkws.pagerNext = function(tname) {
 
 
   function init(rootsel) {
+    mkws.autoHasAuto = false;
     if (!rootsel) var rootsel = ':root';
     var saved_config;
     if (typeof mkws_config === 'undefined') {
index ce24206..866dc8a 100644 (file)
@@ -15,7 +15,7 @@ Handlebars.registerHelper('mkws-paragraphs', function(obj, nPara, nSent) {
   // {"hash":{},"data":{}} for parameters that are not provided. So we
   // have to be prepared for actual numbers, explicitly undefined
   // values and this dumb magic value.
-  if (nPara === undefined || nPara.hasOwnProperty('hash') || nPara == 0 || nPara > obj.length) {
+  if (obj && (nPara === undefined || nPara.hasOwnProperty('hash') || nPara == 0 || nPara > obj.length)) {
     nPara = obj.length;
   }
   if (nSent === undefined || nSent.hasOwnProperty('hash') || nSent == 0) {
diff --git a/src/mkws-jquery.js b/src/mkws-jquery.js
deleted file mode 100644 (file)
index 4145652..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*! jQuery plugin for MKWS, the MasterKey Widget Set.
- *  Copyright (C) 2013-2014 Index Data
- *  See the file LICENSE for details
- */
-
-"use strict";
-
-
-/*
- * implement jQuery plugin $.pazpar2({})
- */
-function _mkws_jquery_plugin($) {
-  function debug(string) {
-    mkws.log("jQuery.pazpar2: " + string);
-  }
-
-  function init_popup(obj) {
-    var config = obj ? obj : {};
-
-    var height = config.height || 760;
-    var width = config.width || 880;
-    var id_button = config.id_button || "input.mkwsButton";
-    var id_popup = config.id_popup || ".mkwsPopup";
-
-    debug("popup height: " + height + ", width: " + width);
-
-    // make sure that jquery-ui was loaded afte jQuery core lib, e.g.:
-    // <script src="http://code.jquery.com/ui/1.10.3/jquery-ui.min.js"></script>
-    if (!$.ui) {
-      debug("Error: jquery-ui.js is missing, did you include it after jQuery core in the HTML file?");
-      return;
-    }
-
-    $(id_popup).dialog({
-      closeOnEscape: true,
-      autoOpen: false,
-      height: height,
-      width: width,
-      modal: true,
-      resizable: true,
-      buttons: {
-        Cancel: function() {
-          $(this).dialog("close");
-        }
-      },
-      close: function() { }
-    });
-
-    $(id_button)
-      .button()
-      .click(function() {
-        $(id_popup).dialog("open");
-      });
-  };
-
-  $.extend({
-
-    // service-proxy or pazpar2
-    pazpar2: function(config) {
-      if (config == null || typeof config != 'object') {
-        config = {};
-      }
-      var id_popup = config.id_popup || ".mkwsPopup";
-      id_popup = id_popup.replace(/^[#\.]/, "");
-
-      // simple layout
-      var div = '\
-<div class="mkwsSwitch"></div>\
-<div class="mkwsLang"></div>\
-<div class="mkwsSearch"></div>\
-<div class="mkwsResults"></div>\
-<div class="mkwsTargets"></div>\
-<div class="mkwsStat"></div>';
-
-      // new table layout
-      var table = '\
-<style type="text/css">\
-  .mkwsTermlists div.facet {\
-  float:left;\
-  width: 30%;\
-  margin: 0.3em;\
-  }\
-  .mkwsStat {\
-  text-align: right;\
-  }\
-</style>\
-    \
-<table width="100%" border="0">\
-  <tr>\
-    <td>\
-      <div class="mkwsSwitch"></div>\
-      <div class="mkwsLang"></div>\
-      <div class="mkwsSearch"></div>\
-    </td>\
-  </tr>\
-  <tr>\
-    <td>\
-      <div style="height:500px; overflow: auto">\
-        <div class="mkwsPager"></div>\
-        <div class="mkwsNavi"></div>\
-        <div class="mkwsRecords"></div>\
-        <div class="mkwsTargets"></div>\
-        <div class="mkwsRanking"></div>\
-      </div>\
-    </td>\
-  </tr>\
-  <tr>\
-    <td>\
-      <div style="height:300px; overflow: hidden">\
-        <div class="mkwsTermlists"></div>\
-      </div>\
-    </td>\
-  </tr>\
-  <tr>\
-    <td>\
-      <div class="mkwsStat"></div>\
-    </td>\
-  </tr>\
-</table>';
-
-      var popup = '\
-<div class="mkwsSearch"></div>\
-<div class="' + id_popup + '">\
-  <div class="mkwsSwitch"></div>\
-  <div class="mkwsLang"></div>\
-  <div class="mkwsResults"></div>\
-  <div class="mkwsTargets"></div>\
-  <div class="mkwsStat"></div>\
-</div>'
-
-      if (config && config.layout == 'div') {
-        debug("jquery plugin layout: div");
-        document.write(div);
-      } else if (config && config.layout == 'popup') {
-        debug("jquery plugin layout: popup with id: " + id_popup);
-        document.write(popup);
-        $(document).ready(function() { init_popup(config); });
-      } else {
-        debug("jquery plugin layout: table");
-        document.write(table);
-      }
-    }
-  });
-};
-
-
-// XXX: enable before page load, so we could call it before mkws() runs
-_mkws_jquery_plugin(mkws.$);
-
diff --git a/src/mkws-popup.js b/src/mkws-popup.js
new file mode 100644 (file)
index 0000000..bc54f3c
--- /dev/null
@@ -0,0 +1,60 @@
+/* generic function to open results in a popup window
+ *
+ */
+
+//"use strict";
+// $(document).ready(function () {
+mkws.registerWidgetType('Popup', function() {
+    var $ = mkws.$;
+    var debug = mkws.log;
+    debug("init popup window");
+
+    var popup_window = $(this.node); // mkws.registerWidgetType('Popup',....)
+    // var popup_window = $(".mkwsPopup"); // $(document).ready()
+    if (!popup_window) {
+        debug("no popup found, skip...");
+        return;
+    } else {
+        debug("number of popup windows found: " + popup_window.length);
+    }
+
+    if (!$.ui) {
+        alert("Error: jquery-ui.js is missing, did you include it after jQuery core in the HTML file?");
+        return;
+    }
+
+    // more than one widget on a page are possible
+    popup_window.each(function(i) {
+        var that = $(this);
+
+        // all atributes are strings, convert them to integers here
+        var width = parseInt(that.attr("popup_width") || "800");
+        var height = parseInt(that.attr("popup_height") || "600");
+        var autoOpen = parseInt(that.attr("popup_autoOpen") || "0");
+        var modal = parseInt(that.attr("popup_modal") || "0");
+
+        debug("Popup parameters: width: " + width + ", height: " + height + ", autoOpen: " + autoOpen);
+        that.dialog({
+            closeOnEscape: true,
+            autoOpen: autoOpen,
+            height: height,
+            width: width,
+            modal: modal ? true : false,
+            resizable: true,
+            buttons: {
+                Cancel: function() {
+                    that.dialog("close");
+                }
+            },
+            close: function() {}
+        });
+
+        // open at search query submit: "input.mkwsButton"
+        var id_botton = that.attr("popup_button");
+        if (id_botton) {
+            $(id_botton).button().click(function() {
+                that.dialog("open");
+            });
+        }
+    });
+});
index 3f610cf..b2bf974 100644 (file)
@@ -28,9 +28,11 @@ function team($, teamName) {
   var m_paz; // will be initialised below
   var m_templateText = {}; // widgets can register templates to be compiled
   var m_template = {}; // compiled templates, from any source
-  var m_config = mkws.objectInheritingFrom(mkws.config);
   var m_widgets = {}; // Maps widget-type to array of widget objects
   var m_gotRecords = false;
+  
+  var config = mkws.objectInheritingFrom(mkws.config);
+  that.config = config;
 
   that.toString = function() { return '[Team ' + teamName + ']'; };
 
@@ -44,7 +46,6 @@ function team($, teamName) {
   that.currentRecordId = function() { return m_currentRecordId; };
   that.currentRecordData = function() { return m_currentRecordData; };
   that.filters = function() { return m_filterSet; };
-  that.config = function() { return m_config; };
 
   // Accessor methods for individual widgets: writers
   that.set_sortOrder = function(val) { m_sortOrder = val };
@@ -86,23 +87,23 @@ function team($, teamName) {
 
   log("making new widget team");
 
-  m_sortOrder = m_config.sort_default;
-  m_perpage = m_config.perpage_default;
+  m_sortOrder = config.sort_default;
+  m_perpage = config.perpage_default;
 
   // create a parameters array and pass it to the pz2's constructor
   // then register the form submit event with the pz2.search function
   // autoInit is set to true on default
   m_paz = new pz2({ "windowid": teamName,
-                    "pazpar2path": m_config.pazpar2_url,
-                    "usesessions" : m_config.use_service_proxy ? false : true,
+                    "pazpar2path": config.pazpar2_url,
+                    "usesessions" : config.use_service_proxy ? false : true,
                     "oninit": onInit,
                     "onbytarget": onBytarget,
                     "onstat": onStat,
-                    "onterm": (m_config.facets.length ? onTerm : undefined),
+                    "onterm": (config.facets.length ? onTerm : undefined),
                     "onshow": onShow,
                     "onrecord": onRecord,
                     "showtime": 500,            //each timer (show, stat, term, bytarget) can be specified this way
-                    "termlist": m_config.facets.join(',')
+                    "termlist": config.facets.join(',')
                   });
   log("created main pz2 object");
 
@@ -257,7 +258,7 @@ function team($, teamName) {
   function newSearch(query, sortOrder, maxrecs, perpage, limit, targets, torusquery) {
     log("newSearch: " + query);
 
-    if (m_config.use_service_proxy && !mkws.authenticated) {
+    if (config.use_service_proxy && !mkws.authenticated) {
       alert("searching before authentication");
       return;
     }
index f5fb1f7..e327941 100644 (file)
@@ -411,7 +411,7 @@ mkws.registerWidgetType('Config', function() {
   var c = this.config;
   for (var name in c) {
     if (c.hasOwnProperty(name)) {
-      this.team.config()[name] = c[name];
+      this.team.config[name] = c[name];
       this.log(this + " copied property " + name + "='" + c[name] + "' up to team");
     }
   }
@@ -446,6 +446,5 @@ mkws.registerWidgetType('Progress', function() {
 mkws.registerWidgetType('Query', function() {});
 mkws.registerWidgetType('MOTDContainer', function() {});
 mkws.registerWidgetType('Button', function() {});
-mkws.registerWidgetType('Popup', function() {});
 
 
index 39513d9..722db5e 100644 (file)
@@ -10,7 +10,7 @@ function widget($, team, type, node) {
     team: team,
     type: type,
     node: $(node),
-    config: mkws.objectInheritingFrom(team.config())
+    config: mkws.objectInheritingFrom(team.config)
   };
 
   function log(s) {
@@ -98,10 +98,10 @@ function widget($, team, type, node) {
     var that = this;
     var query = this.config.autosearch;
     if (query) {
-      var old = this.team.config().query;
+      var old = this.team.config.query;
       if (!old) {
         // Stash this for subsequent inspection
-        this.team.config().query = query;
+        this.team.config.query = query;
       } else if (old === query) {
         this.log("duplicate autosearch: '" + query + "': ignoring");
         return;
index 7ac5062..89c0c02 100644 (file)
@@ -56,6 +56,12 @@ phantomjs p: apache-stop apache-start _phantomjs
 _phantomjs:
        perl ./bin/bomb.pl --timeout="${PHANTOMJS_TIMEOUT}.5" ${PHANTOMJS} phantom/run-jasmine.js ${PHANTOMJS_URL} ${PHANTOMJS_TIMEOUT}
 
+phantomjs-all p-all:
+       ${MAKE} phantomjs PHANTOMJS_PATH=jasmine.html
+       ${MAKE} phantomjs PHANTOMJS_PATH=jasmine-cors-popup.html
+       ${MAKE} phantomjs PHANTOMJS_PATH=jasmine-local-popup.html
+       ${MAKE} phantomjs PHANTOMJS_PATH=jasmine-popup.html
+
 mike-test:
        $(MAKE) _phantomjs PHANTOMJS_URL=http://x.example.indexdata.com/jasmine-popup.html
 
@@ -102,15 +108,17 @@ apache-stop:
 
 help:
        @echo "make [ all | check | clean | distclean ]"
-       @echo "     [ phantomjs | screenshot ]"
-       @echo "     [ jsbeautifier | perltidy ]"
+       @echo "     [ phantomjs | phantomjs-all ]"
+       @echo "     [ jsbeautifier | perltidy | screenshot ]"
        @echo "     [ node-modules ]"
        @echo "     [ apache-stop apache-start ]"
        @echo ""
-       @echo "Examples"
+       @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=2 make phantomjs PHANTOMJS_TIMEOUT=12 PHANTOMJS_URL=${PHANTOMJS_URL}"
        @echo ""
+       @echo "make phantomjs-all"
+       @echo ""
 
index 1aec289..1037775 100644 (file)
@@ -35,4 +35,8 @@ function mkws_jasmine_init(delay) {
     }
 };
 
+mkws.$(document).ready(function() { 
+    mkws_jasmine_init(100);
+});
+
 /* EOF */
index e849dbf..ed76bf0 100644 (file)
@@ -6,7 +6,10 @@
 
 // get references from mkws.js, lazy evaluation
 var debug = function (text) {
-        mkws.log("Jasmine: " + text)
+        // use a debug function with time stamps
+        mkws.teams["AUTO"].log("Jasmine: " + text);
+
+        //mkws.log("Jasmine: " + text)
     }
 
     // Define empty jasmine_config for simple applications that don't define it.
@@ -53,28 +56,30 @@ function init_jasmine_config() {
     }
 
     mkws.jasmine_done = false;
-}
-
-var get_hit_counter = function () {
-        // not yet here
-        if (mkws.$(".mkwsPager").length == 0) return -1;
-
-        var found = mkws.$(".mkwsPager").text();
-        var re = /\([A-Za-z]+:\s+([0-9]+)\)/;
-        re.exec(found);
-        var hits = -1;
+};
 
-        if (RegExp.$1) {
-            hits = parseInt(RegExp.$1);
-            if (hits <= 0) {
-                debug("Oooops in get_hit_counter: " + RegExp.$1 + " '" + found + "'");
-            }
+function get_hit_counter() {
+    var $ = mkws.$;
+    // not yet here
+    if ($(".mkwsPager").length == 0) return -1;
+
+    var found = $(".mkwsPager").text();
+    var re = /\([A-Za-z]+:\s+([0-9]+)\)/;
+    re.exec(found);
+    var hits = -1;
+
+    if (RegExp.$1) {
+        hits = parseInt(RegExp.$1);
+        if (hits <= 0) {
+            debug("Oooops in get_hit_counter: " + RegExp.$1 + " '" + found + "'");
         }
-
-        //debug("Hits: " + hits);
-        return hits;
     }
 
+    //debug("Hits: " + hits);
+    return hits;
+};
+
+/******************************************************************************/
 describe("Init jasmine config", function () {
     it("jasmine was successfully initialized", function () {
         init_jasmine_config();
@@ -88,6 +93,8 @@ describe("Init jasmine config", function () {
 
 //disabled
 xdescribe("Check MOTD before search", function () {
+    var $ = mkws.$;
+
     // Check that the MOTD has been moved into its container, and
     // is visible before the search.
     // the mkwsMOTD div was originally inside a testMOTD div, which should
@@ -95,35 +102,37 @@ xdescribe("Check MOTD before search", function () {
     // Note that the testMOTD is a regular div, and uses #testMOTD,
     // since the automagic class-making does not apply to it.
     it("MOTD is hidden", function () {
-        expect(mkws.$(".mkwsMOTD").length).toBe(1);
-        expect(mkws.$("#testMOTD").length).toBe(1);
-        expect(mkws.$("#testMOTD").text()).toMatch("^ *$");
+        expect($(".mkwsMOTD").length).toBe(1);
+        expect($("#testMOTD").length).toBe(1);
+        expect($("#testMOTD").text()).toMatch("^ *$");
     });
 
     it("mkwsMOTDContainer has received the text", function () {
-        expect(mkws.$(".mkwsMOTDContainer").length).toBe(1);
-        expect(mkws.$(".mkwsMOTDContainer").text()).toMatch(/MOTD/);
+        expect($(".mkwsMOTDContainer").length).toBe(1);
+        expect($(".mkwsMOTDContainer").text()).toMatch(/MOTD/);
     });
 });
 
 describe("Check pazpar2 search", function () {
+    var $ = mkws.$;
+
     it("pazpar2 was successfully initialized", function () {
         expect(mkws.config.error).toBe(undefined);
     });
 
     it("validate HTML id's", function () {
-        expect(mkws.$("input.mkwsQuery").length).toBe(1);
-        expect(mkws.$("input.mkwsButton").length).toBe(1);
+        expect($("input.mkwsQuery").length).toBe(1);
+        expect($("input.mkwsButton").length).toBe(1);
 
-        expect(mkws.$(".mkwsNext").length).not.toBe(1);
-        expect(mkws.$(".mkwsPrev").length).not.toBe(1);
+        expect($(".mkwsNext").length).not.toBe(1);
+        expect($(".mkwsPrev").length).not.toBe(1);
     });
 
     it("run search query", function () {
         var search_query = jasmine_config.search_query; // short hit counter with some paging
-        mkws.$("input.mkwsQuery").val(search_query);
+        $("input.mkwsQuery").val(search_query);
         debug("set search query: " + search_query)
-        expect(mkws.$("input.mkwsQuery").val()).toMatch("^" + search_query + "$");
+        expect($("input.mkwsQuery").val()).toMatch("^" + search_query + "$");
 
         if (mkws.config.use_service_proxy) {
             // wait for service proxy auth
@@ -136,21 +145,23 @@ describe("Check pazpar2 search", function () {
 
         runs(function () {
             debug("Click on submit button");
-            mkws.$("input.mkwsButton").trigger("click");
+            $("input.mkwsButton").trigger("click");
         })
     });
 });
 
 describe("Check MOTD after search", function () {
+    var $ = mkws.$;
+
     it("MOTD is hidden", function () {
         if (!jasmine_config.check_motd) {
             return;
         }
 
-        expect(mkws.$(".mkwsMOTD").length).toBe(1);
-        expect(mkws.$(".mkwsMOTD").is(":hidden")).toBe(true);
-        debug("motd t=" + mkws.$(".mkwsMOTD").text());
-        debug("motd v=" + mkws.$(".mkwsMOTD").is(":visible"));
+        expect($(".mkwsMOTD").length).toBe(1);
+        expect($(".mkwsMOTD").is(":hidden")).toBe(true);
+        debug("motd t=" + $(".mkwsMOTD").text());
+        debug("motd v=" + $(".mkwsMOTD").is(":visible"));
     });
 });
 
@@ -161,19 +172,21 @@ describe("Check MOTD after search", function () {
  *
  */
 describe("Check pazpar2 navigation", function () {
+    var $ = mkws.$;
+
     // Asynchronous part
     it("check running search next/prev", function () {
-        expect(mkws.$(".mkwsPager").length).toBe(1);
+        expect($(".mkwsPager").length).toBe(1);
 
         function my_click(id, time) {
             setTimeout(function () {
                 debug("trigger click on id: " + id);
-                mkws.$(id).trigger("click");
+                $(id).trigger("click");
             }, time * jasmine_config.second);
         }
 
         waitsFor(function () {
-            return mkws.$("div.mkwsPager div:nth-child(2) a").length >= 2 ? true : false;
+            return $("div.mkwsPager div:nth-child(2) a").length >= 2 ? true : false;
         }, "Expect next link 2", 10 * jasmine_config.second);
 
         runs(function () {
@@ -182,7 +195,7 @@ describe("Check pazpar2 navigation", function () {
         });
 
         waitsFor(function () {
-            return mkws.$("div.mkwsPager div:nth-child(2) a").length >= 3 ? true : false;
+            return $("div.mkwsPager div:nth-child(2) a").length >= 3 ? true : false;
         }, "Expect next link 3", 5 * jasmine_config.second);
 
         runs(function () {
@@ -194,6 +207,8 @@ describe("Check pazpar2 navigation", function () {
 });
 
 describe("Check pazpar2 hit counter", function () {
+    var $ = mkws.$;
+
     it("check running search hit counter", function () {
         var max_time = jasmine_config.max_time; // in seconds
         var expected_hits = jasmine_config.expected_hits; // at least expected hit counter
@@ -206,41 +221,43 @@ describe("Check pazpar2 hit counter", function () {
 
         runs(function () {
             debug("mkws pager found records: '" + hits + "'");
-            expect(mkws.$(".mkwsPager").length).toBe(1);
+            expect($(".mkwsPager").length).toBe(1);
             expect(hits).toBeGreaterThan(expected_hits);
         });
     });
 });
 
 describe("Check Termlist", function () {
+    var $ = mkws.$;
+
     it("found Termlist", function () {
-        var termlist = mkws.$("div.mkwsTermlists");
+        var termlist = $("div.mkwsTermlists");
         debug("Termlist success: " + termlist.length);
         expect(termlist.length).toBe(1);
 
         waitsFor(function () {
-            return mkws.$("div.mkwsFacet[data-mkws-facet='xtargets']").length == 1 ? true : false;
+            return $("div.mkwsFacet[data-mkws-facet='xtargets']").length == 1 ? true : false;
         }, "check for facet sources", 4 * jasmine_config.second);
 
         // everything displayed?
         runs(function () {
-            var sources = mkws.$("div.mkwsFacet[data-mkws-facet='xtargets']");
+            var sources = $("div.mkwsFacet[data-mkws-facet='xtargets']");
             debug("Termlist sources success: " + sources.length);
             expect(sources.length).toBe(1);
 
-            var subjects = mkws.$("div.mkwsFacet[data-mkws-facet='subject']");
+            var subjects = $("div.mkwsFacet[data-mkws-facet='subject']");
             expect(subjects.length).toBe(1);
 
-            var authors = mkws.$("div.mkwsFacet[data-mkws-facet='author']");
+            var authors = $("div.mkwsFacet[data-mkws-facet='author']");
             expect(authors.length).toBe(1);
         });
 
         waitsFor(function () {
-            return mkws.$("div.mkwsFacet[data-mkws-facet='author'] div.mkwsTerm").length >= 2 ? true : false;
+            return $("div.mkwsFacet[data-mkws-facet='author'] div.mkwsTerm").length >= 2 ? true : false;
         }, "At least one author link displayed", 4 * jasmine_config.second);
 
         runs(function () {
-            expect(mkws.$("div.mkwsFacet[data-mkws-facet='author'] div.mkwsTerm").length).toBeGreaterThan(1);
+            expect($("div.mkwsFacet[data-mkws-facet='author'] div.mkwsTerm").length).toBeGreaterThan(1);
         });
     });
 });
@@ -248,6 +265,8 @@ describe("Check Termlist", function () {
 
 
 describe("Check Author Facets", function () {
+    var $ = mkws.$;
+
     it("limit search to first author", function () {
         if (mkws.config.disable_facet_authors_search) {
             debug("Facets: ignore limit search for authors");
@@ -260,9 +279,9 @@ describe("Check Author Facets", function () {
         // do not click on author names without a comma, e.g.: "Joe Barbara"
         // because searching on such authors won't find anything.
         runs(function () {
-            var terms = mkws.$("div.mkwsFacet[data-mkws-facet='author'] div.mkwsTerm a");
+            var terms = $("div.mkwsFacet[data-mkws-facet='author'] div.mkwsTerm a");
             for (var i = 0; i < terms.length; i++) {
-                var term = mkws.$(terms[i]).text();
+                var term = $(terms[i]).text();
                 if (term.match(/[0-9].+[0-9]/i) || !term.match(/,/)) {
                     debug("ignore author facet: " + term);
                     author_number++;
@@ -270,13 +289,13 @@ describe("Check Author Facets", function () {
                     break;
                 }
             }
-            if (mkws.$("div.mkwsFacet[data-mkws-facet='author'] div.mkwsTerm:nth-child(" + author_number + ") a").text().length == 0) {
+            if ($("div.mkwsFacet[data-mkws-facet='author'] div.mkwsTerm:nth-child(" + author_number + ") a").text().length == 0) {
                 debug("No good authors found. Not clicking on the bad ones");
                 return;
             }
 
-            debug("Clicking on author (" + author_number + ") " + mkws.$("div.mkwsFacet[data-mkws-facet='author'] div.mkwsTerm:nth-child(" + author_number + ") a").text());
-            mkws.$("div.mkwsFacet[data-mkws-facet='author'] div.mkwsTerm:nth-child(" + author_number + ") a").trigger("click");
+            debug("Clicking on author (" + author_number + ") " + $("div.mkwsFacet[data-mkws-facet='author'] div.mkwsTerm:nth-child(" + author_number + ") a").text());
+            $("div.mkwsFacet[data-mkws-facet='author'] div.mkwsTerm:nth-child(" + author_number + ") a").trigger("click");
         });
 
         waitsFor(function () {
@@ -293,15 +312,17 @@ describe("Check Author Facets", function () {
 });
 
 describe("Check active clients author", function () {
+    var $ = mkws.$;
+
     it("check for active clients after limited author search", function () {
         waitsFor(function () {
-            var clients = mkws.$("div.mkwsStat span.mkwsClientCount");
+            var clients = $("div.mkwsStat span.mkwsClientCount");
             // debug("clients: " + clients.text());
             return clients.length == 1 && clients.text().match("/[1-9]+[0-9]*$");
         }, "wait for Active clients: x/y", 5.5 * jasmine_config.second);
 
         runs(function () {
-            var clients = mkws.$("div.mkwsStat span.mkwsClientCount");
+            var clients = $("div.mkwsStat span.mkwsClientCount");
             debug("span.mkwsClientCount: " + clients.text());
             expect(clients.text()).toMatch("/[1-9]+[0-9]*$");
 
@@ -315,6 +336,8 @@ describe("Check active clients author", function () {
 });
 
 describe("Check Source Facets", function () {
+    var $ = mkws.$;
+
     it("limit search to first source", function () {
         var hits_all_targets = get_hit_counter();
         var source_number = 2; // 2=first source
@@ -325,15 +348,15 @@ describe("Check Source Facets", function () {
 
         // wait for a visible source link in facets
         waitsFor(function () {
-            var terms = mkws.$(link);
+            var terms = $(link);
             return terms && terms.length > 0;
         }, "wait for source facets after author search", 5 * jasmine_config.second);
 
 
         runs(function () {
-            var terms = mkws.$(link);
+            var terms = $(link);
             for (var i = 0; i < terms.length; i++) {
-                var term = mkws.$(terms[i]).text();
+                var term = $(terms[i]).text();
                 debug("check for good source: " + term);
 
                 if (term.match(/wikipedia/i)) {
@@ -345,22 +368,22 @@ describe("Check Source Facets", function () {
             }
             debug("Source counter: " + terms.length + ", select: " + (source_number - 1));
 
-            if (mkws.$("div.mkwsFacet[data-mkws-facet='xtargets'] div.mkwsTerm:nth-child(" + source_number + ") a").text().length == 0) {
+            if ($("div.mkwsFacet[data-mkws-facet='xtargets'] div.mkwsTerm:nth-child(" + source_number + ") a").text().length == 0) {
                 debug("No good source found. Not clicking on the bad ones");
                 return;
             }
 
             debug("click on source link nth-child(): " + source_number);
-            mkws.$("div.mkwsFacet[data-mkws-facet='xtargets'] div.mkwsTerm:nth-child(" + source_number + ") a").trigger("click");
+            $("div.mkwsFacet[data-mkws-facet='xtargets'] div.mkwsTerm:nth-child(" + source_number + ") a").trigger("click");
 
-            mkws.$(".mkwsPager").bind("DOMNodeInserted DOMNodeRemoved propertychange", function () {
+            $(".mkwsPager").bind("DOMNodeInserted DOMNodeRemoved propertychange", function () {
                 waitcount++;
-                debug("DOM wait for stat: " + waitcount);
+                debug("DOM change mkwsPager, for stat: " + waitcount);
             });
         });
 
         waitsFor(function () {
-            if (mkws.$("div.mkwsNavi").length && mkws.$("div.mkwsNavi").text().match(/(Source|datenquelle|kilder): /i)) {
+            if ($("div.mkwsNavi").length && $("div.mkwsNavi").text().match(/(Source|datenquelle|kilder): /i)) {
                 return true;
             } else {
                 return false;
@@ -381,13 +404,15 @@ describe("Check Source Facets", function () {
             expect(hits_all_targets).not.toBeLessThan(hits_single_target);
             jasmine_status.source_click = 1;
 
-            mkws.$(".mkwsPager").unbind("DOMNodeInserted DOMNodeRemoved propertychange");
+            $(".mkwsPager").unbind("DOMNodeInserted DOMNodeRemoved propertychange");
         });
     });
 });
 
 
 describe("Check record list", function () {
+    var $ = mkws.$;
+
     it("check for single active client", function () {
         if (!jasmine_status.source_click) {
             debug("skip clients check due missing source click");
@@ -395,13 +420,13 @@ describe("Check record list", function () {
         }
 
         waitsFor(function () {
-            var clients = mkws.$("div.mkwsStat span.mkwsClientCount");
+            var clients = $("div.mkwsStat span.mkwsClientCount");
             //debug("clients: " + clients.text());
             return clients.length == 1 && clients.text().match("/1$");
         }, "wait for Active clients: x/1", 5 * jasmine_config.second);
 
         runs(function () {
-            var clients = mkws.$("div.mkwsStat span.mkwsClientCount");
+            var clients = $("div.mkwsStat span.mkwsClientCount");
             debug("span.mkwsClientCount: " + clients.text());
             expect(clients.text()).toMatch("/1$");
         });
@@ -412,32 +437,34 @@ describe("Check record list", function () {
 
         waitsFor(function () {
             // remove + insert node: must be at least 2
-            return mkws.$(linkaddr).length > 0;
+            return $(linkaddr).length > 0;
         }, "wait until we see a new record", 2.5 * jasmine_config.second);
 
         runs(function () {
-            expect(mkws.$(linkaddr).length).toBeGreaterThan(0);
+            expect($(linkaddr).length).toBeGreaterThan(0);
         });
     });
 });
 
 describe("Show record", function () {
+    var $ = mkws.$;
+
     var record_number = 1; // the Nth record in hit list
     it("show record author", function () {
-        var click = mkws.$("div.mkwsRecords div.mkwsSummary:nth-child(" + record_number + ") a").trigger("click");
+        var click = $("div.mkwsRecords div.mkwsSummary:nth-child(" + record_number + ") a").trigger("click");
         debug("show record click is success: " + click.length);
         expect(click.length).toBe(1);
 
         // wait until the record pops up
         waitsFor(function () {
-            var show = mkws.$("div.mkwsRecords div.mkwsSummary:nth-child(" + record_number + ") > div.mkwsDetails");
-            //debug("poprecord: " + (show ? show.length : -1) + " " + mkws.$("div.mkwsRecords div.mkwsSummary").text());
+            var show = $("div.mkwsRecords div.mkwsSummary:nth-child(" + record_number + ") > div.mkwsDetails");
+            //debug("poprecord: " + (show ? show.length : -1) + " " + $("div.mkwsRecords div.mkwsSummary").text());
             return show != null && show.length ? true : false;
         }, "wait some miliseconds to show up a record", 2 * jasmine_config.second);
 
         runs(function () {
             debug("show record pop up");
-            expect(mkws.$("div.mkwsRecords div.mkwsSummary:nth-child(" + record_number + ") div")).not.toBe(null);
+            expect($("div.mkwsRecords div.mkwsSummary:nth-child(" + record_number + ") div")).not.toBe(null);
         });
     });
 
@@ -447,11 +474,11 @@ describe("Show record", function () {
             return;
         }
 
-        var urls = mkws.$("div.mkwsRecords div.mkwsSummary:nth-child(" + record_number + ") div table tbody tr td a");
+        var urls = $("div.mkwsRecords div.mkwsSummary:nth-child(" + record_number + ") div table tbody tr td a");
         debug("number of extracted URL from record: " + urls.length);
         // expect(urls.length).toBeGreaterThan(0); // LoC has records without links
         for (var i = 0; i < urls.length; i++) {
-            var url = mkws.$(urls[i]);
+            var url = $(urls[i]);
             debug("URL: " + url.attr('href') + " text: " + url.text());
 
             expect(url.attr('href')).not.toBe(null);
@@ -462,19 +489,21 @@ describe("Show record", function () {
 });
 
 describe("Check switch menu Records/Targets", function () {
+    var $ = mkws.$;
+
     it("check mkwsSwitch", function () {
-        expect(mkws.$("div.mkwsSwitch").length).toBe(1);
+        expect($("div.mkwsSwitch").length).toBe(1);
 
         // expect 2 clickable links
-        expect(mkws.$("div.mkwsSwitch > a").length).toBe(2);
+        expect($("div.mkwsSwitch > a").length).toBe(2);
     });
 
     it("switch to target view", function () {
-        mkws.$("div.mkwsSwitch > a").eq(1).trigger("click");
+        $("div.mkwsSwitch > a").eq(1).trigger("click");
 
         // now the target table must be visible
-        expect(mkws.$("div.mkwsTargets").is(":visible")).toBe(true);
-        expect(mkws.$("div.mkwsRecords").is(":visible")).toBe(false);
+        expect($("div.mkwsTargets").is(":visible")).toBe(true);
+        expect($("div.mkwsRecords").is(":visible")).toBe(false);
 
         // wait a half second, to show the target view
         var time = (new Date).getTime();
@@ -484,20 +513,22 @@ describe("Check switch menu Records/Targets", function () {
 
         // look for table header
         runs(function () {
-            expect(mkws.$("div.mkwsTargets").html()).toMatch(/Target ID/);
+            expect($("div.mkwsTargets").html()).toMatch(/Target ID/);
         });
     });
 
     it("switch back to record view", function () {
-        mkws.$("div.mkwsSwitch > a").eq(0).trigger("click");
+        $("div.mkwsSwitch > a").eq(0).trigger("click");
 
         // now the target table must be visible
-        expect(mkws.$("div.mkwsTargets").is(":visible")).toBe(false);
-        expect(mkws.$("div.mkwsRecords").is(":visible")).toBe(true);
+        expect($("div.mkwsTargets").is(":visible")).toBe(false);
+        expect($("div.mkwsRecords").is(":visible")).toBe(true);
     });
 });
 
 describe("Check status client counter", function () {
+    var $ = mkws.$;
+
     function get_time() {
         var date = new Date();
         return date.getTime();
@@ -511,7 +542,7 @@ describe("Check status client counter", function () {
         }
 
         waitsFor(function () {
-            var clients = mkws.$("div.mkwsStat span.mkwsClientCount");
+            var clients = $("div.mkwsStat span.mkwsClientCount");
             debug("clients: " + clients.text());
             if (clients.length == 1 && clients.text().match("0/1$")) {
                 return true;
@@ -521,7 +552,7 @@ describe("Check status client counter", function () {
         }, "wait for Active clients: 0/1", 4 * jasmine_config.second);
 
         runs(function () {
-            var clients = mkws.$("div.mkwsStat span.mkwsClientCount");
+            var clients = $("div.mkwsStat span.mkwsClientCount");
             debug("span.mkwsClientCount: " + clients.text());
             expect(clients.text()).toMatch("0/1$");
         });
@@ -547,31 +578,38 @@ describe("Check removable facets links", function () {
         });
 
         runs(function () {
-            $(".mkwsPager").bind("DOMNodeInserted DOMNodeRemoved propertychange", function () {
+            $("div.mkwsRecords").bind("DOMNodeInserted DOMNodeRemoved propertychange", function () {
                 waitcount++;
-                debug("DOM change for removeable: " + waitcount);
+                debug("DOM change mkwsRecords for removeable: " + waitcount);
             });
         });
 
         waitsFor(function () {
-            return $("a.mkwsRemovable").length == 1 ? 1 : 0;
-        });
+            return waitcount >= 2 && $("a.mkwsRemovable").length == 1 ? 1 : 0;
+        }, "Records DOM change mkwsRecords, removable", 2 * jasmine_config.second);
 
         runs(function () {
+            debug("unbind removable");
+            $("div.mkwsRecords").unbind("DOMNodeInserted DOMNodeRemoved propertychange");
+            waitcount = 0;
+
+            $("div.mkwsRecords").bind("DOMNodeInserted DOMNodeRemoved propertychange", function () {
+                waitcount++;
+                debug("DOM change mkwsRecords for removeable2: " + waitcount);
+            });
+
             var click = $("a.mkwsRemovable").eq(0).trigger("click");
             debug("Removed second facets link: " + click.length);
             expect(click.length).toBe(1);
         });
 
         waitsFor(function () {
-            // debug("wait for: " + waitcount);
-            return waitcount >= 2 ? true : false;
-        }, "Records DOM change, by per page", 2 * jasmine_config.second);
-
+            return waitcount >= 2 && $("a.mkwsRemovable").length == 0 ? true : false;
+        }, "DOM change mkwsRecords, removable2", 2 * jasmine_config.second);
 
         runs(function () {
-            debug("unbind removable");
-            $(".mkwsPager").unbind("DOMNodeInserted DOMNodeRemoved propertychange");
+            debug("unbind removable2");
+            $("div.mkwsRecords").unbind("DOMNodeInserted DOMNodeRemoved propertychange");
         });
     });
 });
@@ -600,23 +638,21 @@ describe("Check per page options", function () {
 
             $("div.mkwsRecords").bind("DOMNodeInserted DOMNodeRemoved propertychange", function () {
                 waitcount++;
-                debug("DOM wait for change, per page: " + waitcount);
+                debug("DOM change mkwsRecords, per page: " + waitcount);
             });
         });
 
         waitsFor(function () {
-            //debug("wait for: " + waitcount);
-            return waitcount >= 30 ? true : false;
-        }, "Records DOM change, by per page", 3 * jasmine_config.second);
+            // debug("per page waitcounter: " + waitcount)
+            return waitcount >= (per_page_number + 10) ? true : false;
+        }, "DOM change mkwsRecords, by per page", 3 * jasmine_config.second);
 
         runs(function () {
-            $("div.mkwsRecords").unbind("DOMNodeInserted DOMNodeRemoved propertychange");
             debug("unbind per page");
-        });
+            $("div.mkwsRecords").unbind("DOMNodeInserted DOMNodeRemoved propertychange");
 
-        runs(function () {
             var records = $("div.mkwsRecords > div.mkwsSummary");
-            debug("Got now " + records.length + " records");
+            debug("Per page got now " + records.length + " records");
             expect(records.length).toBe(per_page_number);
         });
     });
@@ -650,7 +686,7 @@ describe("Check SortBy options", function () {
         runs(function () {
             $("div.mkwsRecords").bind("DOMNodeInserted DOMNodeRemoved propertychange", function () {
                 waitcount++;
-                //debug("DOM wait for change, sort by: " + waitcount);
+                debug("DOM change mkwsRecords, sort by: " + waitcount);
             });
 
             var select = $("select.mkwsSort option[selected='selected']");
@@ -664,17 +700,15 @@ describe("Check SortBy options", function () {
 
         waitsFor(function () {
             //debug("wait for2: " + waitcount);
-            return waitcount >= 6 ? true : false;
-        }, "Records DOM change, by sort page", 3 * jasmine_config.second);
+            return waitcount >= (per_page_number + 10) ? true : false;
+        }, "DOM change mkwsRecords, by sort page", 3 * jasmine_config.second);
 
         runs(function () {
             $("div.mkwsRecords").unbind("DOMNodeInserted DOMNodeRemoved propertychange");
-            debug("unbind per page");
-        });
+            debug("unbind by sort");
 
-        runs(function () {
             var records = $("div.mkwsRecords > div.mkwsSummary a");
-            debug("Got now " + records.length + " records");
+            debug("Sort by got now " + records.length + " records");
             expect(records.length).toBe(per_page_number);
         });
 
@@ -699,5 +733,6 @@ describe("Check SortBy options", function () {
 describe("All tests are done", function () {
     it(">>> hooray <<<", function () {
         mkws.jasmine_done = true;
+        debug(">>> hooray <<<");
     });
 });
index 1bf7ab2..088b741 100644 (file)
@@ -16,7 +16,7 @@ Listen ${APACHE_PORT}
 Include ${APACHE_MODULES}
 
 <IfModule log_config_module>
-   #LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
+   LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
 </IfModule>
 
 # pazpar2 / service proxy config
index 9d74c0a..e0cfd60 100644 (file)
     RewriteLog /var/log/apache2/mkws-rewrite.log 
 
     # Credential-hiding rewrite rules for standard MKWS account, testing account and various application accounts
-    RewriteRule /service-proxy-auth(/)?(;jsessionid=.+)?       /service-proxy/$2?command=auth&action=check,login&username=mkws&password=mkws [P]
-    RewriteRule /service-proxy-testauth(/)?(;jsessionid=.+)?   /service-proxy/$2?command=auth&action=check,login&username=mkwstest&password=mkwstest [P]
-    RewriteRule /service-proxy-credoauth(/)?(;jsessionid=.+)?          /service-proxy/$2?command=auth&action=check,login&username=credo&password=emu [P]
-    RewriteRule /service-proxy-kohaauth(/)?(;jsessionid=.+)?   /service-proxy/$2?command=auth&action=check,login&username=kohademo&password=kohademo [P]
-    RewriteRule /service-proxy-orexauth(/)?(;jsessionid=.+)?   /service-proxy/$2?command=auth&action=check,login&username=orex&password=orexmkc [P]
+    RewriteRule /service-proxy-auth(/)?(;jsessionid=.+)?       /service-proxy/$2?command=auth&action=check,login&username=mkws&password=mkws&identity=mkws [P]
+    RewriteRule /service-proxy-testauth(/)?(;jsessionid=.+)?   /service-proxy/$2?command=auth&action=check,login&username=mkwstest&password=mkwstest&identity=mkws_test [P]
+    RewriteRule /service-proxy-credoauth(/)?(;jsessionid=.+)?          /service-proxy/$2?command=auth&action=check,login&username=credo&password=emu&identity=testing_credo_emulator [P]
+    RewriteRule /service-proxy-kohaauth(/)?(;jsessionid=.+)?   /service-proxy/$2?command=auth&action=check,login&username=kohademo&password=kohademo&identity=demo_koha_mkws [P]
+    RewriteRule /service-proxy-orexauth(/)?(;jsessionid=.+)?   /service-proxy/$2?command=auth&action=check,login&username=orex&password=orexmkc&identity=orex_digital2 [P]
 
     # The following rule allows the server to accept service-proxy
     # requests that begin with an escaped "%3F" rather than a literal
index ff5f6fa..9c724ae 100644 (file)
@@ -11,4 +11,4 @@ mkws-jquery.js
 mkws.js
 mkws.min.js
 pz2.js
-whitepaper.html
+mkws-manual.html
index 02d64f8..c62af37 100644 (file)
@@ -16,11 +16,20 @@ JQUERY_UI_URL =     http://code.jquery.com/ui/1.10.3/jquery-ui.js
 VERSION = $(shell tr -d '\012' < ${SRC}/VERSION)
 
 COMPONENTS = ${SRC}/mkws-handlebars.js \
-       ${SRC}/mkws-core.js ${SRC}/mkws-team.js ${SRC}/mkws-filter.js \
+       ${SRC}/mkws-core.js \
+       ${SRC}/mkws-team.js \
+       ${SRC}/mkws-filter.js \
        ${SRC}/mkws-templates.js \
-       ${SRC}/mkws-widget.js ${SRC}/mkws-widget-main.js ${SRC}/mkws-widget-termlists.js \
-       ${SRC}/mkws-widget-authname.js ${SRC}/mkws-widget-categories.js ${SRC}/mkws-widget-log.js \
-       ${SRC}/mkws-widget-record.js ${SRC}/mkws-widget-reference.js ${SRC}/mkws-widget-builder.js
+       ${SRC}/mkws-popup.js \
+       ${SRC}/mkws-widget.js \
+       ${SRC}/mkws-widget-main.js \
+       ${SRC}/mkws-widget-termlists.js \
+       ${SRC}/mkws-widget-authname.js \
+       ${SRC}/mkws-widget-categories.js \
+       ${SRC}/mkws-widget-log.js \
+       ${SRC}/mkws-widget-record.js \
+       ${SRC}/mkws-widget-reference.js \
+       ${SRC}/mkws-widget-builder.js
 
 GENERATED = ${HANDLEBARS_FILE} ${JQUERY_FILE} ${JQUERY_JSON_FILE} ${PP2_FILE} \
        mkws.js mkws.min.js mkws-complete.js mkws-complete.min.js mkws-templates.js
@@ -29,7 +38,7 @@ GENERATED = ${HANDLEBARS_FILE} ${JQUERY_FILE} ${JQUERY_JSON_FILE} ${PP2_FILE} \
 
 all: mkws.min.js mkws-complete.min.js
 
-mkws-js mkws-complete.js: Makefile mkws.js ${SRC}/mkws-jquery.js ${HANDLEBARS_FILE} ${JQUERY_FILE} ${JQUERY_JSON_FILE} ${PP2_FILE}
+mkws-js mkws-complete.js: Makefile mkws.js ${HANDLEBARS_FILE} ${JQUERY_FILE} ${JQUERY_JSON_FILE} ${PP2_FILE}
        ( set -e; \
          echo "/*! Copyright (c) 2013-2014 IndexData ApS. http://indexdata.com"; \
          echo "   Licence: GPL, http://www.indexdata.com/licences/gpl"; \
@@ -43,7 +52,6 @@ mkws-js mkws-complete.js: Makefile mkws.js ${SRC}/mkws-jquery.js ${HANDLEBARS_FI
          cat ${HANDLEBARS_FILE}; \
          cat ${PP2_FILE}; \
          cat  mkws.js; \
-         cat  ${SRC}/mkws-jquery.js; \
        ) > mkws-complete.js.tmp
        mv -f mkws-complete.js.tmp mkws-complete.js
 
@@ -91,6 +99,10 @@ mkws.js: mkws-templates.js $(COMPONENTS) Makefile
 mkws-templates.js:
        handlebars -n mkws.defaultTemplates ${SRC}/*.templates/*.handlebars -f ${SRC}/mkws-templates.js
 
+mkws-html-includes: 
+       echo $(COMPONENTS) | perl -npe "s,${SRC},,g; s/\s+/\0/g" | \
+         perl -n0e 'chomp(); print qq{    <script type="text/javascript" src="src$$_"></script>\n}'
+
 distclean: clean
        @echo "(No need for distclean, 'make clean' is fine)"
 
index c1341be..f98e095 100644 (file)
@@ -65,7 +65,7 @@
           The <a href="README.html">README</a> -- mostly technical details.
        </li>
        <li>
-          The <a href="whitepaper.html">whitepaper, including a
+          The <a href="mkws-manual.html">MKWS manual, including a
           reference section.</a>
          This is a much better introduction.
        </li>
       <ul>
        <li>
           A very simple application at
-          <a href="//example.indexdata.com/"
-             >//example.indexdata.com/</a>.
+          <a href="//example.indexdata.com/simple.html"
+             >//example.indexdata.com/simple.html</a>.
        </li>
        <li>
           <a href="//example.indexdata.com/minimal.html"
     </div>
 
     <p style="text-align: right; font-size: small">
-      Copyright © 2013 IndexData ApS.
+      Copyright (&copy;) 2013-2014 IndexData ApS.
       <a href="http://indexdata.com"><code>http://indexdata.com</code></a>
     </p>
   </body>
diff --git a/tools/service-proxy/service-proxy.properties b/tools/service-proxy/service-proxy.properties
new file mode 100644 (file)
index 0000000..8f4c8d8
--- /dev/null
@@ -0,0 +1,49 @@
+# Service Proxy configuration for MKWS (host sp-mkws.indexdata.com)
+# Initially based on MKC's configuration
+
+# Register plugin classes with custom names
+plugins.relay      = com.indexdata.serviceproxy.plugins.Pazpar2RelayPlugin
+plugins.authn      = com.indexdata.serviceproxy.plugins.AuthNTorusPlugin
+plugins.categories = com.indexdata.serviceproxy.plugins.TargetCategoriesPlugin
+plugins.ils        = com.indexdata.serviceproxy.plugins.ILSPlugin
+
+
+# Configuration properties for individual plug-ins 
+
+# relay plugin, proxies commands through to Pazpar2
+relay.PROXY_MODE = 3
+relay.PAZPAR2_URL = http://localhost:8004
+relay.PAZPAR2_SERVICE_ID = mkc
+relay.TORUS_BASEURL = http://mkc-admin.indexdata.com/torus2/
+relay.TORUS_REALM = *
+relay.TORUS_PARAMS = ?param1=value1
+relay.STREAMBUFF_SIZE = 4096
+relay.PARSE_RESPONSES = true
+relay.CF_ENGINE_ADDRESS = localhost:9003
+
+# authn plugin, for torus based authentication 
+authn.TORUS_URL        = http://mkc-admin.indexdata.com/torus2/identity.USERS/records/
+authn.MASTER_TORUS_URL = http://mkc-admin.indexdata.com/torus2/admin.admin/records/
+authn.ACTION_SEQUENCE = check,login,referrer,constraint
+authn.SPECIFIC_CONSTRAINT = hostName=${thisHost} 
+
+# categories plugin, for Torus-based target categories
+categories.TORUS_BASEURL            = http://mkc-admin.indexdata.com/torus2/
+categories.TORUS_BASEURL_SEARCHABLE = http://mkc-admin.indexdata.com/torus2/
+categories.EXCLUDE_EMPTY_CATEGORIES = true
+
+# ils plugin, for ILS operations such as holds and renewals
+ils.CFWS_URL = http://localhost:9003/connector
+
+
+# Map SP commands to command-separated sequences of plugins
+chains.auth = authn
+chains.categories = categories
+chains.ils = ils
+# Map all other commands to the Pazpar2 relayer
+chains.* = relay
+
+
+# Just so I can check that this particular SP config is in use
+chains.mike = info
+plugins.info = com.indexdata.serviceproxy.plugins.InfoPlugin
index 6328a36..b098e0c 100644 (file)
@@ -5,3 +5,8 @@
   It provides a service on
   <a href="/service-proxy/">/service-proxy/</a>.
 </p>
+<p>
+  Maybe you meant to go to
+  <a href="http://mkws.indexdata.com/"
+          >http://mkws.indexdata.com/</a>?
+</p>