Merge remote branch 'origin/master' into wosch
authorWolfram Schneider <wosch@indexdata.dk>
Tue, 6 May 2014 07:07:06 +0000 (07:07 +0000)
committerWolfram Schneider <wosch@indexdata.dk>
Tue, 6 May 2014 07:07:06 +0000 (07:07 +0000)
14 files changed:
doc/whitepaper.markdown
examples/htdocs/heikki-motd.html
examples/htdocs/heikki.html
examples/htdocs/lolcat.html
examples/htdocs/mike.html
examples/htdocs/mkws-widget-reference.js
examples/htdocs/templates.html
src/NEWS
src/mkws-core.js
src/mkws-handlebars.js
src/mkws-team.js
src/mkws-widget-main.js
src/mkws-widget-termlists.js
src/mkws-widget.js

index 376da7a..74a3234 100644 (file)
@@ -260,8 +260,8 @@ 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
-`mkwsTermlistContainer1` element; and provide an
-`mkwsTermlistContainer2` element in the place where the narrow-screen
+`mkwsTermlists-Container-wide` element; and provide an
+`mkwsTermlists-Container-narrow` element in the place where the narrow-screen
 termlists should appear.
 
 
index f46036a..10a2a82 100644 (file)
     <script type="text/javascript" src="tools/htdocs/mkws.js"></script>
 
     <style type="text/css">
-      #mkwsTermlists div.facet {
+      .mkwsTermlists div.facet {
       float:left;
       width: 30%;
       margin: 0.3em;
       }
-      #mkwsStat {
+      .mkwsStat {
       text-align: right;
       }
     </style>
index eda424c..5cebd8f 100644 (file)
     <script type="text/javascript" src="tools/htdocs/jquery.json-2.4.js"></script>
     <script type="text/javascript" src="tools/htdocs/mkws.js"></script>
     <style type="text/css">
-      #mkwsTermlists div.facet {
+      .mkwsTermlists div.facet {
       float:left;
       width: 30%;
       margin: 0.3em;
       }
-      #mkwsStat {
+      .mkwsStat {
       text-align: right;
       }
     </style>
index 89c6790..512c990 100644 (file)
@@ -9,9 +9,9 @@
     <script type="text/javascript" src="http://mkws.indexdata.com/mkws-complete.js"></script>
     <script class="mkwsTemplate_Summary" type="text/x-handlebars-template">
       <a href="#" id="{{_id}}" onclick="{{_onclick}}">
-        {{#first md-thumburl}}
+        {{#mkws-first md-thumburl}}
          <img src="{{this}}" alt="{{../md-title}}"/>
-        {{/first}}
+        {{/mkws-first}}
        <br/>
       </a>
     </script>
index b58405e..7ab295d 100644 (file)
@@ -7,7 +7,8 @@
     <link rel="stylesheet" type="text/css" href="http://x.mkws.indexdata.com/mkws.css" />
     <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" };
+      var mkws_config = { service_proxy_auth: "//mkws.indexdata.com/service-proxy-testauth",
+                          responsive_design_width: 800 };
     </script>
     <script type="text/javascript" src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
     <script type="text/javascript" src="http://x.mkws.indexdata.com/jquery.json-2.4.js"></script>
   <body>
     <div class="mkwsSwitch"></div>
     <div class="mkwsLang"></div>
-    <div class="mkwsSearch"></div>
+    <div class="mkwsSearch-Container-wide"><div class="mkwsSearch"></div></div>
     <div class="mkwsResults"></div>
     <div class="mkwsTargets"></div>
     <div class="mkwsStat"></div>
     <div class="mkwsBuilder"></div>
+    <div class="mkwsSearch-Container-narrow"></div>
   </body>
 </html>
index 3231ebc..20e701a 100644 (file)
@@ -13,7 +13,7 @@ mkws.registerWidgetType('Reference', function() {
   <i>{{md-title-responsibility}}</i>\
 {{/if}}\
   <p>\
-    {{{paragraphs md-description}}}\
+    {{{mkws-paragraphs md-description}}}\
   </p>\
 ');
 });
index 2f39dd2..bed0122 100644 (file)
          </td>
        </tr>
        {{/if}}
-       {{#if-any location having="md-subject"}}
+       {{#mkws-if-any location having="md-subject"}}
        <tr>
          <th>Subject</th>
          <td>
-           {{#first location having="md-subject"}}
+           {{#mkws-first location having="md-subject"}}
              {{#if md-subject}}
                {{md-subject}}
              {{/if}}
-           {{/first}}
+           {{/mkws-first}}
          </td>
        </tr>
-       {{/if-any}}
+       {{/mkws-if-any}}
        <tr>
          <th>Locations</th>
          <td>
-           {{#commaList location}}
-             {{attr "@name"}}{{/commaList}}
+           {{#mkws-commaList location}}
+             {{mkws-attr "@name"}}{{/mkws-commaList}}
          </td>
        </tr>
       </table>
index 5bbb6ad..7d9df79 100644 (file)
--- a/src/NEWS
+++ b/src/NEWS
@@ -7,7 +7,7 @@ The 0.9.x series of releases are beta quality. They are functional but
 have not yet been extensively battle-tested.
 
 0.9.2 [IN PROGRESS]
-       - Full-record template invokes {{translate}} on fieldnames.
+       - Full-record template invokes {{mkws-translate}} on fieldnames.
          Fixes MKWS-84 Translate fieldnames in full-record popup.
 
 0.9.1 Thu Dec 19 15:33:13 GMT 2013
index e0811ff..1e84fca 100644 (file)
@@ -97,6 +97,17 @@ mkws.log = function(string) {
 };
 
 
+// Translation function.
+mkws.M = function (word) {
+    var lang = mkws.config.lang;
+
+    if (!lang || !mkws.locale_lang[lang])
+        return word;
+
+    return mkws.locale_lang[lang][word] || word;
+};
+
+
 // This function is taken from a StackOverflow answer
 // http://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript/901144#901144
 mkws.getParameterByName = function(name) {
@@ -169,7 +180,7 @@ mkws.defaultTemplate = function(name) {
        return '\
 <table>\
   <tr>\
-    <th>{{translate "Title"}}</th>\
+    <th>{{mkws-translate "Title"}}</th>\
     <td>\
       {{md-title}}\
       {{#if md-title-remainder}}\
@@ -182,44 +193,44 @@ mkws.defaultTemplate = function(name) {
   </tr>\
   {{#if md-date}}\
   <tr>\
-    <th>{{translate "Date"}}</th>\
+    <th>{{mkws-translate "Date"}}</th>\
     <td>{{md-date}}</td>\
   </tr>\
   {{/if}}\
   {{#if md-author}}\
   <tr>\
-    <th>{{translate "Author"}}</th>\
+    <th>{{mkws-translate "Author"}}</th>\
     <td>{{md-author}}</td>\
   </tr>\
   {{/if}}\
   {{#if md-electronic-url}}\
   <tr>\
-    <th>{{translate "Links"}}</th>\
+    <th>{{mkws-translate "Links"}}</th>\
     <td>\
       {{#each md-electronic-url}}\
-       <a href="{{this}}">Link{{index1}}</a>\
+       <a href="{{this}}">Link{{mkws-index1}}</a>\
       {{/each}}\
     </td>\
   </tr>\
   {{/if}}\
-  {{#if-any location having="md-subject"}}\
+  {{#mkws-if-any location having="md-subject"}}\
   <tr>\
-    <th>{{translate "Subject"}}</th>\
+    <th>{{mkws-translate "Subject"}}</th>\
     <td>\
-      {{#first location having="md-subject"}}\
+      {{#mkws-first location having="md-subject"}}\
        {{#if md-subject}}\
-         {{#commaList md-subject}}\
-           {{this}}{{/commaList}}\
+         {{#mkws-commaList md-subject}}\
+           {{this}}{{/mkws-commaList}}\
        {{/if}}\
-      {{/first}}\
+      {{/mkws-first}}\
     </td>\
   </tr>\
-  {{/if-any}}\
+  {{/mkws-if-any}}\
   <tr>\
-    <th>{{translate "Locations"}}</th>\
+    <th>{{mkws-translate "Locations"}}</th>\
     <td>\
-      {{#commaList location}}\
-       {{attr "@name"}}{{/commaList}}\
+      {{#mkws-commaList location}}\
+       {{mkws-attr "@name"}}{{/mkws-commaList}}\
     </td>\
   </tr>\
 </table>\
@@ -239,9 +250,9 @@ mkws.defaultTemplate = function(name) {
     } else if (name === "Image") {
        return '\
       <a href="#" id="{{_id}}" onclick="{{_onclick}}">\
-        {{#first md-thumburl}}\
+        {{#mkws-first md-thumburl}}\
          <img src="{{this}}" alt="{{../md-title}}"/>\
-        {{/first}}\
+        {{/mkws-first}}\
        <br/>\
       </a>\
 ';
@@ -330,32 +341,35 @@ mkws.pagerNext = function(tname) {
 
 
     function resizePage() {
-       var list = ["mkwsSwitch", "mkwsLang"];
-
-       var width = mkws.config.responsive_design_width;
-       var parent = $(".mkwsTermlists").parent();
-
-       if ($(window).width() <= width &&
-           parent.hasClass("mkwsTermlistContainer1")) {
-           log("changing from wide to narrow: " + $(window).width());
-           $(".mkwsTermlistContainer1").hide();
-           $(".mkwsTermlistContainer2").show();
+       var threshhold = mkws.config.responsive_design_width;
+        var width = $(window).width();
+        var from, to, method;
+
+        if ((mkws.width === undefined || mkws.width > threshhold) &&
+                   width <= threshhold) {
+            from = "wide"; to = "narrow"; method = "hide";
+        } else if ((mkws.width === undefined || mkws.width <= threshhold) &&
+                   width > threshhold) {
+            from = "narrow"; to = "wide"; method = "show";
+        }
+        mkws.width = width;
+
+        if (from) {
+           log("changing from " + from + " to " + to + ": " + width);
            for (var tname in mkws.teams) {
-               $(".mkwsTermlists.mkwsTeam_" + tname).appendTo($(".mkwsTermlistContainer2.mkwsTeam_" + tname));
-               for(var i = 0; i < list.length; i++) {
-                   $("." + list[i] + ".mkwsTeam_" + tname).hide();
-               }
-           }
-       } else if ($(window).width() > width &&
-                  parent.hasClass("mkwsTermlistContainer2")) {
-           log("changing from narrow to wide: " + $(window).width());
-           $(".mkwsTermlistContainer1").show();
-           $(".mkwsTermlistContainer2").hide();
-           for (var tname in mkws.teams) {
-               $(".mkwsTermlists.mkwsTeam_" + tname).appendTo($(".mkwsTermlistContainer1.mkwsTeam_" + tname));
-               for(var i = 0; i < list.length; i++) {
-                   $("." + list[i] + ".mkwsTeam_" + tname).show();
-               }
+                var team = mkws.teams[tname];
+                team.visitWidgets(function (t, w) {
+                    var w1 = team.widget(t + "-Container-" + from);
+                    var w2 = team.widget(t + "-Container-" + to);
+                    if (w1) {
+                        $(w1.node).hide();
+                    }
+                    if (w2) {
+                        $(w2.node).show();
+                       $(w.node).appendTo($(w2.node));
+                    }
+                });
+                team.queue("resize-" + to).publish();
            }
        }
     };
@@ -422,7 +436,7 @@ mkws.pagerNext = function(tname) {
                 myTeam.addWidget(myWidget);
                 var newHTML = this.innerHTML;
                 if (newHTML !== oldHTML) {
-                    log("widget " + tname + ":" + type + " HTML changed from '" + oldHTML + "' to '" + newHTML + "': reparse!");
+                    log("widget " + tname + ":" + type + " HTML changed: reparsing");
                     makeWidgetsWithin(level+1, $(this));
                 }
             });
@@ -452,6 +466,15 @@ mkws.pagerNext = function(tname) {
            }
        }
 
+        var lang = mkws.getParameterByName("lang") || mkws.config.lang;
+        if (!lang || !mkws.locale_lang[lang]) {
+            mkws.config.lang = ""
+        } else {
+            mkws.config.lang = lang;
+        }
+
+        log("Locale language: " + (mkws.config.lang ? mkws.config.lang : "none"));
+
        if (mkws.config.query_width < 5 || mkws.config.query_width > 150) {
            log("Reset query width: " + mkws.config.query_width);
            mkws.config.query_width = 50;
@@ -502,15 +525,15 @@ mkws.pagerNext = function(tname) {
        var now = $.now();
        log("Walking MKWS nodes took " + (now-then) + " ms");
 
-//        for (var tName in mkws.teams) {
-//            var myTeam = mkws.teams[tName]
-//            var types = myTeam.widgetTypes();
-//            log("TEAM '" + tName + "' = " + myTeam + " has widget types " + types);
-//            for (var i = 0; i < types.length; i++) {
-//                var type = types[i];
-//                log("  has widget of type '" + type + "': " + myTeam.widget(type));
-//            }
-//        }
+        /*
+        for (var tName in mkws.teams) {
+            var myTeam = mkws.teams[tName]
+            log("TEAM '" + tName + "' = " + myTeam + " ...");
+            myTeam.visitWidgets(function(t, w) {
+                log("  has widget of type '" + t + "': " + w);
+            });
+        }
+        */
 
        if (mkws.config.use_service_proxy) {
            authenticateSession(mkws.config.service_proxy_auth,
index 5fae905..58c95a1 100644 (file)
@@ -1,10 +1,10 @@
 // Handlebars helpers
-Handlebars.registerHelper('json', function(obj) {
+Handlebars.registerHelper('mkws-json', function(obj) {
     return $.toJSON(obj);
 });
 
 
-Handlebars.registerHelper('paragraphs', function(obj) {
+Handlebars.registerHelper('mkws-paragraphs', function(obj) {
     var acc = [];
     for (var i = 0; i < obj.length; i++) {
         acc.push('<p>', obj[i], '</p>');
@@ -13,24 +13,24 @@ Handlebars.registerHelper('paragraphs', function(obj) {
 });
 
 
-Handlebars.registerHelper('translate', function(s) {
+Handlebars.registerHelper('mkws-translate', function(s) {
     return mkws.M(s);
 });
 
 
-// We need {{attr '@name'}} because Handlebars can't parse {{@name}}
-Handlebars.registerHelper('attr', function(attrName) {
+// We need {{mkws-attr '@name'}} because Handlebars can't parse {{@name}}
+Handlebars.registerHelper('mkws-attr', function(attrName) {
     return this[attrName];
 });
 
 
 /*
- * Use as follows: {{#if-any NAME1 having="NAME2"}}
+ * Use as follows: {{#mkws-if-any NAME1 having="NAME2"}}
  * Applicable when NAME1 is the name of an array
  * The guarded code runs only if at least one element of the NAME1
  * array has a subelement called NAME2.
  */
-Handlebars.registerHelper('if-any', function(items, options) {
+Handlebars.registerHelper('mkws-if-any', function(items, options) {
     var having = options.hash.having;
     for (var i in items) {
        var item = items[i]
@@ -42,7 +42,7 @@ Handlebars.registerHelper('if-any', function(items, options) {
 });
 
 
-Handlebars.registerHelper('first', function(items, options) {
+Handlebars.registerHelper('mkws-first', function(items, options) {
     var having = options.hash.having;
     for (var i in items) {
        var item = items[i]
@@ -54,7 +54,7 @@ Handlebars.registerHelper('first', function(items, options) {
 });
 
 
-Handlebars.registerHelper('commaList', function(items, options) {
+Handlebars.registerHelper('mkws-commaList', function(items, options) {
     var out = "";
 
     for (var i in items) {
@@ -66,6 +66,6 @@ Handlebars.registerHelper('commaList', function(items, options) {
 });
 
 
-Handlebars.registerHelper('index1', function(obj) {
+Handlebars.registerHelper('mkws-index1', function(obj) {
     return obj.data.index + 1;
 });
index 2bac42e..3974fd9 100644 (file)
@@ -29,7 +29,7 @@ function team($, teamName) {
     var m_tempateText = {}; // widgets can register tempates 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 object
+    var m_widgets = {}; // Maps widget-type to array of widget objects
 
     that.toString = function() { return '[Team ' + teamName + ']'; };
 
@@ -303,16 +303,16 @@ function team($, teamName) {
 
        switch(view) {
         case 'targets':
-            if (targets) targets.css('display', 'block');
-            if (results) results.css('display', 'none');
-            if (blanket) blanket.css('display', 'none');
-            if (motd) motd.css('display', 'none');
+            if (targets) $(targets).show();
+            if (results) $(results).hide();
+            if (blanket) $(blanket).hide();
+            if (motd) $(motd).hide();
             break;
         case 'records':
-            if (targets) targets.css('display', 'none');
-            if (results) results.css('display', 'block');
-            if (blanket) blanket.css('display', 'block');
-            if (motd) motd.css('display', 'none');
+            if (targets) $(targets).hide();
+            if (results) $(results).show();
+            if (blanket) $(blanket).show();
+            if (motd) $(motd).hide();
             break;
         default:
             alert("Unknown view '" + view + "'");
@@ -341,22 +341,6 @@ function team($, teamName) {
     };
 
 
-    // Translation function. At present, this is properly a
-    // global-level function (hence the assignment to mkws.M) but we
-    // want to make it per-team so different teams can operate in
-    // different languages.
-    //
-    function M(word) {
-       var lang = m_config.lang;
-
-       if (!lang || !mkws.locale_lang[lang])
-           return word;
-
-       return mkws.locale_lang[lang][word] || word;
-    }
-    mkws.M = M; // so the Handlebars helper can use it
-
-
     // Finds the node of the specified class within the current team
     function findnode(selector, teamName) {
        teamName = teamName || m_teamName;
@@ -372,11 +356,8 @@ function team($, teamName) {
        //log('findnode(' + selector + ') found ' + node.length + ' nodes');
        return node;
     }
-    that.findnode = findnode;
 
 
-    // This much simpler and more efficient function should be usable
-    // in place of most uses of findnode.
     function widgetNode(type) {
         var w = that.widget(type);
         return w ? $(w.node) : undefined;
@@ -428,37 +409,39 @@ function team($, teamName) {
 
 
     that.addWidget = function(w) {
-        if (!m_widgets[w.type]) {
-            m_widgets[w.type] = w;
-            log("Registered '" + w.type + "' widget in team '" + m_teamName + "'");
-        } else if (typeof(m_widgets[w.type]) !== 'number') {
-            m_widgets[w.type] = 2;
-            log("Registered duplicate '" + w.type + "' widget in team '" + m_teamName + "'");
+        if (m_widgets[w.type] === undefined) {
+            m_widgets[w.type] = [ w ];
+            log("Added '" + w.type + "' widget to team '" + m_teamName + "'");
         } else {
-            m_widgets[w.type] += 1;
-            log("Registered '" + w.type + "' widget #" + m_widgets[w.type] + "' in team '" + m_teamName + "'");
+            m_widgets[w.type].push(w);
+            log("Added '" + w.type + "' widget #" + m_widgets[w.type].length + "' to team '" + m_teamName + "'");
         }
     }
 
-    that.widgetTypes = function() {
-        var keys = [];
-        for (var k in m_widgets) keys.push(k);
-        return keys.sort();
-    }
-
     that.widget = function(type) {
-        return m_widgets[type];
-    }
+        var list = m_widgets[type];
 
+        if (!list)
+            return undefined;
+        if (list.length > 1) {
+            alert("widget('" + type + "') finds " + list.length + " widgets: using first");
+        }
+        return list[0];
+    }
 
-    var lang = mkws.getParameterByName("lang") || m_config.lang;
-    if (!lang || !mkws.locale_lang[lang]) {
-       m_config.lang = ""
-    } else {
-       m_config.lang = lang;
+    that.visitWidgets = function(callback) {
+        for (var type in m_widgets) {
+            var list = m_widgets[type];
+            for (var i = 0; i < list.length; i++) {
+                var res = callback(type, list[i]);
+                if (res !== undefined) {
+                    return res;
+                }
+            }
+        }
+        return undefined;
     }
 
-    log("Locale language: " + (m_config.lang ? m_config.lang : "none"));
 
     return that;
 };
index 69d1360..9bb08eb 100644 (file)
@@ -117,13 +117,6 @@ mkws.registerWidgetType('Pager', function() {
 });
 
 
-mkws.registerWidgetType('Results', function() {
-    // Nothing to do apart from act as an autosearch trigger
-    // Contained elements do all the real work
-    widget.autosearch(this);
-});
-
-
 mkws.registerWidgetType('Records', function() {
     var that = this;
     var team = this.team;
@@ -228,6 +221,7 @@ mkws.registerWidgetType('Switch', function() {
 <a href="#" onclick="mkws.switchView(\'' + tname + '\', \'records\')">Records</a><span> \
 | \
 </span><a href="#" onclick="mkws.switchView(\'' + tname + '\', \'targets\')">Targets</a>');
+    widget.hideWhenNarrow(this);
 });
 
 
@@ -259,7 +253,7 @@ mkws.registerWidgetType('Results', function() {
     $(this.node).html('\
 <table width="100%" border="0" cellpadding="6" cellspacing="0">\
   <tr>\
-    <td class="mkwsTermlistContainer1 mkwsTeam_' + tname + '" width="250" valign="top">\
+    <td class="mkwsTermlists-Container-wide mkwsTeam_' + tname + '" width="250" valign="top">\
       <div class="mkwsTermlists mkwsTeam_' + tname + '"></div>\
     </td>\
     <td class="mkwsMOTDContainer mkwsTeam_' + tname + '" valign="top">\
@@ -271,10 +265,12 @@ mkws.registerWidgetType('Results', function() {
   </tr>\
   <tr>\
     <td colspan="2">\
-      <div class="mkwsTermlistContainer2 mkwsTeam_' + tname + '"></div>\
+      <div class="mkwsTermlists-Container-narrow mkwsTeam_' + tname + '"></div>\
     </td>\
   </tr>\
 </table>');
+
+    widget.autosearch(this);
 });
 
 
@@ -381,6 +377,7 @@ mkws.registerWidgetType('Lang', function() {
     }
 
     $(this.node).html(data);
+    widget.hideWhenNarrow(this);
 
 
     // set or re-set "lang" URL parameter
@@ -413,3 +410,18 @@ mkws.registerWidgetType('MOTD', function() {
 });
 
 
+// Some elements have mkws* classes that makes them appear as widgets
+// -- for example, because we want to style them using CSS -- but have
+// no actual functionality. We register these to prevent ignorable
+// warnings when they occur.
+
+mkws.registerWidgetType('Query', function() {});
+mkws.registerWidgetType('MOTDContainer', function() {});
+mkws.registerWidgetType('Button', function() {});
+mkws.registerWidgetType('Popup', function() {});
+
+// Not sure whether the following should have functionality:
+// Select              HTMLFormElement
+// *-Container-wide    HTMLTableCellElement
+// *-Container-narrow  HTMLDivElement
+// Bytarget            HTMLDivElement
index 33d12b9..3ea68f5 100644 (file)
@@ -35,6 +35,10 @@ mkws.registerWidgetType('Facet', function() {
     var max = ref[1];
     var pzIndex = ref[2] ? name : null;
 
+    that.toString = function() {
+       return '[Widget ' + that.team.name() + ':' + that.type + '(' + name + ')]';
+    };
+
     that.team.queue("termlists").subscribe(function(data) {
        data = data[name];
 
index a16dec1..faee22d 100644 (file)
@@ -116,3 +116,14 @@ widget.autosearch = function(widget) {
 };
 
 
+// Utility function for all widgets that want to hide in narrow windows
+widget.hideWhenNarrow = function(widget) {
+    widget.team.queue("resize-narrow").subscribe(function(n) {
+       $(widget.node).hide();
+    });
+    widget.team.queue("resize-wide").subscribe(function(n) {
+       $(widget.node).show();
+    });
+};
+
+