picturefill-rails 0.1.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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);
|