Releases: mavoweb/mavo
v0.3.2
This is a minor update with fixes for some bugs and regressions.
What's Changed
- Unsupported events that backend services might send are ignored and don't break anything
- Live storage attributes don't break the autosave anymore
- Mavo now correctly interprets boolean data when loading it to the properties without the explicit
datatype="boolean"
v0.3.1 Hotfix
What's Changed
We removed polyfill.io
, a third-party service that has been recently compromised to serve malware. For more details, see: https://dev.to/snyk/polyfill-supply-chain-attack-embeds-malware-in-javascript-cdn-assets-55d6.
If you are unable to upgrade to v0.3.1
, the good news is that Mavo only used this service for features that are currently supported everywhere, and any requests to it were gated behind our own local feature testing, so the impact should be minimal.
v0.3.0
We have some very exciting plans for Mavo going forwards, but the first step was to make a new, long overdue, release.
Breaking changes
- A new way to define collections (
mv-list
/mv-list-item
). You can use both to define a collection ormv-item-list
ormv-list
on their own, and the other one will be auto-added for you.mv-multiple
is now deprecated but still works fine and just gets rewritten tomv-list
/mv-list-item
markup, so this is only a breaking change because you may have CSS that depends on the previous markup structure (e.g. child selectors). - The previously deprecated
mv-like
attribute has now been removed. - Property queries in
get()
(i.e.get(object, "key=value")
) are not supported anymore. Usewhere
orfilter()
for this. - The Dropbox backend is moved to a separate plugin to make Mavo lighter. Use
mv-plugins="dropbox"
anywhere to re-add support. - The
CTRL/CMD + Backspace
shortcut to delete a list entry is not supported anymore. url()
now does case insensitive matching by default—you can opt in to case sensitive matching viacase_sensitive: true
.
New Features
- 🆕
mv-options
attribute: limit properties to predefined options without having to create a<select>
- 🆕
mv-item-bar
attribute to customize list item controls (remove controls, add custom ones). - 🆕
mv-edit-as
attribute: Teach Mavo how to edit new elements, e.g. web components. - 🆕
mv-attr-*
family of attributes—a way for attributes to contain expressions without triggering browser errors or false loading. - You can now specify a plugin version in
mv-plugins
. - GitHub backend improvements:
- When performing raw API calls, there is now a way to fetch more than one page, by adding a
max_pages
parameter. - When saving to a repo that doesn't yet exist, it is now possible to create a private repo (via the
private
storage attribute).
- When performing raw API calls, there is now a way to fetch more than one page, by adding a
- Local storage backend: 🆕
mv-storage-key
attribute to override thelocalStorage
key used. - You can now use
mv-mode="edit"
onmv-value
elements to make dynamic collections editable.
MavoScript Changes
New functions
intersection()
—to get a list of items that two lists have in common.readable_datetime()
—to get a date or date/time value as human-readable text (e.g.,13 Jun 1986 16:45
).pluralize()
—to get the correct plural form of a word corresponding to the given number.sort()
—for locale-aware sorting of lists.datetime()
—Combine a date and (optionally) a time into a single date/time value in ISO format (e.g.,1986-06-13T16:45
) that can be used as input for other date/time functions.map()
—Get properties from list items.
Function improvements
get()
can accept multiple keys, e.g.,get(group("foo": group("bar": "baz")), "foo", "bar")
will returnbaz
.duration()
now allows units to be specified explicitly, e.g.,duration(ms, "days")
. Negative inputs toduration()
now produce negative time outputs.url()
now supports options to control case sensitivity, what is matched, what URL is used, and whether multiple results are returned.- Functions with 2-word names—
groupby()
,fromlast()
, andtofirst()
—renamed togroup_by()
,from_last()
, andto_first()
respectively to be consistent with other functions and better readability. Old functions still work but are deprecated and will be removed in the next release.
Special property improvements
$all.$previous
/$all.$next
to get all collection items before/after the current one.
Bugfixes and other improvements
- Order of relative button ids in the
mv-bar
attribute is now preserved. - When changing the storage location of a Mavo app via the URL (e.g. via a
?myapp-storage=...
URL), app id is now case insensitive. - Expressions now work properly with
on*
attributes. - The boolean
disabled
attribute works correctly with expressions on all supported elements, including<optgroup>
,<option>
, and<fieldset>
. - And 130 more bugfixes and smaller improvements!
Plugins
New plugins
- 🆕 List Separator plugin—Store and read lists of simple properties as a single text value. Useful in conjunction with the Google Sheets plugin to store multiple values in a single cell.
- 🆕 Share plugin—Share data via system clipboard, email, contacts or messaging applications, and Bluetooth or Wi-Fi channels.
- 🆕 Google Calendar Backend plugin—Integrate Google calendars into your Mavo apps.
- 🆕 Autoload plugin—Let Mavo load all the needed plugins for you automatically.
- 🆕 Spanish Locale plugin—Translates all Mavo UI to Spanish.
Notable improvements to existing plugins
- TinyMCE: Added a
CMD/CTRL + E
shortcut to mark up code blocks.
For developers of custom backends
Mavo#load()
now accepts a data parameter for overriding the data loaded.- New
Mavo#push()
for backend pushes. - New
mv-remotedatachange
event onMavo.Backend
to signify that data changed remotely.
New Contributors
- @BarishNamazov made their first contribution in #927
- @mohammadKhalafi made their first contribution in #946
- @rafidoth made their first contribution in #949
- @notpushkin made their first contribution in #834
- @norbitrial made their first contribution in #821
- @speciale made their first by adding their Spanish Locale plugin to the plugins registry
v0.2.4
This is a relatively small release that fixes a few bugs and regressions. There are however a few new features and potentially breaking changes, detailed below.
Breaking changes
mv-edit
andmv-edit-*
attributes have been renamed tomv-editor
andmv-editor-*
. Mavo does try to rewrite existing markup to minimize breakage during the transition whenever possible. Going forwards,mv-edit
andmv-edit-*
will be used for attributes that control how editing works (starting withmv-edit-type
below)- When an object is displayed on a simple property, instead of Mavo trying to find a suitable property to use, the value of the property is now the entire object (#692)
mv-like
still works, but is deprecated and will be removed in the next release.
New features
- You can now control whether a property is edited via a popup or inline with the
mv-edit-type
attribute! (#695) - The
mv-editor
property is now "live", i.e. expressions work in it. mv-storage-query
(andmv-source-query
/mv-init-query
) attribute now can be used to make a GraphQL query when using the Github backend
v0.2.3
We noticed some nasty regressions that v0.2.2 introduced so we are releasing a new version shortly after.
You should avoid v0.2.2 and go straight to v0.2.3 especially in apps that:
- Include lists of simple properties, with
mv-mode="edit"
applied - Include radio buttons that are Mavo properties
In addition, this new version includes an experimental new feature, intended for JS developers, plugin authors, or otherwise advanced users: Asynchronous data (i.e. promises) are now supported, both in loaded data, as well as expressions. This opens the door for many kinds of expressions that were not previously possible, and allows us to introduce more powerful functions in the future.
v0.2.2
This is not a huge release, but there are some breaking changes. Make sure to review before upgrading!
Note that anyone using get.mavo.io/stable/
or get.mavo.io/0.2/
will be automatically upgraded to this release. You can rollback to v0.2.1 by using get.mavo.io/0.2.1/
instead.
Breaking changes
- JS syntax is not allowed in Mavo expressions anymore. This opens the way for many future improvements to how expressions are handled. Note that if you're using custom JS functions in your expressions, those will continue to work fine, since function calls are perfectly valid MavoScript. One example of something you may need to convert: if you were using
{}
to define key-value pairs in your expressions, you will now need to usegroup()
instead. - This version drops support for IE11, Chrome 41, Microsoft Edge < 16 as their market share is fairly low at this point
- The code that allowed people to send "edit suggestions" as Github pull requests has now been moved to a plugin: https://plugins.mavo.io/plugin/github-pr . Use
mv-plugins="github-pr"
on any apps of yours that depend on this functionality.
Other changes
duration()
now accepts a second parameter for number of terms returned (e.g. "2 hours, 30 minutes").duration()
is now multi-valued, i.e. if used with a list of values, it will return a list of durations.- Github backend now works correctly when the default branch is
main
if no branch is specified. It will continue to work correctly for repos where the default branch is stillmaster
, but that will cost an extra HTTP request. indeterminate
is now correctly supported as a boolean attribute. This allows you to easily do checkboxes that follow the select/unselect all pattern a highly recommended UI enhancement for collections that contain checkboxes.- 12 bugfixes
- Several more code improvements
For plugin authors and JS developers
- For developers of custom backends: Authors can now pass arbitrary data to your backend via attributes. E.g.
mv-storage-foo="1"
will be converted to{foo: "1"}
and passed to your backend as a second constructor argument. See how the awesome new Google Sheets plugin uses this for additional metadata like sheet and range. These attributes are "live" as well, and could contain expressions, opening up so many creative possibilities! - A new hook allows you to use JS to easily transform data before it's rendered (read more)
- A new save-start hook allows you to intercept saving
- There is now a
Mavo#destroy()
method
Additional credits:
- @DmitrySharabin for his huge help with this release, both in terms of code, as well as issue triaging, assisting with debugging etc.
- @parulsingh23 for the
duration()
enhancements
v0.2.1
A rather small release.
- One can now specify a separate backend for uploads, via the
mv-uploads
attribute condense()
function to remove empty values from a list. Basically a more readable shortcut to thefirst(count(list), list)
hack.- New precision argument to
time()
, defaulting to"seconds"
<pre>
is added to block elements- 13 bugfixes
v0.2.0
It's been almost a year and a half since our last release, so this one is pretty huge. We'll try to summarize the changes the 330 (!) commits this release introduced below, but this list is far from comprehensive.
We strongly recommend that everyone upgrades to this version of Mavo, anything before that is fairly outdated at this point. We will not provide support for older versions, unless you discover a regression (i.e. something that was working in the old version that isn't working in the new one)
Backwards incompatible changes
- The URL structure to use our CDN has slightly changed to be more consistent and predictable. If you were using e.g.
https://get.mavo.io/mavo.js
to link to the latest stable version, you should now usehttps://get.mavo.io/stable/mavo.js
. Thehttps://get.mavo.io/mavo.js
URL will now link to the latest development version (i.e. it is the same as the old dev.mavo.io/dist/mavo.js which still works as well). If this seems confusing, just visit mavo.io/get, answer the questions again and copy the provided URLs! You don't need to change anything if you're linking to a specific version, or to the latest dev version. - Date formatting is now done via an extra parameter on date functions (see "Date-based expressions" below)
mv-autosave
without a value now defaults to 0 seconds (instant) instead of 3 seconds. However, we strongly recommend using it with a non-zero value for backends that generate an edit history (such as Github or Dropbox), otherwise you will end up with a huge, useless history.- The previously deprecated
mv-optional
attribute is now removed. Usemv-initial-items="0"
instead - Microdata attributes (
itemprop
,itemscope
,itemtype
) are no longer supported for specifying Mavo properties. Mavo will still look initemprop
for a property name, if theproperty
attribute is used without a value. The primary reason for this was that a) our research indicated that this syntax was very rarely used for specifying Mavo properties and b) People were often using Microdata in conjunction with Mavo, without expecting Mavo to do anything with these attributes, and then did not understand why this changed the way their apps were working. - The previously deprecated
yes-*
syntax inmv-bar
has now been removed. Please use the new syntax only.
Mavo Actions
Probably the biggest major new feature is Mavo Actions. They allow you to create your own controls that modify the data in custom ways when activated, and they can be quite powerful. You can read all about them in the documentation.
These actions are sufficiently novel, that we published a peer-reviewed research paper about them at a top-tier Human-Computer Interaction conference (UIST). If it's your cup of tea, you can read the paper here.
Note that Mavo's own data manipulation controls (buttons for deleting items, adding new items etc) are now implemented with Actions as well!
Date-based expressions
- Date formatting is now done via a second parameter in each date component function, not via the weird
.formatType
syntax we had before. E.g. instead ofmonth(date).name
you would writemonth(date, 'name')
and instead ofdigits(2, month(date))
, you would writemonth(date, '00')
. For details, you can look at the documentation for these functions. - All date component functions (e.g.
day()
anddays()
) now return the number of milliseconds for that date component when called with no parameters, so you can do more readable comparisons of date intervals, (e.g.day()
anddays()
both return86400000
). So something likebirthday - $today > 6 * 86400000
can now be more readably written asbirthday - $today > 6 * days()
. - New
duration()
function for displaying time intervals in a readable way, based on a number of milliseconds (which is what subtracting dates returns in Mavo). E.g.duration(10000)
will print out "10 seconds",duration(1000000)
will print out "16 minutes" andduration(100000000)
will print out "1 day". - Date formatting functions (as well as the new
duration()
) are localized based on the language of the Mavo app and not just that of the document root.
Uploads
- jsdelivr now used instead of rawgit.com for serving images uploaded to Github (if Github Pages is disabled), since rawgit is officially dead.
- Uploads are now allowed on
<a>
and<link>
elements with anmv-uploads
attribute, not just on<img>
,<audio>
,<video>
elements. - New
mv-upload-url
attribute to override the backend-provided URL for the upload. - For Plugin Developers: New hooks in upload popup, that make plugins like Cropper possible
UI changes
- New UI for undoing deletion. Instead of "Item Deleted" elements all over the place, we now use a "toast" notification at the top.
- Removed Mavo logo from toolbar
MavoScript changes
- Better error reporting for expressions: Separate errors for syntax mistakes and errors during expression evaluation. The former only appear once in the console.
- Smart property resolution now also works for "hidden" data that is not rendered on any HTML. This way you can have multiple Mavos that work on the same data and calculate things based on that data without having to add properties that you never intend to display.
New operators
- New
where
operator and correspondingfilter()
function for filtering lists of values. - New
in
operator and correspondinghas()
function for searching in lists of values or groups - New
..
operator for generating lists of integers, and correspondingrange()
function with more parameters (namely, a step) - New experimental
by
operator and correspondinggroupBy()
function, thanks to @jwass91
New special properties
- New
$item
special property which always returns the closest collection item - New
$all
special property which can be used in two ways: a) By itself it returns all items of the closest collection b) after another property (likefoo.$all
), which returns all values offoo
- New
$this
special property for the current group, useful in conjunction withwhere
- Special properties are now also available without a
$
, albeit with lower priority (to avoid collisions with other types of variables). E.g. instead of$next
, you can also usenext
. It's still recommended to use the$
anyway, for clarity.
New functions and improvements on existing functions
list()
andgroup()
functions for imitating the kinds of data that comes from collections and groups (for those who know JS or JSON:list(1, 2, 3)
is analogous to[1, 2, 3]
andgroup(name: 'Lea', age: 33)
to{"name": "Lea", "age": 33}
)- New
contains()
function for searching entire objects and lists, thanks to @efeichen - New
split()
function for splitting text into a list (the opposite ofjoin()
) - New
random()
function for generating random numbers - New
median()
function for calculating the median of a list of values - New
phrase()
function for custom localized text - Almost every Mavo function now works with lists of values as well, thanks to @efeichen
- Optional
n
argument infirst(n, list)
andlast(n, list)
for how many first/last items to return (if omitted it defaults to 1)
Other changes
- New
mv-expressions-ignore
attribute to ignore expression syntax (usually brackets) inside a specific attribute. E.g. to use a data URI with JSON insidemv-storage
without its brackets interfering with expressions, you can just domv-expressions-ignore="mv-storage"
. In the past, the only way to do this was to change the expression syntax for the entire element viamv-expressions
. - Lots of improvements with the Github backend and the edit suggestion (pull request) flow, thanks to @jwass91
- Simple properties can now contain arbitrary HTML that does not take part in the value of the property. E.g. if you want to have a static image inside your simple property, you can write
<span property="foo">Hello <img src="foo.png"></span>
and only the "Hello" will become editable. aria-label
is now dynamic and can be used to provide custom placeholders- Multiple property names are now supported in
mv-alias
thanks to @jwass91 - Hundreds of bugfixes
- Lots of performance improvements with expression evaluation
- Improvements to memory management, thanks to [@hopef...
v0.1.6
This is a small incremental release. Huge things coming in the next one though! :)
- Experimental
mv-like="propertyName"
attribute for copying templates from another collection. Property names are resolved in the same way as in expressions, except the current element is excluded (otherwiseproperty="foo" mv-like="foo"
would refer to itself). Collections created this way always start from 0 elements. Note that this allows infinitely nested collections where the children have the same template as the parent (e.g. comment nesting). In the future we plan to expand this beyond collections. Try it out and report bugs! - Experimental
mv-optional
attribute (boolean attribute, no value) to create collections that start with 0 elements. - When pasting an image, you will now be prompted for a filename. The auto-generated filename will still be there as a default.
- 50% speedup in expression evaluation.
- Raw GraphQL queries supported in Github backend (read-only, just like all raw API calls). To use, specify a URL like
api.github.com/graphql#query{…}
ordinal()
/th()
functions now only return the ordinal part (e.g."th"
) without the number. This is to allow for more flexible formatting.- Improvements in
idify()
- Several other bugfixes and improvements.
v0.1.5
Breaking changes
Important, the following changes mean you need to modify your code to use this version:
$url
, which became deprecated in the previous version, is now removed. Please use theurl()
function instead.- The syntax of the
mv-bar
attribute has changed, although most of the previous syntax still works for compatibility. Theyes-
prefix will be removed in the next version. Please read about the newmv-bar
syntax in the docs. - In case you were using identifiers in
mv-path
to only edit a collection item with that id, you will now need to useid=
before it (e.g.mv-path="pages/foo"
becomesmv-path="pages/id=foo"
). And yes, other properties besidesid
are now possible too :) - For advanced users using Mavo with JS: Event names have changed. You will need to change them in your code or it will stop working.
mavo:datachange
becamemv-change
, all othermavo:*
events becamemv-*
.
Other changes:
- Basic IE 11 support!
- New Import and Export optional toolbar buttons! Try them out by using
mv-bar="with import export"
or visit the SVG Path demo which already uses them. - The Mavo toolbar now uses
position: sticky
in browsers that support it, so that it remains visible while its Mavo app is visible. This is especially useful for long Mavo applications, to avoid scrolling up and down to toggle between edit and read modes. - The
$now
special property now updates on every repaint instead of every 100ms, making it possible to use it for smooth animations. - New
$startup
special property, which corresponds to the value of$now
when the page loaded. - Improved editing popups: Now positioned above the property they are editing if there is no space below, with the arrow pointing downwards.
- Improved image uploading user experience: Image is now displayed immediately, even before it's uploaded to the remote service.
- New MavoScript functions:
reverse()
- Backspace (or Shift + Backspace in complex collections) can now delete collection items.
- For advanced users using Mavo with JS: new
mv-edit
andmv-done
events.Mavo.prototype.dataLoaded
promise for when the data has loaded.Mavo.options()
utility method for
loosely parsing key-value pairs. - 39 smaller improvements and bugfixes