Skip to content

Commit

Permalink
[fix bug 1250225] Use srcset for high res images.
Browse files Browse the repository at this point in the history
  • Loading branch information
jpetto committed Mar 2, 2016
1 parent 2689fb6 commit 1371266
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 130 deletions.
14 changes: 5 additions & 9 deletions bedrock/mozorg/helpers/misc.py
Expand Up @@ -231,15 +231,11 @@ def high_res_img(ctx, url, optional_attributes=None):
class_name = ''
attrs = ''

# Don't download any image until the javascript sets it based on
# data-src so we can do high-dpi detection. If no js, show the
# normal-res version.
markup = ('<img class="js {class_name}" src="" data-processed="false" '
'data-src="{url}" data-high-res="true" '
'data-high-res-src="{url_high_res}"{attrs}><noscript>'
'<img class="{class_name}" src="{url}"{attrs}>'
'</noscript>').format(url=url, url_high_res=url_high_res,
attrs=attrs, class_name=class_name)
# Use native srcset attribute for high res images
markup = ('<img class="{class_name}" src="{url}" '
'srcset="{url_high_res} 1.5x"'
'{attrs}>').format(url=url, url_high_res=url_high_res,
attrs=attrs, class_name=class_name)

return jinja2.Markup(markup)

Expand Down
23 changes: 9 additions & 14 deletions bedrock/mozorg/tests/test_helper_misc.py
Expand Up @@ -472,19 +472,17 @@ def test_high_res_img_no_optional_attributes(self):
"""Should return expected markup without optional attributes"""
markup = self._render('test.png')
expected = (
u'<img class="js " src="" data-processed="false" data-src="/media/img/test.png" '
u'data-high-res="true" data-high-res-src="/media/img/test-high-res.png">'
u'<noscript><img class="" src="/media/img/test.png"></noscript>')
u'<img class="" src="/media/img/test.png" '
u'srcset="/media/img/test-high-res.png 1.5x">')
self.assertEqual(markup, expected)

def test_high_res_img_with_optional_attributes(self):
"""Should return expected markup with optional attributes"""
markup = self._render('test.png', {'data-test-attr': 'test', 'class': 'logo'})
expected = (
u'<img class="js logo" src="" data-processed="false" data-src="/media/img/test.png" '
u'data-high-res="true" data-high-res-src="/media/img/test-high-res.png" '
u'data-test-attr="test"><noscript>'
u'<img class="logo" src="/media/img/test.png" data-test-attr="test"></noscript>')
u'<img class="logo" src="/media/img/test.png" '
u'srcset="/media/img/test-high-res.png 1.5x" '
u'data-test-attr="test">')
self.assertEqual(markup, expected)

def test_high_res_img_with_l10n(self):
Expand All @@ -493,9 +491,8 @@ def test_high_res_img_with_l10n(self):
l10n_hr_url = convert_to_high_res(l10n_url)
markup = self._render('test.png', {'l10n': True})
expected = (
u'<img class="js " src="" data-processed="false" data-src="' + l10n_url + '" '
u'data-high-res="true" data-high-res-src="' + l10n_hr_url + '">'
u'<noscript><img class="" src="' + l10n_url + '"></noscript>')
u'<img class="" src="' + l10n_url + '" '
u'srcset="' + l10n_hr_url + ' 1.5x">')
self.assertEqual(markup, expected)

def test_high_res_img_with_l10n_and_optional_attributes(self):
Expand All @@ -504,10 +501,8 @@ def test_high_res_img_with_l10n_and_optional_attributes(self):
l10n_hr_url = convert_to_high_res(l10n_url)
markup = self._render('test.png', {'l10n': True, 'data-test-attr': 'test'})
expected = (
u'<img class="js " src="" data-processed="false" data-src="' + l10n_url + '" '
u'data-high-res="true" data-high-res-src="' + l10n_hr_url + '" data-test-attr="test">'
u'<noscript><img class="" src="' + l10n_url + '" data-test-attr="test">'
u'</noscript>')
u'<img class="" src="' + l10n_url + '" '
u'srcset="' + l10n_hr_url + ' 1.5x" data-test-attr="test">')
self.assertEqual(markup, expected)


Expand Down
63 changes: 13 additions & 50 deletions media/js/base/mozilla-image-helper.js
Expand Up @@ -11,7 +11,6 @@

$(document).ready(function() {
Mozilla.ImageHelper.initPlatformImages();
Mozilla.ImageHelper.initHighResImages();
});

// create namespace
Expand All @@ -24,10 +23,7 @@ if (typeof Mozilla == 'undefined') {
/**
* ImageHelper object
*/
Mozilla.ImageHelper = function() {
};

Mozilla.ImageHelper.is_high_dpi = null;
Mozilla.ImageHelper = function() {};

// }}}

Expand All @@ -38,8 +34,7 @@ Mozilla.ImageHelper.initPlatformImages = function() {
$('.platform-img').each(function() {
var $img = $(this);
var data_attribute = 'src-';
var is_high_res = $img.data('high-res') && Mozilla.ImageHelper.isHighDpi();
var suffix;
var is_high_res = $img.data('high-res');
var new_src;

if (site.platform == 'oldwin') {
Expand All @@ -52,57 +47,25 @@ Mozilla.ImageHelper.initPlatformImages = function() {
data_attribute += site.platform;
}

if (is_high_res) {
suffix = '-high-res';
}
else {
suffix = '';
}
new_src = $img.data(data_attribute);

new_src = $img.data(data_attribute + suffix);
if (!new_src) {
// fall back to windows
new_src = $img.data('src-windows' + suffix);
data_attribute = 'src-windows';
new_src = $img.data(data_attribute);
}

this.src = new_src;
$img.attr('data-processed', 'true');
$img.addClass(site.platform);
});
};

// }}}

// High Resolution Images
// {{{ initHighResImages()

Mozilla.ImageHelper.initHighResImages = function() {
$('img[data-src][data-high-res="true"][data-processed="false"]').each(function() {
var $img = $(this);
var src = $img.data('src');
if (Mozilla.ImageHelper.isHighDpi()) {
src = $img.data('high-res-src');
// if high res requested and path provided, set srcset attribute
// needs to be set prior to src to avoid downloading standard res image
// on high-res screens
if (is_high_res && $img.data(data_attribute + '-high-res')) {
$img.attr('srcset', $img.data(data_attribute + '-high-res') + ' 1.5x');
}
this.src = src;
$img.attr('data-processed', 'true');
});
};

// }}}
// {{{ isHighDpi()

Mozilla.ImageHelper.isHighDpi = function() {
if (Mozilla.ImageHelper.is_high_dpi === null) {
var media_query = '(-webkit-min-device-pixel-ratio: 1.5),' +
'(-o-min-device-pixel-ratio: 3/2),' +
'(min--moz-device-pixel-ratio: 1.5),' +
'(min-resolution: 1.5dppx)';

Mozilla.ImageHelper.is_high_dpi = (window.devicePixelRatio > 1 ||
(window.matchMedia && window.matchMedia(media_query).matches));
}
this.src = new_src;

return Mozilla.ImageHelper.is_high_dpi;
$img.addClass(site.platform);
});
};

// }}}
78 changes: 21 additions & 57 deletions tests/unit/spec/base/mozilla-image-helper.js
Expand Up @@ -28,7 +28,6 @@ describe('mozilla-image-helper.js', function() {
'data-src-ios="/img/browser-ios.png"' +
'data-src-ios-high-res="/img/browser-ios-high-res.png">';

stub = sinon.stub(Mozilla.ImageHelper, 'isHighDpi').returns(false);
window.site = {
platform: 'other'
};
Expand All @@ -37,7 +36,6 @@ describe('mozilla-image-helper.js', function() {
});

afterEach(function(){
Mozilla.ImageHelper.isHighDpi.restore();
window.site.platform = null;
$img.remove();
});
Expand Down Expand Up @@ -77,13 +75,6 @@ describe('mozilla-image-helper.js', function() {
expect($img.hasClass('android')).toBeTruthy();
});

it('should flag when a platform image been processed', function () {
window.site.platform = 'windows';
expect($img.attr('data-processed')).toEqual('false');
Mozilla.ImageHelper.initPlatformImages();
expect($img.attr('data-processed')).toEqual('true');
});

it('should fall back to Windows if no appropriate platform image is found', function () {
var tpl = '<img class="platform-img js" src=""' +
'data-processed="false"' +
Expand Down Expand Up @@ -122,73 +113,46 @@ describe('mozilla-image-helper.js', function() {
});

afterEach(function(){
Mozilla.ImageHelper.isHighDpi.restore();
window.site.platform = null;
$img.remove();
});

it('should update platform image url for high resolution devices', function () {
stub = sinon.stub(Mozilla.ImageHelper, 'isHighDpi').returns(true);
it('should add srcset attribute when data-high-res is true', function () {
window.site.platform = 'osx';
Mozilla.ImageHelper.initPlatformImages();
expect($img.attr('src')).toEqual('/img/browser-mac-high-res.png');
expect($img.attr('src')).toEqual('/img/browser-mac.png');
expect($img.attr('srcset')).toEqual('/img/browser-mac-high-res.png 1.5x');
expect($img.hasClass('osx')).toBeTruthy();
});

it('should not update platform image url for low resolution devices', function () {
stub = sinon.stub(Mozilla.ImageHelper, 'isHighDpi').returns(false);
it('should not add srcset when data-high-res is not present', function () {
$img.removeAttr('data-high-res');

window.site.platform = 'osx';
Mozilla.ImageHelper.initPlatformImages();
expect($img.attr('src')).toEqual('/img/browser-mac.png');
expect($img[0].hasAttribute('srcset')).toBeFalsy();
expect($img.hasClass('osx')).toBeTruthy();
});
});

describe('Mozilla.ImageHelper.initHighResImages', function() {

var stub;
var $img;

beforeEach(function () {
var tpl = '<img class="js" src=""' +
'data-high-res="true"' +
'data-processed="false"' +
'data-src="/img/low-res.png"' +
'data-high-res-src="/img/high-res.png">';
$img = $(tpl);
$img.appendTo('body');
});
it('should not add srcset when high res platform path is not present', function () {
$img.removeAttr('data-src-mac-high-res');

afterEach(function(){
Mozilla.ImageHelper.isHighDpi.restore();
$img.remove();
});

it('should update image url for high resolution devices', function() {
stub = sinon.stub(Mozilla.ImageHelper, 'isHighDpi').returns(true);
Mozilla.ImageHelper.initHighResImages();
expect($img.attr('src')).toEqual('/img/high-res.png');
});

it('should not update image url for low resolution devices', function () {
stub = sinon.stub(Mozilla.ImageHelper, 'isHighDpi').returns(false);
Mozilla.ImageHelper.initHighResImages();
expect($img.attr('src')).toEqual('/img/low-res.png');
window.site.platform = 'osx';
Mozilla.ImageHelper.initPlatformImages();
expect($img.attr('src')).toEqual('/img/browser-mac.png');
expect($img[0].hasAttribute('srcset')).toBeFalsy();
expect($img.hasClass('osx')).toBeTruthy();
});

it('should flag when an image has been processed', function () {
stub = sinon.stub(Mozilla.ImageHelper, 'isHighDpi').returns(true);
expect($img.attr('data-processed')).toEqual('false');
Mozilla.ImageHelper.initHighResImages();
expect($img.attr('data-processed')).toEqual('true');
});
it('should fall back to Windows high res if no appropriate platform image is found', function () {
$img.removeAttr('data-src-mac');

it('should not change the src of an image that is already processed', function () {
stub = sinon.stub(Mozilla.ImageHelper, 'isHighDpi').returns(true);
$img.attr('src', '/img/foo.png');
$img.attr('data-processed', 'true');
Mozilla.ImageHelper.initHighResImages();
expect($img.attr('src')).toEqual('/img/foo.png');
window.site.platform = 'osx';
Mozilla.ImageHelper.initPlatformImages();
expect($img.attr('src')).toEqual('/img/browser-windows.png');
expect($img.attr('srcset')).toEqual('/img/browser-windows-high-res.png 1.5x');
expect($img.hasClass('osx')).toBeTruthy();
});
});

Expand Down

0 comments on commit 1371266

Please sign in to comment.