diff --git a/VERSION.txt b/VERSION.txt index 47860b5d8..944eb9c26 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1,2 +1,2 @@ -// Patternslib 2.0.13 +// Patternslib 2.0.14 diff --git a/bower.json b/bower.json index 8164a3d72..ce8db4ee5 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "patternslib", - "version": "2.0.13", + "version": "2.0.14", "main": "bundle.js", "devDependencies": { "jasmine": "https://github.com/jcbrand/jasmine.git#1_3_x" diff --git a/changes.md b/changes.md index 9a63d1647..6cea1ca15 100644 --- a/changes.md +++ b/changes.md @@ -1,5 +1,12 @@ # Changelog +## 2.0.14 - Aug. 15, 2016 + +- A fix for pat-scroll to scroll up to current scroll container instead of body. +- A fix for pat-scroll to await loading of all images before determining the amount to scroll up. +- A fix for IE10/11 where the modal wouldn`t close anymore due to activeElement being undefined +- Allow to configure different data-pat-inject per formaction, so that different targets can be configured per formaction + ## 2.0.13 - Apr. 27, 2016 - New property for sortable pattern, `drag-class`, the CSS class to apply to item being dragged. Is `"dragged"` by default. diff --git a/package.json b/package.json index a5c132d03..71f4f7181 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "patternslib", - "version": "2.0.13", + "version": "2.0.14", "title": "Markup patterns to drive behaviour.", "description": "Patternslib is a JavaScript library that enables designers to build rich interactive prototypes without the need for writing any Javascript. All events are triggered by classes and other attributes in the HTML, without abusing the HTML as a programming language. Accessibility, SEO and well structured HTML are core values of Patterns.", "author": { diff --git a/src/core/parser.js b/src/core/parser.js index eab3f0fe8..f49ffe757 100644 --- a/src/core/parser.js +++ b/src/core/parser.js @@ -237,7 +237,7 @@ define([ if (!part) { return; } var matches = part.match(this.named_param_pattern); if (!matches) { - this.log.warn("Invalid parameter: " + part); + this.log.warn("Invalid parameter: " + part + ": " + argstring); return; } var name = matches[1], diff --git a/src/core/store.js b/src/core/store.js index fe55f0d48..2c3077978 100644 --- a/src/core/store.js +++ b/src/core/store.js @@ -108,8 +108,7 @@ define(function() { } } return options; - }, - + } }; // Perform the test separately since this may throw a SecurityError as diff --git a/src/core/utils.js b/src/core/utils.js index 684a3a46b..eb2187606 100644 --- a/src/core/utils.js +++ b/src/core/utils.js @@ -1,8 +1,8 @@ define([ "jquery", - "jquery.browser", - "underscore" -], function($) { + "underscore", + "jquery.browser" // adds itself to the jquery object, no need to pass to the define callback. +], function($, _) { $.fn.safeClone = function () { var $clone = this.clone(); diff --git a/src/pat/clone/documentation.md b/src/pat/clone/documentation.md index 7917a49fd..23a24fa8d 100644 --- a/src/pat/clone/documentation.md +++ b/src/pat/clone/documentation.md @@ -91,7 +91,7 @@ The markup below would have exactly the same effect as the first example, but us |------|------|-----|------| | template |Selects the element that will be cloned each time. You might often want to refer to a piece of template markup for this that is hidden with though the CSS. |:first | | CSS Selector | | max |Maximum number of clones that is allowed | | | Integer | -| trigger-element |Selector of the element that will remove the clone when clicked upon. | .add-clone | | CSS Selector | +| trigger-element |Selector of the element that will add the clone when clicked upon. | .add-clone | | CSS Selector | | remove-element |Selector of the element that will remove the clone when clicked upon. | .remove-clone | | CSS Selector| | remove-behaviour or remove-behavior | What should happen when the user clicks on the element to remove a clone? Two choices exist currently. Show a confirmation dialog, or simply remove the clone immediately. | "confirm" | "confirm", "none" | One of the allowed string values. | | clone-element |Selector of the individual clone element(s). | .clone | | CSS Selector| diff --git a/src/pat/gallery/gallery.js b/src/pat/gallery/gallery.js index 55ee433da..d6a88dbf1 100644 --- a/src/pat/gallery/gallery.js +++ b/src/pat/gallery/gallery.js @@ -64,6 +64,6 @@ define("pat-gallery", [ }); gallery.init(); }); - }, + } }); }); diff --git a/src/pat/inject/inject.js b/src/pat/inject/inject.js index 75f3ce66c..fac038ab7 100644 --- a/src/pat/inject/inject.js +++ b/src/pat/inject/inject.js @@ -108,7 +108,8 @@ define([ formaction = $button.attr("formaction"), $form = $button.parents(".pat-inject").first(), opts = {url: formaction}, - cfgs = inject.extractConfig($form, opts); + $cfg_node = $button.closest("[data-pat-inject]"), + cfgs = inject.extractConfig($cfg_node, opts); ev.preventDefault(); $form.trigger("patterns-inject-triggered"); diff --git a/src/pat/inject/tests.js b/src/pat/inject/tests.js index afbe7ded2..1ac6f12b4 100644 --- a/src/pat/inject/tests.js +++ b/src/pat/inject/tests.js @@ -660,6 +660,30 @@ define(["pat-inject", "pat-utils"], function(pattern, utils) { $form.append($submit1).append($submit2); $div.append($target1).append($target2); + pattern.init($form); + $submit2.trigger("click"); + answer("" + + "
some
" + + "
other
" + + ""); + + expect($.ajax).toHaveBeenCalled(); + expect($.ajax.mostRecentCall.args[0].url).toContain("submit=special"); + expect($.ajax.mostRecentCall.args[0].url).toBe("other.html?submit=special"); + expect($target1.html()).toBe("some"); + expect($target2.html()).toBe("other"); + }); + it("formaction works source and target on the button", function() { + var $submit1 = $(""), + $submit2 = $(""), + $target1 = $("
"), + $target2 = $("
"); + + $submit2.attr("data-pat-inject", "#someid #target1 && #otherid #target2"); + $submit2.attr("formaction", "other.html#otherid"); + $form.append($submit1).append($submit2); + $div.append($target1).append($target2); + pattern.init($form); $submit2.trigger("click"); answer("" + diff --git a/src/pat/modal/modal.js b/src/pat/modal/modal.js index fe69fda87..e117e6ec6 100644 --- a/src/pat/modal/modal.js +++ b/src/pat/modal/modal.js @@ -62,7 +62,10 @@ define([ // Restore focus in case the active element was a child of $el and // the focus was lost during the wrapping. - document.activeElement.focus(); + // Only if we have an activeElement, as IE10/11 can have undefined as activeElement + if (document.activeElement) { + document.activeElement.focus(); + } this._init_handlers(); this.resize(); this.setPosition(); diff --git a/src/pat/scroll/index.html b/src/pat/scroll/index.html index fb04042aa..9f49c8339 100644 --- a/src/pat/scroll/index.html +++ b/src/pat/scroll/index.html @@ -77,7 +77,7 @@

3

- Back to top + Back to top

diff --git a/src/pat/scroll/scroll.js b/src/pat/scroll/scroll.js index 89a42bd06..2e39f0a7e 100644 --- a/src/pat/scroll/scroll.js +++ b/src/pat/scroll/scroll.js @@ -8,8 +8,9 @@ define([ "pat-utils", "pat-logger", "pat-parser", - "underscore" -], function($, patterns, Base, utils, logging, Parser, _) { + "underscore", + "imagesloaded" +], function($, patterns, Base, utils, logging, Parser, _, imagesLoaded) { var log = logging.getLogger("scroll"), parser = new Parser("scroll"); parser.addArgument("trigger", "click", ["click", "auto"]); @@ -25,7 +26,11 @@ define([ init: function($el, opts) { this.options = parser.parse(this.$el, opts); if (this.options.trigger == "auto") { - this.smoothScroll(); + // Only calculate the offset when all images are loaded + var that = this; + $('body').imagesLoaded( function() { + that.smoothScroll(); + }); } else if (this.options.trigger == "click") { this.$el.click(this.onClick.bind(this)); } @@ -121,15 +126,40 @@ define([ $el = this.options.selector ? $(this.options.selector) : this.$el; options[scroll] = this.options.offset; } else { - $el = $('body, html'); - options[scroll] = $(this.$el.attr('href')).offset().top; - } - $el.animate(options, { - duration: 500, - start: function() { - $('.pat-scroll').addClass('pat-scroll-animated'); + // Get the first element with overflow auto starting from the trigger + // (the scroll container) + // Then calculate the offset relatively to that container + $el = $(this.$el.parents() + .filter(function() { + return $(this).css('overflow') === 'auto'; }) + .first()) + if (typeof $el[0] === 'undefined') { + $el = $('html, body'); } - }); + + var scroll_container = Math.floor( $el.offset().top ); + var target = Math.floor( $(this.$el.attr('href')).offset().top ); + + if (target == scroll_container) { + options[scroll] = scroll_container; + } else if (target >= scroll_container) { + options[scroll] = target - scroll_container; + $el.animate(options, { + duration: 500, + start: function() { + $('.pat-scroll').addClass('pat-scroll-animated'); + } + }); + } else { + options[scroll] = target + scroll_container ; + $el.animate(options, { + duration: 500, + start: function() { + $('.pat-scroll').addClass('pat-scroll-animated'); + } + }); + } + } } }); }); diff --git a/src/pat/scroll/tests.js b/src/pat/scroll/tests.js index 1da880f30..a86475357 100644 --- a/src/pat/scroll/tests.js +++ b/src/pat/scroll/tests.js @@ -17,7 +17,16 @@ define(["pat-scroll"], function(Pattern) { ].join("\n")); spyOn($.fn, 'animate'); Pattern.init($(".pat-scroll")); - expect($.fn.animate).toHaveBeenCalled(); + var flag; + this.waitsFor(function() { + $("body").imagesLoaded(function() {flag = true;}); + return flag; + }, "The images should be loaded", 750); + + this.runs(function() { + expect($.fn.animate).toHaveBeenCalled(); + }); + // expect($.fn.animate).toHaveBeenCalled(); }); }); @@ -37,8 +46,16 @@ define(["pat-scroll"], function(Pattern) { var $el = $(".pat-scroll"); spyOn($.fn, 'animate'); Pattern.init($el); + var flag; + this.waitsFor(function() { + $("body").imagesLoaded(function() {flag = true;}); + return flag; + }, "The images should be loaded", 750); $el.click(); - expect($.fn.animate).toHaveBeenCalled(); + + this.runs(function() { + expect($.fn.animate).toHaveBeenCalled(); + }); }); it("will scroll to an anchor on pat-update with originalEvent of click", function() {