Changelog ========= Changes to this project will be documented in this file. You may browse a formatted and hyperlinked version of this file at . 2.0.0 ----- [See Unpoly 2 slides](http://triskweline.de/unpoly2-slides/) TODO ---- This list is **far** from complete. - up.network.config.slowDelay is now 800 (up from 300) - up.network.config.cacheSize is now 50 (down from 70) - up.network.isBusy() / isIdle() takes preload events into account - up.observe() callback may return a promise that will prevent callback calls while running - `[aria-label]` attributes are no longer used to build a target selector - Options removed form modals: up-width, up-max-width, up-height. Use up-size or up-class. - Failed responses now change the URL - TODO ... - up.history.config.restoreScroll has been removed. - Feedback works when a layer has no history - Layer A11Y - inert - aria-hidden - focus new - focus return on close - up.nav sets [aria-current] - up.history.config.enabled - Requests sent by Unpoly no longer have a `X-Requested-With: XMLHttpRequest` header. If you need that old behavior: up.on('up:request:load', function(event) { event.request.headers['X-Requested-With'] = 'XMLHttpRequest' }) - up.network.config.requestMetaKeys - up:link:follow is no longer sent when preloading, up:link:preload still is - Preserve focus when validating forms; Add { focus } option for fragment update - up.Request.prototype.isFatalError() has been removed without replacement. Network errors now reject with an error, and not a response. - [up-main], [up-main=overlay], [up-main=modal] - parseSelector can parse attribute selectors with prefix, infix, suffix, space-separated, dash-separated - up.validate() may now be called with a form element - validating emits up:form:validate instead of up:form:submit - When a compiler throws an error, other compilers will now run anyway - When a destructor throws an error, other destructors will now run anyway - Bootstrap integration - Minimal: active, nav, navbar - Bootstrap modal styles are no longer used for Unpoly modals - Now supports three major Bootstrap versions: - unpoly-bootstrap3.js - unpoly-bootstrap4.js - unpoly-bootstrap5.js - Hungry elements no longer get the transition by default. You need to set [up-transition] on the hungry element. - Rejections are now shown if the log is enabled - up.on() can passive: true - Preloads on touchstart and mousedown - Digit groups separators (`60_000`) are a stage 3 ES6 feature and also supported in number attributes. 1.0.0 ----- - TODO 0.62.1 ------ This is another maintenance release while we're finishing [the next major version of Unpoly](https://groups.google.com/forum/#!topic/unpoly/FDdVjxbjNLg). Community members were involved in every change of this release: - [`up.submit()`](/up.submit) has a new options `{ params }`. It may be used to pass extra form [parameters](/up.Params) that will be submitted in addition to the parameters from the form. (fix by @robinvdvleuten) - [`a[up-modal]`](/a-up-modal) will now honor an [`[up-cache]`](/a-up-target#up-cache) attribute on the same link. (fix by @adam12) - Prevent destructor function from being called twice if [`up.destroy()`](/up.destroy) is called twice with the same element (reported by @kratob) - On devices that don't show a vertical scrollbar, users can no longer scroll the underlying page while a [modal overlay](/up.modal) is open. (reported by @msurdi) 0.62.0 ------ This release backports a number of accessibility improvements from [the next major version of Unpoly](https://groups.google.com/forum/#!topic/unpoly/FDdVjxbjNLg). We encourage everyone to upgrade to this release in order to better support users with visual impairments. The following changes are included: - Links with an [`[up-instant]`](/a-up-instant) attribute can now be followed with the keyboard. - Fragments that are being [destroyed](/up.destroy) now get an [`[aria-hidden=true]`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-hidden_attribute) attribute while its disappearance is being animated. When a fragment is being swapped with a new version, the old fragment version is also given `[aria-hidden=true]` while it's disappearing. - [Modal dialogs](/up.modal) now get an [`[aria-modal=true]`](https://a11ysupport.io/tech/aria/aria-modal_attribute) attribute. The next major version of Unpoly will include additional accessibility improvements. In particular the new modal ("layer") implementation will implement all best practices for accessible dialogs. 0.61.1 ------ This is a maintenance release while we're getting ready for [the next major version of Unpoly](https://groups.google.com/forum/#!topic/unpoly/FDdVjxbjNLg). - Fix a bug where [`up.destroy()`](/up.destroy) wouldn't clean up the global jQuery cache. This is only relevant when using Unpoly together with jQuery. - Fields outside a
are now recognized when they have a matching [form] attribute (fixes #85) - [`up.form.fields()`](/up.form.fields) now accepts a jQuery collection as a first argument, as was already documented. 0.61.0 ------ This release makes it easier to migrate to a recent version of Unpoly when your app still depends on jQuery. Unpoly dropped its jQuery dependency with version 0.60.0, but retains optional jQuery support through functions like [`up.$compiler()`](/up.$compiler) and [`up.$on()`](/up.$on). All Unpoly functions that take a native element as an argument may also be called with a jQuery collection as an argument. The following changes to the optional jQuery support were implemented: - In an ES6 build pipeline, Unpoly's jQuery support no longer requires `window.jQuery` to be defined before Unpoly is imported into the build. You still need to define `window.jQuery`, but you may do so at any time in your scripts, regardless of load order. - jQuery support functions like [`up.$compiler()`](/up.$compiler) now fail with a helpful message if the developer forgets to define `window.jQuery`. This release also exposes some convenience functions and selectors: - New experimental function [`up.event.halt()`](/up.event.halt). It prevents the event from bubbling up the DOM. It also prevents other event handlers bound on the same element. It also prevents the event's default action. - New experimental function [`up.form.fields()`](/up.form.fields). It returns a list of form fields within the given element. - The selector [`form[up-validate]`](/form-up-validate) is now supported. It performs [server-side validation](/input-up-validate) when any fieldset within this form changes. Previously only the variant [`input[up-validate]`](/input-up-validate) was supported. 0.60.3 ------ [`[up-validate]`](/up-validate) again recognizes the `[up-fieldset]` attribute to find the form fragment that should be replaced with validation results. In the example below, changing the `email` input would only validate the first fieldset: ```html
Validation message
Validation message
``` 0.60.2 ------ - When [submitting](/up-form) a form with a GET method, any query parameters in the form's `[action]` URL are now discarded. This matches the standard browser behavior when submitting a form without Unpoly. - When [submitting](/up-form) a form with a POST method, any query parameters in the form's `[action]` URL are now kept in the URL, instead of being merged into the form's data payload. This matches the standard browser behavior when submitting a form without Unpoly. - New experimental function [`up.Params.stripURL(url)`](/up.Params.stripURL). It returns the given URL without its [query string](https://en.wikipedia.org/wiki/Query_string). 0.60.1 ------ - When user does not confirm an [`[up-confirm]`](/a-up-target#up-confirm) link, the link's [`.up-active`](/a.up-active) class is now removed (fixes #89) 0.60.0 ------ This is a major update with some breaking changes. ### Highlights - jQuery is no longer required! Unpoly now has zero dependencies. - New `up.element` helpers to complement [native `Element` methods](https://www.w3schools.com/jsref/dom_obj_all.asp). You might not even miss jQuery anymore. - Vastly improved performance on slow devices. - Utility functions that work with arrays and array-like values have been greatly improved. - The `up.util` module now plug the worst emissions in JavaScript's standard library: Equality-by-value, empty-by-value and shallow-copy. Your own objects may hook into those protocols. - You may define a padding when [revealing](/up.reveal). - Smooth [scrolling](/up.scroll) now mimics [native scroll behavior](https://hospodarets.com/native_smooth_scrolling). - Fixed many positioning issues with [popups](/up.popup) and [tooltips](/up.tooltip). - Several modules have been renamed to match the pattern `up.thing.verb()`. `up.dom` is now `up.fragment`, `up.bus` is now `up.event`, `up.layout` is now `up.viewport`. Details below. ### jQuery is no longer required jQuery no longer required to use Unpoly. That means Unpoly no longer has any dependencies! Due to its use of native DOM APIs, Unpoly is now a lot faster. Like, a **lot**. Ditching jQuery also saves you 30 KB of gzipped bundle size and speeds up your own code. #### Migrating apps that use jQuery Effort has been made to ensure that migrating to this version is smooth for existing apps that use jQuery. All Unpoly functions that accept element arguments will accept both native elements and jQuery collections. You will need to prefix some function calls with `$` to have your callbacks called with jQuery collections instead of native elements: - The `up.compiler()` callback now receives a [native element](https://developer.mozilla.org/en-US/docs/Web/API/Element) instead of a jQuery collection. For the old behavior, use `up.$compiler()`. - The `up.macro()` callback now received a [native element](https://developer.mozilla.org/en-US/docs/Web/API/Element) instead of a jQuery collection. For the old behavior, use `up.$macro()`. - The event handler passed to `up.on()` now receives an element instead of a jQuery collection. For the old behavior, use `up.$on()`. Finally, all Unpoly events (`up:*`) are now triggered as native events that can be received with [`Element#addEventListener()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener). You may continue to use jQuery's [`jQuery#on()`](http://api.jquery.com/on/) to listen to Unpoly events, but you need to access custom properties through `event.originalEvent`. Also know that if you use jQuery's `$.fn.trigger()` to emit events, these events are not received by native event listeners (including Unpoly). Use `up.emit()` instead to trigger an event that can be received by both native listeners and jQuery listeners. See below for detailed changes. ### New DOM helpers A new, experimental `up.element` module offers convience functions for DOM manipulation and traversal. It complements [native `Element` methods](https://www.w3schools.com/jsref/dom_obj_all.asp) and works across all [supported browsers](/up.browser) without polyfills. | `up.element.first()` | Returns the first descendant element matching the given selector.| | `up.element.all()` | Returns all descendant elements matching the given selector.| | `up.element.subtree()` | Returns a list of the given parent's descendants matching the given selector. The list will also include the parent element if it matches the selector itself.| | `up.element.closest()` | Returns the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.| | `up.element.matches()` | Matches all elements that have a descendant matching the given selector.| | `up.element.get()` | Casts the given value to a native [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element).| | `up.element.toggle()` | Display or hide the given element, depending on its current visibility.| | `up.element.toggleClass()` | Adds or removes the given class from the given element.| | `up.element.hide()` | Hides the given element.| | `up.element.show()` | Shows the given element.| | `up.element.remove()` | Removes the given element from the DOM tree.| | `up.element.replace()` | Replaces the given old element with the given new element.| | `up.element.setAttrs()` | Sets all key/values from the given object as attributes on the given element.| | `up.element.affix()` | Creates an element matching the given CSS selector and attaches it to the given parent element.| | `up.element.createFromSelector()` | Creates an element matching the given CSS selector.| | `up.element.createFromHtml()` | Creates an element from the given HTML fragment.| | `up.element.toSelector()` | Returns a CSS selector that matches the given element as good as possible.| | `up.element.setAttrs()` | Sets all key/values from the given object as attributes on the given element.| | `up.element.booleanAttr()` | Returns the value of the given attribute on the given element, cast as a boolean value.| | `up.element.numberAttr()` | Returns the value of the given attribute on the given element, cast to a number.| | `up.element.jsonAttr()` | Reads the given attribute from the element, parsed as [JSON](https://www.json.org/).| | `up.element.style()` | Receives [computed CSS styles](https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle) for the given element.| | `up.element.styleNumber()` | Receives a [computed CSS property value](https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle) for the given element, casted as a number.| | `up.element.setStyle()` | Sets the given CSS properties as inline styles on the given element.| | `up.element.isVisible()` | Returns whether the given element is currently visible.| | `:has()` | A non-standard [pseudo-class](https://developer.mozilla.org/en-US/docs/Learn/CSS/Introduction_to_CSS/Pseudo-classes_and_pseudo-elements) that matches all elements that have a descendant matching the given selector. | ### Events - The `up.bus` module has been renamed to `up.event`. We want to normalize Unpoly's API to the pattern `up.thing.verb()` in the future. - All Unpoly events (`up:*`) are now triggered as native events that can be received with [`Element#addEventListener()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener). You may continue to use jQuery's [`jQuery#on()`](http://api.jquery.com/on/) to listen to Unpoly events, but you need to access custom properties from `event.originalEvent`. - Properties named `event.$target` and `event.$element` have been removed from *all* Unpoly events. Use the standard `event.target` to retrieve the element on which the element was [emitted](/up.emit). - `up.on()` may now bind to a given element by passing it as an (optional) first argument: ``` up.on(element, '.button', 'click', (event) => { ... }) ``` You may use this for [event delegation](https://davidwalsh.name/event-delegate). - The event handler passed to `up.on()` now receives an element instead of a jQuery collection: ``` up.on('click', (event, element) => { alert("Clicked on an " + element.tagName) }) ``` For the old behavior, use `up.$on()`. - `up.emit()` may now trigger an event on a given element by passing the element as an (optional) first argument: ``` up.emit(element, 'app:user:login', { email: 'foo@example.com' }) ``` - `up.emit()` option `{ message }` is now `{ log }`. - `up.emit()` no longer logs by default. You can enable the old efault message with `{ log: true }`. - `up.event.nobodyPrevents()` option `{ message }` is now `{ log }`. - The experimental function `up.reset()` was removed without replacement. - The experimental event `up:framework:reset` was removed without replacement. ### Custom JavaScript - [Compilers](/up.compiler) may again return an array of destructor functions. The previous deprecation was removed. - The `up.compiler()` callback now receives a [native element](https://developer.mozilla.org/en-US/docs/Web/API/Element) instead of a jQuery collection: ``` up.compiler('.button', function(button) { alert("We have a new button with class " + button.className) }) ``` For the old behavior, use `up.$compiler()`. - The `up.macro()` callback now received a [native element](https://developer.mozilla.org/en-US/docs/Web/API/Element) instead of a jQuery collection: ``` up.compiler('a.fast-link', function(element) { element.setAttribute('up-preload', 'up-preload') element.setAttribute('up-instant', 'up-instant') }) ``` For the old behavior, use `up.$macro()`. ### Forms - `up:form:submit` no longer has a `{ $form }` property. The event is now [emitted](/up.emit) on the form that is being submitted. - `up.observe()` now accepts a single form field, multiple fields, a `
` or any container that contains form fields. The callback is called once for each change in any of the given elements. - The callback for `up.observe()` now receives the arguments `(value, name)`, where `value` is the changed field value and `name` is the `[name]` of the field element: ``` up.observe('form', function(value, name) { console.log('The value of %o is now %o', name, value); }); ``` The second argument was previously the observed input element as a jQuery collection. - `up.observe()` now accepts a `{ batch: true }` option to receive all changes since the last callback in a single object: ``` up.observe('form', { batch: true }, function(diff) { console.log('Observed one or more changes: %o', diff); }); ``` - The default `up.form.config.validateTargets` no longer includes the selector `'[up-fieldset]'`. ### Animation - CSS property names for custom [animations](/up.animation) and [transitions](/up.transition) must be given in `kebab-case`. `camelCase` properties are no longer supported. ### Fragment update API - The module `up.dom` has been renamed to `up.fragment`. We want to normalize Unpoly's API to the pattern `up.thing.verb()` in the future. - The experimental function `up.all()` has been removed without replacement - The function `up.first()` has been renamed to `up.fragment.first()` to not be confused with the low-level `up.element.first()`. - The event `up:fragment:destroy` has been removed without replacement. This event was previously emitted before a fragment was removed. The event [`up:fragment:destroyed`](/up:fragment:destroyed) (emitted after a fragment was removed), remains in the API. - The `up:fragment:destroyed` event no longer has a `{ $element }` property. It now has a `{ fragment }` property that contains the detached element. Like before, it is emitted on the former parent of the destroyed element. - The properties for the `up:fragment:keep` event have been renamed. - The properties for the `up:fragment:kept` event have been renamed. - The properties for the `up:fragment:inserted` event have been renamed. - The properties for the `up:fragment:destroyed` event have been renamed. ### Utility functions The `up.util` module now plug the worst emissions in JavaScript's standard library: Equality-by-value, empty-by-value, shallow copy: - New experimental function `up.util.isEqual()`. It returns whether the given arguments are equal by value. - New experimental property `up.util.isEqual.key`. This property contains the name of a method that user-defined classes may implement to hook into the `up.util.isEqual()` protocol. - `up.util.isBlank()` now returns false for objects with a constructor. - New experimental property `up.util.isBlank.key`. This property contains the name of a method that user-defined classes may implement to hook into the `up.util.isBlank()` protocol. - New experimental property `up.util.copy.key`. This property contains the name of a method that user-defined classes may implement to hook into the `up.util.copy()` protocol. More utility functions to have been added to work with lists: - New experimental function `up.util.findResult()`. It consecutively calls the given function which each element in the given list and returns the first truthy return value. - New experimental function `up.util.flatten()`. This flattens the given list a single level deep. - New experimental function `up.util.flatMap()`. This maps each element using a mapping function, then flattens the result into a new array. Some list functions have been renamed to names used in the standard `Array` API: - `up.util.all()` was renamed to `up.util.every()` to match the standard [`Array#every()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every), and to be less confusing with `up.element.all()`. - `up.util.any()` was renamed to `up.util.some()` to match the standard [`Array#some()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some). - `up.util.select()` was renamed to `up.util.filter()` to match the standard [`Array#filter()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter). - `up.util.detect()` was renamed to `up.util.find()` to match the standard [`Array#find()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find). All functions that worked for arrays now also work for array-like values: - New experimental function `up.util.isList()`. It returns whether the given argument is an array-like value, like an `Array` or a [`NodeList`](https://developer.mozilla.org/en-US/docs/Web/API/NodeList). - `up.util.reject()` now works for all [array-like values](/up.util.isList), not just arrays. - `up.util.filter()` now works for all [array-like values](/up.util.isList), not just arrays. - `up.util.find()` now works for all [array-like values](/up.util.isList), not just arrays. - `up.util.some()` now works for all [array-like values](/up.util.isList), not just arrays. - `up.util.every()` now works for all [array-like values](/up.util.isList), not just arrays. And some minor changes: - `up.util.nextFrame()` has been renamed to `up.util.task()`. - `up.util.setTimer()` has been renamed to `up.util.timer()`. - `up.util.toArray() now returns its unchanged argument if the argument is already an array. - `up.util.copy()` now works with `Date` objects. - `up.util.isBoolean()` is now stable - `up.util.escapeHtml()` is now stable - `up.util.isJQuery()` now returns `false` if no jQuery is loaded into the `window.jQuery` global - `up.util.unresolvablePromise()` was removed without replacement. - `up.util.trim()` has been removed without replacement. Use the standard [`String#trim()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim) instead. - `up.util.parseUrl()` now returns the correct `{ hostname }`, `{ protocol }` and `{ pathname }` properties on IE11. - `up.util.selectorForElement()` is now `up.element.toSelector()` ### Scrolling Viewports - The `up.layout` module has been renamed to `up.viewport`. We want to normalize Unpoly's API to the pattern `up.thing.verb()` in the future. - Smooth [scrolling](/up.scroll) now mimics [native scroll behavior](https://hospodarets.com/native_smooth_scrolling): - `up.scroll()` no longer takes a `{ duration }` or `{ easing }` option. - `up.scroll()` now takes a `{ behavior }` option. Valid values are `auto` (no animation) and `smooth` (animates the scroll motion). - You may control the pace of `{ behavior: 'smooth' }` by also passing a `{ speed }` option`. - New config property `up.viewport.scrollSpeed`. This sets the default speed for smooth scrolling. The default value (`1`) roughly corresponds to the default speed of Chrome's native smooth scrolling. - Options for `up.reveal()` have been changed: - Options `{ duration }` and `{ easing }` have been removed. - New option `{ padding }` to pass the desired padding between the revealed element and the closest [viewport](/up.viewport) edge (in pixels). - New option `{ snap }`. It can be `true`, `false` or a pixel number. - New option `{ behavior }` - New option `{ speed }`. Defaults to `up.viewport.scrollSpeed`. - Config property `up.layout.config.snap` has been renamed to `up.viewport.config.revealSnap`. - New config option `up.viewport.revealPadding`. - New experimental function `up.viewport.root()`. It return the [scrolling element](https://developer.mozilla.org/en-US/docs/Web/API/document/scrollingElement) for the browser's main content area. - New experimental function `up.viewport.closest()`. It returns the scrolling container for the given element. - When a `#hash` anchor is [revealed](/up.reveal) during the initial page load, Unpoly will look for an `[up-id=hash]` before looking for `[id=hash]` and `a[name=hash]`. - Fix issues with restoring scroll positions when going back on some browsers. ### Navigation feedback - [`[up-alias]`](/up-nav#matching-url-by-pattern) now accepts one or more asterisks (`*`) anywhere in the pattern. It was previously limited to match URLs with a given prefix. ### Performance - Use of native browser APIs has improved performance drastically. - `[up-preload]` and `[up-instant]` links no longer bind to the `touchstart` event, increasing frame rate while scrolling. ### Request parameters The experimental `up.params` module has been replaced with the `up.Params` class. Wrap any type of parameter representation into `up.Params` to get consistent API for reading and manipulation. The following types of parameter representation are supported: 1. An object like `{ email: 'foo@bar.com' }` 2. A query string like `'email=foo%40bar.com'` 3. An array of `{ name, value }` objects like `[{ name: 'email', value: 'foo@bar.com' }]` 4. A [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) object. On IE 11 and Edge, `FormData` payloads require a [polyfill for `FormData#entries()`](https://github.com/jimmywarting/FormData). Supported methods are: | `new up.Params()` | Constructor. | | `up.Params#add()` | Adds a new entry with the given `name` and `value`. | | `up.Params#addAll()` | Adds all entries from the given list of params. | | `up.Params#addField()` | Adds params from the given [HTML form field](https://www.w3schools.com/html/html_form_elements.asp). | | `up.Params#delete()` | Deletes all entries with the given `name`. | | `up.Params#get()` | Returns the first param value with the given `name` from the given `params`. | | `up.Params#set()` | Sets the `value` for the entry with given `name`. | | `up.Params#toArray()` | Returns an array representation of this `up.Params` instance. | | `up.Params#toFormData()` | Returns a [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) representation of this `up.Params` instance. | | `up.Params#toObject()` | Returns an object representation of this `up.Params` instance. | | `up.Params#toQuery()` | Returns an [query string](https://en.wikipedia.org/wiki/Query_string) for this `up.Params` instance. | | `up.Params#toURL()` | Builds an URL string from the given base URL and this `up.Params` instance as a [query string](/up.Params.toString). | | `up.Params.fromFields()` | Constructs a new `up.Params` instance from one or more [HTML form field](https://www.w3schools.com/html/html_form_elements.asp). | | `up.Params.fromForm()` | Constructs a new `up.Params` instance from the given ``. | | `up.Params.fromURL()` | Constructs a new `up.Params` instance from the given URL's [query string](https://en.wikipedia.org/wiki/Query_string). | ### Popups - The HTML markup for a popup has been changed to make it easier to style with CSS. The new structure is: ```
Fragment content here
``` - The default CSS styles for `.up-popup` has been changed. If you have customized popup styles, you should check if your modifications still work with the new defaults. - Popups now update their position when the screen is resized. - Popups now follow scrolling when placed within [viewports](/up.viewport) other than the main document. - The `[up-position]` attribute has been split into two attributes `[up-position]` and `[up-align]`. Similarly the `{ position }` option has been split into two options `{ position }` and `{ align }`: - `{ position }` defines on which side of the opening element the popup is attached. Valid values are `'top'`, `'right'`, `'bottom'` and `'left'`. - `{ align }` defines the alignment of the popup along its side. - When the popup's `{ position }` is `'top'` or `'bottom'`, valid `{ align }` values are `'left'`, `center'` and `'right'`. - When the popup's `{ position }` is `'left'` or `'right'`, valid `{ align }` values are `top'`, `center'` and `bottom'`. - New experimental function `up.popup.sync()`. It forces the popup to update its position when a layout change is not detected automatically. - popup elements are now appended to the respective viewport of the anchor element. They were previously always appended to the end of the ``. - The events `up:popup:open`,`up:popup:opened`, `up:popup:close` and `up:popup:closed` have an `{ anchor }` property. It references the element that the popup was [attached](/up.popup.attach()) to. ### Tooltips - The HTML markup for a popup has been changed to make it easier to style with CSS. The new structure is: ```
Tooltip text here
``` - The default CSS styles for `.up-tooltip` have been changed. If you have customized tooltip styles, you should check if your modifications still work with the new defaults. - Tooltips now update their position when the screen is resized. - Tooltips now follow scrolling when placed within [viewports](/up.viewport) other than the main document. - The `[up-position]` attribute has been split into two attributes `[up-position]` and `[up-align]`. Similarly the `{ position }` option has been split into two options `{ position }` and `{ align }`: - `{ position }` defines on which side of the opening element the popup is attached. Valid values are `'top'`, `'right'`, `'bottom'` and `'left'`. - `{ align }` defines the alignment of the popup along its side. - When the tooltip's `{ position }` is `'top'` or `'bottom'`, valid `{ align }` values are `'left'`, `center'` and `'right'`. - When the tooltip's `{ position }` is `'left'` or `'right'`, valid `{ align }` values are `top'`, `center'` and `bottom'`. - New experimental function `up.tooltip.sync()`. It forces the popup to update its position when a layout change is not detected automatically. - Tooltip elements are now appended to the respective viewport of the anchor element. They were previously always appended to the end of the ``. ### Ruby on Rails integration - Unpoly is now compatible with the jQuery-less UJS adapter (now [part of Action View](https://github.com/rails/rails/tree/master/actionview/app/assets/javascripts)). ### AJAX acceleration - The properties for the `up:link:preload` event have been renamed. ### Modal dialogs - Opening/closing a modal will now manipulate the `{ overflow-y }` style on the same element that was chosen by the CSS author ([nasty details](https://makandracards.com/makandra/55801-does-html-or-body-scroll-the-page)). ### Various - Renamed some files so they won't be blocked by over-eager ad blockers on developer PCs. - Deprecation warnings are only printed once per environment. 0.57.0 ------ ### Request parameters To prevent confusion with [`[up-data]`](/up-data), Unpoly now uses the word "params" when talking about form values or request parameters: - [`up.request()`](/up.request) option `{ data }` has been renamed to `{ params }`. - [`up.replace()`](/up.replace) option `{ data }` has been renamed to `{ params }`. Parameters may be passed in one of the following types: 1. an object like `{ email: 'foo@bar.com' }` 2. a [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) object 3. a query string like `email=foo%40bar.com` 4. an array of `{ name, value }` objects like `[{ name: 'email', value: 'foo@bar.com' }]` To help working with form values and request parameters, an experimental module [`up.params`](/up.params) has been added. It offers a consistent API to manipulate request parameters independent of their type. - [`up.params.fromForm()`](/up.params.fromForm) - serialize a `` - [`up.params.fromURL()`](/up.params.fromURL) - extract params from a URL's query string - [`up.params.toArray()`](/up.params.toArray) - convert any params type to an array of `{ name, value }` elements - [`up.params.toObject()`](/up.params.toObject) - convert any params type to an object - [`up.params.toQuery()`](/up.params.toQuery) - convert any params type to a query string - [`up.params.toFormData()`](/up.params.toFormData) - convert any params type to a [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) object - [`up.params.buildURL()`](/up.params.buildURL) - composes a URL with query section from a base URL and a params value of any type - [`up.params.get()`](/up.params.get) - retrieve the value for the given params key - [`up.params.add()`](/up.params.add) - adds a single key/value to a params value of any type - [`up.params.assign()`](/up.params.assign) - adds the params to another params - [`up.params.merge()`](/up.params.merge) - [merges](/up.util.merge) two params ### Application layout - When Unpoly cannot find the [viewport](/up.layout.config#config.viewports) of an element, it now uses the scrolling root element. This is either `` or ``, depending on the browser. - Fix a bug where linking back and forth between multiple `#anchor` hashes of the same URL would always reveal the first anchor. - Revealing elements below [fixed navigation bars](/up-fixed-top) now honors the navigation bar's `padding`, `border`, `margin`, `top` and `bottom` properties. - Fix a bug where revealing elements [fixed navigation bars](/up-fixed-top) would scroll 1 pixel too short. - [`up.layout.revealHash()`](/up.layout.revealHash) no longer retrieves the hash anchor from the current URL. You need to pass in a `#hash` value as a first argument. - Fix a bug where a `#hash` anchor would not be revealed if it included non-word characters like spaces or dots. ### Compilers - To improve performance, Unpoly no longer parses [`[up-data]`](/up-data) attributes when a [compiler function](/up.compiler) does not require a second `data` argument. - Compilers that return [destructor functions](/up.compiler#cleaning-up-after-yourself) now run slightly faster. - [Compilers](/up.compiler) with `{ batch: true }` now receive an array of [`[up-data]`](/up-data) objects as their second `data` argument. - [Compilers](/up.compiler) with `{ batch: true }` can no longer return destructor functions. Previously the behavior of batch destructors was undefined, now it throws an error. - Returning an array of [destructor functions](/up.compiler#cleaning-up-after-yourself) from [`up.compiler()`](/up.compiler) is now deprecated. Please return a single destructor function instead. - [`up.syntax.data()`](/up.syntax.data) now returns `undefined` if the given object has no (or an empty) [`[up-data]`](/up-data) attribute. It previously returned an empty object. ### Event listeners - To improve performance, Unpoly no longer parses [`[up-data]`](/up-data) attributes when an [`up.on()`](/up.on) listener does not require a third `data` argument. - [`up.on()`](/up.on) now throws an error when the same callback function is registered multiple times. ### Fragment update API - New experimental function [`up.all()`](/up.all), which returns all elements matching the given selector. Like [`up.first()`](/up.first) it ignores elements that are being [destroyed](/up.destroy) or [transitioned](/up.morph). ### Various - New experimental function [`up.util.isBoolean()`](/up.util.isBoolean). - [`up.follow()`](/up.follow) now accepts a `{ url }` option. It can be used to override the given link's `[href]` attribute. - New configuration option [`up.form.config.submitButtons`](/up.form.config#config.submitButtons) - [`up.preload()`](/up.preload) now accepts an options hash that will be passed on to the function making the preload request. - New experimental function [`up.Response#getHeader()`](/up.Response.prototype.getHeader). It looks up the header value for the given name in the HTTP response header. 0.56.7 ------ - Calling `event.preventDefault()` on [`up:modal:close`](/up:modal:close) and [`up:popup:close`](/up:popup:close) events no longer prints `Uncaught (in promise)` to the error console. You still need to catch rejected promises in your own code when it calls Unpoly functions and that function is prevented by an event handler. 0.56.6 ------ - Fix a regression where the contents of `