retinajs-rails 0.2 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b543d7cfda51df21fe2c7633829f99e8187e0d8d
4
- data.tar.gz: 278d5c80eca30acf827d357a26d7abf2a7fbdcaf
3
+ metadata.gz: d7d7b055ab3b02ec01c58e348d388f2d588b8439
4
+ data.tar.gz: 712146e59a0f9842d5465237a6a00509b3718151
5
5
  SHA512:
6
- metadata.gz: 121d8b255c47c3e5d561cc77f272ad244ec0bc31ff2789b198965720f52029d38657f16a53502db3e6710de58800a176c60f38a3ba0d987a0c6f8a132d98e2ef
7
- data.tar.gz: e2d1b3be8a6d4e9ed9f10469d38e089284daa6e4f226d83dcbfe1d2fe5445fbf10c7de510c6a717b341c36427c047d7f092381442940377e5d8c3dd9a05734a6
6
+ metadata.gz: 9276307acb3d2290994064a38f9305c5f2b86b844f726c6a124786eaff2280ed6f5243cd104a35b0a9b90be714414047b1df541a45dccb28b8047e02d92363b8
7
+ data.tar.gz: 0e3a00adb827256b814320bee9e2c33893084931d066b4b25b5ac9d94aac5cba8a8223fdce707faa2f499c2bfbb363cec3ac066fefd18314f5064f377cac85f1
data/README.md CHANGED
@@ -8,7 +8,7 @@ Retina.js is an awesome and simple plugin for rendering retina images for displa
8
8
 
9
9
  Add this line to your application's Gemfile:
10
10
 
11
- gem "retinajs-rails", "~> 0.1"
11
+ gem "retinajs-rails", "~> 2.1"
12
12
 
13
13
  And then execute:
14
14
 
@@ -1,182 +1,253 @@
1
1
  /*!
2
- * Retina.js v1.3.0
2
+ * Retina.js v2.1.0
3
3
  *
4
- * Copyright 2014 Imulus, LLC
4
+ * Copyright 2016 Axial, LLC
5
5
  * Released under the MIT license
6
6
  *
7
7
  * Retina.js is an open source script that makes it easy to serve
8
8
  * high-resolution images to devices with retina displays.
9
9
  */
10
+ 'use strict';
10
11
 
11
- (function() {
12
- var root = (typeof exports === 'undefined' ? window : exports);
13
- var config = {
14
- // An option to choose a suffix for 2x images
15
- retinaImageSuffix : '@2x',
16
-
17
- // Ensure Content-Type is an image before trying to load @2x image
18
- // https://github.com/imulus/retinajs/pull/45)
19
- check_mime_type: true,
20
-
21
- // Resize high-resolution images to original image's pixel dimensions
22
- // https://github.com/imulus/retinajs/issues/8
23
- force_original_dimensions: true
24
- };
25
-
26
- function Retina() {}
27
-
28
- root.Retina = Retina;
29
-
30
- Retina.configure = function(options) {
31
- if (options === null) {
32
- options = {};
33
- }
34
-
35
- for (var prop in options) {
36
- if (options.hasOwnProperty(prop)) {
37
- config[prop] = options[prop];
38
- }
39
- }
40
- };
41
-
42
- Retina.init = function(context) {
43
- if (context === null) {
44
- context = root;
45
- }
46
-
47
- var existing_onload = context.onload || function(){};
48
-
49
- context.onload = function() {
50
- var images = document.getElementsByTagName('img'), retinaImages = [], i, image;
51
- for (i = 0; i < images.length; i += 1) {
52
- image = images[i];
53
- if (!!!image.getAttributeNode('data-no-retina')) {
54
- retinaImages.push(new RetinaImage(image));
55
- }
56
- }
57
- existing_onload();
58
- };
59
- };
12
+ Object.defineProperty(exports, "__esModule", {
13
+ value: true
14
+ });
15
+ /*
16
+ * Determine whether or not `window` is available.
17
+ */
18
+ var hasWindow = typeof window !== 'undefined';
60
19
 
61
- Retina.isRetina = function(){
62
- var mediaQuery = '(-webkit-min-device-pixel-ratio: 1.5), (min--moz-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3/2), (min-resolution: 1.5dppx)';
20
+ /*
21
+ * Get the device pixel ratio per our environment.
22
+ * Default to 1.
23
+ */
24
+ var environment = hasWindow ? window.devicePixelRatio || 1 : 1;
63
25
 
64
- if (root.devicePixelRatio > 1) {
65
- return true;
66
- }
26
+ /*
27
+ * Define a pattern for capturing src url suffixes.
28
+ */
29
+ var srcReplace = /(\.[A-z]{3,4}\/?(\?.*)?)$/;
30
+ var inlineReplace = /url\(('|")?([^\)'"]+)('|")?\)/i;
67
31
 
68
- if (root.matchMedia && root.matchMedia(mediaQuery).matches) {
69
- return true;
70
- }
32
+ /*
33
+ * Define our selectors for elements to target.
34
+ */
35
+ var selector = '[data-rjs]';
71
36
 
72
- return false;
73
- };
37
+ /*
38
+ * Define the attribute we'll use to mark an image as having been processed.
39
+ */
40
+ var processedAttr = 'data-rjs-processed';
74
41
 
42
+ /**
43
+ * Shortcut for turning some iterable object into an array.
44
+ *
45
+ * @param {Iterable} object Any iterable object.
46
+ *
47
+ * @return {Array}
48
+ */
49
+ function arrayify(object) {
50
+ return Array.prototype.slice.call(object);
51
+ }
75
52
 
76
- var regexMatch = /\.\w+$/;
77
- function suffixReplace (match) {
78
- return config.retinaImageSuffix + match;
53
+ /**
54
+ * Chooses the actual image size to fetch, (for example 2 or 3) that
55
+ * will be used to create a suffix like "@2x" or "@3x".
56
+ *
57
+ * @param {String|Number} cap The number the user provided indicating that
58
+ * they have prepared images up to this size.
59
+ *
60
+ * @return {Number} The number we'll be using to create a suffix.
61
+ */
62
+ function chooseCap(cap) {
63
+ var numericCap = parseInt(cap, 10);
64
+
65
+ /*
66
+ * If the environment's device pixel ratio is less than what the user
67
+ * provided, we'll only grab images at that size.
68
+ */
69
+ if (environment < numericCap) {
70
+ return environment;
71
+
72
+ /*
73
+ * If the device pixel ratio is greater than or equal to what the
74
+ * user provided, we'll use what the user provided.
75
+ */
76
+ } else {
77
+ return numericCap;
79
78
  }
79
+ }
80
80
 
81
- function RetinaImagePath(path, at_2x_path) {
82
- this.path = path || '';
83
- if (typeof at_2x_path !== 'undefined' && at_2x_path !== null) {
84
- this.at_2x_path = at_2x_path;
85
- this.perform_check = false;
86
- } else {
87
- if (undefined !== document.createElement) {
88
- var locationObject = document.createElement('a');
89
- locationObject.href = this.path;
90
- locationObject.pathname = locationObject.pathname.replace(regexMatch, suffixReplace);
91
- this.at_2x_path = locationObject.href;
92
- } else {
93
- var parts = this.path.split('?');
94
- parts[0] = parts[0].replace(regexMatch, suffixReplace);
95
- this.at_2x_path = parts.join('?');
96
- }
97
- this.perform_check = true;
98
- }
81
+ /**
82
+ * Makes sure that, since we are going to swap out the source of an image,
83
+ * the image does not change size on the page.
84
+ *
85
+ * @param {Element} image An image element in the DOM.
86
+ *
87
+ * @return {Element} The same element that was passed in.
88
+ */
89
+ function forceOriginalDimensions(image) {
90
+ if (!image.hasAttribute('data-no-resize')) {
91
+ if (image.offsetWidth === 0 && image.offsetHeight === 0) {
92
+ image.setAttribute('width', image.naturalWidth);
93
+ image.setAttribute('height', image.naturalHeight);
94
+ } else {
95
+ image.setAttribute('width', image.offsetWidth);
96
+ image.setAttribute('height', image.offsetHeight);
99
97
  }
100
-
101
- root.RetinaImagePath = RetinaImagePath;
102
-
103
- RetinaImagePath.confirmed_paths = [];
104
-
105
- RetinaImagePath.prototype.is_external = function() {
106
- return !!(this.path.match(/^https?\:/i) && !this.path.match('//' + document.domain) );
107
- };
108
-
109
- RetinaImagePath.prototype.check_2x_variant = function(callback) {
110
- var http, that = this;
111
- if (this.is_external()) {
112
- return callback(false);
113
- } else if (!this.perform_check && typeof this.at_2x_path !== 'undefined' && this.at_2x_path !== null) {
114
- return callback(true);
115
- } else if (this.at_2x_path in RetinaImagePath.confirmed_paths) {
116
- return callback(true);
117
- } else {
118
- http = new XMLHttpRequest();
119
- http.open('HEAD', this.at_2x_path);
120
- http.onreadystatechange = function() {
121
- if (http.readyState !== 4) {
122
- return callback(false);
123
- }
124
-
125
- if (http.status >= 200 && http.status <= 399) {
126
- if (config.check_mime_type) {
127
- var type = http.getResponseHeader('Content-Type');
128
- if (type === null || !type.match(/^image/i)) {
129
- return callback(false);
130
- }
131
- }
132
-
133
- RetinaImagePath.confirmed_paths.push(that.at_2x_path);
134
- return callback(true);
135
- } else {
136
- return callback(false);
137
- }
138
- };
139
- http.send();
140
- }
141
- };
142
-
143
-
144
- function RetinaImage(el) {
145
- this.el = el;
146
- this.path = new RetinaImagePath(this.el.getAttribute('src'), this.el.getAttribute('data-at2x'));
147
- var that = this;
148
- this.path.check_2x_variant(function(hasVariant) {
149
- if (hasVariant) {
150
- that.swap();
151
- }
152
- });
98
+ }
99
+ return image;
100
+ }
101
+
102
+ /**
103
+ * Determines whether the retina image actually exists on the server.
104
+ * If so, swaps out the retina image for the standard one. If not,
105
+ * leaves the original image alone.
106
+ *
107
+ * @param {Element} image An image element in the DOM.
108
+ * @param {String} newSrc The url to the retina image.
109
+ *
110
+ * @return {undefined}
111
+ */
112
+ function setSourceIfAvailable(image, retinaURL) {
113
+ var imgType = image.nodeName.toLowerCase();
114
+
115
+ /*
116
+ * Create a new image element and give it a load listener. When the
117
+ * load listener fires, it means the URL is correct and we will then
118
+ * attach it to the user's image.
119
+ */
120
+ var testImage = document.createElement('img');
121
+ testImage.addEventListener('load', function () {
122
+ /*
123
+ * If we're dealing with an image tag, force it's dimensions
124
+ * and set the source attribute. If not, go after the background-image
125
+ * inline style.
126
+ */
127
+ if (imgType === 'img') {
128
+ forceOriginalDimensions(image).setAttribute('src', retinaURL);
129
+ } else {
130
+ image.style.backgroundImage = 'url(' + retinaURL + ')';
153
131
  }
132
+ });
133
+
134
+ /*
135
+ * Attach the retina URL to our proxy image to load in the new
136
+ * image resource.
137
+ */
138
+ testImage.setAttribute('src', retinaURL);
139
+
140
+ /*
141
+ * Mark our image as processed so that it won't be processed again.
142
+ */
143
+ image.setAttribute(processedAttr, true);
144
+ }
145
+
146
+ /**
147
+ * Attempts to do an image url swap on a given image.
148
+ *
149
+ * @param {Element} image An image in the DOM.
150
+ * @param {String} src The original image source attribute.
151
+ * @param {String|Number} rjs The pixel density cap for images provided.
152
+ *
153
+ * @return {undefined}
154
+ */
155
+ function dynamicSwapImage(image, src) {
156
+ var rjs = arguments.length <= 2 || arguments[2] === undefined ? 1 : arguments[2];
157
+
158
+ var cap = chooseCap(rjs);
159
+
160
+ /*
161
+ * Don't do anything if the cap is less than 2 or there is no src.
162
+ */
163
+ if (src && cap > 1) {
164
+ var newSrc = src.replace(srcReplace, '@' + cap + 'x$1');
165
+ setSourceIfAvailable(image, newSrc);
166
+ }
167
+ }
168
+
169
+ /**
170
+ * Performs an image url swap on a given image with a provided url.
171
+ *
172
+ * @param {Element} image An image in the DOM.
173
+ * @param {String} src The original image source attribute.
174
+ * @param {String} hdsrc The path for a 2x image.
175
+ *
176
+ * @return {undefined}
177
+ */
178
+ function manualSwapImage(image, src, hdsrc) {
179
+ if (environment > 1) {
180
+ setSourceIfAvailable(image, hdsrc);
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Collects all images matching our selector, and converts our
186
+ * NodeList into an Array so that Array methods will be available to it.
187
+ *
188
+ * @param {Iterable} images Optional. An Array, jQuery selection, or NodeList
189
+ * of elements to affect with retina.js.
190
+ *
191
+ * @return {Iterable} Contains all elements matching our selector.
192
+ */
193
+ function getImages(images) {
194
+ if (!images) {
195
+ return typeof document !== 'undefined' ? arrayify(document.querySelectorAll(selector)) : [];
196
+ } else {
197
+ return typeof images.forEach === 'function' ? images : arrayify(images);
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Converts a string like "url(hello.png)" into "hello.png".
203
+ *
204
+ * @param {Element} img An HTML element with a background image.
205
+ *
206
+ * @return {String}
207
+ */
208
+ function cleanBgImg(img) {
209
+ return img.style.backgroundImage.replace(inlineReplace, '$2');
210
+ }
211
+
212
+ /**
213
+ * Gets all participating images and dynamically swaps out each one for its
214
+ * retina equivalent taking into account the environment capabilities and
215
+ * the densities for which the user has provided images.
216
+ *
217
+ * @param {Iterable} images Optional. An Array, jQuery selection, or NodeList
218
+ * of elements to affect with retina.js. If not
219
+ * provided, retina.js will grab all images on the
220
+ * page.
221
+ *
222
+ * @return {undefined}
223
+ */
224
+ function retina(images) {
225
+ getImages(images).forEach(function (img) {
226
+ if (!img.getAttribute(processedAttr)) {
227
+ var isImg = img.nodeName.toLowerCase() === 'img';
228
+ var src = isImg ? img.getAttribute('src') : cleanBgImg(img);
229
+ var rjs = img.getAttribute('data-rjs');
230
+ var rjsIsNumber = !isNaN(parseInt(rjs, 10));
231
+
232
+ /*
233
+ * If the user provided a number, dynamically swap out the image.
234
+ * If the user provided a url, do it manually.
235
+ */
236
+ if (rjsIsNumber) {
237
+ dynamicSwapImage(img, src, rjs);
238
+ } else {
239
+ manualSwapImage(img, src, rjs);
240
+ }
241
+ }
242
+ });
243
+ }
154
244
 
155
- root.RetinaImage = RetinaImage;
156
-
157
- RetinaImage.prototype.swap = function(path) {
158
- if (typeof path === 'undefined') {
159
- path = this.path.at_2x_path;
160
- }
161
-
162
- var that = this;
163
- function load() {
164
- if (! that.el.complete) {
165
- setTimeout(load, 5);
166
- } else {
167
- if (config.force_original_dimensions) {
168
- that.el.setAttribute('width', that.el.offsetWidth);
169
- that.el.setAttribute('height', that.el.offsetHeight);
170
- }
171
-
172
- that.el.setAttribute('src', path);
173
- }
174
- }
175
- load();
176
- };
177
-
245
+ /*
246
+ * If this environment has `window`, activate the plugin.
247
+ */
248
+ if (hasWindow) {
249
+ window.addEventListener('load', retina);
250
+ window.retinajs = retina;
251
+ }
178
252
 
179
- if (Retina.isRetina()) {
180
- Retina.init(root);
181
- }
182
- })();
253
+ exports.default = retina;
@@ -1,20 +1,102 @@
1
- // retina.sass
1
+ // retina.scss
2
2
  // A helper mixin for applying high-resolution background images (http://www.retinajs.com)
3
3
 
4
4
  // Submitted by Nathan Crank
5
5
  // nathancrank.com
6
6
 
7
- @mixin at2x($path, $ext: "jpg", $w: auto, $h: auto) {
8
- $at1x_path: "#{$path}.#{$ext}";
9
- $at2x_path: "#{$path}@2x.#{$ext}";
7
+ // Updated by Gabriel R. Sezefredo
8
+ // gabriel.sezefredo.com.br
10
9
 
11
- background-image: image-url("#{$at1x_path}");
10
+ // Updated by John Newman
11
+ // github.com/jgnewman
12
+ // http://axial.agency
12
13
 
13
- @media all and (-webkit-min-device-pixel-ratio : 1.5),
14
- all and (-o-min-device-pixel-ratio: 3/2),
15
- all and (min--moz-device-pixel-ratio: 1.5),
16
- all and (min-device-pixel-ratio: 1.5) {
17
- background-image: image-url("#{$at2x_path}");
18
- background-size: $w $h;
14
+
15
+ /**
16
+ * Allows you to use retina images at various pixel densities.
17
+ * Examples:
18
+ *
19
+ * @include retina(/images/mypic.jpg, 2);
20
+ * @include retina(/images/mypic.jpg, 3, 100px 100px, left top no-repeat transparent);
21
+ *
22
+ * @param {Value} $path The path to the file name minus extension.
23
+ * @param {Number} $cap: 2 The highest pixel density level images exist for.
24
+ * @param {Value} $size: auto auto The intended width of the rendered image.
25
+ * @param {Value} $extras: null Any other `background` values to be added.
26
+ */
27
+ @mixin retina($path, $cap: 2, $size: auto auto, $extras: null) {
28
+
29
+ /*
30
+ * Set a counter and get the length of the image path.
31
+ */
32
+ $position: -1;
33
+ $strpath: '#{$path}';
34
+ $length: str-length($strpath);
35
+
36
+ /*
37
+ * Loop ver the image path and figure out the
38
+ * position of the dot where the extension begins.
39
+ */
40
+ @for $i from $length through $length - 10{
41
+ @if $position == -1 {
42
+ $char : str-slice($strpath, $i, $i);
43
+ @if str-index($char, ".") == 1 {
44
+ $position: $i;
45
+ }
46
+ }
47
+ }
48
+
49
+ /*
50
+ * If we were able to figure out where the extension is,
51
+ * slice the path into a base and an extension. Use that to
52
+ * calculate urls for different density environments. Set
53
+ * values for different environments.
54
+ */
55
+ @if $position != -1 {
56
+ $ext: str-slice($strpath, $position + 1, $length);
57
+ $base: str-slice($strpath, 1, $position - 1);
58
+ $at1x_path: "#{$base}.#{$ext}";
59
+ $at2x_path: "#{$base}@2x.#{$ext}";
60
+
61
+ /*
62
+ * Set a base background for 1x environments.
63
+ */
64
+ background: url("#{$at1x_path}") $extras;
65
+ background-size: $size;
66
+
67
+ /*
68
+ * Create an @2x-ish media query.
69
+ */
70
+ @media all and (-webkit-min-device-pixel-ratio : 1.5),
71
+ all and (-o-min-device-pixel-ratio: 3/2),
72
+ all and (min--moz-device-pixel-ratio: 1.5),
73
+ all and (min-device-pixel-ratio: 1.5) {
74
+ background : url("#{$at2x_path}") $extras;
75
+ background-size : $size;
76
+ }
77
+
78
+ /*
79
+ * Create media queries for all environments that the user has
80
+ * provided images for.
81
+ */
82
+ @if $cap >= 2 {
83
+ @for $env from 2 through $cap {
84
+ $suffix: "@#{$env}x";
85
+ @media (-webkit-min-device-pixel-ratio: $env),
86
+ (min-resolution: $env * 96dpi) {
87
+ background : url("#{$base}#{$suffix}.#{$ext}") $extras;
88
+ background-size : $size;
89
+ }
90
+ }
91
+ }
92
+
93
+ /*
94
+ * If anything went wrong trying to separate the file from its
95
+ * extension, set a background value without doing anything to it.
96
+ */
97
+ } @else {
98
+ background: url("#{$path}") $extras;
99
+ background-size: $size;
19
100
  }
101
+
20
102
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |gem|
4
4
  gem.name = 'retinajs-rails'
5
- gem.version = '0.2'
5
+ gem.version = '2.1'
6
6
  gem.date = Date.today
7
7
  gem.authors = ["Joshua Jansen"]
8
8
  gem.email = ["joshuajansen88@gmail.com"]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: retinajs-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.2'
4
+ version: '2.1'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Jansen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-05 00:00:00.000000000 Z
11
+ date: 2016-07-14 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Adds retina.js assets and image helpers to your Rails app
14
14
  email: