JGirault has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/249953

Change subject: Portals code should follow the same coding conventions as MW
......................................................................

Portals code should follow the same coding conventions as MW

- Added .jscsrc from wikimedia/core
- Added .jshint from wikimedia/core
- Added gulp-jscs to package.json
- Added jscs validator to gulp lint
- Fixed code style of gulpfile.js
- Fixed code style of wm-portal.js

Bug: T116979
Change-Id: I8b58ac72c66dd8f81b6c46360829241e8e2b8357
---
A .jscsrc
M .jshintrc
M dev/wikipedia.org/assets/js/wm-portal.js
M gulpfile.js
M package.json
M prod/wikipedia.org/index.html
6 files changed, 493 insertions(+), 467 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/wikimedia/portals 
refs/changes/53/249953/1

diff --git a/.jscsrc b/.jscsrc
new file mode 100644
index 0000000..c9db9ba
--- /dev/null
+++ b/.jscsrc
@@ -0,0 +1,19 @@
+{
+  // taken from core
+  "preset": "wikimedia",
+  "es3": true,
+
+  "requireVarDeclFirst": false,
+  "requireMultipleVarDecl": {"allExcept": ["require"]}, // added
+
+  "disallowQuotedKeysInObjects": "allButReserved",
+  "requireDotNotation": { "allExcept": [ "keywords" ] },
+  "jsDoc": {
+       "checkParamNames": true,
+       "checkRedundantReturns": true,
+       "checkTypes": "strictNativeCase",
+       "requireNewlineAfterDescription": true,
+       "requireParamTypes": true,
+       "requireReturnTypes": true
+  }
+}
diff --git a/.jshintrc b/.jshintrc
index b776e8f..9c4d6f8 100644
--- a/.jshintrc
+++ b/.jshintrc
@@ -1,4 +1,5 @@
 {
+  // taken from core
        // Enforcing
        "bitwise": true,
        "eqeqeq": true,
@@ -9,7 +10,8 @@
        "nonew": true,
        "undef": true,
        "unused": true,
-       "strict": false,
+       "strict": true, // changed from core
+    "curly": true, // changed from core
 
        // Relaxing
        "laxbreak": true,
@@ -25,6 +27,9 @@
                "mwPerformance": true,
                "jQuery": false,
                "QUnit": false,
-               "sinon": false
+               "sinon": false,
+               "require": true, // added
+               "process": true, // added
+               "console": true // added
        }
 }
diff --git a/dev/wikipedia.org/assets/js/wm-portal.js 
b/dev/wikipedia.org/assets/js/wm-portal.js
index b315f9b..a5e73f0 100644
--- a/dev/wikipedia.org/assets/js/wm-portal.js
+++ b/dev/wikipedia.org/assets/js/wm-portal.js
@@ -18,464 +18,466 @@
  * Usage:
  * <script 
src="//meta.wikimedia.org/w/load.php?debug=false&amp;lang=en&amp;modules=ext.gadget.wm-portal&amp;only=scripts&amp;skin=vector&amp;*"></script>
  */
-/*jshint eqeqeq:true, strict:true, unused:true, curly:true, browser:true, 
quotmark:double */
-(function () {
-  "use strict";
+( function () {
+       'use strict';
 
-  var attachedEvents = [];
+       var attachedEvents = [];
 
-  /**
-   * Returns the DOM element with the given ID.
-   */
-  function $(id) {
-    return document.getElementById(id);
-  }
+       /**
+        * Returns the DOM element with the given ID.
+        */
+       function $( id ) {
+               return document.getElementById( id );
+       }
 
-  /**
-   * Removes all event handlers in Internet Explorer 8 and below.
-   *
-   * Any attached event handlers are stored in memory until IE exits, leaking
-   * every time you leave (or reload) the page. This method cleans up any
-   * event handlers that remain at the time the page is unloaded.
-   */
-  window.onunload = function () {
-    var i, evt;
-    for (i = 0; i < attachedEvents.length; i++) {
-      evt = attachedEvents[i];
-      if (evt[0]) {
-        evt[0].detachEvent("on" + evt[1], evt[2]);
-      }
-    }
-    attachedEvents = [];
-  };
+       /**
+        * Removes all event handlers in Internet Explorer 8 and below.
+        *
+        * Any attached event handlers are stored in memory until IE exits, 
leaking
+        * every time you leave (or reload) the page. This method cleans up any
+        * event handlers that remain at the time the page is unloaded.
+        */
+       window.onunload = function () {
+               var i, evt;
+               for ( i = 0; i < attachedEvents.length; i++ ) {
+                       evt = attachedEvents[ i ];
+                       if ( evt[ 0 ] ) {
+                               evt[ 0 ].detachEvent( 'on' + evt[ 1 ], evt[ 2 ] 
);
+                       }
+               }
+               attachedEvents = [];
+       };
 
-  function addEvent(obj, evt, fn) {
-    if (!obj) {
-      return;
-    }
+       function addEvent( obj, evt, fn ) {
+               if ( !obj ) {
+                       return;
+               }
 
-    if (obj.addEventListener) {
-      obj.addEventListener(evt, fn, false);
-    } else if (obj.attachEvent) {
-      attachedEvents.push([obj, evt, fn]);
-      obj.attachEvent("on" + evt, fn);
-    }
-  }
+               if ( obj.addEventListener ) {
+                       obj.addEventListener( evt, fn, false );
+               } else if ( obj.attachEvent ) {
+                       attachedEvents.push( [ obj, evt, fn ] );
+                       obj.attachEvent( 'on' + evt, fn );
+               }
+       }
 
-  function removeEvent(obj, evt, fn) {
-    if (!obj) {
-      return;
-    }
+       function removeEvent( obj, evt, fn ) {
+               if ( !obj ) {
+                       return;
+               }
 
-    if (obj.removeEventListener) {
-      obj.removeEventListener(evt, fn);
-    } else if (obj.detachEvent) {
-      obj.detachEvent("on" + evt, fn);
-    }
-  }
+               if ( obj.removeEventListener ) {
+                       obj.removeEventListener( evt, fn );
+               } else if ( obj.detachEvent ) {
+                       obj.detachEvent( 'on' + evt, fn );
+               }
+       }
 
-  /**
-   * Queues the given function to be called once the DOM has finished loading.
-   *
-   * Based on jquery/src/core/ready.js@825ac37 (MIT licensed)
-   */
-  function doWhenReady(fn) {
-    var ready = function () {
-      removeEvent(document, "DOMContentLoaded", ready);
-      removeEvent(window, "load", ready);
-      fn();
-    };
+       /**
+        * Queues the given function to be called once the DOM has finished 
loading.
+        *
+        * Based on jquery/src/core/ready.js@825ac37 (MIT licensed)
+        */
+       function doWhenReady( fn ) {
+               var ready = function () {
+                       removeEvent( document, 'DOMContentLoaded', ready );
+                       removeEvent( window, 'load', ready );
+                       fn();
+               };
 
-    if (document.readyState === "complete") {
-      // Already ready, so call the function synchronously.
-      fn();
-    } else {
-      // Wait until the DOM or whole page loads, whichever comes first.
-      addEvent(document, "DOMContentLoaded", ready);
-      addEvent(window, "load", ready);
-    }
-  }
+               if ( document.readyState === 'complete' ) {
+                       // Already ready, so call the function synchronously.
+                       fn();
+               } else {
+                       // Wait until the DOM or whole page loads, whichever 
comes first.
+                       addEvent( document, 'DOMContentLoaded', ready );
+                       addEvent( window, 'load', ready );
+               }
+       }
 
-  /**
-   * Replaces the “hero graphic” with the given language edition’s logo.
-   */
-  function updateBranding(lang) {
-    var option, logo;
+       /**
+        * Replaces the “hero graphic” with the given language edition’s logo.
+        */
+       function updateBranding( lang ) {
+               var option, logo;
 
-    // Only Wiktionary has such a mess of logos.
-    if (!document.querySelector || document.body.id !== "www-wiktionary-org") {
-      return;
-    }
+               // Only Wiktionary has such a mess of logos.
+               if ( !document.querySelector || document.body.id !== 
'www-wiktionary-org' ) {
+                       return;
+               }
 
-    option = document.querySelector("option[lang|='" + lang + "']");
-    logo = option && option.getAttribute("data-logo");
-    if (logo) {
-      document.body.setAttribute("data-logo", logo);
-    }
-  }
+               option = document.querySelector( 'option[lang|="' + lang + '"]' 
);
+               logo = option && option.getAttribute( 'data-logo' );
+               if ( logo ) {
+                       document.body.setAttribute( 'data-logo', logo );
+               }
+       }
 
-  /**
-   * Returns the user's preferred language according to browser preferences.
-   */
-  function getUALang() {
-    var uiLang = ((navigator.languages && navigator.languages[0]) ||
-    navigator.language || navigator.userLanguage || "");
-    return uiLang.toLowerCase().split("-")[0];
-  }
+       /**
+        * Returns the user's preferred language according to browser 
preferences.
+        */
+       function getUALang() {
+               var uiLang = ( navigator.languages && navigator.languages[ 0 ] 
) ||
+               navigator.language || navigator.userLanguage || '';
+               return uiLang.toLowerCase().split( '-' )[ 0 ];
+       }
 
-  /**
-   * Returns the preferred language as stored in a cookie. Falls back on the
-   * browser's language.
-   */
-  function getSavedLang() {
-    var match = document.cookie.match(/(?:^|\W)searchLang=([^;]+)/);
-    return (match ? match[1] : getUALang()).toLowerCase();
-  }
+       /**
+        * Returns the preferred language as stored in a cookie. Falls back on 
the
+        * browser's language.
+        */
+       function getSavedLang() {
+               var match = document.cookie.match( /(?:^|\W)searchLang=([^;]+)/ 
);
+               return ( match ? match[ 1 ] : getUALang() ).toLowerCase();
+       }
 
-  /**
-   * Converts Chinese strings from traditional to simplified.
-   *
-   * Convertible elements start out with traditional text and title attributes
-   * along with simplified counterparts in the data-*-Hans attributes.
-   */
-  function convertChinese(lang) {
-    var i, elt,
-        txtAttr = "data-convert-Hans",
-        titleAttr = "data-convertTitle-Hans";
+       /**
+        * Converts Chinese strings from traditional to simplified.
+        *
+        * Convertible elements start out with traditional text and title 
attributes
+        * along with simplified counterparts in the data-*-Hans attributes.
+        */
+       function convertChinese( lang ) {
+               var i, elt,
+                       txtAttr = 'data-convert-hans',
+                       titleAttr = 'data-converttitle-hans';
 
-    if ("zh-hans,zh-cn,zh-sg,zh-my,".indexOf(lang + ",") === -1) {
-      return;
-    }
+               if ( 'zh-hans,zh-cn,zh-sg,zh-my,'.indexOf( lang + ',' ) === -1 
) {
+                       return;
+               }
 
-    // If we ever drop support for IE 8 and below, we can put all these
-    // elements in a "convertible" class and call
-    // document.getElementsByClassName() instead.
-    var ids = ["zh_art", "zh_others", "zh_search", "zh_tag", "zh_top10", 
"zh-yue_wiki", "gan_wiki", "hak_wiki", "wuu_wiki"];
-    for (i = 0; i < ids.length; i += 1) {
-      if ((elt = $(ids[i]))) {
-        if (elt.hasAttribute(txtAttr)) {
-          elt.innerHTML = elt.getAttribute(txtAttr);
-        }
-        if (elt.hasAttribute(titleAttr)) {
-          elt.title = elt.getAttribute(titleAttr);
-        }
-      }
-    }
-  }
+               // If we ever drop support for IE 8 and below, we can put all 
these
+               // elements in a "convertible" class and call
+               // document.getElementsByClassName() instead.
+               var ids = [ 'zh_art', 'zh_others', 'zh_search', 'zh_tag', 
'zh_top10', 'zh-yue_wiki', 'gan_wiki', 'hak_wiki', 'wuu_wiki' ];
+               for ( i = 0; i < ids.length; i += 1 ) {
+                       if ( ( elt = $( ids[ i ] ) ) ) {
+                               if ( elt.hasAttribute( txtAttr ) ) {
+                                       elt.innerHTML = elt.getAttribute( 
txtAttr );
+                               }
+                               if ( elt.hasAttribute( titleAttr ) ) {
+                                       elt.title = elt.getAttribute( titleAttr 
);
+                               }
+                       }
+               }
+       }
 
-  /**
-   * Modifies links to the Chinese language edition to point to traditional or
-   * simplified versions, based on the user's preference.
-   */
-  function convertZhLinks(lang) {
-    var locale;
+       /**
+        * Modifies links to the Chinese language edition to point to 
traditional or
+        * simplified versions, based on the user's preference.
+        */
+       function convertZhLinks( lang ) {
+               var locale;
 
-    if (lang.indexOf("zh") !== 0) {
-      return;
-    }
+               if ( lang.indexOf( 'zh' ) !== 0 ) {
+                       return;
+               }
 
-    locale = lang.substring(3 /* "zh-".length */);
-    if (locale === "mo") {
-      locale = "hk";
-    } else if (locale === "my") {
-      locale = "sg";
-    }
+               locale = lang.substring( 3 /* 'zh-'.length */ );
+               if ( locale === 'mo' ) {
+                       locale = 'hk';
+               } else if ( locale === 'my' ) {
+                       locale = 'sg';
+               }
 
-    if (locale && "cn,tw,hk,sg,".indexOf(locale + ",") >= 0) {
-      $("zh_wiki").href += "zh-" + locale + "/";
-      $("zh_others").href = $("zh_others").href.replace("wiki/", "zh-" + 
locale + "/");
-    }
+               if ( locale && 'cn,tw,hk,sg,'.indexOf( locale + ',' ) >= 0 ) {
+                       $( 'zh_wiki' ).href += 'zh-' + locale + '/';
+                       $( 'zh_others' ).href = $( 'zh_others' ).href.replace( 
'wiki/', 'zh-' + locale + '/' );
+               }
 
-    convertChinese(lang);
-  }
+               convertChinese( lang );
+       }
 
-  /**
-   * Selects the language from the dropdown according to the user's preference.
-   */
-  doWhenReady(function () {
-    var iso639, select, options, i, len, matchingLang, matchingLink,
-        customOption,
-        lang = getSavedLang();
+       /**
+        * Selects the language from the dropdown according to the user's 
preference.
+        */
+       doWhenReady( function () {
+               var iso639, select, options, i, len, matchingLang, matchingLink,
+                       customOption,
+                       lang = getSavedLang();
 
-    if (!lang) {
-      return;
-    }
+               if ( !lang ) {
+                       return;
+               }
 
-    convertZhLinks(lang);
+               convertZhLinks( lang );
 
-    iso639 = lang.match(/^\w+/);
-    if (!iso639) {
-      return;
-    }
-    iso639 = (iso639[0] === "nb") ? "no" : iso639[0];
+               iso639 = lang.match( /^\w+/ );
+               if ( !iso639 ) {
+                       return;
+               }
+               iso639 = ( iso639[ 0 ] === 'nb' ) ? 'no' : iso639[ 0 ];
 
-    select = $("searchLanguage");
-    // Verify that an <option> exists for the langCode that was
-    // in the cookie. If so, set the value to it.
-    if (select) {
-      options = select.getElementsByTagName("option");
-      for (i = 0, len = options.length; !matchingLang && i < len; i += 1) {
-        if (options[i].value === iso639) {
-          matchingLang = iso639;
-        }
-      }
-      if (!matchingLang && document.querySelector) {
-        matchingLink = document.querySelector(".langlist a[lang|='" + iso639 + 
"']");
-        if (matchingLink) {
-          matchingLang = iso639;
-          customOption = document.createElement("option");
-          customOption.setAttribute("lang", iso639);
-          customOption.setAttribute("value", iso639);
-          customOption.innerHTML = matchingLink.textContent || 
matchingLink.innerText || iso639;
-          select.appendChild(customOption);
-        }
-      }
-      if (matchingLang) {
-        select.value = matchingLang;
-        updateBranding(matchingLang);
-      }
-    }
-  });
+               select = $( 'searchLanguage' );
+               // Verify that an <option> exists for the langCode that was
+               // in the cookie. If so, set the value to it.
+               if ( select ) {
+                       options = select.getElementsByTagName( 'option' );
+                       for ( i = 0, len = options.length; !matchingLang && i < 
len; i += 1 ) {
+                               if ( options[ i ].value === iso639 ) {
+                                       matchingLang = iso639;
+                               }
+                       }
+                       if ( !matchingLang && document.querySelector ) {
+                               matchingLink = document.querySelector( 
'.langlist a[lang|="' + iso639 + '"]' );
+                               if ( matchingLink ) {
+                                       matchingLang = iso639;
+                                       customOption = document.createElement( 
'option' );
+                                       customOption.setAttribute( 'lang', 
iso639 );
+                                       customOption.setAttribute( 'value', 
iso639 );
+                                       customOption.innerHTML = 
matchingLink.textContent || matchingLink.innerText || iso639;
+                                       select.appendChild( customOption );
+                               }
+                       }
+                       if ( matchingLang ) {
+                               select.value = matchingLang;
+                               updateBranding( matchingLang );
+                       }
+               }
+       } );
 
-  /**
-   * Invokes the MediaWiki API of the selected wiki to search for articles
-   * whose titles begin with the entered text.
-   */
-  function setupSuggestions() {
-    // For simplicity's sake, rely on the HTML5 <datalist> element available
-    // on IE 10+ (and all other modern browsers).
-    if (window.HTMLDataListElement === undefined) {
-      return;
-    }
+       /**
+        * Invokes the MediaWiki API of the selected wiki to search for articles
+        * whose titles begin with the entered text.
+        */
+       function setupSuggestions() {
+               // For simplicity's sake, rely on the HTML5 <datalist> element 
available
+               // on IE 10+ (and all other modern browsers).
+               if ( window.HTMLDataListElement === undefined ) {
+                       return;
+               }
 
-    var list = document.createElement("datalist"),
-        search = $("searchInput");
+               var list = document.createElement( 'datalist' ),
+                       search = $( 'searchInput' );
 
-    list.id = "suggestions";
-    document.body.appendChild(list);
-    search.autocomplete = "off";
-    search.setAttribute("list", "suggestions");
+               list.id = 'suggestions';
+               document.body.appendChild( list );
+               search.autocomplete = 'off';
+               search.setAttribute( 'list', 'suggestions' );
 
-    addEvent(search, "input", function () {
-      var head = document.getElementsByTagName("head")[0],
-          hostname = window.location.hostname.replace("www.", 
$("searchLanguage").value + "."),
-          script = $("api_opensearch");
+               addEvent( search, 'input', function () {
+                       var head = document.getElementsByTagName( 'head' )[ 0 ],
+                               hostname = window.location.hostname.replace( 
'www.', $( 'searchLanguage' ).value + '.' ),
+                               script = $( 'api_opensearch' );
 
-      if (script) {
-        head.removeChild(script);
-      }
-      script = document.createElement("script");
-      script.id = "api_opensearch";
-      script.src = "//" + hostname + 
"/w/api.php?action=opensearch&limit=10&format=json&callback=portalOpensearchCallback&search="
 + search.value;
-      head.appendChild(script);
-    });
-  }
+                       if ( script ) {
+                               head.removeChild( script );
+                       }
+                       script = document.createElement( 'script' );
+                       script.id = 'api_opensearch';
+                       script.src = '//' + hostname + 
'/w/api.php?action=opensearch&limit=10&format=json&callback=portalOpensearchCallback&search='
 + search.value;
+                       head.appendChild( script );
+               } );
+       }
 
-  /**
-   * Sets the search box's data list to the results returned by the MediaWiki
-   * API. The results are returned in JSON-P format, so this callback must be
-   * global.
-   */
-  window.portalOpensearchCallback = function(xhrResults) {
-    var i,
-        suggestions = $("suggestions"),
-        oldOptions = suggestions.children;
+       /**
+        * Sets the search box's data list to the results returned by the 
MediaWiki
+        * API. The results are returned in JSON-P format, so this callback 
must be
+        * global.
+        */
+       window.portalOpensearchCallback = function ( xhrResults ) {
+               var i,
+                       suggestions = $( 'suggestions' ),
+                       oldOptions = suggestions.children;
 
-    // Update the list, reusing any existing items from the last search.
-    for (i = 0; i < xhrResults[1].length; i += 1) {
-      var option = oldOptions[i] || document.createElement("option");
-      option.value = xhrResults[1][i];
-      if (!oldOptions[i]) {
-        suggestions.appendChild(option);
-      }
-    }
+               // Update the list, reusing any existing items from the last 
search.
+               for ( i = 0; i < xhrResults[ 1 ].length; i += 1 ) {
+                       var option = oldOptions[ i ] || document.createElement( 
'option' );
+                       option.value = xhrResults[ 1 ][ i ];
+                       if ( !oldOptions[ i ] ) {
+                               suggestions.appendChild( option );
+                       }
+               }
 
-    // If this search has fewer results than the last one, trim the list.
-    for (i = suggestions.children.length - 1; i >= xhrResults[1].length; i -= 
1) {
-      suggestions.removeChild(suggestions.children[i]);
-    }
-  };
+               // If this search has fewer results than the last one, trim the 
list.
+               for ( i = suggestions.children.length - 1; i >= xhrResults[ 1 
].length; i -= 1 ) {
+                       suggestions.removeChild( suggestions.children[ i ] );
+               }
+       };
 
-  /**
-   * Stores the user's preferred language in a cookie. This function is called
-   * once a language other than the browser's default is selected from the
-   * dropdown.
-   */
-  function setLang(lang) {
-    if (!lang) {
-      return;
-    }
-    var uiLang = getUALang(),
-        match = uiLang.match(/^\w+/),
-        date = new Date();
+       /**
+        * Stores the user's preferred language in a cookie. This function is 
called
+        * once a language other than the browser's default is selected from the
+        * dropdown.
+        */
+       function setLang( lang ) {
+               if ( !lang ) {
+                       return;
+               }
+               var uiLang = getUALang(),
+                       match = uiLang.match( /^\w+/ ),
+                       date = new Date();
 
-    updateBranding(lang);
-    if (match && match[0] === lang) {
-      date.setTime(date.getTime() - 1);
-    } else {
-      date.setFullYear(date.getFullYear() + 1);
-    }
+               updateBranding( lang );
+               if ( match && match[ 0 ] === lang ) {
+                       date.setTime( date.getTime() - 1 );
+               } else {
+                       date.setFullYear( date.getFullYear() + 1 );
+               }
 
-    document.cookie = "searchLang=" + lang + ";expires=" +
-        date.toUTCString() + ";domain=" + location.host + ";";
-  }
+               document.cookie = 'searchLang=' + lang + ';expires=' +
+                       date.toUTCString() + ';domain=' + location.host + ';';
+       }
 
-  doWhenReady(function () {
-    var params, i, param,
-        search = $("searchInput"), select = $("searchLanguage");
+       doWhenReady( function () {
+               var params, i, param,
+                       search = $( 'searchInput' ),
+                       select = $( 'searchLanguage' );
 
-    if (search) {
-      // Add a search icon to the box in Safari.
-      search.setAttribute("results", "10");
-      setupSuggestions();
+               if ( search ) {
+                       // Add a search icon to the box in Safari.
+                       search.setAttribute( 'results', '10' );
+                       setupSuggestions();
 
-      if (search.autofocus === undefined) {
-        // Focus the search box.
-        search.focus();
-      } else {
-        // autofocus causes scrolling in most browsers that
-        // support it.
-        window.scroll(0, 0);
-      }
+                       if ( search.autofocus === undefined ) {
+                               // Focus the search box.
+                               search.focus();
+                       } else {
+                               // autofocus causes scrolling in most browsers 
that
+                               // support it.
+                               window.scroll( 0, 0 );
+                       }
 
-      // Prefills the search box with the "search" URL parameter.
-      params = location.search && location.search.substr(1).split("&");
-      for (i = 0; i < params.length; i += 1) {
-        param = params[i].split("=");
-        if (param[0] === "search" && param[1]) {
-          search.value = decodeURIComponent(param[1].replace(/\+/g, " "));
-          return;
-        }
-      }
-    }
+                       // Prefills the search box with the "search" URL 
parameter.
+                       params = location.search && location.search.substr( 1 
).split( '&' );
+                       for ( i = 0; i < params.length; i += 1 ) {
+                               param = params[ i ].split( '=' );
+                               if ( param[ 0 ] === 'search' && param[ 1 ] ) {
+                                       search.value = decodeURIComponent( 
param[ 1 ].replace( /\+/g, ' ' ) );
+                                       return;
+                               }
+                       }
+               }
 
-    addEvent(select, "change", function () {
-      setLang(select.value);
-    });
-  });
+               addEvent( select, 'change', function () {
+                       setLang( select.value );
+               } );
+       } );
 
-  doWhenReady(function () {
-    var uselang = document.searchwiki && document.searchwiki.elements.uselang;
-    if (uselang) {
-      // Don't use getSavedLang() since that uses the cookie for the search 
form.
-      // The searchwiki form should not be affected by the values in the 
searchpage form.
-      uselang.value = getUALang();
-    }
-  });
+       doWhenReady( function () {
+               var uselang = document.searchwiki && 
document.searchwiki.elements.uselang;
+               if ( uselang ) {
+                       // Don't use getSavedLang() since that uses the cookie 
for the search form.
+                       // The searchwiki form should not be affected by the 
values in the searchpage form.
+                       uselang.value = getUALang();
+               }
+       } );
 
-  // Based on jquery.hidpi module with the jQuery removed and support for the
-  // full srcset syntax added.
+       // Based on jquery.hidpi module with the jQuery removed and support for 
the
+       // full srcset syntax added.
 
-  /**
-   * Detects reported or approximate device pixel ratio.
-   * * 1.0 means 1 CSS pixel is 1 hardware pixel
-   * * 2.0 means 1 CSS pixel is 2 hardware pixels
-   * * etc.
-   *
-   * Uses window.devicePixelRatio if available, or CSS media queries on IE.
-   *
-   * @returns {number} Device pixel ratio
-   */
-  function devicePixelRatio() {
-    if ( window.devicePixelRatio !== undefined ) {
-      // Most web browsers:
-      // * WebKit (Safari, Chrome, Android browser, etc)
-      // * Opera
-      // * Firefox 18+
-      return window.devicePixelRatio;
-    } else if ( window.msMatchMedia !== undefined ) {
-      // Windows 8 desktops / tablets, probably Windows Phone 8
-      //
-      // IE 10 doesn't report pixel ratio directly, but we can get the
-      // screen DPI and divide by 96. We'll bracket to [1, 1.5, 2.0] for
-      // simplicity, but you may get different values depending on zoom
-      // factor, size of screen and orientation in Metro IE.
-      if ( window.msMatchMedia( "(min-resolution: 192dpi)" ).matches ) {
-        return 2;
-      } else if ( window.msMatchMedia( "(min-resolution: 144dpi)" ).matches ) {
-        return 1.5;
-      } else {
-        return 1;
-      }
-    } else {
-      // Legacy browsers...
-      // Assume 1 if unknown.
-      return 1;
-    }
-  }
+       /**
+        * Detects reported or approximate device pixel ratio.
+        * * 1.0 means 1 CSS pixel is 1 hardware pixel
+        * * 2.0 means 1 CSS pixel is 2 hardware pixels
+        * * etc.
+        *
+        * Uses window.devicePixelRatio if available, or CSS media queries on 
IE.
+        *
+        * @returns {number} Device pixel ratio
+        */
+       function devicePixelRatio() {
+               if ( window.devicePixelRatio !== undefined ) {
+                       // Most web browsers:
+                       // * WebKit (Safari, Chrome, Android browser, etc)
+                       // * Opera
+                       // * Firefox 18+
+                       return window.devicePixelRatio;
+               } else if ( window.msMatchMedia !== undefined ) {
+                       // Windows 8 desktops / tablets, probably Windows Phone 
8
+                       //
+                       // IE 10 doesn't report pixel ratio directly, but we 
can get the
+                       // screen DPI and divide by 96. We'll bracket to [1, 
1.5, 2.0] for
+                       // simplicity, but you may get different values 
depending on zoom
+                       // factor, size of screen and orientation in Metro IE.
+                       if ( window.msMatchMedia( '(min-resolution: 192dpi)' 
).matches ) {
+                               return 2;
+                       } else if ( window.msMatchMedia( '(min-resolution: 
144dpi)' ).matches ) {
+                               return 1.5;
+                       } else {
+                               return 1;
+                       }
+               } else {
+                       // Legacy browsers...
+                       // Assume 1 if unknown.
+                       return 1;
+               }
+       }
 
-  /**
-   * Matches a srcset entry for the given device pixel ratio.
-   *
-   * @param {number} devicePixelRatio
-   * @param {string} srcset
-   * @return {mixed} null or the matching src string
-   */
-  function matchSrcSet( devicePixelRatio, srcset ) {
-    var candidates,
-        candidate,
-        i,
-        ratio,
-        selection = {ratio: 1};
-    candidates = srcset.split( / *, */ );
-    for ( i = 0; i < candidates.length; i++ ) {
-      // 
http://www.w3.org/html/wg/drafts/srcset/w3c-srcset/#additions-to-the-img-element
-      candidate = 
candidates[i].match(/\s*(\S+)(?:\s*([\d.]+)w)?(?:\s*([\d.]+)h)?(?:\s*([\d.]+)x)?\s*/);
-      ratio = candidate[4] && parseFloat(candidate[4]);
-      if ( ratio <= devicePixelRatio && ratio > selection.ratio ) {
-        selection.ratio = ratio;
-        selection.src = candidate[1];
-        selection.width = candidate[2] && parseFloat(candidate[2]);
-        selection.height = candidate[3] && parseFloat(candidate[3]);
-      }
-    }
-    return selection;
-  }
+       /**
+        * Matches a srcset entry for the given device pixel ratio.
+        *
+        * @param {number} devicePixelRatio
+        * @param {string} srcset
+        * @return {mixed} null or the matching src string
+        */
+       function matchSrcSet( devicePixelRatio, srcset ) {
+               var candidates,
+                       candidate,
+                       i,
+                       ratio,
+                       selection = { ratio: 1 };
+               candidates = srcset.split( / *, */ );
+               for ( i = 0; i < candidates.length; i++ ) {
+                       // 
http://www.w3.org/html/wg/drafts/srcset/w3c-srcset/#additions-to-the-img-element
+                       candidate = candidates[ i ].match( 
/\s*(\S+)(?:\s*([\d.]+)w)?(?:\s*([\d.]+)h)?(?:\s*([\d.]+)x)?\s*/ );
+                       ratio = candidate[ 4 ] && parseFloat( candidate[ 4 ] );
+                       if ( ratio <= devicePixelRatio && ratio > 
selection.ratio ) {
+                               selection.ratio = ratio;
+                               selection.src = candidate[ 1 ];
+                               selection.width = candidate[ 2 ] && parseFloat( 
candidate[ 2 ] );
+                               selection.height = candidate[ 3 ] && 
parseFloat( candidate[ 3 ] );
+                       }
+               }
+               return selection;
+       }
 
-  /**
-   * Implements responsive images based on srcset attributes, if browser has
-   * no native srcset support.
-   */
-  function hidpi() {
-    var imgs, i,
-        ratio = devicePixelRatio(),
-        testImage = new Image();
+       /**
+        * Implements responsive images based on srcset attributes, if browser 
has
+        * no native srcset support.
+        */
+       function hidpi() {
+               var imgs, i,
+                       ratio = devicePixelRatio(),
+                       testImage = new Image();
 
-    if ( ratio > 1 && testImage.srcset === undefined ) {
-      // No native srcset support.
-      imgs = document.getElementsByTagName( "img" );
-      for ( i = 0; i < imgs.length; i++ ) {
-        var img = imgs[i],
-            srcset = img.getAttribute( "srcset" ),
-            match;
-        if ( typeof srcset === "string" && srcset !== "" ) {
-          match = matchSrcSet( ratio, srcset );
-          if ( match.src !== undefined ) {
-            img.setAttribute( "src", match.src );
-            if ( match.width !== undefined ) {
-              img.setAttribute( "width", match.width );
-            }
-            if ( match.height !== undefined ) {
-              img.setAttribute( "height", match.height );
-            }
-          }
-        }
-      }
-    }
-  }
-  doWhenReady(hidpi);
+               if ( ratio > 1 && testImage.srcset === undefined ) {
+                       // No native srcset support.
+                       imgs = document.getElementsByTagName( 'img' );
+                       for ( i = 0; i < imgs.length; i++ ) {
+                               var img = imgs[ i ],
+                                       srcset = img.getAttribute( 'srcset' ),
+                                       match;
+                               if ( typeof srcset === 'string' && srcset !== 
'' ) {
+                                       match = matchSrcSet( ratio, srcset );
+                                       if ( match.src !== undefined ) {
+                                               img.setAttribute( 'src', 
match.src );
+                                               if ( match.width !== undefined 
) {
+                                                       img.setAttribute( 
'width', match.width );
+                                               }
+                                               if ( match.height !== undefined 
) {
+                                                       img.setAttribute( 
'height', match.height );
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
 
-}());
+       doWhenReady( hidpi );
+
+}() );
 
 /*
  * Depending on how this script is loaded, it may not have
  * the mediaWiki global object.  Simulate if needed, for the
  * load.php?only=scripts response that calls mw.loader.state(.., ..);
  */
-if (!window.mw) {
-  window.mw = window.mediaWiki = {
-    loader: {
-      state: function () {}
-    }
-  };
+if ( !window.mw ) {
+       window.mw = window.mediaWiki = {
+               loader: {
+                       state: function () {
+                       }
+               }
+       };
 }
diff --git a/gulpfile.js b/gulpfile.js
index 54b47b0..512aa08 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -1,66 +1,65 @@
-var gulp = require('gulp'),
-    gulpLoadPlugins = require('gulp-load-plugins');
+/*jshint strict:false */
+var gulp = require( 'gulp' ),
+       gulpLoadPlugins = require( 'gulp-load-plugins' ),
+       exec = require( 'child_process' ).exec,
+       argv = require( 'yargs' ).argv,
+       imageminPngquant = require( 'imagemin-pngquant' );
 
-var exec = require('child_process').exec;
+var plugins = gulpLoadPlugins(),
+       portalParam = argv.portal;
 
-var argv = require('yargs').argv;
-
-var plugins = gulpLoadPlugins();
-
-var imageminPngquant = require('imagemin-pngquant');
-
-var portalParam = argv.portal;
-
-if (!portalParam && process.argv[2] !== "help") {
-  console.log("\x1b[31m");
-  console.log("Error: please specify the portal you wish to build.");
-  console.log("Type gulp help for more information.");
-  console.log("\x1b[0m");
-  process.exit(1);
+if ( !portalParam && process.argv[ 2 ] !== 'help' ) {
+       console.log( '\x1b[31m' );
+       console.log( 'Error: please specify the portal you wish to build.' );
+       console.log( 'Type gulp help for more information.' );
+       console.log( '\x1b[0m' );
+       process.exit( 1 );
 }
 
-var baseDir = "dev/"+portalParam+"/";
-var prodDir = "prod/"+portalParam+"/";
+var baseDir = 'dev/' + portalParam + '/',
+       prodDir = 'prod/' + portalParam + '/';
 
-gulp.task('help', function () {
-  console.log();
-  
console.log('+-------------------------------------------------------------------------------------------------+');
-  console.log('|                                     =====  USAGE     =====    
                                  |');
-  
console.log('+-------------------------------------------------------------------------------------------------+');
-  console.log('| gulp inline-assets --portal wikipedia.org   - build inline 
CSS and JS assets                    |');
-  console.log('| gulp optimize-images --portal wikipedia.org - run imagemin on 
image directory                   |');
-  console.log('| gulp lint --portal wikipedia.org            - run jslint on 
JS files on portal                  |');
-  console.log('| gulp --portal wikipedia.org                 - run all of the 
above on the specified portal page |');
-  
console.log('+-------------------------------------------------------------------------------------------------+');
-  console.log();
-});
+gulp.task( 'help', function () {
+       console.log();
+       console.log( 
'+-------------------------------------------------------------------------------------------------+'
 );
+       console.log( '|                                     =====  USAGE     
=====                                      |' );
+       console.log( 
'+-------------------------------------------------------------------------------------------------+'
 );
+       console.log( '| gulp inline-assets --portal wikipedia.org   - build 
inline CSS and JS assets                    |' );
+       console.log( '| gulp optimize-images --portal wikipedia.org - run 
imagemin on image directory                   |' );
+       console.log( '| gulp lint --portal wikipedia.org            - run 
jslint on JS files on portal                  |' );
+       console.log( '| gulp --portal wikipedia.org                 - run all 
of the above on the specified portal page |' );
+       console.log( 
'+-------------------------------------------------------------------------------------------------+'
 );
+       console.log();
+} );
 
-gulp.task('inline-assets', function(){
-  gulp.src(baseDir+"index.html")
-      .pipe(plugins.inline({
-        base: baseDir,
-        js: plugins.uglify,
-        css: plugins.minifyCss,
-        disabledTypes: ["svg", "img"]
-      }))
-      .pipe(gulp.dest(prodDir));
-});
+gulp.task( 'inline-assets', function () {
+       gulp.src( baseDir + 'index.html' )
+               .pipe( plugins.inline( {
+                       base: baseDir,
+                       js: plugins.uglify,
+                       css: plugins.minifyCss,
+                       disabledTypes: [ 'svg', 'img' ]
+               } ) )
+               .pipe( gulp.dest( prodDir ) );
+} );
 
-gulp.task('optimize-images', function(){
-  gulp.src(baseDir+"assets/img/*")
-      .pipe(imageminPngquant({quality: '80-95', speed: 1})())
-      .pipe(plugins.imagemin())
-      .pipe(gulp.dest(prodDir+"assets/img"));
-});
+gulp.task( 'optimize-images', function () {
+       gulp.src( baseDir + 'assets/img/*' )
+               .pipe( imageminPngquant( { quality: '80-95', speed: 1 } )() )
+               .pipe( plugins.imagemin() )
+               .pipe( gulp.dest( prodDir + 'assets/img' ) );
+} );
 
-gulp.task('lint', function(){
-  gulp.src(baseDir+"assets/js/*.js")
-      .pipe(plugins.jshint(".jshintrc"))
-      .pipe(plugins.jshint.reporter('default'));
-});
+gulp.task( 'lint', function () {
+       gulp.src( [ 'gulpfile.js', baseDir + 'assets/js/*.js' ] )
+               .pipe( plugins.jshint( '.jshintrc' ) )
+               .pipe( plugins.jshint.reporter( 'default' ) )
+               .pipe( plugins.jscs() )
+               .pipe( plugins.jscs.reporter() );
+} );
 
-gulp.task('prod-symlink', function(){
-  exec("cd "+prodDir+" && ln -s ../../ portal");
-});
+gulp.task( 'prod-symlink', function () {
+       exec( 'cd ' + prodDir + ' && ln -s ../../ portal' );
+} );
 
-gulp.task('default', ['lint', 'inline-assets', 'optimize-images', 
'prod-symlink']);
\ No newline at end of file
+gulp.task( 'default', [ 'lint', 'inline-assets', 'optimize-images', 
'prod-symlink' ] );
diff --git a/package.json b/package.json
index 5be88ab..f74db3e 100644
--- a/package.json
+++ b/package.json
@@ -2,13 +2,14 @@
   "dependencies": {},
   "devDependencies": {
     "gulp": "^3.9.0",
+    "gulp-imagemin": "^2.3.0",
     "gulp-inline": "^0.1.0",
+    "gulp-jscs": "^3.0.2",
     "gulp-jshint": "^1.11.2",
     "gulp-load-plugins": "^1.0.0",
     "gulp-minify-css": "^1.2.1",
     "gulp-uglify": "^1.4.2",
-    "yargs": "^3.29.0",
-    "gulp-imagemin": "^2.3.0",
-    "imagemin-pngquant": "^4.2.0"
+    "imagemin-pngquant": "^4.2.0",
+    "yargs": "^3.29.0"
   }
-}
\ No newline at end of file
+}
diff --git a/prod/wikipedia.org/index.html b/prod/wikipedia.org/index.html
index 03489fd..61b01d9 100644
--- a/prod/wikipedia.org/index.html
+++ b/prod/wikipedia.org/index.html
@@ -599,7 +599,7 @@
 <div style="text-align:center"><span id="discovery-feedback-survey" 
style="display:none"><a 
href="//wikimedia.qualtrics.com/jfe/form/SV_3rZFiKhpb2JzWbb">Give Us 
Feedback</a> | </span><a 
href="//wikimediafoundation.org/wiki/Terms_of_Use">Terms of Use</a> | <a 
href="//wikimediafoundation.org/wiki/Privacy_policy">Privacy Policy</a></div>
 <script>if (Math.floor( Math.random() * 5 ) === 0) { document.getElementById( 
"discovery-feedback-survey" ).style.display="inline"; }</script>
 <script>
-!function(){"use strict";function e(e){return 
document.getElementById(e)}function 
t(e,t,n){e&&(e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent&&(m.push([e,t,n]),e.attachEvent("on"+t,n)))}function
 
n(e,t,n){e&&(e.removeEventListener?e.removeEventListener(t,n):e.detachEvent&&e.detachEvent("on"+t,n))}function
 a(e){var 
a=function(){n(document,"DOMContentLoaded",a),n(window,"load",a),e()};"complete"===document.readyState?e():(t(document,"DOMContentLoaded",a),t(window,"load",a))}function
 i(e){var 
t,n;document.querySelector&&"www-wiktionary-org"===document.body.id&&(t=document.querySelector("option[lang|='"+e+"']"),n=t&&t.getAttribute("data-logo"),n&&document.body.setAttribute("data-logo",n))}function
 o(){var 
e=navigator.languages&&navigator.languages[0]||navigator.language||navigator.userLanguage||"";return
 e.toLowerCase().split("-")[0]}function r(){var 
e=document.cookie.match(/(?:^|\W)searchLang=([^;]+)/);return(e?e[1]:o()).toLowerCase()}function
 c(t){var 
n,a,i="data-convert-Hans",o="data-convertTitle-Hans";if(-1!=="zh-hans,zh-cn,zh-sg,zh-my,".indexOf(t+",")){var
 
r=["zh_art","zh_others","zh_search","zh_tag","zh_top10","zh-yue_wiki","gan_wiki","hak_wiki","wuu_wiki"];for(n=0;n<r.length;n+=1)(a=e(r[n]))&&(a.hasAttribute(i)&&(a.innerHTML=a.getAttribute(i)),a.hasAttribute(o)&&(a.title=a.getAttribute(o)))}}function
 s(t){var 
n;0===t.indexOf("zh")&&(n=t.substring(3),"mo"===n?n="hk":"my"===n&&(n="sg"),n&&"cn,tw,hk,sg,".indexOf(n+",")>=0&&(e("zh_wiki").href+="zh-"+n+"/",e("zh_others").href=e("zh_others").href.replace("wiki/","zh-"+n+"/")),c(t))}function
 u(){if(void 0!==window.HTMLDataListElement){var 
n=document.createElement("datalist"),a=e("searchInput");n.id="suggestions",document.body.appendChild(n),a.autocomplete="off",a.setAttribute("list","suggestions"),t(a,"input",function(){var
 
t=document.getElementsByTagName("head")[0],n=window.location.hostname.replace("www.",e("searchLanguage").value+"."),i=e("api_opensearch");i&&t.removeChild(i),i=document.createElement("script"),i.id="api_opensearch",i.src="//"+n+"/w/api.php?action=opensearch&limit=10&format=json&callback=portalOpensearchCallback&search="+a.value,t.appendChild(i)})}}function
 d(e){if(e){var t=o(),n=t.match(/^\w+/),a=new 
Date;i(e),n&&n[0]===e?a.setTime(a.getTime()-1):a.setFullYear(a.getFullYear()+1),document.cookie="searchLang="+e+";expires="+a.toUTCString()+";domain="+location.host+";"}}function
 h(){return void 0!==window.devicePixelRatio?window.devicePixelRatio:void 
0!==window.msMatchMedia?window.msMatchMedia("(min-resolution: 
192dpi)").matches?2:window.msMatchMedia("(min-resolution: 
144dpi)").matches?1.5:1:1}function l(e,t){var 
n,a,i,o,r={ratio:1};for(n=t.split(/ *, 
*/),i=0;i<n.length;i++)a=n[i].match(/\s*(\S+)(?:\s*([\d.]+)w)?(?:\s*([\d.]+)h)?(?:\s*([\d.]+)x)?\s*/),o=a[4]&&parseFloat(a[4]),e>=o&&o>r.ratio&&(r.ratio=o,r.src=a[1],r.width=a[2]&&parseFloat(a[2]),r.height=a[3]&&parseFloat(a[3]));return
 r}function g(){var e,t,n=h(),a=new Image;if(n>1&&void 
0===a.srcset)for(e=document.getElementsByTagName("img"),t=0;t<e.length;t++){var 
i,o=e[t],r=o.getAttribute("srcset");"string"==typeof r&&""!==r&&(i=l(n,r),void 
0!==i.src&&(o.setAttribute("src",i.src),void 
0!==i.width&&o.setAttribute("width",i.width),void 
0!==i.height&&o.setAttribute("height",i.height)))}}var 
m=[];window.onunload=function(){var 
e,t;for(e=0;e<m.length;e++)t=m[e],t[0]&&t[0].detachEvent("on"+t[1],t[2]);m=[]},a(function(){var
 
t,n,a,o,c,u,d,h,l=r();if(l&&(s(l),t=l.match(/^\w+/),t&&(t="nb"===t[0]?"no":t[0],n=e("searchLanguage")))){for(a=n.getElementsByTagName("option"),o=0,c=a.length;!u&&c>o;o+=1)a[o].value===t&&(u=t);!u&&document.querySelector&&(d=document.querySelector(".langlist
 
a[lang|='"+t+"']"),d&&(u=t,h=document.createElement("option"),h.setAttribute("lang",t),h.setAttribute("value",t),h.innerHTML=d.textContent||d.innerText||t,n.appendChild(h))),u&&(n.value=u,i(u))}}),window.portalOpensearchCallback=function(t){var
 n,a=e("suggestions"),i=a.children;for(n=0;n<t[1].length;n+=1){var 
o=i[n]||document.createElement("option");o.value=t[1][n],i[n]||a.appendChild(o)}for(n=a.children.length-1;n>=t[1].length;n-=1)a.removeChild(a.children[n])},a(function(){var
 
n,a,i,o=e("searchInput"),r=e("searchLanguage");if(o)for(o.setAttribute("results","10"),u(),void
 
0===o.autofocus?o.focus():window.scroll(0,0),n=location.search&&location.search.substr(1).split("&"),a=0;a<n.length;a+=1)if(i=n[a].split("="),"search"===i[0]&&i[1])return
 void(o.value=decodeURIComponent(i[1].replace(/\+/g," 
")));t(r,"change",function(){d(r.value)})}),a(function(){var 
e=document.searchwiki&&document.searchwiki.elements.uselang;e&&(e.value=o())}),a(g)}(),window.mw||(window.mw=window.mediaWiki={loader:{state:function(){}}});
+!function(){"use strict";function e(e){return 
document.getElementById(e)}function 
t(e,t,n){e&&(e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent&&(m.push([e,t,n]),e.attachEvent("on"+t,n)))}function
 
n(e,t,n){e&&(e.removeEventListener?e.removeEventListener(t,n):e.detachEvent&&e.detachEvent("on"+t,n))}function
 a(e){var 
a=function(){n(document,"DOMContentLoaded",a),n(window,"load",a),e()};"complete"===document.readyState?e():(t(document,"DOMContentLoaded",a),t(window,"load",a))}function
 i(e){var 
t,n;document.querySelector&&"www-wiktionary-org"===document.body.id&&(t=document.querySelector('option[lang|="'+e+'"]'),n=t&&t.getAttribute("data-logo"),n&&document.body.setAttribute("data-logo",n))}function
 o(){var 
e=navigator.languages&&navigator.languages[0]||navigator.language||navigator.userLanguage||"";return
 e.toLowerCase().split("-")[0]}function r(){var 
e=document.cookie.match(/(?:^|\W)searchLang=([^;]+)/);return(e?e[1]:o()).toLowerCase()}function
 c(t){var 
n,a,i="data-convert-hans",o="data-converttitle-hans";if(-1!=="zh-hans,zh-cn,zh-sg,zh-my,".indexOf(t+",")){var
 
r=["zh_art","zh_others","zh_search","zh_tag","zh_top10","zh-yue_wiki","gan_wiki","hak_wiki","wuu_wiki"];for(n=0;n<r.length;n+=1)(a=e(r[n]))&&(a.hasAttribute(i)&&(a.innerHTML=a.getAttribute(i)),a.hasAttribute(o)&&(a.title=a.getAttribute(o)))}}function
 s(t){var 
n;0===t.indexOf("zh")&&(n=t.substring(3),"mo"===n?n="hk":"my"===n&&(n="sg"),n&&"cn,tw,hk,sg,".indexOf(n+",")>=0&&(e("zh_wiki").href+="zh-"+n+"/",e("zh_others").href=e("zh_others").href.replace("wiki/","zh-"+n+"/")),c(t))}function
 u(){if(void 0!==window.HTMLDataListElement){var 
n=document.createElement("datalist"),a=e("searchInput");n.id="suggestions",document.body.appendChild(n),a.autocomplete="off",a.setAttribute("list","suggestions"),t(a,"input",function(){var
 
t=document.getElementsByTagName("head")[0],n=window.location.hostname.replace("www.",e("searchLanguage").value+"."),i=e("api_opensearch");i&&t.removeChild(i),i=document.createElement("script"),i.id="api_opensearch",i.src="//"+n+"/w/api.php?action=opensearch&limit=10&format=json&callback=portalOpensearchCallback&search="+a.value,t.appendChild(i)})}}function
 d(e){if(e){var t=o(),n=t.match(/^\w+/),a=new 
Date;i(e),n&&n[0]===e?a.setTime(a.getTime()-1):a.setFullYear(a.getFullYear()+1),document.cookie="searchLang="+e+";expires="+a.toUTCString()+";domain="+location.host+";"}}function
 h(){return void 0!==window.devicePixelRatio?window.devicePixelRatio:void 
0!==window.msMatchMedia?window.msMatchMedia("(min-resolution: 
192dpi)").matches?2:window.msMatchMedia("(min-resolution: 
144dpi)").matches?1.5:1:1}function l(e,t){var 
n,a,i,o,r={ratio:1};for(n=t.split(/ *, 
*/),i=0;i<n.length;i++)a=n[i].match(/\s*(\S+)(?:\s*([\d.]+)w)?(?:\s*([\d.]+)h)?(?:\s*([\d.]+)x)?\s*/),o=a[4]&&parseFloat(a[4]),e>=o&&o>r.ratio&&(r.ratio=o,r.src=a[1],r.width=a[2]&&parseFloat(a[2]),r.height=a[3]&&parseFloat(a[3]));return
 r}function g(){var e,t,n=h(),a=new Image;if(n>1&&void 
0===a.srcset)for(e=document.getElementsByTagName("img"),t=0;t<e.length;t++){var 
i,o=e[t],r=o.getAttribute("srcset");"string"==typeof r&&""!==r&&(i=l(n,r),void 
0!==i.src&&(o.setAttribute("src",i.src),void 
0!==i.width&&o.setAttribute("width",i.width),void 
0!==i.height&&o.setAttribute("height",i.height)))}}var 
m=[];window.onunload=function(){var 
e,t;for(e=0;e<m.length;e++)t=m[e],t[0]&&t[0].detachEvent("on"+t[1],t[2]);m=[]},a(function(){var
 
t,n,a,o,c,u,d,h,l=r();if(l&&(s(l),t=l.match(/^\w+/),t&&(t="nb"===t[0]?"no":t[0],n=e("searchLanguage")))){for(a=n.getElementsByTagName("option"),o=0,c=a.length;!u&&c>o;o+=1)a[o].value===t&&(u=t);!u&&document.querySelector&&(d=document.querySelector('.langlist
 
a[lang|="'+t+'"]'),d&&(u=t,h=document.createElement("option"),h.setAttribute("lang",t),h.setAttribute("value",t),h.innerHTML=d.textContent||d.innerText||t,n.appendChild(h))),u&&(n.value=u,i(u))}}),window.portalOpensearchCallback=function(t){var
 n,a=e("suggestions"),i=a.children;for(n=0;n<t[1].length;n+=1){var 
o=i[n]||document.createElement("option");o.value=t[1][n],i[n]||a.appendChild(o)}for(n=a.children.length-1;n>=t[1].length;n-=1)a.removeChild(a.children[n])},a(function(){var
 
n,a,i,o=e("searchInput"),r=e("searchLanguage");if(o)for(o.setAttribute("results","10"),u(),void
 
0===o.autofocus?o.focus():window.scroll(0,0),n=location.search&&location.search.substr(1).split("&"),a=0;a<n.length;a+=1)if(i=n[a].split("="),"search"===i[0]&&i[1])return
 void(o.value=decodeURIComponent(i[1].replace(/\+/g," 
")));t(r,"change",function(){d(r.value)})}),a(function(){var 
e=document.searchwiki&&document.searchwiki.elements.uselang;e&&(e.value=o())}),a(g)}(),window.mw||(window.mw=window.mediaWiki={loader:{state:function(){}}});
 </script>
 </body>
 </html>

-- 
To view, visit https://gerrit.wikimedia.org/r/249953
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I8b58ac72c66dd8f81b6c46360829241e8e2b8357
Gerrit-PatchSet: 1
Gerrit-Project: wikimedia/portals
Gerrit-Branch: master
Gerrit-Owner: JGirault <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to