Skip to content

Releases: eclipsesource/tabris-js

v2.4.0

20 Mar 12:05
Compare
Choose a tag to compare

New RefreshComposite for "pull-to-refresh" gesture

The new widget RefreshComposite allows to perform the "pull-to-refresh" gesture on a simple layout hierarchy. The API and features are similar to the CollectionView but the usage is as simple as replacing a regular Composite with a RefreshComposite.

The following example lets the RefreshComposite show activity for 2 seconds.

new RefreshComposite({
  left: 0, right: 0, top: 0, bottom: 0,
}).on('refresh', () => setTimeout(({target}) => target.refreshIndicator = false, 2000))
  .appendTo(ui.contentView);

New printing support via tabris.Printer

Support for native printing has been added via tabris.Printer. Currently only documents in PDF format are supported.

A Printer has a method print(..) which takes the data to print as a ByteArray and an options object where a jobName can be provided. A native printing dialog will be shown where additional settings can be applied. The print(..) method returns a promise which resolves when the print job has been dispatched or throws an error otherwise.

fetch(app.getResourceLocation('resources/example.pdf'))
  .then(res => res.arrayBuffer())
  .then(data => printer.print(data, {jobName: 'tabris print example'}))
  .then(event => console.log('Finished', event))
  .catch(err => console.error(err));

ImageView supports "pinch-to-zoom" gesture

A new "pinch-to-zoom" gesture can be used on an ImageView to magnify an image. To enable the gesture a new property zoomEnabled along with a zoomLevel, minZoomLevel and maxZoomLevel has been added. The properties also dispatch the expected change events when the user uses a gesture to zoom.

The resting position of a zoomed image is 1.0 with the minZoomLevel also on 1.0 and the maxZoomLevel at 3.0.

let imageView = new ImageView({
  left: 0, right: 0, top: 0, bottom: 0,
  image: 'resources/salad.jpg',
  zoomEnabled: true
}).on('zoomChanged', ({value: zoomLevel}) => console.log(zoomLevel)
  .appendTo(ui.contentView);

Added support for "next()" in layout references

Similar to the keyword prev(), next() can be used in a layout declaration. It references the next widget sibling in the parent widget after the current widget.

New API to close a running app

To close a running app the following call can be made on the tabris.App. Closing a running app is only supported on Android.

tabris.app.close();

API additions for the TextInput widget

The TextInput gained two new properties to better integrate into the UI theme and to deal with passwords.

  • The new property cursorColor allows to give the cursor a specific color. Only supported on iOS.
  • The new property revealPassword toggles the visibility of a password inside a TextInput with type password. This addition allows to create common sign-in UIs with a checkbox "Show password".

New TabFolder navigation events

The TabFolder has received new events for tab switching. The appear event is fired on a Tab when the tab becomes the selected tab. Complementary, the previously selected Tab fires the disappear event.

In case the currently selected Tab is disposed, the TabFolder now correctly fires a selectionChanged event with the newly selected tab as the selection.

2.3.0

22 Dec 13:30
Compare
Choose a tag to compare

Custom font support

An API is provided to register a font to use throughout the app. It currently supports TrueType and OpenType fonts.

iPhone X support

Tabris.js apps are now displayed in full screen on the iPhone X and widgets have been optimized for the new hardware specifics.

More fine-grained "autoCapitalize" property of TextInput

TextInput can now be configured to auto capitalize the first word of a sentence, every word or every letter.

NavigationBar theme (Android)

The theme enables customization of the appearance of the navigation bar buttons on devices running Android version 8+.

2.2.0

29 Nov 13:56
Compare
Choose a tag to compare

New date and time input dialogs

To input date or time with native UI elements, a new DateDialog and TimeDialog has been added. These dialogs accept listeners which are informed when a new value is picked. To open the DateDialog the following code can be used:

new DateDialog({
  date: new Date()
}).on({
  select: ({date}) => console.log(date),
}).open();

New device vendor property

To retrieve the devices vendor a new property tabris.device.vendor has been added. It returns the device manufacturer, e.g.: "Apple" or "Samsung".

Functions as JSX elements

Functions that return a WidgetCollection can now be used as JSX elements. As per convention their name has to start with an uppercase letter. The function is called with two arguments: The element's attributes as an object and its children (if any) as an array. An example of this feature would be to call a given widget factory a given number of times:

function Repeat(properties: {times: number}, [callback]: [() => Widget]): WidgetCollection<Widget> {
  let result = [];
  for (let i = 0; i < properties.times; i++) {
    result[i] = callback();
  }
  return new WidgetCollection(result);
}

It can then be used like a regular element:

ui.contentView.append(
  <Repeat times={10}>{() => <textView top='prev() 10'>Hello Again!</textView>}</Repeat>
)

Note that this example assumes that the element has exactly one child (the callback function), but the type and number of children are not checked at compile time. (The attributes are.) It would therefore be a good idea to check the type of the children at runtime.

Improved support for custom properties in TypeScript

When creating a custom subclass of an existing Tabris widget, new properties don't behave the same as the built-in ones out of the box. Getting the constructor as well as the set and get methods to accept the new properties has previously been rather tedious. Now, with the with the addition of the tsProperties property and the Properties and Partial interfaces, this process has been greatly simplified.

The following example shows a custom UI component with full support of its new properties:

import {Composite, Partial, Properties} from 'tabris';

class MyCustomForm extends Composite {

  public tsProperties: Properties<Composite> & Partial<this, 'foo' | 'bar'>;

  // initializing plain properties is a must for "super" and "set" to work as a expected.
  public foo: string = null;
  public bar: number = null;

  constructor(properties?: Properties<MyCustomForm>) {
    super(properties);
  }

}

Read the section "Interfaces" at EcmaScript 6, TypeScript and JSX for detailed explanations.

2.1.1

29 Nov 10:18
Compare
Choose a tag to compare

Tabris.js

Issues with console output for thrown errors have been fixed.

Tabris.js Developer App

Since 2.1.0, the Tabris.js developer app didn't run on iOS 9 anymore. This has been fixed in 2.1.1.

Android

  • Fix an issue where touchEnd would not fire in some cases.
  • Fix an issue causing images loaded from external resources not to be scaled according to the device pixel density.
  • Fix various issues related to canvas scaling.

iOS

  • Fix images not being scaled according to the device pixel density.

2.1.0

04 Sep 09:16
Compare
Choose a tag to compare

Launching external apps

The app object has a new method launch() that accepts a URL and asks the operating system to open this URL in an appropriate external app. Operating systems usually support a variety of URL schemes including http, https, mailto, tel, and sms. Apps can also register for custom URL schemes. The method returns a promise to indicate success.

Example:

app.launch('http://tabrisjs.com')
  .then(() => console.log('success'))
  .catch(err => console.error(err));

New ActionSheet dialog allows to show unlimited dialog options

The new ActionSheet allows to show a modal dialog with a set of actions. If many actions are configured the user can scroll the sheet to reveal all actions. The ActionSheet compliments the existing AlertDialog when many options with longer text need to be shown. Example:

new ActionSheet({
  title: 'Actions',
  actions: [
    {title: 'Search'},
    {title: 'Delete', style: 'destructive'},
    {title: 'Cancel', style: 'cancel'},
  ]
}).on({select: ({index}) => console.log(`${index} selected`)})
  .open();

Tint colors for CheckBox, RadioButton, and ActivityIndicator

CheckBox and RadioButtons support two new properties tintColor and checkedTintColor to set custom tint colors. When only tintColor is set, it applies to both the checked and the unchecked state. Setting both properties allows for different tint color when checked.

Also the ActivityIndicator can be given a custom tintColor now.

Improved console logging

The console methods debug(), log(), info(), warn(), and error() now use an improved formatting and print different types of values consistently across all platforms. Like the console in Node.js and in web browsers, they now also support printf-like placeholders. Example:

console.log('processed %d items in %d ms', items.length, time);

Extended file system API

The new file system API introduced in Tabris.js 2.0 has been extended to support reading and writing of text files and listing directories. The functions remain similar to those known from Node.js except that they return a Promise instead of accepting a callback.

To read a text file, call fs.readFile() with the encoding in an additional argument. The returned promise will then resolve to a string instead ofreaddir function, an array buffer:

fs.readFile(path, 'utf-8')
  .then(text => console.log('read text from %s:', path, text))
  .catch(err => console.error(err));

To write a text file, pass a string instead of an array buffer as second argument to fs.writeFile(). You can also specify an encoding, if you don't, UTF-8 will be used:

fs.writeFile(path, 'Hello World!', 'ascii')
  .then(() => console.log('file written:', path))
  .catch(err => console.error(err));

To list the contents of a directory, use the new function fs.readDir() that returns an array with the names of all files and sub-directories of the given directory, not including '.' and '..'. Note that, unlike its equivalent in Node.js, this method name is written in camel case to be consistent with the other functions.

Padding on Composite

Sometimes, it was necessary to include a wrapper composite just to add some additional white space to a layout. To simplify those layouts, we've added a padding property to Composite that allows to add space inside the widget's bounds. The padding can either be set to an object with any of the fields left, right, top, and bottom, or to a single number which would then be applied to all four sides.

new Composite({
  padding: {left: 2, right: 2, bottom: 10}
});

Font property in CanvasContext

The CanvasContext now supports the property font, allowing you to set the text size, font family, weight and style.

Listener Registration via JSX

It's now possible register listeners directly in JSX. Any attribute that follows the naming scheme on{EventType} is used to register a listener with that event. For example:

    <button text='Show Message' onSelect={handleButtonSelect}/>

TypeScript Interfaces

The tabris module now exports the TypeScript interfaces used by the tabris API, including all parameter objects. This is useful when creating your own widgets classes in TypeScript. For details see documentation.

2.0.0

18 Jul 10:12
Compare
Choose a tag to compare

Final touch

Improved documentation, snippets and examples.
Last bug fixes.

2.0.0 RC 2

13 Jun 17:25
Compare
Choose a tag to compare
2.0.0 RC 2 Pre-release
Pre-release

Support for declarative UI using JSX

Widgets can now be created using JSX syntax. When using TypeScript this requires no extra dependencies, simply generate a new TypeScript project using tabris init and create a file with the .tsx file extension. Example:

import {ui} from 'tabris';

ui.contentView.append(
  <tabFolder left={0} top={0} right={0} bottom={0}>
    <tab title='First tab'>
      <textView text='Hello World' />
    </tab>
  </tabFolder>
);

JSX can be much more expressive than pure JavaScript/TypeScript. Compare the "input" example in JavaScript vs. TypeScript/JSX.

New basic filesystem API

We started to implement a basic filesystem API in Tabris.js. This first version can only read, write, and delete binary files. The API will be extended over time.

The new fs object provides two properties filesDir and cacheDir that point to the base paths for the app. Only files in these directories can be accessed.

The methods writeFile(path, data), readFile(path), and removeFile(path) are all asynchronous and return a promise.

Example:

let data = new Uint8Array([1, 2, 3]).buffer;

fs.writeFile(fs.fileDir + '/test.data', data)
  .then(() => console.log( data.byteLength + ' bytes written'))
  .catch(err => console.error(err));

See the documentation for the details.

New data property on Widget

To attach custom data to a Widget without the risk of clashes with widget internals, you can now use the data property. This property holds an empty object that is not used by the framework and can be freely used by the application code. Manipulations on this object will not affect the widget itself. Example:

widget.data.myItem = 23;

New load() method on CollectionView

We introduced a new method load() in CollectionView that replaces the current items with a new ones. To load new data into a CollectionView, use this method instead of setting the itemCount property.

Support for selectors in NavigationView.pages()

The pages() method on NavigationView now accepts a selector argument similar to children() to filter the list of pages. Example:

navigationView.pages('.temporary').dispose();

Introduce tintColor on Slider and ProgressBar

The color of the indicator in Slider and ProgressBar widgets can now be controlled by the new property tintColor. This had been possible with textColor, which is no longer supported on these widgets.

Windows support for existing (pre-RC2) Tabris.js APIs:

  • Support for tabris.app events background, foreground, pause and resume. terminate will not be supported in the foreseeable future.
  • Support for tabris.app properties appID, version and versionID.
  • Support for tabris.CollectionView property cellType, and support for automatic itemHeight.
  • Support for tabris.CollectionView method reveal
  • Support for tabris.AlertDialog. The neutral button is not yet supported.
  • Support for WebSocket.

Windows changes on TabFolder

  • Property background is now applied only to the tab bar, as on Android.
  • Property textColor will not be supported in the foreseeable future.
  • New property win_tabBarTheme allows setting the windows dark/light theme on the tab bar only.

Build service uses Tabris CLI

When you build your Tabris 2.0 app with the online build service at tabrisjs.com, this build will now use the Tabris CLI. As a notable difference to 1.x, apps that built in debug mode won't be wrapped in a developer app anymore. You can load a remote app using the new URL field in the developer console. Also note that the developer console must be enabled explicitly in your config.xml, e.g.:

<preference name="EnableDeveloperConsole" value="$IS_DEBUG" />

2.0.0 RC 1

15 May 09:59
Compare
Choose a tag to compare
2.0.0 RC 1 Pre-release
Pre-release

With this first release candidate, we've finalized the API for Tabris.js 2.0.

New CollectionView API

The CollectionView has a new API based on item indexes instead of the items itself. This gives the developer more control over binding different types of models to a CollectionView.

The items property has been replaced by a new property itemCount that controls the number of items to be displayed. To add or remove items at runtime, the methods insert() and remove() can be used, however, insert() now expects and item count instead of an array.

The cells of a CollectionView must now be created by the application in the callback createCell, which replaces the initializeCell callback. Any type of widget can be used as a cell. The type Cell has become obsolete and was removed. Example:

function createCell(type) {
  return new TextView({
    font: type === 'header' ? 'bold 18px' : '14px'
  });
}

Instead of the change:item event, the cells are now populated in a dedicated updateCell callback that receives the cell view and the item index to show:

function updateCell(cell, index) {
  cell.text = items[index].name;
}

The property itemHeight has been renamed to cellHeight for consistency. This property now also supports the value 'auto' that will calculate the height of each cell individually.

New Picker API

Since the CollectionView now works on item count and indexes instead of an array of items, the Picker API now follows the same approach.

The property items has been replaced by itemCount. The property selection that accepted the selected item has been removed in favor of the existing property selectionIndex.

The itemText callback is now required to provide a text for a given item. This callback is now called with an index instead of an item.

NavigationView

Removing hidden pages from a NavigationView using detach() or dispose() does no longer auto-remove pages stacked on top of the removed page. This allows you to remove underlying pages and so to change the target for back navigation.

The height of the toolbar(s) is now available as read-only properties topToolbarHeight and bottomToolbarHeight.

To prepare for pre-configured page transitions, the property animated has been replaced by a property pageAnimation that accepts the values 'default' and 'none'.

WebView history support

The WebView now supports navigating in the history using the new methods goBack() and goForward(). To check if this navigation is currently possible, you can use the read-only properties canGoBack and canGoForward.

Configurable enter key

The new property enterKeyType on TextInput allows to specify the label or icon shown on the return key of the keyboard. Supported values are 'default', 'done', 'next', 'send', 'search', and 'go'.

Renamed events

All-lowercase event names and those with a colon in their name (such as pan:left) have been renamed to camelCase (e.g. panLeft). This affects the following events:

  • Gesture events prefixed with pan: and swipe:.
  • The variants of the close event on AlertDialog have been renamed from close:ok, close:cancel and close:neutral to closeOk, closeCancel, and closeNeutral.
  • addchild and removechild are now addChild and removeChild.
  • Touch events (all lowercase) renamed to touchStart, touchEnd, touchCancel and touchMove.
  • Property change events (like change:text) are now named after the pattern <property>Changed. For example, the event change:text becomes textChanged.

Pan events now have separate properties for translationX and translationY instead of translation to match with the properties of the Widget's transform object. The property velocity has been replaced by individual properties velocityX and velocityY.

Events API

The methods on(), off(), and once() now also support maps of events and listeners to allow adding and removing multiple listeners in a single statement. Example:

new CheckBox({
  left: 12, top: 12
}).on({
  tap: onTap,
  select: onSelect
}).appendTo(parent);

This version of these methods also offer improved typing and tool support.

Besides the target property, all events now include the additional properties type (the event name) and timeStamp (the event timestamp in milliseconds). The latter replaces the property time on touch events.

As all listeners now receive an event object, the trigger() method also expects an object as second parameter and does not delegate additional parameters to the listeners anymore.

New fetch implementation

Instead of using a polyfill, a subset of the fetch API is now implemented in Tabris.js directly. With this change, the response objects now include the method arrayBuffer() to allow downloading binary content using fetch:

fetch(url).then(response => response.arrayBuffer()).then(buffer => ...)

As an addition to the standard, this implementation also features a timeout option:

fetch(url, {
  timeout: 5000 // request timeout in ms
}).then(...);

Support for #RRGGBBAA colors

Color properties now accept colors in the format #rrggbbaa where the aa part defines the alpha channel (opacity) as hex value between 00 (transparent) and ff (opaque).

Nightly builds

For those who like to try out the latest developments in tabris, nightly builds are now available on npm. You can install the latest nightly using npm install tabris@nightly or include a dependency like this:

"dependencies": {
  "tabris": "nightly"
}

2.0.0 Beta 2

17 Mar 08:14
Compare
Choose a tag to compare
2.0.0 Beta 2 Pre-release
Pre-release

Event listener API

We've redesigned the API for event listeners. All event listeners now receive a single event object instead of separate parameters. This change requires adjustments to all existing applications, however, it will allow us to add new event properties over time without introducing any more breaking changes.

All event objects have a target property that references the object that received the event. All change listeners (change:property) include a property value that contains the new value of the changed property. Other properties are specific to the event type.

For example, an event listener for a checkbox would now look like this:

checkbox.on('select', (event) => {
  event.target // the checkbox that received the event
  event.checked // the checked state
});

Please refer to the documentation for the properties available on the respective events. You may also want to look at the updated snippets.

Renamed properties

On all stateful button widgets, that is CheckBox, RadioButton, ToggleButton, and Switch, the property selection has been renamed to checked. The select event also contains a parameter checked that reflects the new state.

On touch events, the properties pageX and pageY have been renamed to absoluteX and absoluteY, respectively. These properties reflect the position relative to the content view (ui.contentView).

Animations

The events animationstart and animationend have been removed in favour of the new Promise API. Those events were hard to consume as they could fire before the listener was even attached and they weren't specific to a certain animation. With the Promise returned by the animate() method, it has become much easier to perform actions on completion. Example:

widget.animate({opacity: 0}, {duration: 300, easing: 'ease-out'}).then(() => widget.dispose());

Windows support

Tabris.js can now create Windows 10 Store apps for desktop, tablet and phone. Not all APIs will be supported on the launch of Tabris.js 2.0, so keep an eye on the Windows 10 support article of the Tabris.js documentation. For now Tabris Connect can build appxbundle files suitable for sideloading, appxupload files for store deployment will be available at launch.

Local builds with the CLI

The latest version of tabris-cli supports building apps on your local machine by calling

tabris build [android|ios|windows]

Custom widgets

The interface for custom widgets has changed. If you've developed a native custom widget, please refer to the custom widget documentation for the new API.

Migration Guide

To facilitate the migration of existing apps, we've created a migration guide.

2.0.0 Beta 1

08 Feb 09:29
Compare
Choose a tag to compare
2.0.0 Beta 1 Pre-release
Pre-release

New UI model

Tabris.js does not dictate the use of pages anymore. Widgets can be added directly to the main area of the app.

The object tabris.ui, which represents the UI root, now has a number of children, that represent different parts of the app's user interface:

  • tabris.ui.statusBar - shows the time and some system status icons
  • tabris.ui.navigationBar - contains the Back, Home, etc. buttons on Android
  • tabris.ui.contentView - contains the app's main UI
  • tabris.ui.drawer - can be swiped in from the left

Widgets can be appended to contentView, and optionally to the drawer:

new tabris.Button({
  left: 16, top: 16
}).appendTo(tabris.ui.contentView);

Drawer is now a singleton

There's only a single drawer widget available as tabris.ui.drawer. The type tabris.Drawer cannot be instantiated anymore. The drawer is disabled by default, to use it in an application, you have to enable it:

tabris.ui.drawer.enabled = true;

New NavigationView, changes to Page

The new widget NavigationView offers page-based navigation. By creating multiple instances of this widget, it is now possible to have multiple page stacks in an app, for example in different tabs.

Pages are now appended to and removed from a NavigationView using the standard widget methods append(), appendTo(), detach(), and dispose(), respectively. When a page is added, it becomes the topmost page on the page stack and covers any previous page. The methods open() and close() on Page are obsolete and have been removed.

On back navigation, the topmost page will be disposed. When a page is removed from a NavigationView, all pages on top will be disposed automatically. To prevent pages from being automatically disposed, you can set the property autoDispose to false. The property topLevel has also been removed.

The header of a NavigationView can be styled using the new properties toolbarColor, actionColor, titleTextColor, and actionTextColor.

Actions and SearchActions are now also added to instances of a NavigationView.

Remove PageSelector

The helper type PageSelector, that showed a list of pages did not fit with the new UI model that allows for multiple page stacks. It has been removed.

Widgets

New AlertDialog

The new type AlertDialog can be used to display modal dialogs to the user. An alert dialog can contain a message text and up to three buttons with custom texts.

ScrollView scrolling

The ScrollView properties offsetX and offsetY are now read-only. To scroll programmatically, use the methods scrollToX() and scrollToY(). You can omit the animation by adding {animate: false} as second parameter.

TabFolder scrolling

A new property tabMode on TabFolder allows to enable overflow behavior on Android. It can be set to 'fixed' (default) or 'scrollable'. When set to 'scrollable', the tabs in the tab bar will overflow and can be scrolled.

A new TabFolder event scroll is fired when paging is enabled and a tab is scrolled. This event can be used to implement transition effects such as parallax scrolling.

TextView selectable mode

With a new property selectable on TextView, you can allow copying from a TextView into the clipboard. This property is currently only support on Android.

TextInput keepFocus property

A new property keepFocus has been introduced on TextInput. When set to true the TextInput will keep its focus, even when tapped outside of the widget bounds, thereby leaving the keyboard open.

New color properties on TextInput and Picker

The new properties fillColor and borderColor provide more fine-grained control over the look and feel of TextInput and Picker widgets.

Support for data URIs in image properties

Data URIs can now be used in all widget properties that accept an image.

Properties on tabris.app

The read-only properties id, version, and versionCode on tabris.app provide information on the app id and version.

HTTP

Support for binary responses in XHR

The responseType 'arraybuffer' is now supported by the XHR implementation in Tabris.js and supports downloading binary content.

Support for certificate pinning

A new property pinnedCertificate on tabris.app can be used to enable certificate pinning.
The property accepts an array of pinned certificates in the form of

[
  {host: <string>, hash: <string>, algorithm: <RSA2048|RSA4096|ECDSA256>},
  ...
]

Overall Widget API

Direct access to widget properties

You can now access all widget properties directly, without using get() and set():

button.text = 'OK';
var text = button.text;

The methods get() and set() remain available.

Remove support for off() with zero or one argument

In Tabris 1.0, calling a widget's off() method with zero arguments could be used to remove all listeners from a widget and off(topic) to remove all listeners for a given event topic. As these calls could affect other modules, they were considered risky and have been removed.

New detach method to remove widgets from their parent

Tabris widgets can be created without a parent and appended to a parent later. Using appendTo() they can be re-parented. A new method detach() now allows to remove a widget from its current parent for later re-use.

New includes method on WidgetCollection

You can use the new method includes() to find out whether a widget exists in a collection, e.g.

if (parent.children().includes(widget)) {
  ...
}

Custom widgets

The method tabris.registerWidget that had been recommended for custom widgets has been removed. Native widgets should now extend Widget. We recommend to use ES6 classes and transpile the code as needed.

class MyWidget extends Widget {

  get foo() {}
  set foo(value) {}
  ...

}

Android platform

Resource drawables in image objects

A new Android specific image url scheme android-drawable allows to load bundled resource drawables, e.g. new tabris.ImageView({image: 'android-drawable://ic_icon' }). The bundled resources have to be placed in their respective drawable folders during app build time.

Added support for splash screens

The cordova build now supports to configure a splash screen via the <splash ..> element. To customize the theme extend one of the SplashScreen themes.

Breaking changes

  • Minimum support Android version raised to API level 17 (Android 4.2)
  • Base theme to extend when creating a custom theme has been renamed from DarkActionBar to DarkAppBar
  • TabrisActivity intent extra theme now expects a theme resource id instead of a qualified class name