picturefill-rails 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +112 -1
- data/VERSION +1 -1
- data/lib/picturefill/view_helper.rb +21 -1
- data/picturefill-rails.gemspec +17 -3
- data/spec/srcset/banner-HD.jpeg +0 -0
- data/spec/srcset/banner-phone-HD.jpeg +0 -0
- data/spec/srcset/banner-phone.jpeg +0 -0
- data/spec/srcset/banner.jpeg +0 -0
- data/spec/srcset/index.html +16 -0
- data/spec/srcset/tests/index.html +29 -0
- data/spec/srcset/tests/srcset-tests.js +100 -0
- data/spec/srcset/view_helper_spec.rb +35 -0
- data/vendor/assets/javascripts/jquery-picture.js +241 -0
- data/vendor/assets/javascripts/jquery-picture.min.js +18 -0
- data/vendor/assets/javascripts/picturefill.js +60 -0
- data/vendor/assets/javascripts/picturefill/matchmedia.js +2 -0
- data/vendor/assets/javascripts/srcset.js +755 -0
- data/vendor/assets/javascripts/srcset.min.js +1 -0
- metadata +17 -3
data/README.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# Picturefill View helpers for Rails
|
2
2
|
|
3
|
+
This gem provides polyfills for 3 wys to render responsive images:
|
4
|
+
|
5
|
+
* picturefill
|
6
|
+
* jquery-picture
|
7
|
+
* srcset
|
8
|
+
|
3
9
|
[picturefill](https://github.com/scottjehl/picturefill) is currently the best way for rendering [Responsive Images](http://5by5.tv/webahead/25) on a web page.
|
4
10
|
|
5
11
|
*picturefill-rails* provides nice view helper methods to render the picturefill.
|
@@ -32,6 +38,8 @@ The above can be rendered in Rails 3+ by writing the following code, using the V
|
|
32
38
|
= picture_src 'medium_x2.jpg', "(min-width: 400px) and (min-device-pixel-ratio: 2.0)"
|
33
39
|
= picture_src 'largs.jpg', "(min-width: 800px)"
|
34
40
|
= picture_src 'large_x2.jpg', "(min-width: 800px) and (min-device-pixel-ratio: 2.0)"
|
41
|
+
# ...
|
42
|
+
= picture_fallback "external/imgs/small.jpg", alt: "A giant stone face at The Bayon temple in Angkor Thom, Cambodia"
|
35
43
|
```
|
36
44
|
|
37
45
|
Note: This example uses [HAML](https://github.com/haml/haml) as the rendering engine.
|
@@ -45,6 +53,8 @@ Using conventions, and an extra `ratio:` option, the following shorthand is poss
|
|
45
53
|
= picture_src 'small.jpg', ratio: 'x2'
|
46
54
|
= picture_src 'medium.jpg', "400", ratio: 'x2'
|
47
55
|
= picture_src 'large.jpg', "800", ratio: 'x2'
|
56
|
+
# ...
|
57
|
+
= picture_fallback "external/imgs/small.jpg", alt: "A giant stone face at The Bayon temple in Angkor Thom, Cambodia"
|
48
58
|
```
|
49
59
|
|
50
60
|
This will ouput exactly the same HTML as the previous example :)
|
@@ -60,7 +70,108 @@ A number of specs are included which all pass and should ensure that the view he
|
|
60
70
|
|
61
71
|
## TODO
|
62
72
|
|
63
|
-
The `#picture_src` method works, but could use some heavy refactoring! I don't like methods of more than 10 lines!
|
73
|
+
The `#picture_src` method works, but could use some heavy refactoring! I don't like methods of more than 10 lines! Reponsibilities should be off-loaded to other methods (or classes)
|
74
|
+
|
75
|
+
Currently the gem only supports Ruby 1.9+ and has only been tested on 1.9.3.
|
76
|
+
|
77
|
+
## Assets
|
78
|
+
|
79
|
+
The gem includes the picturefill javascript assets that are automatically available for the asset pipeline. In your `application.js` manifest file require:
|
80
|
+
|
81
|
+
* `picturefill.js`
|
82
|
+
* `picturefill\matchemedia.js`
|
83
|
+
|
84
|
+
See [demo](http://scottjehl.github.com/picturefill/) for a full example!
|
85
|
+
|
86
|
+
## jQuery Picture
|
87
|
+
|
88
|
+
[jquery picture](http://jquerypicture.com/) is now also partly supported. It is very similar to picturefill but with slightly different tags.
|
89
|
+
|
90
|
+
The assets `jquery-picture.min.js` and `jquery-picture.js` are included in vendor/assets.
|
91
|
+
|
92
|
+
The view helper includes the helper methods:
|
93
|
+
|
94
|
+
* `picture_tag(alt)`
|
95
|
+
* `source_tag(src, media, options = {})
|
96
|
+
|
97
|
+
Usage example:
|
98
|
+
|
99
|
+
```haml
|
100
|
+
= picture_tag 'A giant stone face at The Bayon temple in Angkor Thom, Cambodia' do
|
101
|
+
= source_tag 'small.jpg', ratio: 'x2'
|
102
|
+
= source_tag 'medium.jpg', "400", ratio: 'x2'
|
103
|
+
= source_tag 'large.jpg', "800", ratio: 'x2'
|
104
|
+
# ...
|
105
|
+
= picture_fallback "external/imgs/small.jpg", alt: "A giant stone face at The Bayon
|
106
|
+
```
|
107
|
+
|
108
|
+
And to enable via jquery:
|
109
|
+
|
110
|
+
```javascript
|
111
|
+
$(function(){
|
112
|
+
$('picture').picture();
|
113
|
+
});
|
114
|
+
```
|
115
|
+
|
116
|
+
*Arcticles*
|
117
|
+
|
118
|
+
[critique of picturefill](http://oscargodson.com/posts/picturefill-needs-to-die.html)
|
119
|
+
|
120
|
+
## Img SrcSet Polyfill
|
121
|
+
|
122
|
+
See [the specification][spec] for the reference algorithm.
|
123
|
+
|
124
|
+
See [repo]: https://github.com/borismus/srcset-polyfill
|
125
|
+
|
126
|
+
### Usage
|
127
|
+
|
128
|
+
Use the `srcset` attribute of `<img>` elements. For example:
|
129
|
+
|
130
|
+
<img alt="The Breakfast Combo"
|
131
|
+
src="banner.jpeg"
|
132
|
+
srcset="banner-HD.jpeg 2x, banner-phone.jpeg 100w,
|
133
|
+
banner-phone-HD.jpeg 100w 2x"/>
|
134
|
+
|
135
|
+
|
136
|
+
Include `srcset.min.js` in your page.
|
137
|
+
|
138
|
+
*View helper*
|
139
|
+
|
140
|
+
* `imgset_tag src, srcset, options = {}` (alias `imageset_tag`)
|
141
|
+
|
142
|
+
```haml
|
143
|
+
= imgset_tag "banner.jpeg", "banner-HD.jpeg 2x, banner-phone.jpeg 100w,banner-phone-HD.jpeg 100w 2x", alt: "The Breakfast Combo"
|
144
|
+
```
|
145
|
+
|
146
|
+
outputs the HTML code shown above.
|
147
|
+
|
148
|
+
If you leave out the srcset argument it will fallback to a single src image
|
149
|
+
|
150
|
+
```haml
|
151
|
+
= imgset_tag "banner.jpeg", alt: "The Breakfast Combo"
|
152
|
+
```
|
153
|
+
|
154
|
+
Same as
|
155
|
+
|
156
|
+
```haml
|
157
|
+
= image_tag "banner.jpeg", alt: "The Breakfast Combo"
|
158
|
+
```
|
159
|
+
|
160
|
+
### Assets
|
161
|
+
|
162
|
+
The gem includes srcset javascript assets that are automatically available for the asset pipeline. In your `application.js` manifest file require:
|
163
|
+
|
164
|
+
* `srcset.min.js` (prod)
|
165
|
+
* `srcset.js` (dev/test)
|
166
|
+
|
167
|
+
### Open questions
|
168
|
+
|
169
|
+
- How to reliably check for srcset support in the browser (so as to not
|
170
|
+
attempt to polyfill if it's not necessary?)
|
171
|
+
- Is it safe to use `-webkit-transform` to scale things?
|
172
|
+
- Is it worth falling back to `-webkit-image-set` if available?
|
173
|
+
|
174
|
+
[spec]: http://www.whatwg.org/specs/web-apps/current-work/multipage/embedded-content-1.html#processing-the-image-candidates
|
64
175
|
|
65
176
|
## Contributing to picturefill-rails
|
66
177
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1
|
1
|
+
0.2.1
|
@@ -1,5 +1,24 @@
|
|
1
1
|
module Picturefill
|
2
2
|
module ViewHelper
|
3
|
+
def imgset_tag src, srcset = nil, options = {}
|
4
|
+
options.merge!(:src => src)
|
5
|
+
options.merge!(:srcset => srcset) if srcset
|
6
|
+
content_tag :img, nil, options
|
7
|
+
end
|
8
|
+
alias_method :imageset_tag, :imgset_tag
|
9
|
+
|
10
|
+
def picture_tag alt = nil
|
11
|
+
options = {}
|
12
|
+
options.merge alt: alt if alt
|
13
|
+
content_tag :picture, nil, options
|
14
|
+
end
|
15
|
+
|
16
|
+
def source_tag src, *args
|
17
|
+
options = args.extract_options!
|
18
|
+
media = args.first.to_s if args.first.kind_of?(String) || args.first.kind_of?(Fixnum)
|
19
|
+
picture_src src, media, options.merge(tag: :source)
|
20
|
+
end
|
21
|
+
|
3
22
|
def picturefill options = {}, &block
|
4
23
|
opts = {}
|
5
24
|
alt = options.delete :alt
|
@@ -17,6 +36,7 @@ module Picturefill
|
|
17
36
|
options = args.extract_options!
|
18
37
|
media = args.first.to_s if args.first.kind_of?(String) || args.first.kind_of?(Fixnum)
|
19
38
|
|
39
|
+
tag = options[:tag] || :div
|
20
40
|
ratio_opt = options.delete(:ratio)
|
21
41
|
media_opt = Picturefill::ViewHelper.extract media unless media.blank?
|
22
42
|
|
@@ -43,7 +63,7 @@ module Picturefill
|
|
43
63
|
options.merge! :"data-media" => media_opt unless auto_ratio_tag || media_opt.blank?
|
44
64
|
options.merge! :"data-src" => src
|
45
65
|
|
46
|
-
content_tag(
|
66
|
+
content_tag(tag, nil, options) + next_content
|
47
67
|
end
|
48
68
|
|
49
69
|
def picture_fallback src, options = {}
|
data/picturefill-rails.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "picturefill-rails"
|
8
|
-
s.version = "0.1
|
8
|
+
s.version = "0.2.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Kristian Mandrup"]
|
12
|
-
s.date = "2012-08-
|
12
|
+
s.date = "2012-08-29"
|
13
13
|
s.description = "Use picturefill with Rails :)"
|
14
14
|
s.email = "kmandrup@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -30,7 +30,21 @@ Gem::Specification.new do |s|
|
|
30
30
|
"lib/picturefill/view_helper.rb",
|
31
31
|
"picturefill-rails.gemspec",
|
32
32
|
"spec/picturefill/view_helper_spec.rb",
|
33
|
-
"spec/spec_helper.rb"
|
33
|
+
"spec/spec_helper.rb",
|
34
|
+
"spec/srcset/banner-HD.jpeg",
|
35
|
+
"spec/srcset/banner-phone-HD.jpeg",
|
36
|
+
"spec/srcset/banner-phone.jpeg",
|
37
|
+
"spec/srcset/banner.jpeg",
|
38
|
+
"spec/srcset/index.html",
|
39
|
+
"spec/srcset/tests/index.html",
|
40
|
+
"spec/srcset/tests/srcset-tests.js",
|
41
|
+
"spec/srcset/view_helper_spec.rb",
|
42
|
+
"vendor/assets/javascripts/jquery-picture.js",
|
43
|
+
"vendor/assets/javascripts/jquery-picture.min.js",
|
44
|
+
"vendor/assets/javascripts/picturefill.js",
|
45
|
+
"vendor/assets/javascripts/picturefill/matchmedia.js",
|
46
|
+
"vendor/assets/javascripts/srcset.js",
|
47
|
+
"vendor/assets/javascripts/srcset.min.js"
|
34
48
|
]
|
35
49
|
s.homepage = "http://github.com/kristianmandrup/picturefill-rails"
|
36
50
|
s.licenses = ["MIT"]
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Srcset Polyfill Demo</title>
|
5
|
+
<script src="../../vendor/assets/javascripts/srcset.js"></script>
|
6
|
+
<style>
|
7
|
+
body { background: gray; }
|
8
|
+
</style>
|
9
|
+
</head>
|
10
|
+
|
11
|
+
<div id="container"><img alt="The Breakfast Combo"
|
12
|
+
src="banner.jpeg"
|
13
|
+
srcset="banner-HD.jpeg 2x, banner-phone.jpeg 100w, banner-phone-HD.jpeg 100w 2x"></div>
|
14
|
+
</body>
|
15
|
+
</html>
|
16
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Srcset Polyfill Unit tests</title>
|
5
|
+
<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css">
|
6
|
+
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
|
7
|
+
<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
|
8
|
+
<script src="../../../vendor/assets/javascripts/srcset.js"></script>
|
9
|
+
<script src="srcset-tests.js"></script>
|
10
|
+
</head>
|
11
|
+
|
12
|
+
<h1><img alt="The Breakfast Combo"
|
13
|
+
src="banner.jpeg"
|
14
|
+
srcset="banner-HD.jpeg 2x, banner-phone.jpeg 100w, banner-phone-HD.jpeg 100w 2x"></h1>
|
15
|
+
|
16
|
+
|
17
|
+
<body>
|
18
|
+
<h1 id="qunit-header">Srcset Polyfill Unit Tests</h1>
|
19
|
+
<h2 id="qunit-banner"></h2>
|
20
|
+
<div id="qunit-testrunner-toolbar"></div>
|
21
|
+
<h2 id="qunit-userAgent"></h2>
|
22
|
+
<ol id="qunit-tests"></ol>
|
23
|
+
<div id="qunit-fixture">test markup, will be hidden</div>
|
24
|
+
|
25
|
+
<div id="test">
|
26
|
+
</div>
|
27
|
+
</body>
|
28
|
+
</html>
|
29
|
+
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module('srcset validation');
|
2
|
+
|
3
|
+
test('valid image candidate strings validate', function() {
|
4
|
+
var s1 = new SrcsetInfo({src: 'pear.jpeg', srcset: 'pear-mobile.jpeg'});
|
5
|
+
ok(s1.isValid, 'simple image candidates without descriptors understood.');
|
6
|
+
var s2 = new SrcsetInfo({src: 'pear.jpeg', srcset: 'pear-mobile.jpeg 720w'});
|
7
|
+
ok(s2.isValid, 'simple image candidates understood.');
|
8
|
+
var s3 = new SrcsetInfo({srcset: 'pear-mobile.jpeg 1.1x'});
|
9
|
+
ok(s3.isValid, 'simple image candidates understood.');
|
10
|
+
var s4 = new SrcsetInfo({srcset: 'pear-mobile.jpeg 720w, pear-tablet.jpeg 1280w'});
|
11
|
+
ok(s4.isValid, 'compound image candidates understood.');
|
12
|
+
var s5 = new SrcsetInfo({srcset: 'pear-mobile.jpeg 720w, pear-tablet.jpeg 1280w, pear-desktop.jpeg 1x'});
|
13
|
+
ok(s5.isValid, 'complex compound image candidates understood.');
|
14
|
+
});
|
15
|
+
|
16
|
+
test('invalid image candidate strings do not validate', function() {
|
17
|
+
var s1 = new SrcsetInfo({srcset: 'pear-mobile.jpeg 720k, pear-tablet.jpeg 1280w'});
|
18
|
+
ok(!s1.isValid, 'unknown descriptor units rejected');
|
19
|
+
var s2 = new SrcsetInfo({srcset: 'pear-mobile.jpeg 7.2w, pear-tablet.jpeg 1280w'});
|
20
|
+
ok(!s2.isValid, 'non-integer widths rejected.');
|
21
|
+
});
|
22
|
+
|
23
|
+
module('srcset parsing');
|
24
|
+
|
25
|
+
test('single image declarations set to the right defaults', function() {
|
26
|
+
var s1 = new SrcsetInfo({srcset: 'pear-mobile.jpeg'});
|
27
|
+
var img = s1.imageCandidates[0];
|
28
|
+
equal(img.x, 1, 'default density set');
|
29
|
+
equal(img.w, Infinity, 'default width set');
|
30
|
+
equal(img.h, Infinity, 'default height set');
|
31
|
+
});
|
32
|
+
|
33
|
+
test('single image declarations parse correctly', function() {
|
34
|
+
var s1 = new SrcsetInfo({srcset: 'pear-mobile.jpeg 720w'});
|
35
|
+
var img = s1.imageCandidates[0];
|
36
|
+
equal(img.src, 'pear-mobile.jpeg', 'image src validates');
|
37
|
+
equal(img.w, 720, 'width set');
|
38
|
+
});
|
39
|
+
|
40
|
+
test('multiple image candidates parse correctly', function() {
|
41
|
+
var s1 = new SrcsetInfo({srcset: 'pear-mobile.jpeg 720w, pear-tablet.jpeg 1280w, pear-desktop.jpeg 1.5x'});
|
42
|
+
equal(s1.imageCandidates.length, 3, '3 image candidates found');
|
43
|
+
var img = s1.imageCandidates[2];
|
44
|
+
equal(img.x, 1.5, 'last image candidate density is 1.5');
|
45
|
+
});
|
46
|
+
|
47
|
+
test('repeated values for image candidates are ignored', function() {
|
48
|
+
var s1 = new SrcsetInfo({srcset: 'pear-mobile.jpeg 720w, pear-tablet.jpeg 720w'});
|
49
|
+
equal(s1.imageCandidates.length, 1, '1 image candidate found');
|
50
|
+
var img = s1.imageCandidates[0];
|
51
|
+
equal(img.src, 'pear-mobile.jpeg', 'last candidate ignored.');
|
52
|
+
});
|
53
|
+
|
54
|
+
|
55
|
+
module('image candidate selection');
|
56
|
+
|
57
|
+
test('simple srcset picks correct image candidate', function() {
|
58
|
+
var old = new ViewportInfo();
|
59
|
+
old.setForTesting({w: 2000, h: 1000, x: 1});
|
60
|
+
var s1 = new SrcsetInfo({src: 'banner.jpeg', srcset: 'banner-HD.jpeg 2x'});
|
61
|
+
var img = old.getBestImage(s1);
|
62
|
+
equal(img.src, 'banner.jpeg', 'picked right image');
|
63
|
+
var hd = new ViewportInfo();
|
64
|
+
hd.setForTesting({w: 2000, h: 1000, x: 2});
|
65
|
+
var img = hd.getBestImage(s1);
|
66
|
+
equal(img.src, 'banner-HD.jpeg', 'picked right image');
|
67
|
+
});
|
68
|
+
|
69
|
+
test('ambiguous srcset picks best image candidate', function() {
|
70
|
+
var vp = new ViewportInfo();
|
71
|
+
vp.setForTesting({w: 500, h: 500});
|
72
|
+
var s1 = new SrcsetInfo({src: 'banner.jpeg',
|
73
|
+
srcset: 'banner-wide.jpeg 300w 1000h, banner-tall.jpeg 1000w 300h, banner.jpeg'});
|
74
|
+
var img = vp.getBestImage(s1);
|
75
|
+
equal(img.src, 'banner.jpeg', 'makes sense.');
|
76
|
+
});
|
77
|
+
|
78
|
+
test('complex srcset picks best image candidate', function() {
|
79
|
+
var mobile = new ViewportInfo();
|
80
|
+
mobile.setForTesting({w: 320, h: 480, x: 2});
|
81
|
+
var s1 = new SrcsetInfo({src: 'banner.jpeg', srcset: 'banner-HD.jpeg 2x, banner-phone.jpeg 400w, banner-phone-HD.jpeg 400w 2x'});
|
82
|
+
var img = mobile.getBestImage(s1);
|
83
|
+
equal(img.src, 'banner-phone-HD.jpeg', 'picked best image for phone');
|
84
|
+
var desktop = new ViewportInfo();
|
85
|
+
desktop.setForTesting({w: 1440, h: 1280, x: 2});
|
86
|
+
var img = desktop.getBestImage(s1);
|
87
|
+
equal(img.src, 'banner-HD.jpeg', 'picked best image for desktop');
|
88
|
+
var old = new ViewportInfo();
|
89
|
+
old.setForTesting({w: 320, h: 480, x: 1});
|
90
|
+
var img = old.getBestImage(s1);
|
91
|
+
equal(img.src, 'banner-phone.jpeg', 'picked best image for desktop');
|
92
|
+
});
|
93
|
+
|
94
|
+
test('john mellor test', function() {
|
95
|
+
var mobile = new ViewportInfo();
|
96
|
+
mobile.setForTesting({w: 320, h: 480, x: 2.1});
|
97
|
+
var s1 = new SrcsetInfo({srcset: 'ipad1.jpg 1024w, iphone4.jpg 320w 2x'});
|
98
|
+
var img = mobile.getBestImage(s1);
|
99
|
+
equal(img.src, 'iphone4.jpg', 'picked best image for phone');
|
100
|
+
});
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Picturefill::ViewHelper do
|
4
|
+
include ControllerTestHelpers,
|
5
|
+
Picturefill::ViewHelper
|
6
|
+
|
7
|
+
describe '#imgset_tag' do
|
8
|
+
context 'no arguments' do
|
9
|
+
specify do
|
10
|
+
expect { imgset_tag }.to raise_error
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'one argument' do
|
15
|
+
specify do
|
16
|
+
output = imgset_tag('hello.jpg')
|
17
|
+
output.should == "<img src=\"hello.jpg\"></img>"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'alt option' do
|
22
|
+
it "should add the data-alt atribute" do
|
23
|
+
output = imgset_tag "banner.jpeg", "banner-HD.jpeg 2x, banner-phone.jpeg 100w,banner-phone-HD.jpeg 100w 2x"
|
24
|
+
output.should == "<img src=\"banner.jpeg\" srcset=\"banner-HD.jpeg 2x, banner-phone.jpeg 100w,banner-phone-HD.jpeg 100w 2x\"></img>"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'alt option and block' do
|
29
|
+
it "should add a piture src" do
|
30
|
+
output = imgset_tag "banner.jpeg", "banner-HD.jpeg 2x, banner-phone.jpeg 100w,banner-phone-HD.jpeg 100w 2x", alt: "The Breakfast Combo"
|
31
|
+
output.should == "<img alt=\"The Breakfast Combo\" src=\"banner.jpeg\" srcset=\"banner-HD.jpeg 2x, banner-phone.jpeg 100w,banner-phone-HD.jpeg 100w 2x\"></img>"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,241 @@
|
|
1
|
+
/**
|
2
|
+
* jQuery Picture
|
3
|
+
* http://jquerypicture.com
|
4
|
+
* http://github.com/Abban/jQuery-Picture
|
5
|
+
*
|
6
|
+
* May 2012
|
7
|
+
*
|
8
|
+
* @version 0.9
|
9
|
+
* @author Abban Dunne http://abandon.ie
|
10
|
+
* @license MIT
|
11
|
+
*
|
12
|
+
* jQuery Picture is a plugin to add support for responsive images to your layouts.
|
13
|
+
* It supports both figure elements with some custom data attributes and the new
|
14
|
+
* proposed picture format. This plugin will be made redundant when the format is
|
15
|
+
* approved and implemented by browsers. Lets hope that happens soon. In the meantime
|
16
|
+
* this plugin will be kept up to date with latest developments.
|
17
|
+
*
|
18
|
+
*/
|
19
|
+
(function($){
|
20
|
+
|
21
|
+
$.fn.picture = function(args){
|
22
|
+
|
23
|
+
var defaults = {
|
24
|
+
|
25
|
+
container : null
|
26
|
+
|
27
|
+
};
|
28
|
+
|
29
|
+
var settings = $.extend({}, defaults, args);
|
30
|
+
|
31
|
+
this.each(function(){
|
32
|
+
|
33
|
+
var breakpoints = new Array();
|
34
|
+
|
35
|
+
var windowWidth, currentMedia, element, timeoutOffset;
|
36
|
+
|
37
|
+
// Check the device pixel ratio
|
38
|
+
var PixelRatio = 1;
|
39
|
+
if(window.devicePixelRatio !== undefined) PixelRatio = window.devicePixelRatio;
|
40
|
+
|
41
|
+
// Save off the element so it can be easily used inside a function
|
42
|
+
element = $(this);
|
43
|
+
|
44
|
+
// Initialise the images
|
45
|
+
getCurrentMedia(true);
|
46
|
+
|
47
|
+
// Only call the image resize function 200ms after window stops being resized
|
48
|
+
timeoutOffset = false;
|
49
|
+
|
50
|
+
$(window).resize(function(){
|
51
|
+
|
52
|
+
if(timeoutOffset !== false)
|
53
|
+
clearTimeout(timeoutOffset);
|
54
|
+
|
55
|
+
timeoutOffset = setTimeout(getCurrentMedia, 200);
|
56
|
+
|
57
|
+
});
|
58
|
+
|
59
|
+
|
60
|
+
/**
|
61
|
+
* getCurrentMedia
|
62
|
+
*
|
63
|
+
* Checks the window width off the media query types and selects the current one.
|
64
|
+
* Calls the setPicture or setFigure function to set the image.
|
65
|
+
*
|
66
|
+
*/
|
67
|
+
function getCurrentMedia(init){
|
68
|
+
|
69
|
+
if(init){
|
70
|
+
|
71
|
+
if(element.get(0).tagName.toLowerCase() == 'figure'){
|
72
|
+
|
73
|
+
var mediaObj = element.data();
|
74
|
+
|
75
|
+
$.each(mediaObj, function(media){
|
76
|
+
|
77
|
+
var num;
|
78
|
+
|
79
|
+
num = media.replace(/[^\d.]/g, '');
|
80
|
+
|
81
|
+
if(num)
|
82
|
+
breakpoints.push(num);
|
83
|
+
|
84
|
+
});
|
85
|
+
|
86
|
+
}else{
|
87
|
+
|
88
|
+
element.find('source').each(function(){
|
89
|
+
|
90
|
+
var media, num;
|
91
|
+
|
92
|
+
media = $(this).attr('media');
|
93
|
+
|
94
|
+
if(media){
|
95
|
+
|
96
|
+
num = media.replace(/[^\d.]/g, '');
|
97
|
+
|
98
|
+
breakpoints.push(num);
|
99
|
+
}
|
100
|
+
|
101
|
+
});
|
102
|
+
|
103
|
+
}
|
104
|
+
|
105
|
+
}
|
106
|
+
|
107
|
+
var c = 0;
|
108
|
+
|
109
|
+
// Check if user defined container, otherwise take window
|
110
|
+
if (settings.container == null){
|
111
|
+
|
112
|
+
windowWidth = ($(window).width()) * PixelRatio;
|
113
|
+
|
114
|
+
}else{
|
115
|
+
|
116
|
+
windowWidth = ($(settings.container).width()) * PixelRatio;
|
117
|
+
|
118
|
+
}
|
119
|
+
|
120
|
+
// Set the c variable to the current media width
|
121
|
+
$.each(breakpoints, function(i,v){
|
122
|
+
|
123
|
+
if(parseInt(windowWidth) >= parseInt(v) && parseInt(c) <= parseInt(v))
|
124
|
+
c = v;
|
125
|
+
|
126
|
+
});
|
127
|
+
|
128
|
+
if(currentMedia !== c){
|
129
|
+
currentMedia = c;
|
130
|
+
|
131
|
+
if(element.get(0).tagName.toLowerCase() == 'figure')
|
132
|
+
setFigure();
|
133
|
+
else
|
134
|
+
setPicture();
|
135
|
+
}
|
136
|
+
|
137
|
+
}
|
138
|
+
|
139
|
+
|
140
|
+
/**
|
141
|
+
* setPicture
|
142
|
+
*
|
143
|
+
* Pulls the image src and media attributes from the source tags and sets
|
144
|
+
* the src of the enclosed img tag to the appropriate one.
|
145
|
+
*
|
146
|
+
*/
|
147
|
+
function setPicture(){
|
148
|
+
|
149
|
+
var sizes = new Object();
|
150
|
+
|
151
|
+
element.find('source').each(function(){
|
152
|
+
|
153
|
+
var media, path, num;
|
154
|
+
media = $(this).attr('media');
|
155
|
+
path = $(this).attr('src');
|
156
|
+
|
157
|
+
if(media)
|
158
|
+
num = media.replace(/[^\d.]/g, '');
|
159
|
+
else
|
160
|
+
num = 0;
|
161
|
+
|
162
|
+
sizes[num] = path;
|
163
|
+
|
164
|
+
});
|
165
|
+
|
166
|
+
if(element.find('img').length == 0){
|
167
|
+
|
168
|
+
var prep = '<img src="' + sizes[currentMedia] + '" style="' + element.attr('style') + '" alt="' + element.attr('alt') + '">';
|
169
|
+
|
170
|
+
if(element.find('a').length == 0){
|
171
|
+
|
172
|
+
element.append(prep);
|
173
|
+
|
174
|
+
}else{
|
175
|
+
|
176
|
+
element.find('a').append(prep);
|
177
|
+
|
178
|
+
}
|
179
|
+
|
180
|
+
}else{
|
181
|
+
|
182
|
+
element.find('img').attr('src', sizes[currentMedia]);
|
183
|
+
|
184
|
+
}
|
185
|
+
|
186
|
+
}
|
187
|
+
|
188
|
+
|
189
|
+
/**
|
190
|
+
* setFigure
|
191
|
+
*
|
192
|
+
* Pulls the image src and and media values from the data attributes
|
193
|
+
* and sets the src of the enclosed img tag to the appropriate one.
|
194
|
+
*
|
195
|
+
*/
|
196
|
+
function setFigure(){
|
197
|
+
|
198
|
+
var sizes = new Object();
|
199
|
+
|
200
|
+
var mediaObj = element.data();
|
201
|
+
|
202
|
+
$.each(mediaObj, function(media, path){
|
203
|
+
|
204
|
+
var num;
|
205
|
+
|
206
|
+
num = media.replace(/[^\d.]/g, '');
|
207
|
+
|
208
|
+
if(!num)
|
209
|
+
num = 0;
|
210
|
+
|
211
|
+
sizes[num] = path;
|
212
|
+
|
213
|
+
});
|
214
|
+
|
215
|
+
if(element.find('img').length == 0){
|
216
|
+
|
217
|
+
var prep = '<img src="' + sizes[currentMedia] + '" alt="' + element.attr('title') + '">';
|
218
|
+
|
219
|
+
if(element.find('a').length == 0){
|
220
|
+
|
221
|
+
element.prepend(prep);
|
222
|
+
|
223
|
+
}else{
|
224
|
+
|
225
|
+
element.find('a').prepend(prep);
|
226
|
+
|
227
|
+
}
|
228
|
+
|
229
|
+
}else{
|
230
|
+
|
231
|
+
element.find('img').attr('src', sizes[currentMedia]);
|
232
|
+
|
233
|
+
}
|
234
|
+
|
235
|
+
}
|
236
|
+
|
237
|
+
});
|
238
|
+
|
239
|
+
};
|
240
|
+
|
241
|
+
})(jQuery);
|