diff --git a/CHANGES.md b/CHANGES.md index 681342722..2a74316da 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -26,9 +26,27 @@ - pat date picker: Remove ``format`` argument and just use the ISO 8601 standard "YYYY-MM-DD", like the specification of date inputs defines it. Format would have submitted a formatted value where the ISO standard is expected. This also allows for removing the dependency of ``pat-date-picker`` on MomentJS. +- pat datetime picker: + - Change CSS selectors for better namespacing and remove implicit dependency on glyphicons. + - Remove dependency on MomentJS. + - After updating the original input, let the ``change`` event bubble up. + - Support ``native`` behavior. + ### Features +- pat gallery: Import styles for photoswipe. +- pat carousel: Import styles for slick carousel. +- pat auto suggest: Import styles for select2. +- pat-tooltip: Import styles for tippy. +- pat-modal: Import styles. +- pat datetime picker: Import styles. +- pat date picker: Import styles for pikaday. +- Styles: Import styles by setting ``__patternslib_import_styles`` + Allow importing styles from external libraries in Patternslib JavaScript via the global variable ``window.__patternslib_import_styles`` set to ``true``. + This allows loading these styles automatically via Webpack. + Disable setting style import per default. +- pat carousel: Use ``imagesloaded`` instead of timeout to wait for images to have been loaded. - core registry: Do not scan patterns within trees with attribute ``hidden`` or class ``cant-touch-this``. - Implenent lazy loading for external libraries via dynamic imports. Leads to significantly reduced bundle sizes. - Upgrade pat-calendar to use latest fullcalendar version (5.3.0). @@ -72,8 +90,13 @@ - pat-scroll: Implement `selector:bottom` attribute value to scroll to the bottom of the scroll container. - pat-scroll: Do handle click events also when trigger is set to `auto`. + ### Technical +- Infrastructure: Upgrade jQuery to 3.6.0. +- Webpack: Backport changes from Mockup - add loaders for images, svg, sass and xml. +- Webpack: Automatically detect the chunk path or "__webpack_public_path__" while still allowing for overriding via "__patternslib_public_path__". +- Export all parsers in all patterns to be able to modify default values or add aliases. - core polyfills: Add polyfill for Node.closest method. - Core Base: ``await`` for initalization in the base class constructor, so that the ``init`` event is really thrown after initialization is done. - pat calendar: Explicitly import JavaScript language files to avoid missing Webpack TypeScript loader errors. @@ -104,6 +127,7 @@ - core base: Add the parser instance to pattern attributes if available. We can then reuse the parser from registered patterns. This is used in the ``_rebaseHTML`` method of pat-inject to URL-rebase the pattern configuration. + ### Fixes - core dom is_visible: Mock in tests to check only for hidden to avoid unavailable offsetWidth/offsetHeight in Jest. diff --git a/package.json b/package.json index 4c7f44f07..b9fc8e2c6 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "google-code-prettify": "^1.0.5", "imagesloaded": "^4.1.4", "intersection-observer": "^0.7.0", - "jquery": "^3.5.1", + "jquery": "^3.6.0", "jquery-jcrop": "^0.9.13", "luxon": "^1.24.1", "masonry-layout": "^4.2.2", @@ -64,6 +64,7 @@ "eslint": "^7.0.0", "eslint-config-prettier": "^6.11.0", "expose-loader": "^0.7.5", + "file-loader": "^6.2.0", "identity-obj-proxy": "^3.0.0", "imports-loader": "^0.8.0", "jest": "^26.0.1", @@ -71,8 +72,10 @@ "prettier": "^2.1.2", "raw-loader": "^4.0.1", "regenerator-runtime": "^0.13.5", - "sass": "^1.26.5", + "sass": "^1.32.8", + "sass-loader": "^10.1.1", "style-loader": "^1.2.1", + "svg-inline-loader": "^0.8.2", "terser-webpack-plugin": "^2.3.6", "webpack": "^4.43.0", "webpack-bundle-analyzer": "^3.8.0", @@ -84,7 +87,7 @@ }, "resolutions": { "clean-css": "4.2.3", - "jquery": "3.5.1", + "jquery": "3.6.0", "lodash": "4.17.20", "moment": "2.29.0", "serialize-javascript": "4.0.0", diff --git a/src/core/push_kit.js b/src/core/push_kit.js index 077214c66..a2c2856a1 100644 --- a/src/core/push_kit.js +++ b/src/core/push_kit.js @@ -31,9 +31,6 @@ import "regenerator-runtime/runtime"; // needed for ``await`` support import $ from "jquery"; -// Lazy loading modules. -let StompJS; - const push_kit = { async init() { const push_url = $("meta[name=patterns-push-server-url]").attr("content"); // prettier-ignore @@ -47,7 +44,7 @@ const push_kit = { const push_login = $("meta[name=patterns-push-login]").attr("content"); // prettier-ignore const push_pass = $("meta[name=patterns-push-password]").attr("content"); // prettier-ignore - StompJS = await import("@stomp/stompjs"); + const StompJS = await import("@stomp/stompjs"); const client = new StompJS.Client({ brokerURL: push_url, connectHeaders: { diff --git a/src/pat/ajax/ajax.js b/src/pat/ajax/ajax.js index 125b51652..d553fc400 100644 --- a/src/pat/ajax/ajax.js +++ b/src/pat/ajax/ajax.js @@ -9,8 +9,9 @@ import logging from "../../core/logging"; import Parser from "../../core/parser"; import registry from "../../core/registry"; -var log = logging.getLogger("pat.ajax"), - parser = new Parser("ajax"); +const log = logging.getLogger("pat.ajax"); + +export const parser = new Parser("ajax"); parser.addArgument("url", function ($el) { return ($el.is("a") ? $el.attr("href") diff --git a/src/pat/auto-scale/auto-scale.js b/src/pat/auto-scale/auto-scale.js index 68f66fe22..496cd4ba9 100644 --- a/src/pat/auto-scale/auto-scale.js +++ b/src/pat/auto-scale/auto-scale.js @@ -11,7 +11,7 @@ import Parser from "../../core/parser"; import _ from "underscore"; import utils from "../../core/utils"; -const parser = new Parser("auto-scale"); +export const parser = new Parser("auto-scale"); parser.addArgument("method", "scale", ["scale", "zoom"]); parser.addArgument("size", "width", ["width", "height", "contain", "cover"]); parser.addArgument("min-width", 0); diff --git a/src/pat/auto-submit/auto-submit.js b/src/pat/auto-submit/auto-submit.js index 393e4870d..de0df8306 100644 --- a/src/pat/auto-submit/auto-submit.js +++ b/src/pat/auto-submit/auto-submit.js @@ -8,7 +8,7 @@ import utils from "../../core/utils"; const log = logging.getLogger("autosubmit"); -const parser = new Parser("autosubmit"); +export const parser = new Parser("autosubmit"); // - 400ms -> 400 // - 400 -> 400 // - defocus diff --git a/src/pat/auto-suggest/_auto-suggest.scss b/src/pat/auto-suggest/_auto-suggest.scss index 25353d014..38be9537b 100644 --- a/src/pat/auto-suggest/_auto-suggest.scss +++ b/src/pat/auto-suggest/_auto-suggest.scss @@ -3,11 +3,6 @@ /* @group Auto suggest */ -.lt-ie9 .pat-autosuggest { - min-width: 175px; - /* Trying to resolve the 1px wide issue in IE8 */ -} - /* Version: 3.4.3 Timestamp: Tue Sep 17 06:47:14 PDT 2013 */ @@ -23,11 +18,6 @@ Version: 3.4.3 Timestamp: Tue Sep 17 06:47:14 PDT 2013 width: 100%; } -.lt-ie10 .select2-container { - width: 100% !important; - height: auto !important; -} - .select2-container, .select2-drop { box-sizing: border-box; diff --git a/src/pat/auto-suggest/auto-suggest.js b/src/pat/auto-suggest/auto-suggest.js index d76f02906..4394ddcf6 100644 --- a/src/pat/auto-suggest/auto-suggest.js +++ b/src/pat/auto-suggest/auto-suggest.js @@ -7,7 +7,7 @@ import Parser from "../../core/parser"; const log = logging.getLogger("autosuggest"); -const parser = new Parser("autosuggest"); +export const parser = new Parser("autosuggest"); parser.addArgument("ajax-data-type", "JSON"); parser.addArgument("ajax-search-index", ""); parser.addArgument("ajax-url", ""); @@ -41,6 +41,9 @@ export default Base.extend({ trigger: ".pat-autosuggest,.pat-auto-suggest", async init() { + if (window.__patternslib_import_styles) { + import("select2/select2.css"); + } await import("select2"); this.options = parser.parse(this.el, this.options); diff --git a/src/pat/bumper/bumper.js b/src/pat/bumper/bumper.js index 8c4b0317f..15f44bb93 100644 --- a/src/pat/bumper/bumper.js +++ b/src/pat/bumper/bumper.js @@ -13,7 +13,7 @@ import Base from "../../core/base"; import Parser from "../../core/parser"; import utils from "../../core/utils"; -const parser = new Parser("bumper"); +export const parser = new Parser("bumper"); parser.addArgument("margin", 0); parser.addArgument("selector"); parser.addArgument("bump-add", "bumped"); diff --git a/src/pat/calendar/calendar.js b/src/pat/calendar/calendar.js index e8edcc3fa..7b6c8e3cc 100644 --- a/src/pat/calendar/calendar.js +++ b/src/pat/calendar/calendar.js @@ -7,7 +7,7 @@ import registry from "../../core/registry"; import store from "../../core/store"; const log = logging.getLogger("calendar"); -const parser = new Parser("calendar"); +export const parser = new Parser("calendar"); parser.addArgument("calendar-controls", ""); // Calendar controls must have "id" attr set parser.addArgument("category-controls", ""); @@ -101,18 +101,12 @@ export default Base.extend({ async init($el, opts) { const el = this.el; - let Calendar = await import("@fullcalendar/core"); - Calendar = Calendar.Calendar; - let fcDayGrid = await import("@fullcalendar/daygrid"); - let fcInteraction = await import("@fullcalendar/interaction"); - let fcList = await import("@fullcalendar/list"); - let fcLuxon = await import("@fullcalendar/luxon"); - let fcTimeGrid = await import("@fullcalendar/timegrid"); - fcDayGrid = fcDayGrid.default; - fcInteraction = fcInteraction.default; - fcList = fcList.default; - fcLuxon = fcLuxon.default; - fcTimeGrid = fcTimeGrid.default; + const Calendar = (await import("@fullcalendar/core")).Calendar; + const fcDayGrid = (await import("@fullcalendar/daygrid")).default; + const fcInteraction = (await import("@fullcalendar/interaction")).default; // prettier-ignore + const fcList = (await import("@fullcalendar/list")).default; + const fcLuxon = (await import("@fullcalendar/luxon")).default; + const fcTimeGrid = (await import("@fullcalendar/timegrid")).default; // Save some UI elements for reuse. this.el_jump_next = el.querySelector(".jump-next"); diff --git a/src/pat/carousel/carousel.js b/src/pat/carousel/carousel.js index a2170dbba..d0d2665dd 100644 --- a/src/pat/carousel/carousel.js +++ b/src/pat/carousel/carousel.js @@ -8,11 +8,10 @@ import $ from "jquery"; import Base from "../../core/base"; import logging from "../../core/logging"; import Parser from "../../core/parser"; -import utils from "../../core/utils"; -var log = logging.getLogger("pat.carousel"), - parser = new Parser("carousel"); +const log = logging.getLogger("pat.carousel"); +export const parser = new Parser("carousel"); parser.addArgument("auto-play", false); parser.addArgument("auto-play-speed", 1000); parser.addArgument("speed", 500); @@ -28,46 +27,34 @@ export default Base.extend({ name: "carousel", trigger: ".pat-carousel", - async init(el, opts) { - await import("slick-carousel"); - - if (el.jquery) { - el = el[0]; + async init() { + if (window.__patternslib_import_styles) { + import("slick-carousel/slick/slick.scss"); } - const options = parser.parse(el, opts); - const settings = {}; + await import("slick-carousel"); + const ImagesLoaded = (await import("imagesloaded")).default; - settings.autoplay = options.auto.play; - settings.autoplaySpeed = options.auto["play-speed"]; - settings.speed = options.speed; - settings.adaptiveHeight = options.height === "adaptive"; - settings.arrows = options.arrows === "show"; - settings.slidesToShow = options.slides["to-show"]; - settings.slidesToScroll = options.slides["to-scroll"]; - settings.dots = options.dots === "show"; - if (options.appendDots) { - settings.appendDots = options.appendDots; + this.options = parser.parse(this.el, this.options); + this.settings = { + autoplay: this.options.auto.play, + autoplaySpeed: this.options.auto["play-speed"], + speed: this.options.speed, + adaptiveHeight: this.options.height === "adaptive", + arrows: this.options.arrows === "show", + slidesToShow: this.options.slides["to-show"], + slidesToScroll: this.options.slides["to-scroll"], + dots: this.options.dots === "show", + infinite: this.options.infinite, + }; + if (this.options.appendDots) { + this.settings.appendDots = this.options.appendDots; } - settings.infinite = options.infinite; - this.setup(el, settings); + ImagesLoaded(this.el, () => this.setup()); }, - async setup(el, settings) { - let loaded = true; - const images = el.querySelectorAll("img"); - for (let img of images) { - if (!img.complete || img.naturalWidth === 0) { - loaded = false; - } - } - if (!loaded) { - log.debug("Delaying carousel setup until images have loaded."); - await utils.timeout(50); - this.setup(el, settings); - return; - } - const $carousel = $(el).slick(settings); + setup() { + const $carousel = $(this.el).slick(this.settings); let $panel_links = $(); $carousel diff --git a/src/pat/carousel/carousel.test.js b/src/pat/carousel/carousel.test.js index bdc42b1bf..fe4f932b0 100644 --- a/src/pat/carousel/carousel.test.js +++ b/src/pat/carousel/carousel.test.js @@ -13,7 +13,7 @@ describe("carousel-plugin", function () { }); describe("init", function () { - it("Default options", async () => { + it("Default options 1", async () => { $("#lab").html( "