From d85150d7c927f73f759bf24fb7db57e0f2d0906e Mon Sep 17 00:00:00 2001 From: Darren Hurley Date: Fri, 15 Aug 2014 17:35:08 +0100 Subject: [PATCH 1/6] use lodash, for IE support --- .../javascripts/bootstraps/commercial.js | 15 ++-- .../modules/analytics/clickstream.js | 12 ++-- .../javascripts/modules/commercial/dfp.js | 30 ++++---- .../modules/commercial/keywords.js | 8 ++- .../javascripts/modules/commercial/loader.js | 16 +++-- .../modules/commercial/slice-adverts.js | 27 ++++--- .../tags/audience-science-gateway.js | 22 +++--- .../modules/commercial/tags/media-math.js | 25 +++---- .../javascripts/modules/commercial/video.js | 14 ++-- .../javascripts/modules/experiments/ab.js | 62 ++++++++++------ .../modules/onward/popular-fronts.js | 2 +- common/app/assets/javascripts/utils/$.js | 14 ++-- common/app/assets/javascripts/utils/config.js | 18 +++-- .../app/assets/javascripts/utils/cookies.js | 10 ++- .../app/assets/javascripts/utils/template.js | 10 ++- .../fragments/javaScriptFirstSteps.scala.html | 71 ++++++++++++++++++- .../fragments/javaScriptLaterSteps.scala.html | 2 +- 17 files changed, 241 insertions(+), 117 deletions(-) diff --git a/common/app/assets/javascripts/bootstraps/commercial.js b/common/app/assets/javascripts/bootstraps/commercial.js index 93e08792adaf..6830a930d637 100644 --- a/common/app/assets/javascripts/bootstraps/commercial.js +++ b/common/app/assets/javascripts/bootstraps/commercial.js @@ -1,6 +1,7 @@ define([ 'bonzo', 'qwery', + 'lodash/collections/forEach', 'common/utils/config', 'common/modules/userPrefs', 'common/modules/commercial/tags/container', @@ -14,6 +15,7 @@ define([ ], function ( bonzo, qwery, + forEach, config, userPrefs, tagsContainer, @@ -29,10 +31,12 @@ define([ function init() { // forces a commercial component on a page, for testing - [ - ['commercial-component', 'merchandising'], - ['commercial-component-high', 'merchandising-high'] - ].forEach(function(data) { + forEach( + [ + ['commercial-component', 'merchandising'], + ['commercial-component-high', 'merchandising-high'] + ], + function(data) { var commercialComponent = new RegExp('^#' + data[0] + '=(.*)$').exec(window.location.hash), slot = qwery('[data-name="' + data[1] + '"]').shift(); if (commercialComponent && slot) { @@ -45,7 +49,8 @@ define([ loader.postLoadEvents = postLoadEvents; loader.init(commercialComponent[1], slot); } - }); + } + ); if (!userPrefs.isOff('adverts') && !config.page.shouldHideAdverts && !config.page.isSSL) { diff --git a/common/app/assets/javascripts/modules/analytics/clickstream.js b/common/app/assets/javascripts/modules/analytics/clickstream.js index 8ca74063f9ca..9081ec6ddc1b 100644 --- a/common/app/assets/javascripts/modules/analytics/clickstream.js +++ b/common/app/assets/javascripts/modules/analytics/clickstream.js @@ -1,12 +1,14 @@ define([ - 'common/utils/mediator', - 'common/utils/detect', 'bean', + 'lodash/collections/map', + 'common/utils/detect', + 'common/utils/mediator', 'common/modules/experiments/ab' ], function ( - mediator, - detect, bean, + map, + detect, + mediator, ab ) { @@ -107,7 +109,7 @@ define([ // prefix ab tests to the click spec var applicableTests = ab.getActiveTestsEventIsApplicableTo(clickSpec); if (applicableTests !== undefined && applicableTests.length > 0) { - clickSpec.tag = applicableTests.map(function (test) { + clickSpec.tag = map(applicableTests, function (test) { var variant = ab.getTestVariant(test); return 'AB,' + test + ',' + variant + ',' + clickSpec.tag; }).join(','); diff --git a/common/app/assets/javascripts/modules/commercial/dfp.js b/common/app/assets/javascripts/modules/commercial/dfp.js index 3e0a70b21f1d..b7f316ca1f7d 100644 --- a/common/app/assets/javascripts/modules/commercial/dfp.js +++ b/common/app/assets/javascripts/modules/commercial/dfp.js @@ -5,12 +5,14 @@ define([ 'lodash/functions/debounce', 'lodash/arrays/flatten', 'lodash/arrays/uniq', + 'lodash/collections/map', 'lodash/functions/once', 'lodash/objects/defaults', 'lodash/objects/forOwn', 'lodash/objects/isArray', 'lodash/objects/pairs', 'common/utils/$', + 'common/utils/_', 'common/utils/cookies', 'common/utils/detect', 'common/utils/mediator', @@ -28,12 +30,14 @@ define([ debounce, flatten, uniq, + map, once, defaults, forOwn, isArray, pairs, $, + _, cookies, detect, mediator, @@ -209,8 +213,8 @@ define([ * Multiple sizes - `data-mobile="300,50|320,50"` */ createSizeMapping = function (attr) { - return attr.split('|').map(function(size) { - return size.split(',').map(Number); + return map(attr.split('|'), function(size) { + return map(size.split(','), Number); }); }, /** @@ -310,8 +314,8 @@ define([ '{{sizeMappings}}>', { name: name, - types: (isArray(types) ? types : [types]).map(function(type) { return 'ad-slot--' + type; }).join(' '), - sizeMappings: pairs(definition.sizeMappings).map(function(size) { return ' data-' + size[0] + '="' + size[1] + '"'; }).join('') + types: map((isArray(types) ? types : [types]), function(type) { return 'ad-slot--' + type; }).join(' '), + sizeMappings: map(pairs(definition.sizeMappings), function(size) { return ' data-' + size[0] + '="' + size[1] + '"'; }).join('') })); for (var attrName in dataAttrs) { if (dataAttrs[attrName] === false) { @@ -324,14 +328,13 @@ define([ return $adSlot[0]; }, parseKeywords = function(keywords) { - return (keywords || '') - .split(',').map(function (keyword) { - return keyword.split('/').pop(); - }); + return map((keywords || '') .split(','), function (keyword) { + return keyword.split('/').pop(); + }); }, parseContributors = function(contributors) { var contributorArray = parseKeywords(contributors); - return contributorArray.map(function(contrib) { + return map(contributorArray, function(contrib) { return keywords.format(contrib); }); }; @@ -427,14 +430,17 @@ define([ config.adSlotSelector = '.ad-slot--dfp:not(.ad-slot--commercial-component)'; } - adSlots = qwery(config.adSlotSelector) + adSlots = _(qwery(config.adSlotSelector)) // filter out hidden ads .map(function (adSlot) { return bonzo(adSlot); }) .filter(function ($adSlot) { - return $adSlot.css('display') !== 'none'; - }); + // bonzo needs these - default to true if unavailable (e.g. IE8) + return (window.document.defaultView && window.document.defaultView.getComputedStyle) + ? $adSlot.css('display') !== 'none' : true; + }) + .valueOf(); if (adSlots.length > 0) { // if we don't already have googletag, create command queue (assumes it's loaded further up the chain) diff --git a/common/app/assets/javascripts/modules/commercial/keywords.js b/common/app/assets/javascripts/modules/commercial/keywords.js index 36d09f139cda..700c78a6b052 100644 --- a/common/app/assets/javascripts/modules/commercial/keywords.js +++ b/common/app/assets/javascripts/modules/commercial/keywords.js @@ -1,11 +1,15 @@ -define(function () { +define([ + 'lodash/collections/map' +], function( + map +) { function format(keyword) { return keyword.replace(/[+\s]+/g, '-').toLowerCase(); } function get(config) { - return config.keywords.split(',').map(function(keyword){ + return map(config.keywords.split(','), function(keyword){ return 'k=' + encodeURIComponent(format(keyword)); }).join('&'); } diff --git a/common/app/assets/javascripts/modules/commercial/loader.js b/common/app/assets/javascripts/modules/commercial/loader.js index ffe3f350e118..4597c44f7d77 100644 --- a/common/app/assets/javascripts/modules/commercial/loader.js +++ b/common/app/assets/javascripts/modules/commercial/loader.js @@ -3,24 +3,26 @@ Description: Loads our commercial components */ define([ + 'bean', 'bonzo', + 'lodash/collections/map', 'common/utils/$', 'common/utils/config', 'common/utils/mediator', 'common/utils/storage', - 'common/modules/lazyload', 'common/modules/component', - 'bean', + 'common/modules/lazyload', 'common/modules/ui/tabs' ], function ( + bean, bonzo, + map, $, config, mediator, storage, - LazyLoad, Component, - bean, + LazyLoad, Tabs ) { @@ -50,8 +52,8 @@ define([ this.isbn = page.isbn || ''; this.oastoken = options.oastoken || ''; this.adType = options.adType || 'desktop'; - this.multiComponents = (options.components || []).map(function(c) { return 'c=' + c; }).join('&'); - this.capi = (options.capi || []).map(function(t) {return 't=' + t;}).join('&'); + this.multiComponents = map(options.components || [], function(c) { return 'c=' + c; }).join('&'); + this.capi = map(options.capi || [], function(t) {return 't=' + t;}).join('&'); this.components = { bestbuy: this.host + 'money/bestbuys.json', bestbuyHigh: this.host + 'money/bestbuys-high.json', @@ -97,7 +99,7 @@ define([ Loader.prototype.getKeywords = function () { if (this.keywordIds) { - return this.keywordIds.split(',').map(function (keywordId) { + return map(this.keywordIds.split(','), function (keywordId) { return 'k=' + encodeURIComponent(keywordId.split('/').pop()); }).join('&'); } else { diff --git a/common/app/assets/javascripts/modules/commercial/slice-adverts.js b/common/app/assets/javascripts/modules/commercial/slice-adverts.js index 7ff9a34c6eb1..4b4f982cd045 100644 --- a/common/app/assets/javascripts/modules/commercial/slice-adverts.js +++ b/common/app/assets/javascripts/modules/commercial/slice-adverts.js @@ -1,9 +1,11 @@ define([ 'bonzo', 'qwery', - 'lodash/objects/defaults', + 'lodash/collections/contains', 'lodash/functions/once', + 'lodash/objects/defaults', 'common/utils/$', + 'common/utils/_', 'common/utils/config', 'common/utils/template', 'common/modules/userPrefs', @@ -11,9 +13,11 @@ define([ ], function ( bonzo, qwery, - defaults, + contains, once, + defaults, $, + _, globalConfig, template, userPrefs, @@ -50,7 +54,7 @@ define([ containerId = bonzo(container).data('id'), $adSlice = $(config.sliceSelector, container), // don't display ad in the first container on the fronts - isFrontFirst = ['uk', 'us', 'au'].indexOf(config.page.pageId) > -1 && index === 0; + isFrontFirst = contains(['uk', 'us', 'au'], config.page.pageId) && index === 0; if ($adSlice.length && !isFrontFirst && (!prefs || prefs[containerId] !== 'closed')) { adSlices.push($adSlice.first()); index += (containerGap + 1); @@ -59,13 +63,16 @@ define([ } } - adSlices.slice(0, adNames.length).forEach(function($adSlice, index) { - var adName = adNames[index], - $adSlot = bonzo(dfp.createAdSlot(adName, 'container-inline')); - $adSlice - .addClass('slice--has-ad') - .append($adSlot); - }); + _(adSlices) + .slice(0, adNames.length) + .forEach(function($adSlice, index) { + var adName = adNames[index], + $adSlot = bonzo(dfp.createAdSlot(adName, 'container-inline')); + $adSlice + .addClass('slice--has-ad') + .append($adSlot); + }) + .valueOf(); return adSlices; }; diff --git a/common/app/assets/javascripts/modules/commercial/tags/audience-science-gateway.js b/common/app/assets/javascripts/modules/commercial/tags/audience-science-gateway.js index db2ae049152f..6c29599d1203 100644 --- a/common/app/assets/javascripts/modules/commercial/tags/audience-science-gateway.js +++ b/common/app/assets/javascripts/modules/commercial/tags/audience-science-gateway.js @@ -1,14 +1,14 @@ define([ - 'lodash/arrays/zipObject', 'lodash/functions/once', 'lodash/objects/pairs', + 'common/utils/_', 'common/utils/config', 'common/utils/storage', 'common/utils/url' ], function ( - zipObject, once, pairs, + _, config, storage, urlUtils @@ -38,15 +38,15 @@ define([ return require(['js!' + url + '!exports=asiPlacements']) .then(function(asiPlacements) { var segments = storage.local.get(storageKey) || {}; - segments[section] = zipObject( - pairs(asiPlacements) - .filter(function(placement) { - return placement[1]['default']; - }) - .map(function(placement) { - return ['pq_' + placement[0], 'T']; - }) - ); + segments[section] = _(pairs(asiPlacements)) + .filter(function(placement) { + return placement[1]['default']; + }) + .map(function(placement) { + return ['pq_' + placement[0], 'T']; + }) + .zipObject() + .valueOf(); storage.local.set(storageKey, segments); }); } diff --git a/common/app/assets/javascripts/modules/commercial/tags/media-math.js b/common/app/assets/javascripts/modules/commercial/tags/media-math.js index 037a7814e511..deec361cf497 100644 --- a/common/app/assets/javascripts/modules/commercial/tags/media-math.js +++ b/common/app/assets/javascripts/modules/commercial/tags/media-math.js @@ -1,25 +1,25 @@ define([ - 'common/utils/config', 'lodash/objects/defaults', - 'lodash/objects/pairs' + 'common/utils/_', + 'common/utils/config', + 'common/utils/url' ], function( - defaultConfig, defaults, - pairs + _, + defaultConfig, + urlUtils ) { var mediaMathBaseUrl = '//pixel.mathtag.com/event/img?mt_id=328671&mt_adid=114751', extractSearchTerm = function (referrer) { - return referrer - .split('?') - .pop() - .split('&') + return _(referrer.split('?').pop().split('&')) .filter(function(query) { return ['q','p','as_q','as_epq','as_oq','query','search','wd','ix'].indexOf(query.split('=').shift()) > -1; }) .map(function(searchQuery) { return decodeURIComponent(searchQuery.split('=').pop().replace(/\\+/g, ' ')); }) + .valueOf() .shift(); }; @@ -40,20 +40,17 @@ define([ } var page = config.page, - tags = pairs({ + tags = { v1: (page.host ? page.host : '') + '/' + page.pageId, v2: page.section, v3: extractSearchTerm(config.referrer), v4: config.referrer, v5: page.keywords ? page.keywords.replace(/,/g, '|') : '', v6: page.contentType ? page.contentType.toLowerCase() : '' - }) - // turn into a query string - .map(function (pair) { return pair.join('='); }) - .join('&'); + }; var img = new Image(); - img.src = mediaMathBaseUrl + '&' + tags; + img.src = mediaMathBaseUrl + '&' + urlUtils.constructQuery(tags); return img; } }; diff --git a/common/app/assets/javascripts/modules/commercial/video.js b/common/app/assets/javascripts/modules/commercial/video.js index 81cee5f23db1..cfd2bdb9cc17 100644 --- a/common/app/assets/javascripts/modules/commercial/video.js +++ b/common/app/assets/javascripts/modules/commercial/video.js @@ -1,20 +1,22 @@ define([ + 'bean', + 'lodash/collections/map', 'common/utils/$', + 'common/utils/ajax', 'common/utils/mediator', 'common/utils/to-array', - 'bean', - 'common/utils/ajax', 'common/utils/url', 'common/modules/commercial/dfp' ], function( + bean, + map, $, + ajax, mediator, toArray, - bean, - ajax, urlUtils, dfp - ) { +) { function Video(config) { this.config = config.config; @@ -156,7 +158,7 @@ define([ impressionList = (xml.querySelector('Impression URL')) ? xml.querySelectorAll('Impression URL') : xml.querySelectorAll('Impression'); - this.vastData.impressionEvents = toArray(impressionList).map(function(el) { + this.vastData.impressionEvents = map(toArray(impressionList), function(el) { return self.getNodeContent(el); }); diff --git a/common/app/assets/javascripts/modules/experiments/ab.js b/common/app/assets/javascripts/modules/experiments/ab.js index 890dfbf041da..565db3824d94 100644 --- a/common/app/assets/javascripts/modules/experiments/ab.js +++ b/common/app/assets/javascripts/modules/experiments/ab.js @@ -1,12 +1,22 @@ define([ + 'lodash/collections/filter', + 'lodash/collections/forEach', + 'lodash/collections/map', 'lodash/objects/assign', + 'lodash/objects/keys', + 'common/utils/_', 'common/utils/storage', 'common/utils/mediator', 'common/utils/config', 'common/modules/analytics/mvt-cookie', 'common/modules/experiments/tests/high-commercial-component' ], function ( + filter, + forEach, + map, assign, + keys, + _, store, mediator, globalConfig, @@ -46,7 +56,7 @@ define([ // Removes any tests from localstorage that have been // renamed/deleted from the backend var participations = getParticipations(); - Object.keys(participations).forEach(function (k) { + forEach(keys(participations), function (k) { if (typeof(assign({}, globalConfig, config).switches['ab' + k]) === 'undefined') { removeParticipation({ id: k }); } else { @@ -62,7 +72,7 @@ define([ } function getActiveTests() { - return TESTS.filter(function(test) { + return filter(TESTS, function(test) { var expired = (new Date() - new Date(test.expiry)) > 0; if (expired) { removeParticipation(test); @@ -73,7 +83,7 @@ define([ } function getExpiredTests() { - return TESTS.filter(function(test) { + return filter(TESTS, function(test) { return (new Date() - new Date(test.expiry)) > 0; }); } @@ -84,7 +94,7 @@ define([ } function getTest(id) { - var test = TESTS.filter(function (test) { + var test = filter(TESTS, function (test) { return (test.id === id); }); return (test) ? test[0] : ''; @@ -94,7 +104,7 @@ define([ var participations = getParticipations(), tag = []; - Object.keys(participations).forEach(function (k) { + forEach(keys(participations), function (k) { if (testCanBeRun(getTest(k), config)) { tag.push(['AB', k, participations[k].variant].join(' | ')); } @@ -137,7 +147,7 @@ define([ if (smallestTestId <= mvtCookieId && largestTestId > mvtCookieId) { // This mvt test id is in the test range, so allocate it to a test variant. - var variantIds = test.variants.map(function(variant) { + var variantIds = map(test.variants, function(variant) { return variant.id; }); var testVariantId = mvtCookieId % variantIds.length; @@ -169,17 +179,20 @@ define([ }, segment: function(config) { - getActiveTests().forEach(function(test) { + forEach(getActiveTests(), function(test) { allocateUserToTest(test, config); }); }, forceSegment: function(testId, variant) { - getActiveTests().filter(function (test) { - return (test.id === testId); - }).forEach(function (test) { - addParticipation(test, variant); - }); + _(getActiveTests()) + .filter(function (test) { + return (test.id === testId); + }) + .forEach(function (test) { + addParticipation(test, variant); + }) + .valueOf(); }, segmentUser: function(config) { @@ -198,13 +211,13 @@ define([ }, run: function(config, context) { - getActiveTests().forEach(function(test) { + forEach(getActiveTests(), function(test) { run(test, config, context); }); }, isEventApplicableToAnActiveTest: function (event) { - var participations = Object.keys(getParticipations()); + var participations = keys(getParticipations()); return participations.some(function (id) { var listOfEventStrings = getTest(id).events; return listOfEventStrings.some(function (ev) { @@ -220,21 +233,24 @@ define([ } var eventTag = event.tag; - return eventTag && getActiveTests().filter(function (test) { - var testEvents = test.events; - return testEvents && testEvents.some(function (testEvent) { - return startsWith(eventTag, testEvent); - }); - }).map(function (test) { - return test.id; - }); + return eventTag && _(getActiveTests()) + .filter(function (test) { + var testEvents = test.events; + return testEvents && testEvents.some(function (testEvent) { + return startsWith(eventTag, testEvent); + }); + }) + .map(function (test) { + return test.id; + }) + .valueOf(); }, getAbLoggableObject: function(config) { var abLogObject = {}; try { - getActiveTests().forEach(function (test) { + forEach(getActiveTests(), function (test) { if (isParticipating(test) && testCanBeRun(test, config)) { var variant = getTestVariant(test.id); diff --git a/common/app/assets/javascripts/modules/onward/popular-fronts.js b/common/app/assets/javascripts/modules/onward/popular-fronts.js index ed1f26c9af8e..becfd64bba5a 100644 --- a/common/app/assets/javascripts/modules/onward/popular-fronts.js +++ b/common/app/assets/javascripts/modules/onward/popular-fronts.js @@ -26,7 +26,7 @@ define([ crossOrigin: true }).then( function(resp) { - var container = bonzo.create(resp.faciaHtml.trim())[0]; + var container = bonzo.create(resp.faciaHtml.replace(/^\s+|\s+$/g, ''))[0]; if (!container) { return false; } diff --git a/common/app/assets/javascripts/utils/$.js b/common/app/assets/javascripts/utils/$.js index bc26a1394315..e40b34ae9cbe 100644 --- a/common/app/assets/javascripts/utils/$.js +++ b/common/app/assets/javascripts/utils/$.js @@ -6,12 +6,12 @@ define([ qwery ) { -function $(selector, context) { - return bonzo(qwery(selector, context)); -} -$.create = function(s) { - return bonzo(bonzo.create(s)); -}; -return $; + function $(selector, context) { + return bonzo(qwery(selector, context)); + } + $.create = function(s) { + return bonzo(bonzo.create(s)); + }; + return $; }); // define diff --git a/common/app/assets/javascripts/utils/config.js b/common/app/assets/javascripts/utils/config.js index 6f81718fc22e..61b7f7e8d5f6 100644 --- a/common/app/assets/javascripts/utils/config.js +++ b/common/app/assets/javascripts/utils/config.js @@ -4,10 +4,14 @@ Common functions to simplify access to page data */ define([ + 'lodash/collections/contains', 'lodash/objects/assign', + 'common/utils/_', 'common/utils/pad' ], function ( + contains, extend, + _, pad ) { var config = guardian.config; @@ -20,11 +24,14 @@ define([ return (config.page.series || '').indexOf(name) > -1; }, referencesOfType: function (name) { - return (config.page.references || []).filter(function (reference) { - return typeof reference[name] !== 'undefined'; - }).map(function (reference) { + return _(config.page.references || []) + .filter(function (reference) { + return typeof reference[name] !== 'undefined'; + }) + .map(function (reference) { return reference[name]; - }); + }) + .valueOf(); }, referenceOfType: function (name) { return this.referencesOfType(name)[0]; @@ -47,7 +54,8 @@ define([ return s ? s[0] : null; }, - isMedia: ['Video', 'Audio'].indexOf(config.page.contentType) > -1 + isMedia: contains(['Video', 'Audio'], config.page.contentType) }, config); + }); diff --git a/common/app/assets/javascripts/utils/cookies.js b/common/app/assets/javascripts/utils/cookies.js index ec93e165b4a0..f3473e838269 100644 --- a/common/app/assets/javascripts/utils/cookies.js +++ b/common/app/assets/javascripts/utils/cookies.js @@ -1,4 +1,8 @@ -define(function () { +define([ + 'lodash/collections/forEach' +], function( + forEach +) { function cleanUp(list) { for (var i = 0, j = list.length; i 1) { // This remove is conservative; we know it is safe to remove the cookie @@ -67,7 +71,7 @@ define(function () { nameEq = name + '=', cookies = document.cookie.split(';'); - cookies.forEach(function(cookie) { + forEach(cookies, function(cookie) { while (cookie.charAt(0) === ' ') { cookie = cookie.substring(1, cookie.length); } diff --git a/common/app/assets/javascripts/utils/template.js b/common/app/assets/javascripts/utils/template.js index 6b5f2482332a..f91f8202152f 100644 --- a/common/app/assets/javascripts/utils/template.js +++ b/common/app/assets/javascripts/utils/template.js @@ -1,7 +1,13 @@ -define(function() { +define([ + 'lodash/collections/reduce', + 'lodash/objects/keys' +], function( + reduce, + keys +) { return function template(tmpl, params) { - return Object.keys(params).reduce(function(tmpl, token) { + return reduce(keys(params), function(tmpl, token) { return tmpl.replace(new RegExp('{{' + token + '}}', 'g'), params[token]); }, tmpl); }; diff --git a/common/app/views/fragments/javaScriptFirstSteps.scala.html b/common/app/views/fragments/javaScriptFirstSteps.scala.html index 4c6fd4f5371a..4812a053f2cb 100644 --- a/common/app/views/fragments/javaScriptFirstSteps.scala.html +++ b/common/app/views/fragments/javaScriptFirstSteps.scala.html @@ -59,6 +59,68 @@ return fBound; }; } +(function () { +'use strict'; +var _slice = Array.prototype.slice; + +try { +// Can't be used with DOM elements in IE < 9 +_slice.call(document.documentElement); +} catch (e) { // Fails in IE < 9 +// This will work for genuine arrays, array-like objects, +// NamedNodeMap (attributes, entities, notations), +// NodeList (e.g., getElementsByTagName), HTMLCollection (e.g., childNodes), +// and will not fail on other DOM objects (as do DOM elements in IE < 9) +Array.prototype.slice = function (begin, end) { +// IE < 9 gets unhappy with an undefined end argument +end = (typeof end !== 'undefined') ? end : this.length; + +// For native Array objects, we use the native slice function +if (Object.prototype.toString.call(this) === '[object Array]'){ +return _slice.call(this, begin, end); +} + +// For array like object we handle it ourselves. +var i, cloned = [], +size, len = this.length; + +// Handle negative value for "begin" +var start = begin || 0; +start = (start >= 0) ? start: len + start; + +// Handle negative value for "end" +var upTo = (end) ? end : len; +if (end < 0) { +upTo = len + end; +} + +// Actual expected size of the slice +size = upTo - start; + +if (size > 0) { +cloned = new Array(size); +if (this.charAt) { +for (i = 0; i < size; i++) { +cloned[i] = this.charAt(start + i); +} +} else { +for (i = 0; i < size; i++) { +cloned[i] = this[start + i]; +} +} +} + +return cloned; +}; +} +}()); + +if (!String.prototype.trim) { +String.prototype.trim = function () { +return this.replace(/^\s+|\s+$/g, ''); +}; +} + @* JSON support needed for raven *@ if ("object" !== typeof JSON) { var s = document.createElement('script'), @@ -93,7 +155,7 @@ if (!isModern) { return false; } @* we want to add/remove classes to HTML ASAP to avoid FOUC *@ - var htmlClassNames = ""; + var htmlClassNames = document.documentElement.className.split(' '); @* http://modernizr.com/download/#-svg *@ function hasSvgSupport() { @@ -101,10 +163,13 @@ return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect; } if (hasSvgSupport()) { - htmlClassNames += " svg"; + htmlClassNames.push('svg'); } - document.documentElement.className = document.documentElement.className.replace(/\bjs-off\b/g, '') + ' js-on ' + htmlClassNames; + + document.documentElement.className = htmlClassNames.join(' ') })(guardian.isModernBrowser); + document.documentElement.className = document.documentElement.className.replace(/\bjs-off\b/g, 'js-on'); + diff --git a/common/app/views/fragments/javaScriptLaterSteps.scala.html b/common/app/views/fragments/javaScriptLaterSteps.scala.html index ad298ee05b49..367113a754c8 100644 --- a/common/app/views/fragments/javaScriptLaterSteps.scala.html +++ b/common/app/views/fragments/javaScriptLaterSteps.scala.html @@ -119,7 +119,7 @@ require([ 'core', 'domReady!' - ], function (core) { + ], function() { require(['raven', 'common/utils/config'], function(raven, config) { From 2bbf933a6ee417f464dc701463e11d99c71c4cbe Mon Sep 17 00:00:00 2001 From: Darren Hurley Date: Fri, 15 Aug 2014 17:40:40 +0100 Subject: [PATCH 2/6] using real qwery, not lite mobile version --- Gruntfile.js | 2 +- common/app/assets/javascripts/bower.json | 1 - .../components/qwery/qwery-mobile.js | 79 ---- .../javascripts/components/qwery/qwery.js | 369 ++++++++++++++++++ .../fragments/javaScriptFirstSteps.scala.html | 67 +--- common/test/assets/javascripts/main.js | 2 +- 6 files changed, 377 insertions(+), 143 deletions(-) delete mode 100644 common/app/assets/javascripts/components/qwery/qwery-mobile.js create mode 100644 common/app/assets/javascripts/components/qwery/qwery.js diff --git a/Gruntfile.js b/Gruntfile.js index f29a7058c8a1..c06b8cc5917f 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -94,7 +94,7 @@ module.exports = function (grunt) { bonzo: '../../../../common/app/assets/javascripts/components/bonzo/bonzo', domReady: '../../../../common/app/assets/javascripts/components/domready/ready', EventEmitter: '../../../../common/app/assets/javascripts/components/eventEmitter/EventEmitter', - qwery: '../../../../common/app/assets/javascripts/components/qwery/qwery-mobile', + qwery: '../../../../common/app/assets/javascripts/components/qwery/qwery', reqwest: '../../../../common/app/assets/javascripts/components/reqwest/reqwest', lodash: '../../../../common/app/assets/javascripts/components/lodash-amd', imager: '../../../../common/app/assets/javascripts/components/imager.js/container', diff --git a/common/app/assets/javascripts/bower.json b/common/app/assets/javascripts/bower.json index 6ac632aa7f10..45f0394c8dc5 100644 --- a/common/app/assets/javascripts/bower.json +++ b/common/app/assets/javascripts/bower.json @@ -35,7 +35,6 @@ "bower_components/curl/dist/curl-with-js-and-domReady/curl.js": "curl-domReady.js" } ], - "qwery": "bower_components/qwery/mobile/qwery-mobile.js", "lodash-amd": "bower_components/lodash-amd/modern/**", "imager.js": [ "bower_components/imager.js/src/imager.js", diff --git a/common/app/assets/javascripts/components/qwery/qwery-mobile.js b/common/app/assets/javascripts/components/qwery/qwery-mobile.js deleted file mode 100644 index 65bd08ec7779..000000000000 --- a/common/app/assets/javascripts/components/qwery/qwery-mobile.js +++ /dev/null @@ -1,79 +0,0 @@ -/*! - * @preserve Qwery - A Blazing Fast query selector engine - * https://github.com/ded/qwery - * copyright Dustin Diaz 2012 - * MIT License - */ - -(function (name, context, definition) { - if (typeof module != 'undefined' && module.exports) module.exports = definition() - else if (typeof define == 'function' && define.amd) define(definition) - else context[name] = definition() -})('qwery', this, function () { - - var classOnly = /^\.([\w\-]+)$/ - , doc = document - , win = window - , html = doc.documentElement - , isAncestor = 'compareDocumentPosition' in html ? - function (element, container) { - return (container.compareDocumentPosition(element) & 16) == 16 - } : - function (element, container) { - container = container == doc || container == window ? html : container - return container !== element && container.contains(element) - } - - function toArray(ar) { - return [].slice.call(ar, 0) - } - - function isNode(el) { - var t - return el && typeof el === 'object' && (t = el.nodeType) && (t == 1 || t == 9) - } - - function uniq(ar) { - var a = [], i, j - label: - for (i = 0; i < ar.length; i++) { - for (j = 0; j < a.length; j++) { - if (a[j] == ar[i]) { - continue label - } - } - a[a.length] = ar[i] - } - return a - } - - - /** - * @param {string|Array.|Element|Node} selector - * @param {string|Array.|Element|Node=} opt_root - * @return {Array.} - */ - function qwery(selector, opt_root) { - var m, root = (typeof opt_root == 'string') ? qwery(opt_root)[0] : (opt_root || doc) - root = isFinite(root.length) && root[0] && !root.nodeName ? root[0] : root - if (!root || !selector) { - return [] - } - if (doc.getElementsByClassName && selector == 'string' && (m = selector.match(classOnly))) { - return toArray((root).getElementsByClassName(m[1])) - } - // using duck typing for 'a' window or 'a' document (not 'the' window || document) - if (selector && (selector.document || (selector.nodeType && selector.nodeType == 9))) { - return !opt_root ? [selector] : [] - } - if (isNode(selector)) { - return !opt_root || (isAncestor(selector, root)) ? [selector] : [] - } - return toArray((root).querySelectorAll(selector)) - } - - - qwery.uniq = uniq - - return qwery -}, this); \ No newline at end of file diff --git a/common/app/assets/javascripts/components/qwery/qwery.js b/common/app/assets/javascripts/components/qwery/qwery.js new file mode 100644 index 000000000000..8292d0159086 --- /dev/null +++ b/common/app/assets/javascripts/components/qwery/qwery.js @@ -0,0 +1,369 @@ +/*! + * @preserve Qwery - A Blazing Fast query selector engine + * https://github.com/ded/qwery + * copyright Dustin Diaz 2012 + * MIT License + */ + +(function (name, context, definition) { + if (typeof module != 'undefined' && module.exports) module.exports = definition() + else if (typeof define == 'function' && define.amd) define(definition) + else context[name] = definition() +})('qwery', this, function () { + var doc = document + , html = doc.documentElement + , byClass = 'getElementsByClassName' + , byTag = 'getElementsByTagName' + , qSA = 'querySelectorAll' + , useNativeQSA = 'useNativeQSA' + , tagName = 'tagName' + , nodeType = 'nodeType' + , select // main select() method, assign later + + , id = /#([\w\-]+)/ + , clas = /\.[\w\-]+/g + , idOnly = /^#([\w\-]+)$/ + , classOnly = /^\.([\w\-]+)$/ + , tagOnly = /^([\w\-]+)$/ + , tagAndOrClass = /^([\w]+)?\.([\w\-]+)$/ + , splittable = /(^|,)\s*[>~+]/ + , normalizr = /^\s+|\s*([,\s\+\~>]|$)\s*/g + , splitters = /[\s\>\+\~]/ + , splittersMore = /(?![\s\w\-\/\?\&\=\:\.\(\)\!,@#%<>\{\}\$\*\^'"]*\]|[\s\w\+\-]*\))/ + , specialChars = /([.*+?\^=!:${}()|\[\]\/\\])/g + , simple = /^(\*|[a-z0-9]+)?(?:([\.\#]+[\w\-\.#]+)?)/ + , attr = /\[([\w\-]+)(?:([\|\^\$\*\~]?\=)['"]?([ \w\-\/\?\&\=\:\.\(\)\!,@#%<>\{\}\$\*\^]+)["']?)?\]/ + , pseudo = /:([\w\-]+)(\(['"]?([^()]+)['"]?\))?/ + , easy = new RegExp(idOnly.source + '|' + tagOnly.source + '|' + classOnly.source) + , dividers = new RegExp('(' + splitters.source + ')' + splittersMore.source, 'g') + , tokenizr = new RegExp(splitters.source + splittersMore.source) + , chunker = new RegExp(simple.source + '(' + attr.source + ')?' + '(' + pseudo.source + ')?') + + var walker = { + ' ': function (node) { + return node && node !== html && node.parentNode + } + , '>': function (node, contestant) { + return node && node.parentNode == contestant.parentNode && node.parentNode + } + , '~': function (node) { + return node && node.previousSibling + } + , '+': function (node, contestant, p1, p2) { + if (!node) return false + return (p1 = previous(node)) && (p2 = previous(contestant)) && p1 == p2 && p1 + } + } + + function cache() { + this.c = {} + } + cache.prototype = { + g: function (k) { + return this.c[k] || undefined + } + , s: function (k, v, r) { + v = r ? new RegExp(v) : v + return (this.c[k] = v) + } + } + + var classCache = new cache() + , cleanCache = new cache() + , attrCache = new cache() + , tokenCache = new cache() + + function classRegex(c) { + return classCache.g(c) || classCache.s(c, '(^|\\s+)' + c + '(\\s+|$)', 1) + } + + // not quite as fast as inline loops in older browsers so don't use liberally + function each(a, fn) { + var i = 0, l = a.length + for (; i < l; i++) fn(a[i]) + } + + function flatten(ar) { + for (var r = [], i = 0, l = ar.length; i < l; ++i) arrayLike(ar[i]) ? (r = r.concat(ar[i])) : (r[r.length] = ar[i]) + return r + } + + function arrayify(ar) { + var i = 0, l = ar.length, r = [] + for (; i < l; i++) r[i] = ar[i] + return r + } + + function previous(n) { + while (n = n.previousSibling) if (n[nodeType] == 1) break; + return n + } + + function q(query) { + return query.match(chunker) + } + + // called using `this` as element and arguments from regex group results. + // given => div.hello[title="world"]:foo('bar') + // div.hello[title="world"]:foo('bar'), div, .hello, [title="world"], title, =, world, :foo('bar'), foo, ('bar'), bar] + function interpret(whole, tag, idsAndClasses, wholeAttribute, attribute, qualifier, value, wholePseudo, pseudo, wholePseudoVal, pseudoVal) { + var i, m, k, o, classes + if (this[nodeType] !== 1) return false + if (tag && tag !== '*' && this[tagName] && this[tagName].toLowerCase() !== tag) return false + if (idsAndClasses && (m = idsAndClasses.match(id)) && m[1] !== this.id) return false + if (idsAndClasses && (classes = idsAndClasses.match(clas))) { + for (i = classes.length; i--;) if (!classRegex(classes[i].slice(1)).test(this.className)) return false + } + if (pseudo && qwery.pseudos[pseudo] && !qwery.pseudos[pseudo](this, pseudoVal)) return false + if (wholeAttribute && !value) { // select is just for existance of attrib + o = this.attributes + for (k in o) { + if (Object.prototype.hasOwnProperty.call(o, k) && (o[k].name || k) == attribute) { + return this + } + } + } + if (wholeAttribute && !checkAttr(qualifier, getAttr(this, attribute) || '', value)) { + // select is for attrib equality + return false + } + return this + } + + function clean(s) { + return cleanCache.g(s) || cleanCache.s(s, s.replace(specialChars, '\\$1')) + } + + function checkAttr(qualify, actual, val) { + switch (qualify) { + case '=': + return actual == val + case '^=': + return actual.match(attrCache.g('^=' + val) || attrCache.s('^=' + val, '^' + clean(val), 1)) + case '$=': + return actual.match(attrCache.g('$=' + val) || attrCache.s('$=' + val, clean(val) + '$', 1)) + case '*=': + return actual.match(attrCache.g(val) || attrCache.s(val, clean(val), 1)) + case '~=': + return actual.match(attrCache.g('~=' + val) || attrCache.s('~=' + val, '(?:^|\\s+)' + clean(val) + '(?:\\s+|$)', 1)) + case '|=': + return actual.match(attrCache.g('|=' + val) || attrCache.s('|=' + val, '^' + clean(val) + '(-|$)', 1)) + } + return 0 + } + + // given a selector, first check for simple cases then collect all base candidate matches and filter + function _qwery(selector, _root) { + var r = [], ret = [], i, l, m, token, tag, els, intr, item, root = _root + , tokens = tokenCache.g(selector) || tokenCache.s(selector, selector.split(tokenizr)) + , dividedTokens = selector.match(dividers) + + if (!tokens.length) return r + + token = (tokens = tokens.slice(0)).pop() // copy cached tokens, take the last one + if (tokens.length && (m = tokens[tokens.length - 1].match(idOnly))) root = byId(_root, m[1]) + if (!root) return r + + intr = q(token) + // collect base candidates to filter + els = root !== _root && root[nodeType] !== 9 && dividedTokens && /^[+~]$/.test(dividedTokens[dividedTokens.length - 1]) ? + function (r) { + while (root = root.nextSibling) { + root[nodeType] == 1 && (intr[1] ? intr[1] == root[tagName].toLowerCase() : 1) && (r[r.length] = root) + } + return r + }([]) : + root[byTag](intr[1] || '*') + // filter elements according to the right-most part of the selector + for (i = 0, l = els.length; i < l; i++) { + if (item = interpret.apply(els[i], intr)) r[r.length] = item + } + if (!tokens.length) return r + + // filter further according to the rest of the selector (the left side) + each(r, function (e) { if (ancestorMatch(e, tokens, dividedTokens)) ret[ret.length] = e }) + return ret + } + + // compare element to a selector + function is(el, selector, root) { + if (isNode(selector)) return el == selector + if (arrayLike(selector)) return !!~flatten(selector).indexOf(el) // if selector is an array, is el a member? + + var selectors = selector.split(','), tokens, dividedTokens + while (selector = selectors.pop()) { + tokens = tokenCache.g(selector) || tokenCache.s(selector, selector.split(tokenizr)) + dividedTokens = selector.match(dividers) + tokens = tokens.slice(0) // copy array + if (interpret.apply(el, q(tokens.pop())) && (!tokens.length || ancestorMatch(el, tokens, dividedTokens, root))) { + return true + } + } + return false + } + + // given elements matching the right-most part of a selector, filter out any that don't match the rest + function ancestorMatch(el, tokens, dividedTokens, root) { + var cand + // recursively work backwards through the tokens and up the dom, covering all options + function crawl(e, i, p) { + while (p = walker[dividedTokens[i]](p, e)) { + if (isNode(p) && (interpret.apply(p, q(tokens[i])))) { + if (i) { + if (cand = crawl(p, i - 1, p)) return cand + } else return p + } + } + } + return (cand = crawl(el, tokens.length - 1, el)) && (!root || isAncestor(cand, root)) + } + + function isNode(el, t) { + return el && typeof el === 'object' && (t = el[nodeType]) && (t == 1 || t == 9) + } + + function uniq(ar) { + var a = [], i, j; + o: + for (i = 0; i < ar.length; ++i) { + for (j = 0; j < a.length; ++j) if (a[j] == ar[i]) continue o + a[a.length] = ar[i] + } + return a + } + + function arrayLike(o) { + return (typeof o === 'object' && isFinite(o.length)) + } + + function normalizeRoot(root) { + if (!root) return doc + if (typeof root == 'string') return qwery(root)[0] + if (!root[nodeType] && arrayLike(root)) return root[0] + return root + } + + function byId(root, id, el) { + // if doc, query on it, else query the parent doc or if a detached fragment rewrite the query and run on the fragment + return root[nodeType] === 9 ? root.getElementById(id) : + root.ownerDocument && + (((el = root.ownerDocument.getElementById(id)) && isAncestor(el, root) && el) || + (!isAncestor(root, root.ownerDocument) && select('[id="' + id + '"]', root)[0])) + } + + function qwery(selector, _root) { + var m, el, root = normalizeRoot(_root) + + // easy, fast cases that we can dispatch with simple DOM calls + if (!root || !selector) return [] + if (selector === window || isNode(selector)) { + return !_root || (selector !== window && isNode(root) && isAncestor(selector, root)) ? [selector] : [] + } + if (selector && arrayLike(selector)) return flatten(selector) + if (m = selector.match(easy)) { + if (m[1]) return (el = byId(root, m[1])) ? [el] : [] + if (m[2]) return arrayify(root[byTag](m[2])) + if (hasByClass && m[3]) return arrayify(root[byClass](m[3])) + } + + return select(selector, root) + } + + // where the root is not document and a relationship selector is first we have to + // do some awkward adjustments to get it to work, even with qSA + function collectSelector(root, collector) { + return function (s) { + var oid, nid + if (splittable.test(s)) { + if (root[nodeType] !== 9) { + // make sure the el has an id, rewrite the query, set root to doc and run it + if (!(nid = oid = root.getAttribute('id'))) root.setAttribute('id', nid = '__qwerymeupscotty') + s = '[id="' + nid + '"]' + s // avoid byId and allow us to match context element + collector(root.parentNode || root, s, true) + oid || root.removeAttribute('id') + } + return; + } + s.length && collector(root, s, false) + } + } + + var isAncestor = 'compareDocumentPosition' in html ? + function (element, container) { + return (container.compareDocumentPosition(element) & 16) == 16 + } : 'contains' in html ? + function (element, container) { + container = container[nodeType] === 9 || container == window ? html : container + return container !== element && container.contains(element) + } : + function (element, container) { + while (element = element.parentNode) if (element === container) return 1 + return 0 + } + , getAttr = function () { + // detect buggy IE src/href getAttribute() call + var e = doc.createElement('p') + return ((e.innerHTML = 'x') && e.firstChild.getAttribute('href') != '#x') ? + function (e, a) { + return a === 'class' ? e.className : (a === 'href' || a === 'src') ? + e.getAttribute(a, 2) : e.getAttribute(a) + } : + function (e, a) { return e.getAttribute(a) } + }() + , hasByClass = !!doc[byClass] + // has native qSA support + , hasQSA = doc.querySelector && doc[qSA] + // use native qSA + , selectQSA = function (selector, root) { + var result = [], ss, e + try { + if (root[nodeType] === 9 || !splittable.test(selector)) { + // most work is done right here, defer to qSA + return arrayify(root[qSA](selector)) + } + // special case where we need the services of `collectSelector()` + each(ss = selector.split(','), collectSelector(root, function (ctx, s) { + e = ctx[qSA](s) + if (e.length == 1) result[result.length] = e.item(0) + else if (e.length) result = result.concat(arrayify(e)) + })) + return ss.length > 1 && result.length > 1 ? uniq(result) : result + } catch (ex) { } + return selectNonNative(selector, root) + } + // no native selector support + , selectNonNative = function (selector, root) { + var result = [], items, m, i, l, r, ss + selector = selector.replace(normalizr, '$1') + if (m = selector.match(tagAndOrClass)) { + r = classRegex(m[2]) + items = root[byTag](m[1] || '*') + for (i = 0, l = items.length; i < l; i++) { + if (r.test(items[i].className)) result[result.length] = items[i] + } + return result + } + // more complex selector, get `_qwery()` to do the work for us + each(ss = selector.split(','), collectSelector(root, function (ctx, s, rewrite) { + r = _qwery(s, ctx) + for (i = 0, l = r.length; i < l; i++) { + if (ctx[nodeType] === 9 || rewrite || isAncestor(r[i], root)) result[result.length] = r[i] + } + })) + return ss.length > 1 && result.length > 1 ? uniq(result) : result + } + , configure = function (options) { + // configNativeQSA: use fully-internal selector or native qSA where present + if (typeof options[useNativeQSA] !== 'undefined') + select = !options[useNativeQSA] ? selectNonNative : hasQSA ? selectQSA : selectNonNative + } + + configure({ useNativeQSA: true }) + + qwery.configure = configure + qwery.uniq = uniq + qwery.is = is + qwery.pseudos = {} + + return qwery +}); diff --git a/common/app/views/fragments/javaScriptFirstSteps.scala.html b/common/app/views/fragments/javaScriptFirstSteps.scala.html index 4812a053f2cb..d163624570cd 100644 --- a/common/app/views/fragments/javaScriptFirstSteps.scala.html +++ b/common/app/views/fragments/javaScriptFirstSteps.scala.html @@ -59,67 +59,12 @@ return fBound; }; } -(function () { -'use strict'; -var _slice = Array.prototype.slice; - -try { -// Can't be used with DOM elements in IE < 9 -_slice.call(document.documentElement); -} catch (e) { // Fails in IE < 9 -// This will work for genuine arrays, array-like objects, -// NamedNodeMap (attributes, entities, notations), -// NodeList (e.g., getElementsByTagName), HTMLCollection (e.g., childNodes), -// and will not fail on other DOM objects (as do DOM elements in IE < 9) -Array.prototype.slice = function (begin, end) { -// IE < 9 gets unhappy with an undefined end argument -end = (typeof end !== 'undefined') ? end : this.length; - -// For native Array objects, we use the native slice function -if (Object.prototype.toString.call(this) === '[object Array]'){ -return _slice.call(this, begin, end); -} - -// For array like object we handle it ourselves. -var i, cloned = [], -size, len = this.length; - -// Handle negative value for "begin" -var start = begin || 0; -start = (start >= 0) ? start: len + start; - -// Handle negative value for "end" -var upTo = (end) ? end : len; -if (end < 0) { -upTo = len + end; -} - -// Actual expected size of the slice -size = upTo - start; - -if (size > 0) { -cloned = new Array(size); -if (this.charAt) { -for (i = 0; i < size; i++) { -cloned[i] = this.charAt(start + i); -} -} else { -for (i = 0; i < size; i++) { -cloned[i] = this[start + i]; -} -} -} - -return cloned; -}; -} -}()); - -if (!String.prototype.trim) { -String.prototype.trim = function () { -return this.replace(/^\s+|\s+$/g, ''); -}; -} + + if (!String.prototype.trim) { + String.prototype.trim = function () { + return this.replace(/^\s+|\s+$/g, ''); + }; + } @* JSON support needed for raven *@ if ("object" !== typeof JSON) { diff --git a/common/test/assets/javascripts/main.js b/common/test/assets/javascripts/main.js index ad95e91b2486..39a012af3fe8 100644 --- a/common/test/assets/javascripts/main.js +++ b/common/test/assets/javascripts/main.js @@ -20,7 +20,7 @@ requirejs.config({ bonzo: '/base/common/app/assets/javascripts/components/bonzo/bonzo', domReady: '/base/common/app/assets/javascripts/components/domready/ready', EventEmitter: '/base/common/app/assets/javascripts/components/eventEmitter/EventEmitter', - qwery: '/base/common/app/assets/javascripts/components/qwery/qwery-mobile', + qwery: '/base/common/app/assets/javascripts/components/qwery/qwery', reqwest: '/base/common/app/assets/javascripts/components/reqwest/reqwest', lodash: '/base/common/app/assets/javascripts/components/lodash-amd', imager: '/base/common/app/assets/javascripts/components/imager.js/container', From 3f289ca572a7af1d2074037965c6625d6117c4d5 Mon Sep 17 00:00:00 2001 From: Darren Hurley Date: Fri, 15 Aug 2014 17:54:22 +0100 Subject: [PATCH 3/6] use lodash's forEach --- common/app/assets/javascripts/modules/commercial/dfp.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/common/app/assets/javascripts/modules/commercial/dfp.js b/common/app/assets/javascripts/modules/commercial/dfp.js index b7f316ca1f7d..a64f80d39c50 100644 --- a/common/app/assets/javascripts/modules/commercial/dfp.js +++ b/common/app/assets/javascripts/modules/commercial/dfp.js @@ -5,6 +5,7 @@ define([ 'lodash/functions/debounce', 'lodash/arrays/flatten', 'lodash/arrays/uniq', + 'lodash/collections/forEach', 'lodash/collections/map', 'lodash/functions/once', 'lodash/objects/defaults', @@ -30,6 +31,7 @@ define([ debounce, flatten, uniq, + forEach, map, once, defaults, @@ -358,7 +360,7 @@ define([ var adUnit = config.page.adUnit; - adSlots.forEach(function($adSlot) { + forEach(adSlots, function($adSlot) { var id = $adSlot.attr('id'), sizeMapping = defineSlotSizes($adSlot), From f90f9135cdcbc9a404367254a9d84e5fbc4f2f5d Mon Sep 17 00:00:00 2001 From: Darren Hurley Date: Fri, 15 Aug 2014 18:21:43 +0100 Subject: [PATCH 4/6] handle no class names --- .../app/assets/javascripts/modules/commercial/dfp.js | 12 ++++++------ .../views/fragments/javaScriptFirstSteps.scala.html | 3 ++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/common/app/assets/javascripts/modules/commercial/dfp.js b/common/app/assets/javascripts/modules/commercial/dfp.js index a64f80d39c50..086d814bb1a0 100644 --- a/common/app/assets/javascripts/modules/commercial/dfp.js +++ b/common/app/assets/javascripts/modules/commercial/dfp.js @@ -14,15 +14,15 @@ define([ 'lodash/objects/pairs', 'common/utils/$', 'common/utils/_', + 'common/utils/config', 'common/utils/cookies', 'common/utils/detect', 'common/utils/mediator', - 'common/utils/config', 'common/utils/template', + 'common/modules/commercial/keywords', 'common/modules/commercial/tags/audience-science', 'common/modules/commercial/tags/audience-science-gateway', 'common/modules/commercial/tags/criteo', - 'common/modules/commercial/keywords', 'common/modules/commercial/user-ad-targeting', 'common/modules/experiments/ab' ], function ( @@ -40,15 +40,15 @@ define([ pairs, $, _, + globalConfig, cookies, detect, mediator, - globalConfig, template, + keywords, audienceScience, audienceScienceGateway, criteo, - keywords, userAdTargeting, ab ) { @@ -438,9 +438,9 @@ define([ return bonzo(adSlot); }) .filter(function ($adSlot) { - // bonzo needs these - default to true if unavailable (e.g. IE8) + // bonzo needs these - use currentStyle (not as reliable?) if unavailable (e.g. IE8) return (window.document.defaultView && window.document.defaultView.getComputedStyle) - ? $adSlot.css('display') !== 'none' : true; + ? $adSlot.css('display') !== 'none' : $adSlot[0].currentStyle.display; }) .valueOf(); diff --git a/common/app/views/fragments/javaScriptFirstSteps.scala.html b/common/app/views/fragments/javaScriptFirstSteps.scala.html index d163624570cd..3e48229be494 100644 --- a/common/app/views/fragments/javaScriptFirstSteps.scala.html +++ b/common/app/views/fragments/javaScriptFirstSteps.scala.html @@ -100,7 +100,8 @@ if (!isModern) { return false; } @* we want to add/remove classes to HTML ASAP to avoid FOUC *@ - var htmlClassNames = document.documentElement.className.split(' '); + var currentClassName = document.documentElement.className, + htmlClassNames = currentClassName ? currentClassName.split(' ') : []; @* http://modernizr.com/download/#-svg *@ function hasSvgSupport() { From e085e7d1891cac49a6d907d3586df5f7e056aa85 Mon Sep 17 00:00:00 2001 From: Darren Hurley Date: Fri, 15 Aug 2014 18:25:59 +0100 Subject: [PATCH 5/6] no need fo valueOf --- .../app/assets/javascripts/modules/commercial/tags/media-math.js | 1 - 1 file changed, 1 deletion(-) diff --git a/common/app/assets/javascripts/modules/commercial/tags/media-math.js b/common/app/assets/javascripts/modules/commercial/tags/media-math.js index deec361cf497..14492c44a237 100644 --- a/common/app/assets/javascripts/modules/commercial/tags/media-math.js +++ b/common/app/assets/javascripts/modules/commercial/tags/media-math.js @@ -19,7 +19,6 @@ define([ .map(function(searchQuery) { return decodeURIComponent(searchQuery.split('=').pop().replace(/\\+/g, ' ')); }) - .valueOf() .shift(); }; From 3ddd8a53c588bec4b6021a278411e6b74a6ac35f Mon Sep 17 00:00:00 2001 From: Darren Hurley Date: Mon, 18 Aug 2014 10:59:36 +0100 Subject: [PATCH 6/6] fix scsslint --- common/app/assets/javascripts/bower.json | 2 +- .../javascripts/components/reqwest/reqwest.js | 2 +- .../app/assets/stylesheets/base/_state.scss | 4 ++-- .../assets/stylesheets/layout/_footer.scss | 2 +- .../stylesheets/module/facia/_fromage.scss | 4 ++-- .../stylesheets/module/facia/_items.scss | 4 ++-- .../stylesheets/module/football/_matches.scss | 2 +- .../module/nav/_has-localnav-overrides.scss | 2 +- .../fragments/javaScriptFirstSteps.scala.html | 24 +++++++++++-------- 9 files changed, 25 insertions(+), 21 deletions(-) diff --git a/common/app/assets/javascripts/bower.json b/common/app/assets/javascripts/bower.json index 45f0394c8dc5..4855036bd8e1 100644 --- a/common/app/assets/javascripts/bower.json +++ b/common/app/assets/javascripts/bower.json @@ -10,7 +10,7 @@ "bonzo": "~2.0.0", "curl": "~0.8.9", "qwery": "3.4.2", - "reqwest": "~1.1.0", + "reqwest": "git://github.com/guardian/reqwest.git", "domready": "~1.0.4", "enhancer": "0.1.1", "videojs": "git://github.com/guardian/video.js.git#fabb393da9e139f6869bc0fdb95074d7ca062aa8", diff --git a/common/app/assets/javascripts/components/reqwest/reqwest.js b/common/app/assets/javascripts/components/reqwest/reqwest.js index f54511cde4cb..69c78deb3ce7 100644 --- a/common/app/assets/javascripts/components/reqwest/reqwest.js +++ b/common/app/assets/javascripts/components/reqwest/reqwest.js @@ -411,7 +411,7 @@ } return this } - , catch: function (fn) { + , 'catch': function (fn) { return this.fail(fn) } } diff --git a/common/app/assets/stylesheets/base/_state.scss b/common/app/assets/stylesheets/base/_state.scss index 0a1584f73e83..d8cbca440312 100644 --- a/common/app/assets/stylesheets/base/_state.scss +++ b/common/app/assets/stylesheets/base/_state.scss @@ -1,7 +1,7 @@ @charset 'UTF-8'; -.js-on .js-hidden, -.js-off .js-visible { +.is-modern .js-hidden, +.is-not-modern .js-visible { display: none; } diff --git a/common/app/assets/stylesheets/layout/_footer.scss b/common/app/assets/stylesheets/layout/_footer.scss index 0c134da01af4..f13f2410ae19 100644 --- a/common/app/assets/stylesheets/layout/_footer.scss +++ b/common/app/assets/stylesheets/layout/_footer.scss @@ -31,7 +31,7 @@ $c-primary-footer-background-side-bar: mix($c-primary-footer-background, #ffffff border-top: 0; } - .js-off & { + .is-not-modern & { .navigation--collapsed { height: auto; } diff --git a/common/app/assets/stylesheets/module/facia/_fromage.scss b/common/app/assets/stylesheets/module/facia/_fromage.scss index d7188e4e1673..9d976c5fd626 100644 --- a/common/app/assets/stylesheets/module/facia/_fromage.scss +++ b/common/app/assets/stylesheets/module/facia/_fromage.scss @@ -277,8 +277,8 @@ padding-right: $gs-gutter/4 )); } - .js-on &.fromage--has-discussion .fromage__standfirst, - .js-on &.fromage--has-discussion .fromage__byline { + .is-modern &.fromage--has-discussion .fromage__standfirst, + .is-modern &.fromage--has-discussion .fromage__byline { // If the story has a discussion, make room for the comment count // in the top right of the component @include rem(( diff --git a/common/app/assets/stylesheets/module/facia/_items.scss b/common/app/assets/stylesheets/module/facia/_items.scss index 979bdd84cc8a..8f73943607f1 100644 --- a/common/app/assets/stylesheets/module/facia/_items.scss +++ b/common/app/assets/stylesheets/module/facia/_items.scss @@ -238,7 +238,7 @@ .item__image-container { margin-top: 4px; - .js-off & { + .is-not-modern & { display: none; } } @@ -255,7 +255,7 @@ .item__image-container { display: block; - .js-off & { + .is-not-modern & { display: none !important; } } diff --git a/common/app/assets/stylesheets/module/football/_matches.scss b/common/app/assets/stylesheets/module/football/_matches.scss index 5885696db870..e0120657ceb9 100644 --- a/common/app/assets/stylesheets/module/football/_matches.scss +++ b/common/app/assets/stylesheets/module/football/_matches.scss @@ -139,7 +139,7 @@ } } -.js-on .football-matches tr { +.is-modern .football-matches tr { cursor: pointer; } diff --git a/common/app/assets/stylesheets/module/nav/_has-localnav-overrides.scss b/common/app/assets/stylesheets/module/nav/_has-localnav-overrides.scss index 7c2c2856a165..2f328e4c9932 100644 --- a/common/app/assets/stylesheets/module/nav/_has-localnav-overrides.scss +++ b/common/app/assets/stylesheets/module/nav/_has-localnav-overrides.scss @@ -1,7 +1,7 @@ /* Local navigation - Global container overrides ========================================================================== */ -.js-on .has-localnav { +.is-modern .has-localnav { h2.article__zone:only-child, .hide-on-mobile-if-localnav { display: none; diff --git a/common/app/views/fragments/javaScriptFirstSteps.scala.html b/common/app/views/fragments/javaScriptFirstSteps.scala.html index 3e48229be494..7040a4d339de 100644 --- a/common/app/views/fragments/javaScriptFirstSteps.scala.html +++ b/common/app/views/fragments/javaScriptFirstSteps.scala.html @@ -60,6 +60,7 @@ }; } + @* needed due to class manipulation in bonzo is not x-browser - https://github.com/ded/bonzo/pull/133 *@ if (!String.prototype.trim) { String.prototype.trim = function () { return this.replace(/^\s+|\s+$/g, ''); @@ -97,22 +98,25 @@ // must always be set before the Omniture file is parsed window.s_account = guardian.config.page.omnitureAccount; - if (!isModern) { return false; } - @* we want to add/remove classes to HTML ASAP to avoid FOUC *@ var currentClassName = document.documentElement.className, htmlClassNames = currentClassName ? currentClassName.split(' ') : []; - @* http://modernizr.com/download/#-svg *@ - function hasSvgSupport() { - var ns = {'svg': 'http://www.w3.org/2000/svg'}; - return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect; - } - if (hasSvgSupport()) { - htmlClassNames.push('svg'); + if (!isModern) { + htmlClassNames.push('is-not-modern'); + } else { + @* http://modernizr.com/download/#-svg *@ + function hasSvgSupport() { + var ns = {'svg': 'http://www.w3.org/2000/svg'}; + return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect; + } + if (hasSvgSupport()) { + htmlClassNames.push('svg'); + } + htmlClassNames.push('is-modern'); } - document.documentElement.className = htmlClassNames.join(' ') + document.documentElement.className = htmlClassNames.join(' '); })(guardian.isModernBrowser);