From f303913cff015c0f5ceeb72631e782c035085336 Mon Sep 17 00:00:00 2001 From: Ryan Brewster Date: Mon, 16 Mar 2015 21:30:01 -0700 Subject: [PATCH] 3.0.0 --- README.md | 55 +++++++------ demo/bumper_demo.coffee | 2 + demo/bumper_demo.js | 4 + lib/bumper-core.js | 75 +---------------- lib/bumper-dom-jquery.js | 17 ++-- lib/bumper-responsive-breakpoint.js | 43 +++++++--- lib/bumper-responsive-image.js | 80 ++++++++++++++++-- spec/bumper_spec.coffee | 103 +++++++++++++++++------- src/bumper-core.coffee | 64 +-------------- src/bumper-dom-jquery.coffee | 17 ++-- src/bumper-responsive-breakpoint.coffee | 51 ++++++++---- src/bumper-responsive-image.coffee | 71 ++++++++++++++-- 12 files changed, 335 insertions(+), 247 deletions(-) diff --git a/README.md b/README.md index d52b882..f901d8f 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,21 @@ -# bumper - +# Bumper Bumper is a growing collection of front end tools and opinionated best practices. -## Tools -#### Core `bumper-core.js` -You will always want to include core before all other modules. It registers watchers and has common helper functions that most bumper modules need to access. - -Core uses mutation observers to interact with other bumper modules. Check [caniuse](http://caniuse.com/#feat=mutationobserver) for browser support, and polymer's [polyfill](https://github.com/polymer/MutationObservers) for some unsupported browsers. +## Modules +### Core `bumper-core.js` +You will always want to include core before all other modules. It holds common helper functions and meta data other bumper modules use. -#### Responsive Breakpoint `bumper-responsive-breakpoint.js` +### Responsive Breakpoint `bumper-responsive-breakpoint.js` Responsive Breakpoint allows you to manage your supported breakpoints, or configure to use other tools like jRespond -###### `setBreakpoints` Sets your custom breakpoints - +#### Methods +##### `setBreakpoints` Sets your custom breakpoints > _Arguments_ - ```yaml object: Reference the example for the object structure ``` --- > _example_ - ```coffee Bumper.Responsive.Breakpoint.setBreakpoints 'break-a': @@ -28,39 +23,42 @@ Bumper.Responsive.Breakpoint.setBreakpoints 'max': 1279 # the maximum width in pixels of the breakpoint ``` -###### `current` Gets the current breakpoint - +##### `getCurrent` Gets the current breakpoint > _example_ - ```coffee -Bumper.Responsive.Breakpoint.current() +Bumper.Responsive.Breakpoint.getCurrent() ``` -###### `setCurrentFunction` Overwrite the function used to get the current breakpoint. +##### `setCurrentFunction` Overwrite the function used to get the current breakpoint. If you would rather use a different tool for managing your breakpoints (eg jRespond), set the function that bumper uses to get the current breakpoint. > _Arguments_ - ```yaml function: An alternative function for return the current breakpoint ``` --- > _example_ - ```coffee Bumper.Responsive.Breakpoint.setCurrentFunction jRespond.getBreakpoint ``` -#### Responsive Image `bumper-responsive-image.js` +#### Events +##### `bumper-responsive-breakpoint-change` fires on the window when a breakpoint changes +##### `bumper-responsive-breakpoint-change-increase` fires on the window when a breakpoint changes to a larger breakpoint +##### `bumper-responsive-breakpoint-change-decrease` fires on the window when a breakpoint changes to a smaller breakpoint + +### Responsive Image `bumper-responsive-image.js` Allows you to request appropriate image sizes for different breakpoints with data attributes. * If an `img` is used, it will set the img src attributes. -* Otherwise the background-image css attribute will be set +* If a `div` is used, the background-image css attribute will be set For the best performance, you want to include this script in the and above most all other scripts. This lets bumper start requesting your images as soon as possible. -###### `resize` -Request a single image's source +##### `resizeAll` Resizes all elements on the page +All elements must have the class `bumper-repsonsive-image` + +##### `resize` Request a single image's source _data attribute markup_ * `data-bumper-responsive-image-url` @@ -92,23 +90,25 @@ _data attribute markup_ ``` > _Arguments_ - ```yaml el: An html element breakpoint (optional): A breakpoint name to request an image for ``` -#### DOM Handlers +#### Events +##### `bumper-responsive-image-loaded` fires on the img/div element when an image is loaded +> passes the img/div in the event details + +### DOM Handlers DOM Handlers allow for more complex handling of bumper modules and are AMD compatible ###### jQuery `bumper-dom-jquery.js` -###### `interpolateElementAttrs +##### `interpolateElementAttrs Sometimes you may need details about the context of an element to request the correct image. The responsive image modules support a string convention for finding, and getting attribute values from an element. `{cssSelector:attribute,arg1,arg2,...}` > _Arguments_ - ```yaml cssSelector: any css selector of an element on the DOM attribute: A jquery function that will return usable data @@ -116,7 +116,6 @@ args: A comma delimited list of arguments to pass to the jquery function ``` --- > _example_ - ```html
diff --git a/demo/bumper_demo.coffee b/demo/bumper_demo.coffee index 8437a37..e39674a 100644 --- a/demo/bumper_demo.coffee +++ b/demo/bumper_demo.coffee @@ -1,3 +1,5 @@ +window.Bumper.Responsive.Image.events() +window.Bumper.Responsive.Breakpoint.events() window.Bumper.Responsive.Breakpoint.setBreakpoints mobile: min: 0 diff --git a/demo/bumper_demo.js b/demo/bumper_demo.js index e11addc..06e6d37 100644 --- a/demo/bumper_demo.js +++ b/demo/bumper_demo.js @@ -1,5 +1,9 @@ // Generated by CoffeeScript 1.9.0 (function() { + window.Bumper.Responsive.Image.events(); + + window.Bumper.Responsive.Breakpoint.events(); + window.Bumper.Responsive.Breakpoint.setBreakpoints({ mobile: { min: 0, diff --git a/lib/bumper-core.js b/lib/bumper-core.js index 9319ec8..ffd52ff 100644 --- a/lib/bumper-core.js +++ b/lib/bumper-core.js @@ -4,7 +4,6 @@ * * bumper core * * https://github.com/brewster1134/bumper * * - * * @version 2.0.3 * * @author Ryan Brewster * * Copyright (c) 2014 * * Licensed under the MIT license. @@ -24,79 +23,7 @@ BumperCore = (function() { function BumperCore() {} - BumperCore.prototype.events = function() { - window.onload = (function(_this) { - return function() { - return _this.process(); - }; - })(this); - window.addEventListener('bumper-responsive-breakpoint-change', (function(_this) { - return function() { - return _this.process(); - }; - })(this)); - return window.onresize = requestAnimationFrame(function() { - var _ref, _ref1; - return (_ref = window.Bumper.Responsive) != null ? (_ref1 = _ref.Breakpoint) != null ? _ref1.checkBreakpointChange() : void 0 : void 0; - }); - }; - - BumperCore.prototype.watch = function() { - var responsiveObserver; - responsiveObserver = new MutationObserver(function(mutations) { - var mutation, node, _i, _j, _len, _len1, _ref; - for (_i = 0, _len = mutations.length; _i < _len; _i++) { - mutation = mutations[_i]; - _ref = mutation.addedNodes; - for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) { - node = _ref[_j]; - if (typeof node.className !== 'string') { - return; - } - switch (false) { - case !(node.className.indexOf('bumper-responsive-image') > -1): - window.Bumper.Responsive.Image.resize(node); - } - } - } - }); - return responsiveObserver.observe(document, { - childList: true, - subtree: true - }); - }; - - BumperCore.prototype.process = function() { - var image, images, _i, _len, _results; - images = document.querySelectorAll('.bumper-responsive-image'); - _results = []; - for (_i = 0, _len = images.length; _i < _len; _i++) { - image = images[_i]; - _results.push(window.Bumper.Responsive.Image.resize(image)); - } - return _results; - }; - - BumperCore.prototype.getUrl = function(el, breakpoint) { - var fullUrl, params, url; - url = el.getAttribute("data-bumper-responsive-image-url-" + breakpoint) || el.getAttribute('data-bumper-responsive-image-url'); - params = el.getAttribute("data-bumper-responsive-image-url-params-" + breakpoint) || el.getAttribute('data-bumper-responsive-image-url-params'); - if (!url) { - throw "data-bumper-responsive-image-url[-" + breakpoint + "] is not set."; - } - fullUrl = params ? url + "?" + params : url; - if (fullUrl.indexOf('{') > -1) { - if (window.Bumper.Dom) { - fullUrl = window.Bumper.Dom.interpolateElementAttrs(fullUrl, el); - } else { - if (el.className.indexOf('bumper-responsive-image-delay' === -1)) { - el.className = el.className + " bumper-responsive-image-delay"; - } - return; - } - } - return fullUrl; - }; + BumperCore.prototype.version = '3.0.0'; return BumperCore; diff --git a/lib/bumper-dom-jquery.js b/lib/bumper-dom-jquery.js index fbb0f07..649b1d2 100644 --- a/lib/bumper-dom-jquery.js +++ b/lib/bumper-dom-jquery.js @@ -4,7 +4,6 @@ * * bumper | dom | jquery * * https://github.com/brewster1134/bumper * * - * * @version 2.0.3 * * @author Ryan Brewster * * Copyright (c) 2014 * * Licensed under the MIT license. @@ -16,6 +15,8 @@ return define(['jquery'], function($) { return factory($); }); + } else if (typeof exports !== 'undefined') { + return module.exports = factory(jQuery); } else { return factory(jQuery); } @@ -24,8 +25,11 @@ BumperDom = (function() { function BumperDom() {} - BumperDom.prototype.interpolateElementAttrs = function(string, rootEl) { + BumperDom.prototype.interpolateElementAttrs = function(string, rootEl, restrictToParents) { var $element, $rootEl, arg, args, index, match, matches, method, newArg, regex, splitArray, _i, _j, _len, _len1; + if (restrictToParents == null) { + restrictToParents = false; + } $rootEl = $(rootEl); regex = /\{([^&]+)\}/g; matches = string.match(/\{([^&]+)\}/g); @@ -36,14 +40,14 @@ match = matches[_i]; splitArray = match.replace(/[{}]/g, '').split(':'); $element = $rootEl.closest("" + splitArray[0]); - if (!$element.length) { + if (restrictToParents === false && !$element.length) { $element = $("" + splitArray[0]).first(); } if (!$element.length) { $element = $rootEl.parent(); } if (!$element.length) { - throw "No element for `" + splitArray[0] + "` found."; + throw new Error("No element for `" + splitArray[0] + "` found."); } args = splitArray[1].split(','); method = args.shift(); @@ -70,9 +74,8 @@ })(); window.Bumper || (window.Bumper = {}); - if (window.Bumper.Dom) { - console.warn('There is already a dom handler loaded', window.Bumper.Dom); - console.warn('It will be replaced by the jQuery handler.'); + if (window.Bumper.Dom != null) { + console.warn('There is already a dom handler loaded. It will be replaced by the jQuery handler', window.Bumper.Dom); } return window.Bumper.Dom = new BumperDom; }); diff --git a/lib/bumper-responsive-breakpoint.js b/lib/bumper-responsive-breakpoint.js index e32f4b0..bbc3980 100644 --- a/lib/bumper-responsive-breakpoint.js +++ b/lib/bumper-responsive-breakpoint.js @@ -4,7 +4,6 @@ * * bumper | responsive | breakpoint * * https://github.com/brewster1134/bumper * * - * * @version 2.0.3 * * @author Ryan Brewster * * Copyright (c) 2014 * * Licensed under the MIT license. @@ -16,6 +15,8 @@ return define(['bumper-core'], function() { return factory(); }); + } else if (typeof exports !== 'undefined') { + return module.exports = factory(); } else { return factory(); } @@ -24,18 +25,27 @@ BumperResponsiveBreakpoint = (function() { function BumperResponsiveBreakpoint() {} + BumperResponsiveBreakpoint.prototype.events = function() { + window.addEventListener('resize', (function(_this) { + return function() { + return _this.checkBreakpointChange(); + }; + })(this)); + return this; + }; + BumperResponsiveBreakpoint.prototype.setBreakpoints = function(breakpoints) { var data, name; if (typeof breakpoints !== 'object') { - throw 'breakpoints must be an object'; + throw new Error('breakpoints must be an object'); } for (name in breakpoints) { data = breakpoints[name]; if (data.min === void 0) { - throw "breakpoint " + name + " must have a min value"; + throw new Error("breakpoint " + name + " must have a min value"); } if (data.max === void 0) { - throw "breakpoint " + name + " must have a max value"; + throw new Error("breakpoint " + name + " must have a max value"); } } return this.list = breakpoints; @@ -51,27 +61,40 @@ return this.current = name; } } + return this.current; }; BumperResponsiveBreakpoint.prototype.setCurrentFunction = function(func) { if (typeof func !== 'function') { - throw 'Must be a function!'; + throw new Error('Must be a function!'); } return this.getCurrent = func; }; BumperResponsiveBreakpoint.prototype.checkBreakpointChange = function() { - var bp, currentBp, event; - currentBp = this.current; - if (this.getCurrent() === currentBp) { + var bp, changeDecreaseEvent, changeEvent, changeIncreaseEvent, previousBp; + previousBp = this.current; + if (this.getCurrent() === previousBp) { return false; } bp = {}; bp[this.current] = this.list[this.current]; - event = new CustomEvent('bumper-responsive-breakpoint-change', { + changeEvent = new CustomEvent('bumper-responsive-breakpoint-change', { detail: bp }); - return window.dispatchEvent(event); + window.dispatchEvent(changeEvent); + if (this.list[previousBp].min < this.list[this.current].min) { + changeIncreaseEvent = new CustomEvent('bumper-responsive-breakpoint-change-increase', { + detail: bp + }); + window.dispatchEvent(changeIncreaseEvent); + } else { + changeDecreaseEvent = new CustomEvent('bumper-responsive-breakpoint-change-decrease', { + detail: bp + }); + window.dispatchEvent(changeDecreaseEvent); + } + return bp; }; return BumperResponsiveBreakpoint; diff --git a/lib/bumper-responsive-image.js b/lib/bumper-responsive-image.js index dbd7c9b..90ea619 100644 --- a/lib/bumper-responsive-image.js +++ b/lib/bumper-responsive-image.js @@ -4,7 +4,6 @@ * * bumper | responsive | image * * https://github.com/brewster1134/bumper * * - * * @version 2.0.3 * * @author Ryan Brewster * * Copyright (c) 2014 * * Licensed under the MIT license. @@ -16,6 +15,8 @@ return define(['bumper-core', 'bumper-responsive-breakpoint'], function() { return factory(); }); + } else if (typeof exports !== 'undefined') { + return module.exports = factory(); } else { return factory(); } @@ -24,21 +25,69 @@ BumperResponsiveImage = (function() { function BumperResponsiveImage() {} - BumperResponsiveImage.prototype.resize = function(el, breakpoint) { - var fullUrl, img; + BumperResponsiveImage.prototype.options = { + restrictToParents: false + }; + + BumperResponsiveImage.prototype.events = function() { + var responsiveObserver; + window.addEventListener('load', (function(_this) { + return function() { + return _this.resizeAll(); + }; + })(this)); + window.addEventListener('bumper-responsive-breakpoint-change', (function(_this) { + return function() { + return _this.resizeAll(); + }; + })(this)); + responsiveObserver = new MutationObserver((function(_this) { + return function() { + return _this.resizeAll(); + }; + })(this)); + responsiveObserver.observe(document, { + childList: true, + subtree: true + }); + return this; + }; + + BumperResponsiveImage.prototype.resizeAll = function() { + var image, images, _i, _len; + images = document.querySelectorAll('.bumper-responsive-image'); + for (_i = 0, _len = images.length; _i < _len; _i++) { + image = images[_i]; + this.resize(image); + } + return images; + }; + + BumperResponsiveImage.prototype.resize = function(el, breakpoint, force) { + var fullUrl, img, _ref, _ref1; + if (force == null) { + force = false; + } if (el.jquery) { el = el[0]; } - breakpoint || (breakpoint = window.Bumper.Responsive.Breakpoint.getCurrent()); - fullUrl = window.Bumper.Core.getUrl(el, breakpoint); + breakpoint || (breakpoint = (_ref = window.Bumper.Responsive.Breakpoint) != null ? _ref.getCurrent() : void 0); + fullUrl = this.getUrl(el, breakpoint); if (!fullUrl) { - return; + return false; + } + if (force === false && (((_ref1 = el.getAttribute('src')) != null ? _ref1.indexOf(fullUrl) : void 0) >= 0 || el.style.backgroundImage.indexOf(fullUrl) >= 0)) { + return fullUrl; } if (el.tagName === 'IMG') { img = el; img.addEventListener('load', function() { var event; - event = new CustomEvent('bumper-responsive-image-loaded'); + event = new CustomEvent('bumper-responsive-image-loaded', { + detail: { + img: img + } + }); return img.dispatchEvent(event); }); img.setAttribute('data-bumper-breakpoint', breakpoint); @@ -62,6 +111,23 @@ return fullUrl; }; + BumperResponsiveImage.prototype.getUrl = function(el, breakpoint) { + var fullUrl, params, url; + if (breakpoint == null) { + breakpoint = 'default'; + } + url = el.getAttribute("data-bumper-responsive-image-url-" + breakpoint) || el.getAttribute('data-bumper-responsive-image-url'); + params = el.getAttribute("data-bumper-responsive-image-url-params-" + breakpoint) || el.getAttribute('data-bumper-responsive-image-url-params'); + if (!url) { + throw new Error("data-bumper-responsive-image-url[-" + breakpoint + "] is not set."); + } + fullUrl = params ? url + "?" + params : url; + if ((window.Bumper.Dom != null) && fullUrl.indexOf('{') >= 0) { + fullUrl = window.Bumper.Dom.interpolateElementAttrs(fullUrl, el, this.options.restrictToParents); + } + return fullUrl; + }; + return BumperResponsiveImage; })(); diff --git a/spec/bumper_spec.coffee b/spec/bumper_spec.coffee index 5f5fea6..aa07339 100644 --- a/spec/bumper_spec.coffee +++ b/spec/bumper_spec.coffee @@ -5,30 +5,9 @@ describe 'bumper-core', -> it 'should create global object', -> expect(window.Bumper.Core).to.not.equal undefined - describe '#getUrl', -> - url = null - - context 'with a breakpoint', -> - before -> - $element = $('
') - .attr 'data-bumper-responsive-image-url', '/spec/bike.jpg' - .attr 'data-bumper-responsive-image-url-small', '/spec/bike-small.jpg' - .attr 'data-bumper-responsive-image-url-params', 'wid=200' - .attr 'data-bumper-responsive-image-url-params-small', 'wid=100' - url = window.Bumper.Core.getUrl $element[0], 'small' - - it 'should create a full url from bumper attributes', -> - expect(url).to.equal '/spec/bike-small.jpg?wid=100' - - context 'without a breakpoint', -> - before -> - $element = $('
') - .attr 'data-bumper-responsive-image-url', '/spec/bike.jpg' - .attr 'data-bumper-responsive-image-url-params', 'wid=200' - url = window.Bumper.Core.getUrl $element[0] + it 'should return a version', -> + expect(window.Bumper.Core.version).to.be.a 'string' - it 'should create a full url from bumper attributes', -> - expect(url).to.equal '/spec/bike.jpg?wid=200' # @@ -55,6 +34,7 @@ describe 'bumper-dom', -> expect(url).to.equal 'wid=222&class=foo' + # # RESPONSIVE BREAKPOINT # @@ -98,15 +78,56 @@ describe 'bumper-responsive-breakpoint', -> it 'should fire an event with breakpoint data', -> expect(window.Bumper.Responsive.Breakpoint.current).to.equal 'newbreakpoint' + context 'when increasing breakpoints', -> + before (done) -> + $(window).on 'bumper-responsive-breakpoint-change-increase', (e) -> + expect(e.originalEvent.detail.newbreakpointBar.min).to.equal 0 + done() + + window.Bumper.Responsive.Breakpoint.current = 'newbreakpointFoo' + window.Bumper.Responsive.Breakpoint.setBreakpoints + newbreakpointFoo: + min: -4000 + max: 0 + newbreakpointBar: + min: 0 + max: 4000 + + window.Bumper.Responsive.Breakpoint.checkBreakpointChange() + + it 'should fire an event with breakpoint data', -> + expect(window.Bumper.Responsive.Breakpoint.current).to.equal 'newbreakpointBar' + + context 'when decreasing breakpoints', -> + before (done) -> + $(window).on 'bumper-responsive-breakpoint-change-decrease', (e) -> + expect(e.originalEvent.detail.newbreakpointBar.min).to.equal 0 + done() + + window.Bumper.Responsive.Breakpoint.current = 'newbreakpointFoo' + window.Bumper.Responsive.Breakpoint.setBreakpoints + newbreakpointFoo: + min: 4001 + max: 8000 + newbreakpointBar: + min: 0 + max: 4000 + + window.Bumper.Responsive.Breakpoint.checkBreakpointChange() + + it 'should fire an event with breakpoint data', -> + expect(window.Bumper.Responsive.Breakpoint.current).to.equal 'newbreakpointBar' + + # # RESPONSIVE IMAGE # describe 'bumper-responsive-image', -> - context 'with an img element', -> - $img = null + describe '#resize', -> + context 'with an img element', -> + $img = null - context '#resize', -> before (done) -> $img = $('').attr 'data-bumper-responsive-image-url': '/spec/bike.jpg' @@ -117,10 +138,9 @@ describe 'bumper-responsive-image', -> it 'should add a url to the image src', -> expect($img.attr('src')).to.include('/spec/bike.jpg') - context 'with a div element', -> - $div = null + context 'with a div element', -> + $div = null - context '#resize', -> before (done) -> $div = $('
').attr 'data-bumper-responsive-image-url': '/spec/bike.jpg' @@ -130,3 +150,28 @@ describe 'bumper-responsive-image', -> it 'should add a url to the background image', -> expect($div.css('backgroundImage')).to.include('/spec/bike.jpg') + + describe '#getUrl', -> + url = null + + context 'with a breakpoint', -> + before -> + $element = $('
') + .attr 'data-bumper-responsive-image-url', '/spec/bike.jpg' + .attr 'data-bumper-responsive-image-url-small', '/spec/bike-small.jpg' + .attr 'data-bumper-responsive-image-url-params', 'wid=200' + .attr 'data-bumper-responsive-image-url-params-small', 'wid=100' + url = window.Bumper.Responsive.Image.getUrl $element[0], 'small' + + it 'should create a full url from bumper attributes', -> + expect(url).to.equal '/spec/bike-small.jpg?wid=100' + + context 'without a breakpoint', -> + before -> + $element = $('
') + .attr 'data-bumper-responsive-image-url', '/spec/bike.jpg' + .attr 'data-bumper-responsive-image-url-params', 'wid=200' + url = window.Bumper.Responsive.Image.getUrl $element[0] + + it 'should create a full url from bumper attributes', -> + expect(url).to.equal '/spec/bike.jpg?wid=200' diff --git a/src/bumper-core.coffee b/src/bumper-core.coffee index 646ee63..c00e5a5 100644 --- a/src/bumper-core.coffee +++ b/src/bumper-core.coffee @@ -2,7 +2,6 @@ # * bumper core # * https://github.com/brewster1134/bumper # * -# * @version 2.0.3 # * @author Ryan Brewster # * Copyright (c) 2014 # * Licensed under the MIT license. @@ -17,68 +16,7 @@ ) @, -> class BumperCore - # process inital images - events: -> - # process all modules on page load - window.onload = => @process() - - # process all modules on breakpoint changes - window.addEventListener 'bumper-responsive-breakpoint-change', => @process() - - # check for breakpoint changes on window resize - window.onresize = requestAnimationFrame -> - window.Bumper.Responsive?.Breakpoint?.checkBreakpointChange() - - # Creates a mutation observor for bumper modules when new elements are added to the dom - # Register a module into the switch statement with how to handle the new element - # - watch: -> - # http://caniuse.com/#feat=mutationobserver - # - responsiveObserver = new MutationObserver (mutations) -> - # return unless window.Bumper - for mutation in mutations - for node in mutation.addedNodes - return if typeof node.className != 'string' - switch - when node.className.indexOf('bumper-responsive-image') > -1 - window.Bumper.Responsive.Image.resize node - - responsiveObserver.observe document, - childList: true - subtree: true - - process: -> - images = document.querySelectorAll '.bumper-responsive-image' - for image in images - window.Bumper.Responsive.Image.resize image - - # Gets the full url based on bumper data attributes - # - getUrl: (el, breakpoint) -> - url = el.getAttribute("data-bumper-responsive-image-url-#{breakpoint}") || - el.getAttribute('data-bumper-responsive-image-url') - params = el.getAttribute("data-bumper-responsive-image-url-params-#{breakpoint}") || - el.getAttribute('data-bumper-responsive-image-url-params') - - # Log warning if no url is defined - throw "data-bumper-responsive-image-url[-#{breakpoint}] is not set." unless url - - fullUrl = if params - "#{url}?#{params}" - else - url - - # detect if inteprolation is needed - if fullUrl.indexOf('{') > -1 - if window.Bumper.Dom - fullUrl = window.Bumper.Dom.interpolateElementAttrs fullUrl, el - else - if el.className.indexOf 'bumper-responsive-image-delay' == -1 - el.className = "#{el.className} bumper-responsive-image-delay" - return - - return fullUrl + version: '3.0.0' window.Bumper ||= {} window.Bumper.Core ||= new BumperCore diff --git a/src/bumper-dom-jquery.coffee b/src/bumper-dom-jquery.coffee index 0df1da2..ad968c3 100644 --- a/src/bumper-dom-jquery.coffee +++ b/src/bumper-dom-jquery.coffee @@ -2,7 +2,6 @@ # * bumper | dom | jquery # * https://github.com/brewster1134/bumper # * -# * @version 2.0.3 # * @author Ryan Brewster # * Copyright (c) 2014 # * Licensed under the MIT license. @@ -14,6 +13,8 @@ 'jquery' ], ($) -> factory $ + else if typeof exports != 'undefined' + module.exports = factory jQuery else factory jQuery ) @, ($) -> @@ -21,7 +22,7 @@ class BumperDom # Find an element on the page to use it's attributes as responsive data # - interpolateElementAttrs: (string, rootEl) -> + interpolateElementAttrs: (string, rootEl, restrictToParents = false) -> $rootEl = $(rootEl) regex = /\{([^&]+)\}/g matches = string.match /\{([^&]+)\}/g @@ -35,12 +36,13 @@ $element = $rootEl.closest("#{splitArray[0]}") # find first matching elemnt anywhere in the dom - $element = $("#{splitArray[0]}").first() unless $element.length + if restrictToParents == false && !$element.length + $element = $("#{splitArray[0]}").first() # use the direct parent $element = $rootEl.parent() unless $element.length - throw "No element for `#{splitArray[0]}` found." unless $element.length + throw new Error "No element for `#{splitArray[0]}` found." unless $element.length # extract comma separated method and arguments args = splitArray[1].split ',' @@ -58,10 +60,9 @@ string = string.replace match, $element[method](args...) - string + return string window.Bumper ||= {} - if window.Bumper.Dom - console.warn 'There is already a dom handler loaded', window.Bumper.Dom - console.warn 'It will be replaced by the jQuery handler.' + if window.Bumper.Dom? + console.warn 'There is already a dom handler loaded. It will be replaced by the jQuery handler', window.Bumper.Dom window.Bumper.Dom = new BumperDom diff --git a/src/bumper-responsive-breakpoint.coffee b/src/bumper-responsive-breakpoint.coffee index a492869..bcafd5d 100644 --- a/src/bumper-responsive-breakpoint.coffee +++ b/src/bumper-responsive-breakpoint.coffee @@ -2,7 +2,6 @@ # * bumper | responsive | breakpoint # * https://github.com/brewster1134/bumper # * -# * @version 2.0.3 # * @author Ryan Brewster # * Copyright (c) 2014 # * Licensed under the MIT license. @@ -14,22 +13,27 @@ 'bumper-core' ], -> factory() + else if typeof exports != 'undefined' + module.exports = factory() else factory() ) @, -> class BumperResponsiveBreakpoint + events: -> + # check for breakpoint changes on window resize + window.addEventListener 'resize', => @checkBreakpointChange() - # Sets the breakpoints. + return @ + + # Sets the breakpoints # setBreakpoints: (breakpoints) -> - # validate object - throw 'breakpoints must be an object' unless typeof breakpoints == 'object' - - # validate breakpoint data + # validate object and breakpoint data + throw new Error 'breakpoints must be an object' unless typeof breakpoints == 'object' for name, data of breakpoints - throw "breakpoint #{name} must have a min value" if data.min == undefined - throw "breakpoint #{name} must have a max value" if data.max == undefined + throw new Error "breakpoint #{name} must have a min value" if data.min == undefined + throw new Error "breakpoint #{name} must have a max value" if data.max == undefined @list = breakpoints @@ -42,23 +46,42 @@ if width >= data.min && width <= data.max return @current = name + return @current + # Instead of using setBreakpoints, you can provide a custom method to return a breakpoint value # Can be helpful if you are using jRespond or something similar # setCurrentFunction: (func) -> - throw 'Must be a function!' unless typeof func == 'function' + throw new Error 'Must be a function!' unless typeof func == 'function' @getCurrent = func checkBreakpointChange: -> - currentBp = @current - return false if @getCurrent() == currentBp + # return false if the breakpoint hasn't changed + previousBp = @current + return false if @getCurrent() == previousBp - # trigger event + # create a small object with breakpoint data bp = {} bp[@current] = @list[@current] - event = new CustomEvent 'bumper-responsive-breakpoint-change', + + # trigger breakpoint change event + changeEvent = new CustomEvent 'bumper-responsive-breakpoint-change', detail: bp - window.dispatchEvent event + window.dispatchEvent changeEvent + + # trigger breakpoint change increase event + if @list[previousBp].min < @list[@current].min + changeIncreaseEvent = new CustomEvent 'bumper-responsive-breakpoint-change-increase', + detail: bp + window.dispatchEvent changeIncreaseEvent + + # trigger breakpoint change decrease event + else + changeDecreaseEvent = new CustomEvent 'bumper-responsive-breakpoint-change-decrease', + detail: bp + window.dispatchEvent changeDecreaseEvent + + return bp window.Bumper ||= {} window.Bumper.Responsive ||= {} diff --git a/src/bumper-responsive-image.coffee b/src/bumper-responsive-image.coffee index cfaafc6..0240be2 100644 --- a/src/bumper-responsive-image.coffee +++ b/src/bumper-responsive-image.coffee @@ -2,7 +2,6 @@ # * bumper | responsive | image # * https://github.com/brewster1134/bumper # * -# * @version 2.0.3 # * @author Ryan Brewster # * Copyright (c) 2014 # * Licensed under the MIT license. @@ -15,20 +14,54 @@ 'bumper-responsive-breakpoint' ], -> factory() + else if typeof exports != 'undefined' + module.exports = factory() else factory() ) @, -> class BumperResponsiveImage + options: + restrictToParents: false # used when interpolating - # resize the image for a single jquery element + events: -> + # resize all images on page load + window.addEventListener 'load', => @resizeAll() + + # resize all images on breakpoint change increase + window.addEventListener 'bumper-responsive-breakpoint-change', => @resizeAll() + + # Creates a mutation observor when new elements are added to the dom + # http://caniuse.com/#feat=mutationobserver + responsiveObserver = new MutationObserver => @resizeAll() + responsiveObserver.observe document, + childList: true + subtree: true + + return @ + + # calls resize on all matching elements # - resize: (el, breakpoint) -> + resizeAll: -> + images = document.querySelectorAll '.bumper-responsive-image' + for image in images + @resize image + + return images + + # set the repsonsive image and fire events + # @param el [HTML Element] html img or div element that has responsive image data attributes + # @param breakpoint [String] an optional name of a breakpoint (as defined from setBreakpoints) + # + resize: (el, breakpoint, force = false) -> el = el[0] if el.jquery # convert from a jquery object - breakpoint ||= window.Bumper.Responsive.Breakpoint.getCurrent() - fullUrl = window.Bumper.Core.getUrl el, breakpoint + breakpoint ||= window.Bumper.Responsive.Breakpoint?.getCurrent() + fullUrl = @getUrl el, breakpoint - return unless fullUrl + # return if no url, or url is the same as the existing url + return false unless fullUrl + if force == false && (el.getAttribute('src')?.indexOf(fullUrl) >= 0 || el.style.backgroundImage.indexOf(fullUrl) >= 0) + return fullUrl # handle images # @@ -36,7 +69,9 @@ img = el # trigger event img.addEventListener 'load', -> - event = new CustomEvent 'bumper-responsive-image-loaded' + event = new CustomEvent 'bumper-responsive-image-loaded', + detail: + img: img img.dispatchEvent event img.setAttribute 'data-bumper-breakpoint', breakpoint @@ -62,6 +97,28 @@ return fullUrl + # Gets the full url based on bumper data attributes + # @param el [HTML Element] html img or div element that has responsive image data attributes + # @param breakpoint [String] an optional name of a breakpoint (as defined from setBreakpoints) + # + getUrl: (el, breakpoint = 'default') -> + url = el.getAttribute("data-bumper-responsive-image-url-#{breakpoint}") || + el.getAttribute('data-bumper-responsive-image-url') + params = el.getAttribute("data-bumper-responsive-image-url-params-#{breakpoint}") || + el.getAttribute('data-bumper-responsive-image-url-params') + + # Log warning if no url is defined + throw new Error "data-bumper-responsive-image-url[-#{breakpoint}] is not set." unless url + + # combine params if they are found + fullUrl = if params then "#{url}?#{params}" else url + + # detect if inteprolation is needed + if window.Bumper.Dom? && fullUrl.indexOf('{') >= 0 + fullUrl = window.Bumper.Dom.interpolateElementAttrs fullUrl, el, @options.restrictToParents + + return fullUrl + window.Bumper ||= {} window.Bumper.Responsive ||= {} window.Bumper.Responsive.Image ||= new BumperResponsiveImage