[uses a local authentication regime](//example.indexdata.com/localauth.html)
and the corresponding
[Apache2 configuration stanza](//example.indexdata.com/apache-config.txt).
-* [A version that uses a jQuery popup](//example.indexdata.com/popup.html).
+* [A version that uses a jQuery popup](//example.indexdata.com/popup.html?q=sushi).
### Non-standard interfaces
MKWS makes requests to Service Proxy or Pazpar2 that perform the actual
searching. Depending on how these are configured and what is available from the
targets you are searching there may be more data available than what is
-presented by the default templates. In this case, you can redefine the
-`Record` template to include more fields in the full-record popup.
+presented by the default templates.
Handlebars offers a convenient log helper that will output the contents of a
variable for you to inspect. This lets you look at exactly what is being
search is made.
-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 widgets 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
----------------------------
}
}
-
function handleNodeWithTeam(node, callback) {
// First branch for DOM objects; second branch for jQuery objects
var classes = node.className || node.attr('class');
for (var i = 0; i < list.length; i++) {
var cname = list[i];
- if (cname.match(/^mkws-team-/)) {
- teamName = cname.replace(/^mkws-team-/, '');
- } else if (cname.match(/^mkws-/)) {
- // New-style names of the form mkws-foo-bar
- type = cname.replace(/^mkws-/, '');
+ if (cname.match(/^mkwsTeam_/)) {
+ teamName = cname.replace(/^mkwsTeam_/, '');
} else if (cname.match(/^mkws/)) {
// Old-style names of the form mkwsFooBar
var tmp = cname.replace(/^mkws/, '');
for (var tname in mkws.teams) {
var team = mkws.teams[tname];
team.visitWidgets(function(t, w) {
- var w1 = team.widget(t + "-container-" + from);
- var w2 = team.widget(t + "-container-" + to);
+ var w1 = team.widget(t + "-Container-" + from);
+ var w2 = team.widget(t + "-Container-" + to);
if (w1) {
w1.node.hide();
}
//"use strict";
// $(document).ready(function () {
-mkws.registerWidgetType('popup', function() {
+mkws.registerWidgetType('Popup', function() {
var $ = mkws.$;
var debug = mkws.log;
debug("init popup window");
var popup_window = $(this.node);
- // var popup_window = $(".mkws-popup"); // $(document).ready()
+ // var popup_window = $(".mkwsPopup"); // $(document).ready()
if (!popup_window) {
debug("no popup found, skip...");
return;
close: function() {}
});
- // open at search query submit: "input.mkws-button"
+ // open at search query submit: "input.mkwsButton"
var id_botton = that.attr("popup_button");
if (id_botton) {
$(id_botton).button().click(function() {
// Used by the Records widget and onRecord()
function recordElementId(s) {
- return 'mkws-rec_' + s.replace(/[^a-z0-9]/ig, '_');
+ return 'mkwsRec_' + s.replace(/[^a-z0-9]/ig, '_');
}
that.recordElementId = recordElementId;
// Used by onRecord(), showDetails() and renderDetails()
function recordDetailsId(s) {
- return 'mkws-det_' + s.replace(/[^a-z0-9]/ig, '_');
+ return 'mkwsDet_' + s.replace(/[^a-z0-9]/ig, '_');
}
teamName = teamName || m_teamName;
if (teamName === 'AUTO') {
- selector = (selector + '.mkws-team-' + teamName + ',' +
- selector + ':not([class^="mkwsTeam"],[class*=" mkwsTeam"],[class^="mkws-team-"],[class*=" mkws-team-"])');
+ selector = (selector + '.mkwsTeam_' + teamName + ',' +
+ selector + ':not([class^="mkwsTeam"],[class*=" mkwsTeam"])');
} else {
- selector = selector + '.mkws-team-' + teamName;
+ selector = selector + '.mkwsTeam_' + teamName;
}
var node = $(selector);
function renderDetails(data, marker) {
var template = loadTemplate("Record");
var details = template(data);
- return '<div class="mkws-details mkws-team-' + m_teamName + '" ' +
+ return '<div class="mkwsDetails mkwsTeam_' + m_teamName + '" ' +
'id="' + recordDetailsId(data.recid[0]) + '">' + details + '</div>';
}
that.renderDetails = renderDetails;
var template = m_template[name];
if (template === undefined && Handlebars.compile) {
var source;
- var node = $(".mkws-template_" + name + " .mkws-team-" + that.name());
+ var node = $(".mkwsTemplate_" + name + " .mkwsTeam_" + that.name());
if (node && node.length < 1) {
- node = $(".mkws-template_" + name);
+ node = $(".mkwsTemplate_" + name);
}
if (node) source = node.html();
if (!source) source = m_templateText[name];
-mkws.registerWidgetType('auth-name', function() {
+mkws.registerWidgetType('Authname', function() {
var that = this;
this.team.queue("authenticated").subscribe(function(authName) {
-mkws.registerWidgetType('builder', function() {
+mkws.registerWidgetType('Builder', function() {
var that = this;
var team = this.team;
});
this.node.append(button);
button.click(function() {
- var query = team.widget('query').value();
- var sort = team.widget('sort').value();
- var perpage = team.widget('per-page').value();
+ var query = team.widget('Query').value();
+ var sort = team.widget('Sort').value();
+ var perpage = team.widget('Perpage').value();
- var html = ('<div class="mkws-records" ' +
+ var html = ('<div class="mkwsRecords" ' +
'autosearch="' + query + '" ' +
'sort="' + sort + '" ' +
'perpage="' + perpage + '"></div>');
});
});
-mkws.registerWidgetType('console-builder', function() {
- mkws.promotionFunction('builder').call(this);
+mkws.registerWidgetType('ConsoleBuilder', function() {
+ mkws.promotionFunction('Builder').call(this);
this.callback = function(s) {
console.log("generated widget: " + s);
}
-mkws.registerWidgetType('categories', function() {
+mkws.registerWidgetType('Categories', function() {
var that = this;
if (!mkws.authenticated) {
var text = [];
text.push("Select category: ");
- text.push("<select name='mkws-category' " +
+ text.push("<select name='mkwsCategory' " +
"onchange='mkws.limitCategory(\"" + that.team.name() + "\", this.value)'>");
text.push("<option value=''>[All]</option>");
$(data).find('category').each(function() {
-mkws.registerWidgetType('log', function() {
+mkws.registerWidgetType('Log', function() {
var that = this;
this.team.queue("log").subscribe(function(teamName, timestamp, message) {
// source files.
-mkws.registerWidgetType('targets', function() {
+mkws.registerWidgetType('Targets', function() {
if (!this.config.show_switch) return;
var that = this;
});
-mkws.registerWidgetType('stat', function() {
+mkws.registerWidgetType('Stat', function() {
var that = this;
this.team.queue("stat").subscribe(function(data) {
var template = that.team.loadTemplate(that.config.template || "Stat");
});
-mkws.registerWidgetType('pager', function() {
+mkws.registerWidgetType('Pager', function() {
var that = this;
var M = mkws.M;
});
});
-mkws.registerWidgetType('details', function() {
+mkws.registerWidgetType('Details', function() {
var that = this;
var recid = that.node.attr("data-mkws-recid");
if (this.team.gotRecords()) {
that.autosearch();
});
-mkws.registerWidgetType('records', function() {
+mkws.registerWidgetType('Records', function() {
var that = this;
var team = this.team;
that.team.queue("record").publish(hit);
hit.detailLinkId = team.recordElementId(hit.recid[0]);
hit.detailClick = "mkws.showDetails('" + team.name() + "', '" + hit.recid[0] + "');return false;";
- hit.containerClass = "mkws-summary mkws-team-" + team.name();
+ hit.containerClass = "mkwsSummary mkwsTeam_" + team.name();
hit.containerClass += " " + hit.detailLinkId;
// ### At some point, we may be able to move the
// m_currentRecordId and m_currentRecordData members
});
-mkws.registerWidgetType('navi', function() {
+mkws.registerWidgetType('Navi', function() {
var that = this;
var teamName = this.team.name();
});
-// It seems this and the per-page widget doen't need to subscribe to
+// It seems this and the Perpage widget doen't need to subscribe to
// anything, since they produce events rather than consuming them.
//
-mkws.registerWidgetType('sort', function() {
+mkws.registerWidgetType('Sort', function() {
var that = this;
this.node.change(function() {
});
-mkws.registerWidgetType('per-page', function() {
+mkws.registerWidgetType('Perpage', function() {
var that = this;
this.node.change(function() {
});
-mkws.registerWidgetType('done', function() {
+mkws.registerWidgetType('Done', function() {
var that = this;
this.team.queue("complete").subscribe(function(n) {
var template = that.team.loadTemplate(that.config.template || "Done");
});
-mkws.registerWidgetType('switch', function() {
+mkws.registerWidgetType('Switch', function() {
if (!this.config.show_switch) return;
var tname = this.team.name();
var output = {};
});
-mkws.registerWidgetType('search', function() {
+mkws.registerWidgetType('Search', function() {
var output = {};
output.team = this.team.name();
output.queryWidth = this.config.query_width;
});
-mkws.registerWidgetType('search-form', function() {
+mkws.registerWidgetType('SearchForm', function() {
var team = this.team;
this.node.submit(function() {
- var val = team.widget('query').value();
+ var val = team.widget('Query').value();
team.newSearch(val);
return false;
});
});
-mkws.registerWidgetType('results', function() {
+mkws.registerWidgetType('Results', function() {
var template = this.team.loadTemplate(this.config.template || "Results");
this.node.html(template({team: this.team.name()}));
this.autosearch();
});
-mkws.registerWidgetType('ranking', function() {
+mkws.registerWidgetType('Ranking', function() {
var output = {};
output.perPage = [];
output.sort = [];
});
-mkws.registerWidgetType('lang', function() {
+mkws.registerWidgetType('Lang', function() {
// dynamic URL or static page? /path/foo?query=test
/* create locale language menu */
if (!this.config.show_lang) return;
});
-mkws.registerWidgetType('motd', function() {
- var container = this.team.widget('motd-container');
+mkws.registerWidgetType('MOTD', function() {
+ var container = this.team.widget('MOTDContainer');
if (container) {
// Move the MOTD from the provided element down into the container
this.node.appendTo(container.node);
// is copied up into its team, allowing it to affect other widgets in
// the team.
//
-mkws.registerWidgetType('config', function() {
+mkws.registerWidgetType('Config', function() {
var c = this.config;
for (var name in c) {
if (c.hasOwnProperty(name)) {
});
-mkws.registerWidgetType('progress', function() {
+mkws.registerWidgetType('Progress', function() {
var that = this;
this.node.hide();
this.team.queue("stat").subscribe(function(data) {
// no actual functionality. We register these to prevent ignorable
// warnings when they occur.
-mkws.registerWidgetType('query', function() {});
-mkws.registerWidgetType('motd-container', function() {});
-mkws.registerWidgetType('button', function() {});
+mkws.registerWidgetType('Query', function() {});
+mkws.registerWidgetType('MOTDContainer', function() {});
+mkws.registerWidgetType('Button', function() {});
})(mkws.$); // jQuery wrapper
// A widget for one record
-mkws.registerWidgetType('record', function() {
+mkws.registerWidgetType('Record', function() {
if (!this.config.maxrecs) this.config.maxrecs = 1;
var that = this;
var team = this.team;
that.autosearch();
});
-mkws.registerWidgetType('image', function() {
- mkws.promotionFunction('records').call(this);
+mkws.registerWidgetType('Image', function() {
+ mkws.promotionFunction('Records').call(this);
if (!this.config.template) this.config.template = 'Image';
});
-mkws.registerWidgetType('google-image', function() {
- mkws.promotionFunction('image').call(this);
+mkws.registerWidgetType('GoogleImage', function() {
+ mkws.promotionFunction('Image').call(this);
if (!this.config.target) this.config.target = 'Google_Images';
});
-mkws.registerWidgetType('lolcat', function() {
- mkws.promotionFunction('google-image').call(this);
+mkws.registerWidgetType('Lolcat', function() {
+ mkws.promotionFunction('GoogleImage').call(this);
if (!this.config.autosearch) this.config.autosearch = 'kitteh';
});
-mkws.registerWidgetType('cover-art', function() {
- mkws.promotionFunction('image').call(this);
+mkws.registerWidgetType('Coverart', function() {
+ mkws.promotionFunction('Image').call(this);
if (!this.config.target) this.config.target = 'AmazonBooks';
});
-mkws.registerWidgetType('reference', function() {
- mkws.promotionFunction('record').call(this);
+mkws.registerWidgetType('Reference', function() {
+ mkws.promotionFunction('Record').call(this);
if (!this.config.target) this.config.target = 'wikimedia_wikipedia_single_result';
if (!this.config.template) this.config.template = 'Reference';
this.config.template_vars.paragraphs = this.config.paragraphs || 0;
<i>{{md-title-responsibility}}</i>
{{/if}}
{{{mkws-paragraphs md-description paragraphs sentences}}}
-<p class="mkws-credit">Wikipedia</p>
+<p class="mkwsCredit">Wikipedia</p>
-mkws.registerWidgetType('termlists', function() {
+mkws.registerWidgetType('Termlists', function() {
// Initially hide the termlists; display when we get results
var that = this;
var team = this.team;
});
-mkws.registerWidgetType('facet', function() {
+mkws.registerWidgetType('Facet', function() {
var facetConfig = {
xtargets: [ "Sources", 16, false ],
subject: [ "Subjects", 10, true ],
}
var s = [];
- s.push('<div class="mkws', type, ' mkws-team-', attrs._team, '"');
+ s.push('<div class="mkws', type, ' mkwsTeam_', attrs._team, '"');
for (var name in attrs) {
if (name !== '_team')
s.push(' ', name, '="', attrs[name], '"');
if (fn) {
fn.call(that);
log("made " + type + " widget(node=" + node + ")");
- } else if (type.match(/-[Cc]ontainer-(narrow|wide)$/)) {
+ } else if (type.match(/-Container-(narrow|wide)$/)) {
// Not really a widget: no need to log its lack of promotion
} else {
log("made UNPROMOTED widget(type=" + type + ", node=" + node + ")");
field - for the xtargets facet ONLY, the opaque identifier of the target
}}
-<div class="mkws-facet-title">{{caption}}</div>
+<div class="mkwsFacetTitle">{{caption}}</div>
{{#each terms}}
- <div class="mkws-term">
+ <div class="mkwsTerm">
<a href="#" {{{linkdata}}}>{{term}}</a> <span>{{count}}</span>
</div>
{{/each}}
{{!
Records presented as images.
+The non-metadata keys enable an optional link to display an AJAX popup that
+fetches additional record detail.
+
hits:
- containerClass - class attribute for same
+ containerClass - partial class attribute for element containing a record
detailLinkId - id for the element triggering detail display
detailClick - a click event handler for details
renderedDetails - active record details rendered from the Record template
click - handler script to remove limit
}}
{{#each filters}}
- {{{mkws-translate facet}}}: <a class="mkws-removable" href="#" onclick="{{{click}}}">{{value}}</a>
+ {{{mkws-translate facet}}}: <a class="mkwsRemovable" href="#" onclick="{{{click}}}">{{value}}</a>
{{#unless @last}}|{{/unless}}
{{/each}}
<div style="float: clear">
{{#if prevClick}}
- <a href="#" class="mkws-prev" onclick="{{prevClick}}"><< {{{mkws-translate "Prev"}}}</a> |
+ <a href="#" class="mkwsPrev" onclick="{{prevClick}}"><< {{{mkws-translate "Prev"}}}</a> |
{{else}}
- <span class="mkws-prev"><< {{{mkws-translate "Prev"}}}</span> |
+ <span class="mkwsPrev"><< {{{mkws-translate "Prev"}}}</span> |
{{/if}}
{{#if morePrev}}...{{/if}}
{{#if click}}
<a href="#" onclick="{{click}}">{{number}}</a>
{{else}}
- <span class="mkws-current-page">{{number}}</span>
+ <span class="mkwsCurrentPage">{{number}}</span>
{{/if}}
{{/each}}
{{#if moreNext}}...{{/if}}
{{#if nextClick}}
- | <a href="#" class="mkws-next" onclick="{{nextClick}}">{{{mkws-translate "Next"}}} >></a>
+ | <a href="#" class="mkwsNext" onclick="{{nextClick}}">{{{mkws-translate "Next"}}} >></a>
{{else}}
- | <span class="mkws-next">{{{mkws-translate "Next"}}} >></span>
+ | <span class="mkwsNext">{{{mkws-translate "Next"}}} >></span>
{{/if}}
</div>
Ranking -- widget to select sort ordering and number of records to display
team - team for this widget
-showSort
-showPerPage
+showSort - set if sort control is to be displayed
+showPerPage - set if per-page control is to be displayed
sort
key - machine readable value for this sort option
label - text to display for this sort option
<form>
{{~#if showSort~}}
{{{mkws-translate "Sort by"}}}
- <select class="mkws-sort mkws-team-{{team}}">
+ <select class="mkwsSort mkwsTeam_{{team}}">
{{#each sort}}
{{#if selected}}
<option value="{{{key}}}" selected="selected">{{{mkws-translate label}}}</option>
{{~/if~}}
{{~#if showPerPage}}
{{{mkws-translate "and show"}}}
- <select class="mkws-per-page mkws-team-{{team}}">
+ <select class="mkwsPerpage mkwsTeam_{{team}}">
{{#each perPage}}
{{#if selected}}
<option value="{{perPage}}" selected="selected">{{perPage}}</option>
{{!
Full record display.
+
+Top level object is metadata from Service Proxy / Pazpar2
}}
<table>
<tr>
{{!
Records from a search.
+The non-metadata keys enable an optional link to display an AJAX popup that
+fetches additional record detail.
+
hits:
- containerClass - class attribute for same
+ containerClass - partial class attribute for element containing a record
detailLinkId - id for the element triggering detail display
detailClick - a click event handler for details
renderedDetails - active record details rendered from the Record template
}}
<table width="100%" border="0" cellpadding="6" cellspacing="0">
<tr>
- <td class="mkws-termlists-container-wide mkws-team-{{team}}" width="250" valign="top">
- <div class="mkws-termlists mkws-team-{{team}}"></div>
+ <td class="mkwsTermlists-Container-wide mkwsTeam_{{team}}" width="250" valign="top">
+ <div class="mkwsTermlists mkwsTeam_{{team}}"></div>
</td>
- <td class="mkws-motd-container mkws-team-{{team}}" valign="top">
- <div class="mkws-ranking mkws-team-{{team}}"></div>
- <div class="mkws-pager mkws-team-{{team}}"></div>
- <div class="mkws-navi mkws-team-{{team}}"></div>
- <div class="mkws-records mkws-team-{{team}}"></div>
+ <td class="mkwsMOTDContainer mkwsTeam_{{team}}" valign="top">
+ <div class="mkwsRanking mkwsTeam_{{team}}"></div>
+ <div class="mkwsPager mkwsTeam_{{team}}"></div>
+ <div class="mkwsNavi mkwsTeam_{{team}}"></div>
+ <div class="mkwsRecords mkwsTeam_{{team}}"></div>
</td>
</tr>
<tr>
<td colspan="2">
- <div class="mkws-termlists-container-narrow mkws-team-{{team}}"></div>
+ <div class="mkwsTermlists-Container-narrow mkwsTeam_{{team}}"></div>
</td>
</tr>
</table>
records - number of records returned and available
hits - number of hits across all targets
}}
- -- <span class="mkws-client-count">{{{mkws-translate "Active clients"}}} : {{activeclients}}/{{clients}}</span> -- {{{mkws-translate "Retrieved records"}}} : {{records}}/{{hits}}
+ -- <span class="mkwsClientCount">{{{mkws-translate "Active clients"}}} : {{activeclients}}/{{clients}}</span> -- {{{mkws-translate "Retrieved records"}}} : {{records}}/{{hits}}
facets - array of facet names
}}
-<div class="mkws-termlists-title">Termlists</div>
+<div class="mkwsTermlistsTitle">Termlists</div>
{{#each facets}}
- <div class="mkws-facet mkws-team-{{../team}}" data-mkws-facet="{{this}}"></div>
+ <div class="mkwsFacet mkwsTeam_{{../team}}" data-mkws-facet="{{this}}"></div>
{{/each}}