├── .babelrc ├── .eslintignore ├── .eslintrc.json ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ ├── feature_request.md │ └── question.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── review.yml ├── .gitignore ├── .travis.yml ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── CONTRIBUTING.md ├── Gruntfile.js ├── Jenkinsfile ├── LICENSE ├── README.md ├── doc ├── api │ ├── $.console │ ├── $.json │ ├── $.jsx │ ├── $.tsx │ ├── Action.js │ ├── Action.json │ ├── ActionSheet.js │ ├── ActionSheet.json │ ├── ActionSheetItem.json │ ├── ActivityIndicator.js │ ├── ActivityIndicator.json │ ├── AlertDialog.js │ ├── AlertDialog.json │ ├── Blob.json │ ├── Button.js │ ├── Button.json │ ├── Camera.js │ ├── Camera.json │ ├── CameraView.js │ ├── CameraView.json │ ├── CameraView.jsx │ ├── Canvas.js │ ├── Canvas.json │ ├── CanvasContext.js │ ├── CanvasContext.json │ ├── CanvasContext.post.md │ ├── Cell.json │ ├── Cell.jsx │ ├── ChangeListeners.json │ ├── ChangeListeners.post.md │ ├── CheckBox.js │ ├── CheckBox.json │ ├── CollectionView.js │ ├── CollectionView.json │ ├── Color.js │ ├── Color.json │ ├── Color.post.md │ ├── ColorResources.json │ ├── Composite.js │ ├── Composite.json │ ├── Composite.post.md │ ├── Console.js │ ├── Console.json │ ├── Constraint.json │ ├── Constraint.post.md │ ├── ConstraintLayout.js │ ├── ConstraintLayout.json │ ├── ContentView.json │ ├── Crypto.json │ ├── CryptoKey.json │ ├── DateDialog.js │ ├── DateDialog.json │ ├── Drawer.js │ ├── Drawer.json │ ├── EventObject.json │ ├── File.json │ ├── Font.js │ ├── Font.json │ ├── Font.post.md │ ├── FontResources.json │ ├── FormData.json │ ├── Headers.json │ ├── Image.js │ ├── Image.json │ ├── Image.md │ ├── Image.post.md │ ├── ImageBitmap.json │ ├── ImageView.js │ ├── ImageView.json │ ├── InactivityTimer.js │ ├── InactivityTimer.json │ ├── ItemPicker.json │ ├── ItemPicker.jsx │ ├── ItemPicker.md │ ├── Layout.json │ ├── LayoutData.js │ ├── LayoutData.json │ ├── LayoutData.post.md │ ├── LinearGradient.js │ ├── LinearGradient.json │ ├── LinearGradient.post.md │ ├── List.json │ ├── List.md │ ├── ListView.json │ ├── ListView.jsx │ ├── ListView.md │ ├── Listeners.json │ ├── Module.json │ ├── NativeObject.json │ ├── NavigationBar.js │ ├── NavigationBar.json │ ├── NavigationView.js │ ├── NavigationView.json │ ├── Observable.json │ ├── Observable.post.md │ ├── ObservableData.json │ ├── Page.js │ ├── Page.json │ ├── PdfView.json │ ├── Percent.json │ ├── Percent.post.md │ ├── Picker.js │ ├── Picker.json │ ├── Popover.js │ ├── Popover.json │ ├── Popup.json │ ├── ProgressBar.js │ ├── ProgressBar.json │ ├── RadioButton.js │ ├── RadioButton.json │ ├── RefreshComposite.js │ ├── RefreshComposite.json │ ├── Request.json │ ├── RequestInit.json │ ├── ResourceBuilder.json │ ├── Resources.json │ ├── Response.json │ ├── ResponseInit.json │ ├── Row.js │ ├── Row.json │ ├── RowLayout.js │ ├── RowLayout.json │ ├── ScrollView.js │ ├── ScrollView.json │ ├── SearchAction.js │ ├── SearchAction.json │ ├── Setter.json │ ├── Setter.post.md │ ├── Slider.js │ ├── Slider.json │ ├── Stack.js │ ├── Stack.json │ ├── StackLayout.js │ ├── StackLayout.json │ ├── StatusBar.js │ ├── StatusBar.json │ ├── SubtleCrypto.json │ ├── Switch.js │ ├── Switch.json │ ├── Tab.js │ ├── Tab.json │ ├── TabFolder.js │ ├── TabFolder.json │ ├── Tabris.json │ ├── TextInput.js │ ├── TextInput.json │ ├── TextResources.json │ ├── TextView.js │ ├── TextView.json │ ├── TimeDialog.js │ ├── TimeDialog.json │ ├── ToggleButton.js │ ├── ToggleButton.json │ ├── Video.js │ ├── Video.json │ ├── WebView.js │ ├── WebView.json │ ├── Widget.json │ ├── Widget.post.md │ ├── WidgetCollection.js │ ├── WidgetCollection.json │ ├── WidgetCollection.jsx │ ├── app.json │ ├── authentication.json │ ├── authentication.jsx │ ├── authentication.md │ ├── devTools.json │ ├── device.json │ ├── fetch.json │ ├── fetch.md │ ├── fs.js │ ├── fs.json │ ├── img │ │ ├── Video-state.png │ │ ├── android │ │ │ ├── Action.png │ │ │ ├── ActionSheet.png │ │ │ ├── ActivityIndicator.png │ │ │ ├── AlertDialog.png │ │ │ ├── Button.png │ │ │ ├── CameraView.png │ │ │ ├── Canvas.png │ │ │ ├── CheckBox.png │ │ │ ├── CollectionView.png │ │ │ ├── Composite.png │ │ │ ├── Console.png │ │ │ ├── DateDialog.png │ │ │ ├── Drawer.png │ │ │ ├── ImageView.png │ │ │ ├── NavigationBar.png │ │ │ ├── NavigationView.png │ │ │ ├── Page.png │ │ │ ├── Picker.png │ │ │ ├── Printer.png │ │ │ ├── ProgressBar.png │ │ │ ├── RadioButton.png │ │ │ ├── RefreshComposite.png │ │ │ ├── ScrollView.png │ │ │ ├── SearchAction.png │ │ │ ├── Slider.png │ │ │ ├── StackComposite.png │ │ │ ├── StatusBar.png │ │ │ ├── Switch.png │ │ │ ├── Tab.png │ │ │ ├── TabFolder.png │ │ │ ├── TextInput.png │ │ │ ├── TextView.png │ │ │ ├── TimeDialog.png │ │ │ ├── ToggleButton.png │ │ │ ├── Video.png │ │ │ └── WebView.png │ │ └── ios │ │ │ ├── Action.png │ │ │ ├── ActionSheet.png │ │ │ ├── ActivityIndicator.png │ │ │ ├── AlertDialog.png │ │ │ ├── Button.png │ │ │ ├── CameraView.png │ │ │ ├── Canvas.png │ │ │ ├── CheckBox.png │ │ │ ├── CollectionView.png │ │ │ ├── Composite.png │ │ │ ├── Console.png │ │ │ ├── DateDialog.png │ │ │ ├── Drawer.png │ │ │ ├── ImageView.png │ │ │ ├── NavigationView.png │ │ │ ├── Page.png │ │ │ ├── Picker.png │ │ │ ├── Printer.png │ │ │ ├── ProgressBar.png │ │ │ ├── RadioButton.png │ │ │ ├── RefreshComposite.png │ │ │ ├── ScrollView.png │ │ │ ├── SearchAction.png │ │ │ ├── Slider.png │ │ │ ├── StackComposite.png │ │ │ ├── StatusBar.png │ │ │ ├── Switch.png │ │ │ ├── Tab.png │ │ │ ├── TabFolder.png │ │ │ ├── TextInput.png │ │ │ ├── TextView.png │ │ │ ├── TimeDialog.png │ │ │ ├── ToggleButton.png │ │ │ ├── Video.png │ │ │ └── WebView.png │ ├── input.json │ ├── localStorage.js │ ├── localStorage.json │ ├── permission.js │ ├── permission.json │ ├── printer.js │ ├── printer.json │ ├── sizeMeasurement.json │ ├── timer.js │ ├── timer.json │ └── utils.json ├── build.md ├── cordova.md ├── custom-widgets-android.md ├── custom-widgets-ios.md ├── custom-widgets.md ├── debug.md ├── declarative-ui.md ├── developer-app.md ├── examples.md ├── faq.md ├── functional-components.md ├── getting-started.md ├── img │ ├── app-url.png │ ├── build-app-settings.png │ ├── build-create-app.png │ ├── build-valid-app.png │ ├── contentview.png │ ├── debug-android-webstorm.png │ ├── debug-android.png │ ├── devtools-android.png │ ├── drawer.png │ ├── hello-example.png │ ├── navigationbar.png │ ├── permission-status.png │ ├── social-logo-facebook.png │ ├── social-logo-linkedin.png │ ├── social-logo-twitter.png │ ├── statusbar.png │ └── theming-android.png ├── index.md ├── layout.md ├── migration-guide.md ├── modules.md ├── permissions.md ├── resource-management.md ├── runtime.md ├── selector.md ├── testing.md ├── theming-android.md ├── toc.yml ├── touch.md ├── tsconfig.json ├── typescript.md ├── ui.md ├── w3c-api.md └── widget-basics.md ├── package-lock.json ├── package.json ├── rollup.boot.js ├── rollup.tabris.js ├── schema ├── colors.json ├── fonts.json └── texts.json ├── snippets ├── README.md ├── actionsheet.jsx ├── activityindicator.jsx ├── alertdialog.jsx ├── animate-people.js ├── animate-tray.jsx ├── animate.jsx ├── app-events.jsx ├── app-info.jsx ├── app-launch.jsx ├── app-share.jsx ├── authentication.jsx ├── button-style.jsx ├── button.jsx ├── camera-advanced.tsx ├── camera.tsx ├── canvas-animation.jsx ├── canvas-arc.jsx ├── canvas-imagebitmap.jsx ├── canvas-imagedata.jsx ├── canvas-shapes.jsx ├── canvas-text.jsx ├── canvas-to-image.jsx ├── checkbox.jsx ├── collectionview-cellheightauto.jsx ├── collectionview-celltype-ts.tsx ├── collectionview-celltype.jsx ├── collectionview-columncount.jsx ├── collectionview-refreshenabled.jsx ├── collectionview-scroll-ts.tsx ├── collectionview-scroll.jsx ├── collectionview-swipe-to-dismiss.jsx ├── collectionview-ts.tsx ├── collectionview.jsx ├── composite-apply-jsx.tsx ├── composite-apply.ts ├── composite.jsx ├── console.jsx ├── createimagebitmap-resize.jsx ├── crypto-decrypt.ts ├── crypto-derive.ts ├── crypto-sign.ts ├── crypto.ts ├── datedialog.jsx ├── device.jsx ├── devtools.jsx ├── drawer-pages.tsx ├── drawer.jsx ├── fetch.jsx ├── format.js ├── formdata.jsx ├── fs-append.jsx ├── fs-openfile-advanced.jsx ├── fs-openfile.jsx ├── fs.jsx ├── functional-js-components-typescript.ts ├── functional-js-components.js ├── functional-jsx-components-typescript.tsx ├── functional-jsx-components.jsx ├── global-input.tsx ├── imageview-as-a-button.jsx ├── imageview-base64.jsx ├── imageview-blob.jsx ├── imageview-gallery.tsx ├── imageview-imagebitmap.jsx ├── imageview-load.jsx ├── imageview-scalemode-auto.jsx ├── imageview-scalemode.jsx ├── imageview-tintcolor.jsx ├── imageview-zoom.jsx ├── imageview.jsx ├── inactivitytimer.js ├── input.jsx ├── layout-baseline.jsx ├── layout-center.jsx ├── layout-dynamic.jsx ├── layout-relative-position.jsx ├── layout-relative-size.jsx ├── layout-row.jsx ├── layout-stack.jsx ├── layout-transform-translationz.jsx ├── layout-z-order.jsx ├── layout.jsx ├── local-storage.jsx ├── module-addpath.tsx ├── module-define.tsx ├── navigationbar.jsx ├── navigationview-action-placement.jsx ├── navigationview-action.jsx ├── navigationview-page-stacked.jsx ├── navigationview-properties.jsx ├── navigationview-searchaction.jsx ├── navigationview-tabfolder.js ├── observable-events.tsx ├── observable-mutations.tsx ├── observable.tsx ├── package.json ├── pdfview.jsx ├── permission-advanced.tsx ├── permission.jsx ├── picker-style.jsx ├── picker.jsx ├── popover.jsx ├── printer.js ├── progressbar.jsx ├── radiobutton.jsx ├── reddit.jsx ├── refreshcomposite.jsx ├── resource-management.tsx ├── resources │ ├── Sources.md │ ├── arrow-back-black-24dp@3x.png │ ├── arrow-forward-black-24dp@3x.png │ ├── arrow-upward-white-24pt@3x.png │ ├── card-filled@2x.png │ ├── card@2x.png │ ├── cart-filled@2x.png │ ├── cart@2x.png │ ├── chart-filled@2x.png │ ├── chart@2x.png │ ├── close-black-24dp@3x.png │ ├── close-white-24dp@3x.png │ ├── cloud-check.png │ ├── colors.json │ ├── cover.jpg │ ├── delete-black-24dp@3x.png │ ├── example.pdf │ ├── fonts.json │ ├── holger.jpg │ ├── ian.jpg │ ├── index.ts │ ├── jochen.jpg │ ├── jordi.jpg │ ├── landscape.jpg │ ├── markus.jpg │ ├── moritz.jpg │ ├── pacifico.ttf │ ├── ralf.jpg │ ├── salad.jpg │ ├── search-black-24dp@3x.png │ ├── search-white-24dp@3x.png │ ├── settings-black-24dp@3x.png │ ├── settings-white-24dp@3x.png │ ├── share-black-24dp@3x.png │ ├── share-white-24dp@3x.png │ ├── target_200.png │ ├── texts.json │ ├── tim.jpg │ ├── website.html │ └── worker-script.js ├── row-alignment.jsx ├── row-halign.jsx ├── row.jsx ├── run-all.js ├── screenshots.js ├── scrollview-parallax.jsx ├── scrollview.jsx ├── sizemeasurement.jsx ├── slider.jsx ├── stack-alignment.jsx ├── stack-valign.jsx ├── stack.jsx ├── statusbar.js ├── switch.jsx ├── tabfolder-swipe-parallax.js ├── tabfolder-swipe.jsx ├── tabfolder.jsx ├── textinput-enterkeytype.js ├── textinput-focus.tsx ├── textinput-keyboard.js ├── textinput-keyboard.ts ├── textinput-revealpassword.js ├── textinput-selection.js ├── textinput-style.tsx ├── textinput-validation.ts ├── textinput.jsx ├── textview-font-bundled.js ├── textview-font-external.js ├── textview-linespacing.js ├── textview-link.jsx ├── textview-markupenabled.jsx ├── textview.jsx ├── timedialog.tsx ├── timer.jsx ├── togglebutton.jsx ├── tsconfig.json ├── types.d.ts ├── video.js ├── web-storage.js ├── webview-navigation.js ├── webview-webmessaging.js ├── webview.jsx ├── widget-cornerradius.jsx ├── widget-elevation.jsx ├── widget-exclude-from-layout.jsx ├── widget-highlightontouch.jsx ├── widget-lineargradient.js ├── widget-longpress-to-drag.js ├── widget-padding.jsx ├── widget-touch.js ├── worker.jsx └── xmlhttprequest.js ├── src ├── boot │ ├── Module.ts │ ├── globals.d.ts │ ├── main.ts │ └── tsconfig.json └── tabris │ ├── $.js │ ├── ActionSheet.js │ ├── AlertDialog.js │ ├── Animation.js │ ├── App.js │ ├── Authentication.js │ ├── Blob.js │ ├── Camera.js │ ├── CanvasContext.js │ ├── ChangeListeners.ts │ ├── Color.js │ ├── ColorResources.js │ ├── Console.js │ ├── Constraint.js │ ├── Crypto.ts │ ├── CryptoKey.ts │ ├── DateDialog.js │ ├── DevTools.js │ ├── Device.js │ ├── Document.js │ ├── Event.js │ ├── EventObject.ts │ ├── Events.ts │ ├── File.js │ ├── FileSystem.js │ ├── Font.js │ ├── FontResources.js │ ├── FormData.js │ ├── Formatter.js │ ├── GC.js │ ├── GestureRecognizer.js │ ├── HttpRequest.js │ ├── Image.js │ ├── ImageBitmap.js │ ├── ImageData.js │ ├── InactivityTimer.js │ ├── Input.ts │ ├── JsxProcessor.ts │ ├── Layout.js │ ├── LayoutData.js │ ├── LinearGradient.js │ ├── Listeners.ts │ ├── NativeBridge.ts │ ├── NativeObject.ts │ ├── NativeObjectRegistry.js │ ├── Observable.ts │ ├── Observable.types.d.ts │ ├── ObservableData.ts │ ├── Percent.js │ ├── Permission.js │ ├── Pkcs5.js │ ├── Popover.js │ ├── Popup.ts │ ├── Printer.js │ ├── Process.js │ ├── ProgressEvent.js │ ├── Promise.js │ ├── ResourceBuilder.js │ ├── Resources.js │ ├── RowLayout.js │ ├── Setter.ts │ ├── SizeMeasurement.js │ ├── StackLayout.js │ ├── Storage.js │ ├── Tabris.ts │ ├── TextDecoder.js │ ├── TextEncoder.js │ ├── TextResources.js │ ├── TimeDialog.js │ ├── WebSocket.js │ ├── Widget.ts │ ├── WidgetCollection.js │ ├── WindowTimers.js │ ├── Worker.ts │ ├── XMLHttpRequest.js │ ├── checkType.js │ ├── fetch │ ├── Body.js │ ├── Headers.js │ ├── Request.js │ ├── Response.js │ └── fetch.js │ ├── internals.d.ts │ ├── load-polyfill.js │ ├── main.js │ ├── property-types.js │ ├── resourcesDataTypes.d.ts │ ├── symbols.ts │ ├── tsconfig.json │ ├── util-colors.js │ ├── util-fonts.js │ ├── util-resources.js │ ├── util-stacktrace.js │ ├── util-widget-select.js │ ├── util.js │ ├── version.js │ └── widgets │ ├── Action.js │ ├── ActivityIndicator.js │ ├── Button.js │ ├── CameraView.js │ ├── Canvas.js │ ├── CheckBox.js │ ├── CollectionView.js │ ├── Composite.ts │ ├── ContentView.js │ ├── Drawer.js │ ├── ImageView.js │ ├── NavigationBar.js │ ├── NavigationView.js │ ├── Page.js │ ├── PdfView.js │ ├── Picker.js │ ├── ProgressBar.js │ ├── RadioButton.js │ ├── RefreshComposite.js │ ├── Row.js │ ├── ScrollView.js │ ├── SearchAction.js │ ├── Slider.js │ ├── Stack.js │ ├── StatusBar.js │ ├── Switch.js │ ├── Tab.js │ ├── TabFolder.js │ ├── TextInput.js │ ├── TextView.js │ ├── ToggleButton.js │ ├── Video.js │ ├── WebView.js │ └── util-apply.ts ├── test ├── .eslintrc ├── boot │ ├── Module.test.ts │ └── tsconfig.json ├── tabris-mock.js ├── tabris │ ├── $.test.js │ ├── ActionSheet.test.js │ ├── AlertDialog.test.js │ ├── Animation.test.js │ ├── App.test.js │ ├── Authentication.test.js │ ├── Blob.test.js │ ├── Camera.test.js │ ├── CanvasContext.test.js │ ├── CanvasContext.verify.js │ ├── ClientMock.d.ts │ ├── ClientMock.js │ ├── ClientMock.test.js │ ├── Color.test.js │ ├── ColorResources.test.js │ ├── Console.test.js │ ├── Constraint.test.js │ ├── Crypto.test.ts │ ├── DateDialog.test.js │ ├── DevTools.test.js │ ├── Device.test.js │ ├── Document.test.js │ ├── Event.test.js │ ├── EventObject.test.js │ ├── Events.test.ts │ ├── File.test.js │ ├── FileSystem.test.js │ ├── Font.test.js │ ├── FontResources.test.js │ ├── FormData.test.js │ ├── Formatter.test.js │ ├── HttpRequest.test.js │ ├── Image.test.js │ ├── ImageBitmap.test.js │ ├── ImageData.test.js │ ├── Input.test.ts │ ├── JsxProcessor.test.js │ ├── Layout.test.js │ ├── LayoutData.test.js │ ├── LinearGradient.test.js │ ├── Listeners.test.ts │ ├── NativeBridge.test.ts │ ├── NativeObject.test.ts │ ├── NativeObjectRegistry.test.js │ ├── Observable.test.ts │ ├── ObservableData.test.ts │ ├── Percent.test.js │ ├── Permission.test.js │ ├── Pkcs5.test.js │ ├── Popover.test.js │ ├── Printer.test.js │ ├── Process.test.js │ ├── ProgressEvent.test.js │ ├── Promise.test.js │ ├── Resources.test.js │ ├── RowLayout.test.js │ ├── Setter.test.ts │ ├── SizeMeasurement.test.js │ ├── StackLayout.test.js │ ├── Storage.test.js │ ├── Tabris.test.ts │ ├── TextDecoder.test.js │ ├── TextEncoder.test.js │ ├── TextResources.test.js │ ├── TimeDialog.test.js │ ├── WebSocket.test.js │ ├── WebSocket.verify.js │ ├── WidgetCollection.test.js │ ├── WindowTimers.test.js │ ├── Worker.test.ts │ ├── XMLHttpRequest.test.js │ ├── checkType.test.js │ ├── fetch │ │ ├── Body.test.js │ │ ├── Headers.test.js │ │ ├── Request.test.js │ │ ├── Response.test.js │ │ └── fetch.test.js │ ├── gestures.test.js │ ├── node.d.ts │ ├── property-types.test.js │ ├── tabris.verify.js │ ├── util-colors.test.js │ ├── util-fonts.test.js │ ├── util-stacktrace.test.js │ ├── util.test.js │ ├── version.test.js │ └── widgets │ │ ├── Action.test.js │ │ ├── Button.test.js │ │ ├── CameraView.test.js │ │ ├── Canvas.test.js │ │ ├── CollectionView.test.js │ │ ├── ContentView.test.js │ │ ├── Drawer.test.js │ │ ├── ImageView.test.js │ │ ├── NavigationBar.test.js │ │ ├── NavigationView.test.js │ │ ├── Page.test.js │ │ ├── PdfView.test.js │ │ ├── Picker.test.js │ │ ├── ScrollView.test.js │ │ ├── SearchAction.test.js │ │ ├── StatusBar.test.js │ │ ├── Tab.test.js │ │ ├── TabFolder.test.js │ │ ├── TextInput.test.js │ │ ├── TextView.test.js │ │ ├── Video.test.js │ │ ├── WebView.test.js │ │ ├── Widget.apply.test.js │ │ ├── Widget.test.ts │ │ └── commonWidgets.test.js ├── test.js └── typescript │ ├── $.test.ts │ ├── ActionSheet.test.ts │ ├── AlertDialog.test.ts │ ├── Blob.test.ts │ ├── Camera.test.ts │ ├── CanvasContext.test.ts │ ├── ClientMock.test.ts │ ├── Color.test.ts │ ├── ColorResources.test.ts │ ├── Constraint.test.ts │ ├── DateDialog.test.ts │ ├── Event.test.ts │ ├── File.test.ts │ ├── Font.test.ts │ ├── FontResources.test.ts │ ├── FormData.test.ts │ ├── Headers.test.ts │ ├── Image.test.ts │ ├── ImageBitmap.test.ts │ ├── JSX.test.tsx │ ├── Layout.test.ts │ ├── LayoutData.test.ts │ ├── LinearGradient.test.ts │ ├── Listeners.test.ts │ ├── LocalStorage.test.ts │ ├── Module.test.ts │ ├── NativeObject.test.ts │ ├── NavigationBar.test.ts │ ├── Observable.test.ts │ ├── ObservableData.test.ts │ ├── Percent.test.ts │ ├── Popover.test.ts │ ├── Request.test.ts │ ├── Resources.test.ts │ ├── Response.test.ts │ ├── StatusBar.test.ts │ ├── Tabris.test.ts │ ├── TextResources.test.ts │ ├── TimeDialog.test.ts │ ├── Websocket.test.ts │ ├── WidgetCollection.test.ts │ ├── Widgets │ ├── Action.test.ts │ ├── ActivityIndicator.test.ts │ ├── Button.test.ts │ ├── CameraView.test.ts │ ├── Canvas.test.ts │ ├── Checkbox.test.ts │ ├── CollectionView.test.ts │ ├── Composite.test.ts │ ├── Drawer.test.ts │ ├── ImageView.test.ts │ ├── NavigationView.test.ts │ ├── Page.test.ts │ ├── PdfView.test.ts │ ├── Picker.test.ts │ ├── ProgressBar.test.ts │ ├── RadioButton.test.ts │ ├── RefreshComposite.test.ts │ ├── Row.test.ts │ ├── ScrollView.test.ts │ ├── SearchAction.test.ts │ ├── Slider.test.ts │ ├── Stack.test.ts │ ├── Switch.test.ts │ ├── Tab.test.ts │ ├── TabFolder.test.ts │ ├── TextInput.test.ts │ ├── TextView.test.ts │ ├── ToggleButton.test.ts │ ├── Video.test.ts │ ├── WebView.test.ts │ └── Widget.test.ts │ ├── Worker.test.ts │ ├── XMLHttpRequest.test.ts │ ├── app.test.ts │ ├── authentication.test.ts │ ├── console.test.ts │ ├── cordova.test.ts │ ├── devTools.test.ts │ ├── device.test.ts │ ├── factory-components.test.ts │ ├── fetch.test.ts │ ├── fs.test.ts │ ├── globalTabrisObject.test.ts │ ├── package.json │ ├── permission.test.ts │ ├── promise.test.ts │ ├── propertyTypes.test.ts │ ├── tsconfig.json │ ├── utils.test.ts │ └── window.test.ts ├── tools ├── README.md ├── api-schema.d.ts ├── api-schema.json ├── common.ts ├── generate-doc.ts ├── generate-dts.ts ├── json-schema-to-typescript.js └── tsconfig.json ├── tsconfig.json └── typings ├── global ├── ImageData.d.ts ├── JSX.d.ts ├── WebSocket.d.ts ├── Worker.d.ts ├── XMLHttpRequest.d.ts ├── dom.d.ts └── misc.d.ts ├── propertyTypes.d.ts └── reExports.d.ts /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "build": { 4 | "plugins": [ 5 | "transform-es2015-arrow-functions", 6 | "transform-es2015-block-scoping", 7 | "transform-es2015-classes", 8 | "transform-es2015-shorthand-properties", 9 | "transform-es2015-computed-properties", 10 | "transform-es2015-template-literals", 11 | "transform-es2015-parameters" 12 | ] 13 | }, 14 | "development": { 15 | "plugins": [ 16 | [ 17 | "transform-es2015-modules-commonjs", 18 | { 19 | "strict": false 20 | } 21 | ] 22 | ], 23 | "sourceMaps": "both" 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | *.d.ts 2 | test/typescript/* 3 | doc 4 | build 5 | node_modules 6 | *.json 7 | *.md 8 | $.jsx 9 | typings 10 | dist 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | --- 8 | 9 | 14 | 15 | ### Problem description 16 | 17 | 18 | 19 | ### Expected behavior 20 | 21 | 22 | 23 | ### Environment 24 | 25 | - Tabris.js version: 26 | - Device: 27 | - OS: 28 | 29 | ### Code snippet 30 | 31 | ```js 32 | // A minimal, *self-contained* code snippet to reproduce the problem: 33 | ``` 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Slack community channel 4 | url: https://tabrisjs.herokuapp.com/ 5 | about: Get in touch with the Tabris.js community on Slack 6 | - name: Tabris.js on Twitter 7 | url: https://twitter.com/tabrisjs 8 | about: Get the latest Tabris.js new on Twitter 9 | - name: Tabris.js help on Stack Overflow 10 | url: https://stackoverflow.com/questions/tagged/tabris 11 | about: Ask Tabris.js related question on Stack Overflow 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: feature 6 | assignees: '' 7 | --- 8 | 9 | 13 | 14 | ### Feature description 15 | 16 | 17 | 18 | ### Proposed solution 19 | 20 | 21 | 22 | ### Alternative solutions 23 | 24 | 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Ask a question 4 | title: '' 5 | labels: question 6 | assignees: '' 7 | --- 8 | 9 | 16 | 17 | ### Question 18 | 19 | 20 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | - [ ] Code is up-to-date with current `master` 8 | - [ ] Code is provided under the terms of the [Tabris.js license](https://github.com/EclipseSource/tabris-js/blob/master/LICENSE) 9 | 10 | Fixes # 11 | -------------------------------------------------------------------------------- /.github/workflows/review.yml: -------------------------------------------------------------------------------- 1 | name: Review 2 | 3 | on: 4 | pull_request: 5 | branches: [ "master" ] 6 | workflow_dispatch: 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v3 13 | - name: Use Node.js 14 | uses: actions/setup-node@v3 15 | with: 16 | node-version: 16 17 | cache: 'npm' 18 | - run: npm i grunt-cli -g 19 | - run: npm i 20 | - run: grunt -v 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea/ 3 | .history/ 4 | build/ 5 | node_modules/ 6 | platforms/ 7 | npm-debug.log* 8 | snippets/package-lock.json 9 | *~ 10 | snippets/dist 11 | .project 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "10" 4 | before_script: 5 | - npm install grunt-cli -g 6 | script: 7 | - grunt 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "json.schemas": [ 3 | { 4 | "fileMatch": [ 5 | "doc/**/*.json" 6 | ], 7 | "url": "./tools/api-schema.json" 8 | } 9 | ], 10 | "workbench.colorCustomizations": { 11 | "activityBar.background": "#0088d1", 12 | "activityBar.foreground": "#ffffff", 13 | "activityBar.inactiveForeground": "#ffffff70" 14 | }, 15 | "eslint.alwaysShowStatus": true, 16 | "eslint.lintTask.enable": true, 17 | "eslint.format.enable": true, 18 | "editor.defaultFormatter": "dbaeumer.vscode-eslint", 19 | "typescript.tsdk": "./node_modules/typescript/lib" 20 | } 21 | -------------------------------------------------------------------------------- /doc/api/$.console: -------------------------------------------------------------------------------- 1 | // Obtain any `NativeObject` instance by cid: 2 | 3 | >> console.dirxml(tabris.contentView) 4 | 5 | 6 | 7 | 8 | 9 | 10 | <- undefined 11 | >> $(24) 12 | <- CheckBox[cid="$24"] 13 | >> $(24).textColor 14 | <- rgb(0, 0, 0) 15 | >> 16 | -------------------------------------------------------------------------------- /doc/api/$.jsx: -------------------------------------------------------------------------------- 1 | // Group widgets in a WidgetCollection: 2 | 3 | contentView.append( 4 | <$> 5 | 6 | 6 | 7 | 8 | ); 9 | 10 | async function showActionSheet() { 11 | const actionSheet = ActionSheet.open( 12 | 13 | Select any of the actions below to proceed. 14 | 15 | 16 | 17 | 18 | 19 | 20 | ); 21 | const {action} = await actionSheet.onClose.promise(); 22 | $(TextView).set({text: `${action || 'Nothing'} selected`}); 23 | } 24 | -------------------------------------------------------------------------------- /snippets/activityindicator.jsx: -------------------------------------------------------------------------------- 1 | import {ActivityIndicator, Button, contentView, $} from 'tabris'; 2 | 3 | contentView.append( 4 | <$> 5 | 6 | 7 | 8 | ); 9 | 10 | const activityIndicator = $(ActivityIndicator).only(); 11 | const button = $(Button).only(); 12 | 13 | function executeLongRunningTask() { 14 | activityIndicator.visible = true; 15 | button.visible = false; 16 | setTimeout(() => { 17 | activityIndicator.visible = false; 18 | button.visible = true; 19 | }, 2500); 20 | } 21 | 22 | executeLongRunningTask(); 23 | -------------------------------------------------------------------------------- /snippets/animate.jsx: -------------------------------------------------------------------------------- 1 | import {Button, contentView, Stack, TextView} from 'tabris'; 2 | 3 | contentView.append( 4 | 5 | 7 | 8 | 9 | ); 10 | 11 | const textView = $(TextView).only(); 12 | const textInput = $(TextInput).only(); 13 | 14 | async function launch() { 15 | try { 16 | await app.launch(textInput.text); 17 | textView.text = 'Url has been launched'; 18 | } catch (ex) { 19 | textView.text = ex.message; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /snippets/authentication.jsx: -------------------------------------------------------------------------------- 1 | import {authentication, Button, contentView, Stack, TextView} from 'tabris'; 2 | 3 | contentView.append( 4 | 5 | 7 | ); 8 | 9 | function countUp() { 10 | $(Button).set({text: `Pressed ${++count} times`}); 11 | } 12 | -------------------------------------------------------------------------------- /snippets/camera.tsx: -------------------------------------------------------------------------------- 1 | import {app, Button, CameraView, contentView, device, ImageView, permission, Popover, Stack} from 'tabris'; 2 | 3 | app.idleTimeoutEnabled = false; 4 | const camera = device.cameras[0]; 5 | 6 | permission.withAuthorization('camera', 7 | () => camera.set({active: true, priority: 'performance'}), 8 | () => console.log('"camera" permission is required.'), 9 | (e) => console.error(e) 10 | ); 11 | contentView.append( 12 | 13 | 14 | 5 | ); 6 | 7 | function toggleUi() { 8 | if (!devTools.isUiVisible()) { 9 | devTools.showUi(); 10 | } else { 11 | devTools.hideUi(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /snippets/drawer.jsx: -------------------------------------------------------------------------------- 1 | import {TextView, contentView, drawer} from 'tabris'; 2 | 3 | drawer.set({enabled: true}); 4 | drawer.onOpen(() => console.log('drawer opened')); 5 | drawer.onClose(() => console.log('drawer closed')); 6 | const arrow = String.fromCharCode(8592); 7 | 8 | contentView.append( 9 | drawer.open()}> 10 | {arrow} Swipe from left or tap here 11 | 12 | ); 13 | 14 | drawer.append( 15 | drawer.close()}> 16 | Thank you! 17 | 18 | ); 19 | -------------------------------------------------------------------------------- /snippets/fetch.jsx: -------------------------------------------------------------------------------- 1 | import {Button, TextView, contentView, Stack} from 'tabris'; 2 | 3 | contentView.append( 4 | 5 | 6 | 7 | 8 | ); 9 | 10 | async function loadData() { 11 | const response = await fetch('http://ip-api.com/json'); 12 | if (!response.ok) { 13 | throw new Error(`HTTP ${response.status} - ${response.statusText}`); 14 | } 15 | const data = await response.json(); 16 | $(TextView).only().text = `You appear to be in ${data.city ? data.city : data.country}`; 17 | } 18 | -------------------------------------------------------------------------------- /snippets/format.js: -------------------------------------------------------------------------------- 1 | import {contentView, Stack, TextView, format} from 'tabris'; 2 | 3 | const view = new Stack({ 4 | layoutData: 'stretch', alignment: 'stretchX', spacing: 8, padding: 8 5 | }).appendTo(contentView); 6 | 7 | const log = (...args) => { 8 | console.log(...args); 9 | view.append(new TextView({text: format(...args)})); 10 | }; 11 | 12 | log('This is printed on screen and to console'); 13 | log('Placeholders are filled:'); 14 | log('Data: (%d %i %f %s %j %%)', 23, 42, 3.14, 'foo', {foo: 'bar'}); 15 | log('Formats long arrays...'); 16 | log(new Array(500)); 17 | log('Formats plain objects...'); 18 | log({foo: 1, bar: 2, baz: 3}); 19 | log('Formats other stuff...'); 20 | log('Dates: ', new Date()); 21 | log('Functions:', () => 23); 22 | log('Widgets:', contentView); 23 | log('WidgetCollection:', contentView.children().children()); 24 | log('Errors:', new TypeError('error message')); 25 | -------------------------------------------------------------------------------- /snippets/formdata.jsx: -------------------------------------------------------------------------------- 1 | import {Button, TextView, contentView, Stack} from 'tabris'; 2 | 3 | contentView.append( 4 | 5 | 6 | 7 | 8 | ); 9 | 10 | async function send() { 11 | const formData = new FormData(); 12 | formData.set('Hello', 'World'); 13 | const response = await fetch('https://postman-echo.com/post', {method: 'POST', body: formData}); 14 | const data = await response.json(); 15 | $(TextView).only().text = JSON.stringify(data.form); 16 | } 17 | -------------------------------------------------------------------------------- /snippets/fs-openfile.jsx: -------------------------------------------------------------------------------- 1 | import {Button, contentView, fs, Stack, TextView} from 'tabris'; 2 | 3 | contentView.append( 4 | 5 | 18 | 19 | 20 | 21 | ); 22 | } 23 | 24 | function goToInitialPage() { 25 | navigationView.pages().slice(1).dispose(); 26 | } 27 | 28 | function goBack() { 29 | if (navigationView.pages().length > 1) { 30 | navigationView.pages().last().dispose(); 31 | } 32 | } 33 | 34 | function addPage() { 35 | navigationView.append( 36 | 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /snippets/navigationview-searchaction.jsx: -------------------------------------------------------------------------------- 1 | import {Button, Composite, NavigationView, Page, SearchAction, TextView, contentView, device} from 'tabris'; 2 | 3 | const IMAGE = device.platform === 'iOS' ? 'resources/search-black-24dp@3x.png' : 'resources/search-white-24dp@3x.png'; 4 | const proposals = ['baseball', 'batman', 'battleship', 'bangkok', 'bangladesh', 'banana']; 5 | 6 | contentView.append( 7 | 8 | ev.target.text = ''} 10 | onInput={ev => updateProposals(ev.text)} 11 | onAccept={ev => $(TextView).only().text = 'Selected "' + ev.text + '"'}/> 12 | 13 | 14 | 15 | 8 | 9 | ); 10 | 11 | $(Slider).only().onSelectionChanged.values 12 | .subscribe( 13 | selection => $(TextView).only().text = 'value: ' + selection, 14 | ex => console.error(ex), 15 | () => $(TextView).only().text = 'complete' 16 | ); 17 | -------------------------------------------------------------------------------- /snippets/observable-mutations.tsx: -------------------------------------------------------------------------------- 1 | import {Observable, contentView, TextView, Stack, TextInput} from 'tabris'; 2 | 3 | contentView.append( 4 | 5 | We are listening 6 | 7 | 8 | ); 9 | 10 | Observable.mutations($(TextInput).only()).subscribe( 11 | textInput => 12 | $(TextView).set({ 13 | text: `${textInput.selection} "${textInput.text}"` 14 | }) 15 | ); 16 | -------------------------------------------------------------------------------- /snippets/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tabris-js-snippets", 3 | "version": "3.7.0", 4 | "dependencies": { 5 | "tabris": "^3.7.0" 6 | }, 7 | "devDependencies": { 8 | "typescript": "4.8" 9 | }, 10 | "scripts": { 11 | "build": "tsc -p .", 12 | "watch": "tsc -p . -w --preserveWatchOutput --inlineSourceMap" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /snippets/pdfview.jsx: -------------------------------------------------------------------------------- 1 | import {PdfView, contentView, AlertDialog, ActivityIndicator} from 'tabris'; 2 | 3 | contentView.append( 4 | <$> 5 | 12 | 13 | 14 | ); 15 | 16 | /** @param {tabris.PdfViewLoadEvent} ev */ 17 | function handleLoad(ev) { 18 | $(ActivityIndicator).dispose(); 19 | if (ev.error) { 20 | AlertDialog.open('Failed to load PDF Document'); 21 | } 22 | } 23 | 24 | (async () => { 25 | const response = await fetch('https://tabrisjs.com/downloads/ebook/tabrisjs-3.5.0.pdf'); 26 | $(PdfView).only().src = await response.blob(); 27 | })().catch(console.error); 28 | -------------------------------------------------------------------------------- /snippets/permission.jsx: -------------------------------------------------------------------------------- 1 | import {AlertDialog, permission} from 'tabris'; 2 | 3 | (async () => { 4 | if (permission.isAuthorized('camera')) { 5 | AlertDialog.open('Camera permission is available'); 6 | } else { 7 | const status = await permission.requestAuthorization('camera'); 8 | AlertDialog.open(`Camera permission has been ${status}.`); 9 | } 10 | })().catch(ex => console.error(ex)); 11 | -------------------------------------------------------------------------------- /snippets/picker-style.jsx: -------------------------------------------------------------------------------- 1 | import {contentView, Picker, Stack} from 'tabris'; 2 | 3 | const items = ['San Francisco', 'Berlin', 'Shanghai']; 4 | 5 | /** @param {tabris.Attributes} attributes */ 6 | const CityPicker = attributes => 7 | items[index]} {...attributes}/>; 8 | 9 | contentView.append( 10 | 11 | 12 | 13 | 14 | 15 | 16 | ); 17 | -------------------------------------------------------------------------------- /snippets/picker.jsx: -------------------------------------------------------------------------------- 1 | import {AlertDialog, Button, contentView, Picker, Stack, TextView} from 'tabris'; 2 | 3 | const cities = ['San Francisco', 'Berlin', 'Shanghai']; 4 | const getCity = index => index >= 0 ? cities[index] : 'empty'; 5 | 6 | contentView.append( 7 | 8 | cities[index]} 9 | onSelect={(e) => AlertDialog.open(`You selected ${getCity(e.index)}`)} 10 | onSelectionIndexChanged={(e) => textView.text = `Selection changed to ${getCity(e.value)}`}/> 11 | 12 | 5 | ); 6 | 7 | const IMG_CLOSE = device.platform === 'iOS' ? 'resources/close-black-24dp@3x.png' : 'resources/close-white-24dp@3x.png'; 8 | const button = $(Button).only(); 9 | 10 | function showPopover() { 11 | const popover = Popover.open( 12 | 13 | 14 | popover.close()}/> 15 | 16 | Hello Popover 17 | 18 | 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /snippets/printer.js: -------------------------------------------------------------------------------- 1 | import {Button, printer, contentView, app} from 'tabris'; 2 | 3 | // Print a bundled PDF 4 | 5 | new Button({ 6 | left: 16, right: 16, top: 16, 7 | text: 'Print PDF' 8 | }).onSelect(() => print('resources/example.pdf', 'application/pdf', 'Example PDF')) 9 | .appendTo(contentView); 10 | 11 | new Button({ 12 | left: 16, right: 16, top: 'prev() 16', 13 | text: 'Print Image' 14 | }).onSelect(() => print('resources/salad.jpg', 'image/jpg', 'Salad image')) 15 | .appendTo(contentView); 16 | 17 | function print(file, contentType, jobName) { 18 | fetch(app.getResourceLocation(file)) 19 | .then(res => res.arrayBuffer()) 20 | .then(data => printer.print(data, {jobName, contentType})) 21 | .then(event => console.log('Printing finished', event)) 22 | .catch(err => console.error(err)); 23 | } 24 | -------------------------------------------------------------------------------- /snippets/progressbar.jsx: -------------------------------------------------------------------------------- 1 | import {ProgressBar, contentView} from 'tabris'; 2 | 3 | contentView.set({padding: 16}).append( 4 | 5 | ); 6 | 7 | const progressBar = $(ProgressBar).only(); 8 | 9 | setInterval(() => { 10 | const selection = progressBar.selection + 1; 11 | progressBar.selection = selection > 300 ? 0 : selection; 12 | }, 20); 13 | -------------------------------------------------------------------------------- /snippets/radiobutton.jsx: -------------------------------------------------------------------------------- 1 | import {RadioButton, Stack, contentView} from 'tabris'; 2 | 3 | contentView.set({padding: 12}).append( 4 | 5 | 6 | 7 | 8 | 9 | ); 10 | 11 | /** @param {tabris.PropertyChangedEvent} ev */ 12 | function handleChecked(ev) { 13 | if (ev.value) { 14 | console.log(ev.target.text + ' checked'); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /snippets/refreshcomposite.jsx: -------------------------------------------------------------------------------- 1 | import {RefreshComposite, TextView, contentView} from 'tabris'; 2 | 3 | contentView.append( 4 | 5 | 6 | Pull to refresh 7 | 8 | 9 | 10 | ); 11 | 12 | const refreshComposite = $(RefreshComposite).only(); 13 | const log = $(TextView).only('#log'); 14 | 15 | function handleRefresh() { 16 | setTimeout(() => { 17 | refreshComposite.refreshIndicator = false; 18 | log.text = `last refresh: ${new Date()}\n${log.text}`; 19 | }, 1000); 20 | } 21 | -------------------------------------------------------------------------------- /snippets/resource-management.tsx: -------------------------------------------------------------------------------- 1 | import {contentView, TextView} from 'tabris'; 2 | import {colors, fonts, texts} from './resources'; 3 | 4 | contentView.set({padding: 16, background: colors.myBackground}).append( 5 | 6 | {texts.tintColor}

7 | {texts.emphasisFont} 8 |
9 | ); 10 | -------------------------------------------------------------------------------- /snippets/resources/Sources.md: -------------------------------------------------------------------------------- 1 | target_200.png based on 2 | http://commons.wikimedia.org/wiki/File:Archery_Target_80cm.svg 3 | -------------------------------------------------------------------------------- /snippets/resources/arrow-back-black-24dp@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/arrow-back-black-24dp@3x.png -------------------------------------------------------------------------------- /snippets/resources/arrow-forward-black-24dp@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/arrow-forward-black-24dp@3x.png -------------------------------------------------------------------------------- /snippets/resources/arrow-upward-white-24pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/arrow-upward-white-24pt@3x.png -------------------------------------------------------------------------------- /snippets/resources/card-filled@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/card-filled@2x.png -------------------------------------------------------------------------------- /snippets/resources/card@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/card@2x.png -------------------------------------------------------------------------------- /snippets/resources/cart-filled@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/cart-filled@2x.png -------------------------------------------------------------------------------- /snippets/resources/cart@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/cart@2x.png -------------------------------------------------------------------------------- /snippets/resources/chart-filled@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/chart-filled@2x.png -------------------------------------------------------------------------------- /snippets/resources/chart@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/chart@2x.png -------------------------------------------------------------------------------- /snippets/resources/close-black-24dp@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/close-black-24dp@3x.png -------------------------------------------------------------------------------- /snippets/resources/close-white-24dp@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/close-white-24dp@3x.png -------------------------------------------------------------------------------- /snippets/resources/cloud-check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/cloud-check.png -------------------------------------------------------------------------------- /snippets/resources/colors.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../node_modules/tabris/schema/colors.json", 3 | "myBackground": "#DFFF94", 4 | "myBlue": "#435FBD", 5 | "myRed": { 6 | "android": "#8F0B12", 7 | "ios": "#EC2121" 8 | }, 9 | "tint": { 10 | "android": {"ref": "myBlue"}, 11 | "ios": {"ref": "myRed"} 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /snippets/resources/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/cover.jpg -------------------------------------------------------------------------------- /snippets/resources/delete-black-24dp@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/delete-black-24dp@3x.png -------------------------------------------------------------------------------- /snippets/resources/example.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/example.pdf -------------------------------------------------------------------------------- /snippets/resources/fonts.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../node_modules/tabris/schema/fonts.json", 3 | "main": { 4 | "1x": "medium 22px 'serif'", 5 | "2x": "medium 26px 'serif'" 6 | }, 7 | "emphasis": { 8 | "1x": { 9 | "android": { 10 | "size": 22, 11 | "family": ["san-serif"], 12 | "style": "italic" 13 | }, 14 | "ios": { 15 | "size": 22, 16 | "family": ["san-serif"], 17 | "weight": "black" 18 | } 19 | }, 20 | "2x": { 21 | "size": 26, 22 | "family": ["san-serif"], 23 | "weight": "black", 24 | "style": "italic" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /snippets/resources/holger.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/holger.jpg -------------------------------------------------------------------------------- /snippets/resources/ian.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/ian.jpg -------------------------------------------------------------------------------- /snippets/resources/index.ts: -------------------------------------------------------------------------------- 1 | import {ColorResources, FontResources, TextResources} from 'tabris'; 2 | import * as colorData from './colors.json'; 3 | import * as fontData from './fonts.json'; 4 | import * as textData from './texts.json'; 5 | 6 | export const colors = ColorResources.from(colorData); 7 | export const fonts = FontResources.from(fontData); 8 | export const texts = TextResources.from(textData); 9 | -------------------------------------------------------------------------------- /snippets/resources/jochen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/jochen.jpg -------------------------------------------------------------------------------- /snippets/resources/jordi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/jordi.jpg -------------------------------------------------------------------------------- /snippets/resources/landscape.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/landscape.jpg -------------------------------------------------------------------------------- /snippets/resources/markus.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/markus.jpg -------------------------------------------------------------------------------- /snippets/resources/moritz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/moritz.jpg -------------------------------------------------------------------------------- /snippets/resources/pacifico.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/pacifico.ttf -------------------------------------------------------------------------------- /snippets/resources/ralf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/ralf.jpg -------------------------------------------------------------------------------- /snippets/resources/salad.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/salad.jpg -------------------------------------------------------------------------------- /snippets/resources/search-black-24dp@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/search-black-24dp@3x.png -------------------------------------------------------------------------------- /snippets/resources/search-white-24dp@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/search-white-24dp@3x.png -------------------------------------------------------------------------------- /snippets/resources/settings-black-24dp@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/settings-black-24dp@3x.png -------------------------------------------------------------------------------- /snippets/resources/settings-white-24dp@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/settings-white-24dp@3x.png -------------------------------------------------------------------------------- /snippets/resources/share-black-24dp@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/share-black-24dp@3x.png -------------------------------------------------------------------------------- /snippets/resources/share-white-24dp@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/share-white-24dp@3x.png -------------------------------------------------------------------------------- /snippets/resources/target_200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/target_200.png -------------------------------------------------------------------------------- /snippets/resources/texts.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../node_modules/tabris/schema/texts.json", 3 | "$fallbackLanguage": "en-US", 4 | "emphasisFont": { 5 | "en": "Emphasis Font", 6 | "de": "Hervorgehobene Schrift" 7 | }, 8 | "tintColor": { 9 | "en-us": "Tint Color", 10 | "en-gb": "Tint Colour", 11 | "de": "Akzentfarbe" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /snippets/resources/tim.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eclipsesource/tabris-js/a8486c58cfa414c06c130a7727c7f53b3911140d/snippets/resources/tim.jpg -------------------------------------------------------------------------------- /snippets/resources/website.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 13 | 14 | 15 |

Web Messaging

16 |

No message received from Tabris.js

17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /snippets/resources/worker-script.js: -------------------------------------------------------------------------------- 1 | // Makes the log output from the Worker appear on the CLI: 2 | tabris.logPushInterval = 100; 3 | 4 | console.log('Worker running...'); 5 | 6 | tabris.onMessage(e => { 7 | const number1 = e.data[0]; 8 | const number2 = e.data[1]; 9 | console.log(`Adding numbers ${number1} and ${number2}`); 10 | const result = number1 + number2; 11 | setTimeout(() => { 12 | console.log('Posting result of ' + result + ' to main script'); 13 | tabris.postMessage(result); 14 | }, 2000); 15 | }); 16 | -------------------------------------------------------------------------------- /snippets/row-alignment.jsx: -------------------------------------------------------------------------------- 1 | import {contentView, TextView, Row, Button} from 'tabris'; 2 | 3 | contentView.append( 4 | 5 | lorem 6 | ipsum 7 | dolor 8 | sit 9 | 10 | 11 | ).find(TextView).set({font: '24px', textColor: 'white'}); 12 | -------------------------------------------------------------------------------- /snippets/row-halign.jsx: -------------------------------------------------------------------------------- 1 | import {contentView, TextView, Row} from 'tabris'; 2 | 3 | contentView.append( 4 | 5 | Left 6 | Stretch 7 | Right 8 | 9 | ); 10 | 11 | $(TextView).set({textColor: 'white', font: '24px'}); 12 | -------------------------------------------------------------------------------- /snippets/row.jsx: -------------------------------------------------------------------------------- 1 | import {contentView, TextView, Row} from 'tabris'; 2 | 3 | contentView.append( 4 | 5 | lorem 6 | ipsum 7 | dolor 8 | sit amet 9 | 10 | ).find(TextView).set({font: '24px', textColor: 'white'}); 11 | -------------------------------------------------------------------------------- /snippets/scrollview.jsx: -------------------------------------------------------------------------------- 1 | import {Button, contentView, ScrollView, TextView} from 'tabris'; 2 | 3 | contentView.append( 4 | <$> 5 | $(TextView)[1].text = `Scroll state: ${e.value}`}> 7 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do 8 | eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation 9 | ullamco laboris nisi ut aliquip ex ea commodo consequat. 10 | 11 | 12 | 13 | 6 | 7 | 8 |
9 | ); 10 | 11 | const textView = $(TextView).only(); 12 | 13 | async function showSimpleDialog() { 14 | const {date} = await TimeDialog.open().onClose.promise(); 15 | textView.text = date ? `Picked ${date.toTimeString()}` : 'Canceled'; 16 | } 17 | 18 | async function showSpecificTime() { 19 | const {date} = await TimeDialog.open(new Date(1, 1, 1, 20, 15)).onClose.promise(); 20 | textView.text = date ? `Picked ${date.toTimeString()}` : 'Canceled'; 21 | } 22 | -------------------------------------------------------------------------------- /snippets/togglebutton.jsx: -------------------------------------------------------------------------------- 1 | import {ToggleButton, contentView} from 'tabris'; 2 | 3 | contentView.set({padding: 16}).append( 4 | ev.target.text = ev.value ? 'checked' : 'not checked'}/> 6 | ); 7 | -------------------------------------------------------------------------------- /snippets/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "lib": ["es6", "es2015.promise" ], 6 | "jsx": "react", 7 | "jsxFactory": "JSX.createElement", 8 | "outDir": "dist", 9 | "allowJs": true, 10 | "checkJs": true, 11 | "typeRoots": [], 12 | "alwaysStrict": true, 13 | "resolveJsonModule": true, 14 | "baseUrl": "./", 15 | "paths": { 16 | "@res": ["./resources/index"] 17 | } 18 | }, 19 | "include": [ 20 | "./*.js", 21 | "./*.jsx", 22 | "./*.ts", 23 | "./*.tsx", 24 | "./resources/index.ts" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /snippets/types.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'foo' { 2 | export const hello: string; 3 | } 4 | -------------------------------------------------------------------------------- /snippets/video.js: -------------------------------------------------------------------------------- 1 | import {Button, contentView, Video} from 'tabris'; 2 | 3 | const button = new Button({ 4 | id: 'button', 5 | centerX: 0, bottom: 16, 6 | text: '❚❚' 7 | }).onSelect(() => video.state === 'play' ? video.pause() : video.play()) 8 | .appendTo(contentView); 9 | 10 | const video = new Video({ 11 | left: 0, top: 0, right: 0, bottom: '#button 16', 12 | url: 'http://peach.themazzone.com/durian/movies/sintel-1280-stereo.mp4', 13 | controlsVisible: false 14 | }).onStateChanged(({value: state}) => button.text = state !== 'pause' && state !== 'finish' ? '❚❚' : '▶') 15 | .appendTo(contentView); 16 | -------------------------------------------------------------------------------- /snippets/web-storage.js: -------------------------------------------------------------------------------- 1 | import {TextView, contentView} from 'tabris'; 2 | 3 | const KEY = 'localStorageSnippetCount'; 4 | 5 | const startCount = parseInt(localStorage.getItem(KEY) || '0', 10) + 1; 6 | localStorage.setItem(KEY, startCount.toString()); 7 | new TextView({ 8 | left: 10, right: 10, centerY: 0, 9 | alignment: 'centerX', 10 | font: '22px sans-serif', 11 | text: 'This application was started ' + startCount + ' time(s).' 12 | }).appendTo(contentView); 13 | -------------------------------------------------------------------------------- /snippets/webview-webmessaging.js: -------------------------------------------------------------------------------- 1 | import {Button, Composite, TextView, WebView, contentView} from 'tabris'; 2 | 3 | new Button({ 4 | left: 16, right: 16, bottom: 16, 5 | text: 'Send message to WebView' 6 | }).onSelect(() => webView.postMessage('Hello from Tabris.js', '*')) 7 | .appendTo(contentView); 8 | 9 | const statusTextView = new TextView({ 10 | left: 16, right: 16, bottom: 'prev()', height: 48, 11 | alignment: 'centerX', 12 | text: 'No message received from WebView' 13 | }).appendTo(contentView); 14 | 15 | new Composite({ 16 | left: 0, right: 0, bottom: 'prev()', height: 1, 17 | background: '#e1e1e1' 18 | }).appendTo(contentView); 19 | 20 | const webView = new WebView({ 21 | left: 0, top: 0, right: 0, bottom: 'prev()' 22 | }).appendTo(contentView); 23 | 24 | fetch('./resources/website.html') 25 | .then(result => result.text()) 26 | .then(text => webView.html = text); 27 | 28 | webView.onMessage(({data}) => statusTextView.text = 'Message received: ' + data); 29 | -------------------------------------------------------------------------------- /snippets/webview.jsx: -------------------------------------------------------------------------------- 1 | import {contentView, TextInput, WebView} from 'tabris'; 2 | 3 | contentView.append( 4 | <$> 5 | 7 | 8 | 9 | ); 10 | 11 | function loadUrl() { 12 | $(WebView).only().url = $(TextInput).only().text; 13 | } 14 | 15 | loadUrl(); 16 | -------------------------------------------------------------------------------- /snippets/widget-cornerradius.jsx: -------------------------------------------------------------------------------- 1 | import {Composite, contentView} from 'tabris'; 2 | 3 | contentView.append( 4 | 8 | ); 9 | -------------------------------------------------------------------------------- /snippets/widget-elevation.jsx: -------------------------------------------------------------------------------- 1 | import {Composite, contentView} from 'tabris'; 2 | 3 | contentView.append( 4 | 7 | ); 8 | -------------------------------------------------------------------------------- /snippets/widget-exclude-from-layout.jsx: -------------------------------------------------------------------------------- 1 | import {Stack, CheckBox, TextView, contentView} from 'tabris'; 2 | 3 | contentView.append( 4 | 5 | Exclude Widget 2 from layout 6 | Widget 1 7 | Widget 2 8 | Widget 3 9 | 10 | ); 11 | 12 | const target = $('#target')[0]; 13 | const checkBox = $(CheckBox)[0]; 14 | 15 | function handleSelect() { 16 | target.excludeFromLayout = checkBox.checked; 17 | } 18 | -------------------------------------------------------------------------------- /snippets/widget-highlightontouch.jsx: -------------------------------------------------------------------------------- 1 | import {Composite, contentView} from 'tabris'; 2 | 3 | contentView.append( 4 | 5 | ); 6 | -------------------------------------------------------------------------------- /snippets/widget-padding.jsx: -------------------------------------------------------------------------------- 1 | import {Composite, TextView, contentView} from 'tabris'; 2 | 3 | contentView.append( 4 | 5 | 6 | Tabris.js 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /snippets/widget-touch.js: -------------------------------------------------------------------------------- 1 | import {TextView, contentView} from 'tabris'; 2 | 3 | const textView = new TextView({ 4 | left: 20, top: 20, right: 20, 5 | text: 'Touch anywhere...' 6 | }).appendTo(contentView); 7 | 8 | contentView 9 | .onTouchStart(({touches}) => { 10 | printXY('touchStart', touches); 11 | contentView.background = 'yellow'; 12 | }) 13 | .onTouchMove(({touches}) => printXY('touchMove', touches)) 14 | .onTouchEnd(({touches}) => { 15 | printXY('touchEnd', touches); 16 | contentView.background = 'green'; 17 | }) 18 | .onTouchCancel(({touches}) => { 19 | printXY('touchCancel', touches); 20 | contentView.background = 'red'; 21 | }) 22 | .onLongPress(({touches}) => { 23 | contentView.background = 'blue'; 24 | printXY('longPress', touches); 25 | }); 26 | 27 | function printXY(prefix, touches) { 28 | textView.text = prefix + ': ' + Math.round(touches[0].x) + ' X ' + Math.round(touches[0].y); 29 | } 30 | -------------------------------------------------------------------------------- /snippets/xmlhttprequest.js: -------------------------------------------------------------------------------- 1 | import {Button, TextView, contentView} from 'tabris'; 2 | 3 | new Button({ 4 | left: 10, top: 10, 5 | text: 'Find words starting with "mobile"' 6 | }).onSelect(() => { 7 | const xhr = new XMLHttpRequest(); 8 | xhr.onreadystatechange = () => { 9 | if (xhr.readyState === xhr.DONE) { 10 | new TextView({ 11 | left: 10, right: 10, top: 'prev() 10', 12 | text: JSON.parse(xhr.responseText)[1].join(', ') 13 | }).appendTo(contentView); 14 | } 15 | }; 16 | xhr.open('GET', 'http://en.wiktionary.org/w/api.php?action=opensearch&search=mobile&limit=100'); 17 | xhr.send(); 18 | }).appendTo(contentView); 19 | -------------------------------------------------------------------------------- /src/boot/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "alwaysStrict": true, 5 | "strict": true, 6 | "lib": ["es2017"], 7 | "noEmit": true, 8 | "noImplicitAny": true, 9 | "typeRoots": [], 10 | "outDir": "../../build/boot-transpiled" 11 | }, 12 | "include": [ 13 | "./**/*.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /src/tabris/ColorResources.js: -------------------------------------------------------------------------------- 1 | import Resources from './Resources'; 2 | import Color from './Color'; 3 | import checkType from './checkType'; 4 | 5 | const COLOR_OPTIONS = { 6 | type: Color, 7 | converter: Color.from, 8 | validator: Color.isValidColorValue 9 | }; 10 | 11 | export default class ColorResources extends Resources { 12 | 13 | static from() { 14 | const builder = Resources.build(/** @type {any} */(COLOR_OPTIONS)); 15 | return builder.from.apply(builder, arguments); 16 | } 17 | 18 | constructor(options) { 19 | if (arguments.length !== 1) { 20 | throw new Error(`Expected 1 parameter, got ${arguments.length}`); 21 | } 22 | checkType(options, Object, {name: 'parameter 1'}); 23 | super(Object.assign({}, COLOR_OPTIONS, options)); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/tabris/DevTools.js: -------------------------------------------------------------------------------- 1 | import NativeObject from './NativeObject'; 2 | 3 | export default class DevTools extends NativeObject { 4 | 5 | get _nativeType() { 6 | return 'tabris.DevTools'; 7 | } 8 | 9 | /** @override */ 10 | _nativeCreate(param) { 11 | if (param !== true) { 12 | throw new Error('DevTools can not be created'); 13 | } 14 | super._nativeCreate(); 15 | } 16 | 17 | showUi() { 18 | return this._nativeCall('showUi'); 19 | } 20 | 21 | hideUi() { 22 | this._nativeCall('hideUi'); 23 | } 24 | 25 | isUiVisible() { 26 | return this._nativeCall('isUiVisible'); 27 | } 28 | 29 | dispose() { 30 | throw new Error('Cannot dispose devTools object'); 31 | } 32 | 33 | } 34 | 35 | export function create() { 36 | return new DevTools(true); 37 | } 38 | -------------------------------------------------------------------------------- /src/tabris/File.js: -------------------------------------------------------------------------------- 1 | import Blob from './Blob'; 2 | 3 | export default class File extends Blob { 4 | 5 | /** 6 | * @param {Array} chunks 7 | * @param {string} name 8 | * @param {Object=} options 9 | */ 10 | constructor(chunks, name, options = {}) { 11 | if (arguments.length < 2) { 12 | throw new TypeError(`File requires at least 2 arguments, but only ${arguments.length} were passed.`); 13 | } 14 | super(chunks, options); 15 | Object.defineProperty(this, 'name', {value: name + ''}); 16 | const lastModified = 'lastModified' in options ? options.lastModified : Date.now(); 17 | if (isNaN(lastModified) || !isFinite(lastModified)) { 18 | Object.defineProperty(this, 'lastModified', {value: 0}); 19 | } else { 20 | Object.defineProperty(this, 'lastModified', { 21 | value: Math.round(typeof lastModified === 'string' ? parseInt(lastModified) : 0 + lastModified) 22 | }); 23 | } 24 | } 25 | 26 | } 27 | 28 | File.prototype[Symbol.toStringTag] = 'File'; 29 | Object.defineProperty(File.prototype, 'name', {value: ''}); 30 | Object.defineProperty(File.prototype, 'lastModified', {value: 0}); 31 | -------------------------------------------------------------------------------- /src/tabris/FontResources.js: -------------------------------------------------------------------------------- 1 | import Resources from './Resources'; 2 | import Font from './Font'; 3 | import checkType from './checkType'; 4 | 5 | const FONT_OPTIONS = { 6 | type: Font, 7 | converter: Font.from, 8 | validator: Font.isValidFontValue 9 | }; 10 | 11 | export default class FontResources extends Resources { 12 | 13 | static from() { 14 | const builder = Resources.build(/** @type {any} */(FONT_OPTIONS)); 15 | return builder.from.apply(builder, arguments); 16 | } 17 | 18 | constructor(options) { 19 | if (arguments.length !== 1) { 20 | throw new Error(`Expected 1 parameter, got ${arguments.length}`); 21 | } 22 | checkType(options, Object, {name: 'parameter 1'}); 23 | super(Object.assign({}, FONT_OPTIONS, options)); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/tabris/GestureRecognizer.js: -------------------------------------------------------------------------------- 1 | import NativeObject from './NativeObject'; 2 | import {types} from './property-types'; 3 | 4 | export default class GestureRecognizer extends NativeObject { 5 | 6 | get _nativeType() { 7 | return 'tabris.GestureRecognizer'; 8 | } 9 | 10 | _listen(name, listening) { 11 | if (name === 'gesture') { 12 | this._nativeListen(name, listening); 13 | } else { 14 | super._listen(name, listening); 15 | } 16 | } 17 | 18 | } 19 | 20 | NativeObject.defineProperties(GestureRecognizer.prototype, { 21 | type: {type: types.string, default: null}, 22 | target: {type: types.Widget, default: null}, 23 | fingers: {type: types.natural, default: null}, 24 | touches: {type: types.natural, default: null}, 25 | duration: {type: types.natural, default: null}, 26 | direction: {type: types.string, default: null} 27 | }); 28 | -------------------------------------------------------------------------------- /src/tabris/HttpRequest.js: -------------------------------------------------------------------------------- 1 | import NativeObject from './NativeObject'; 2 | 3 | export default class HttpRequest extends NativeObject { 4 | 5 | constructor() { 6 | super(); 7 | this._nativeListen('stateChanged', true); 8 | this._nativeListen('downloadProgress', true); 9 | this._nativeListen('uploadProgress', true); 10 | } 11 | 12 | abort() { 13 | this._nativeCall('abort', {}); 14 | } 15 | 16 | send(config) { 17 | this._nativeCall('send', config); 18 | } 19 | 20 | get _nativeType() { 21 | return 'tabris.HttpRequest'; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/tabris/InactivityTimer.js: -------------------------------------------------------------------------------- 1 | import NativeObject from './NativeObject'; 2 | 3 | export default class InactivityTimer extends NativeObject { 4 | 5 | constructor(properties) { 6 | super(properties); 7 | this._nativeListen('timeout', true); 8 | } 9 | 10 | start() { 11 | this._nativeCall('start'); 12 | } 13 | 14 | cancel() { 15 | this._nativeCall('cancel'); 16 | } 17 | 18 | get _nativeType() { 19 | return 'tabris.InactivityTimer'; 20 | } 21 | 22 | } 23 | 24 | NativeObject.defineProperties(InactivityTimer.prototype, { 25 | delay: { 26 | type: 'natural', 27 | default: 0 28 | } 29 | }); 30 | 31 | NativeObject.defineEvents(InactivityTimer.prototype, { 32 | timeout: true 33 | }); 34 | -------------------------------------------------------------------------------- /src/tabris/Input.ts: -------------------------------------------------------------------------------- 1 | import NativeObject from './NativeObject'; 2 | 3 | export default class Input extends NativeObject { 4 | 5 | get _nativeType() { 6 | return 'tabris.Input'; 7 | } 8 | 9 | /** @override */ 10 | _nativeCreate(param: any) { 11 | if (param !== true) { 12 | throw new Error('Input can not be created'); 13 | } 14 | super._nativeCreate(null); 15 | } 16 | 17 | dispose() { 18 | throw new Error('Cannot dispose input object'); 19 | } 20 | 21 | } 22 | 23 | NativeObject.defineEvents(Input.prototype, { 24 | pointerDown: {native: true}, 25 | pointerMove: {native: true}, 26 | pointerUp: {native: true}, 27 | pointerCancel: {native: true}, 28 | resize: {native: true} 29 | }); 30 | 31 | export function create() { 32 | return new Input(true); 33 | } 34 | -------------------------------------------------------------------------------- /src/tabris/NativeObjectRegistry.js: -------------------------------------------------------------------------------- 1 | export default class NativeObjectRegistry { 2 | 3 | constructor() { 4 | Object.defineProperties(this, { 5 | $idSequence: {enumerable: false, writable: true, value: 1}, 6 | $objects: {enumerable: false, writable: false, value: {}} 7 | }); 8 | } 9 | 10 | register(nativeObject) { 11 | const cid = this.$generateId(); 12 | if (cid in this.$objects) { 13 | throw new Error('cid already in use: ' + cid); 14 | } 15 | this.$objects[cid] = nativeObject; 16 | return cid; 17 | } 18 | 19 | remove(cid) { 20 | delete this.$objects[cid]; 21 | } 22 | 23 | find(cid) { 24 | return this.$objects[cid] || null; 25 | } 26 | 27 | $generateId() { 28 | return '$' + (this.$idSequence++); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/tabris/Observable.types.d.ts: -------------------------------------------------------------------------------- 1 | import Observable from './Observable'; 2 | 3 | export type TeardownLogic = Function | {unsubscribe: Function} | void; 4 | 5 | export type SubscriptionHandler = ( 6 | this: Observable, 7 | subscriber: Subscriber 8 | ) => TeardownLogic; 9 | 10 | export interface Observer { 11 | next: NextCb; 12 | error: ErrorCb; 13 | complete: CompleteCb; 14 | } 15 | 16 | export type NextCb = ((value: T) => void); 17 | export type ErrorCb = ((value: any) => void); 18 | export type CompleteCb = (() => void); 19 | 20 | export interface PartialObserver { 21 | next?: (value: T) => any; 22 | error?: (ex: any) => any 23 | complete?: () => any 24 | } 25 | 26 | export interface Subscription { 27 | readonly closed: boolean; 28 | unsubscribe: () => void; 29 | } 30 | 31 | export interface Subscriber extends Observer { 32 | readonly closed: boolean; 33 | } 34 | 35 | declare global { 36 | interface SymbolConstructor { 37 | readonly observable: symbol; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/tabris/Popup.ts: -------------------------------------------------------------------------------- 1 | import NativeObject from './NativeObject'; 2 | import JsxProcessor, {JSX} from './JsxProcessor'; 3 | 4 | export default class Popup extends NativeObject { 5 | 6 | open() { 7 | if (this.isDisposed()) { 8 | throw new Error('Can not open a popup that was disposed'); 9 | } 10 | this._nativeCall('open', {}); 11 | return this; 12 | } 13 | 14 | close() { 15 | this._handleClose({}); 16 | return this; 17 | } 18 | 19 | _trigger(name: string, event: {}): boolean { 20 | if (name === 'close') { 21 | return this._handleClose(event); 22 | } else { 23 | return super._trigger(name, event); 24 | } 25 | } 26 | 27 | protected _handleClose(eventData: object) { 28 | if (this._isDisposed || this._inDispose) { 29 | return false; 30 | } 31 | super._trigger('close', eventData); 32 | this.dispose(); 33 | return false; 34 | } 35 | 36 | protected [JSX.jsxFactory](this: JsxProcessor, Type: Constructor, attributes: object) { 37 | return this.createNativeObject(Type, attributes); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/tabris/Process.js: -------------------------------------------------------------------------------- 1 | export default class Process { 2 | 3 | constructor() { 4 | if (arguments[0] !== true || arguments.length !== 2) { 5 | throw new Error('Process can not be created'); 6 | } 7 | /** @type {import('./App').default} */ 8 | const app = arguments[1].app; 9 | /** @type {import('./Device').default} */ 10 | const device = arguments[1].device; 11 | this.env = { 12 | NODE_ENV: app.debugBuild ? 'development' : 'production' 13 | }; 14 | this.platform = (device.platform || '').toLowerCase(); 15 | this.argv = ['tabris', './']; 16 | } 17 | 18 | } 19 | 20 | export function create(tabris) { 21 | return new Process(true, tabris); 22 | } 23 | -------------------------------------------------------------------------------- /src/tabris/ProgressEvent.js: -------------------------------------------------------------------------------- 1 | import Event from './Event'; 2 | 3 | export default class ProgressEvent extends Event { 4 | 5 | constructor(type, config) { 6 | if (arguments.length < 1) { 7 | throw new Error('Not enough arguments to ProgressEvent'); 8 | } 9 | super(type, config); 10 | Object.defineProperties(this, { 11 | $lengthComputable: {enumerable: false, writable: true, value: config && config.lengthComputable || false}, 12 | $loaded: {enumerable: false, writable: true, value: config && config.loaded || 0}, 13 | $total: {enumerable: false, writable: true, value: config && config.total || 0} 14 | }); 15 | } 16 | 17 | get lengthComputable() { 18 | return this.$lengthComputable; 19 | } 20 | 21 | get loaded() { 22 | return this.$loaded; 23 | } 24 | 25 | get total() { 26 | return this.$total; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/tabris/TextResources.js: -------------------------------------------------------------------------------- 1 | import Resources from './Resources'; 2 | import checkType from './checkType'; 3 | 4 | const TEXT_OPTIONS = { 5 | validator: value => typeof value === 'string' 6 | }; 7 | 8 | export default class TextResources extends Resources { 9 | 10 | static from() { 11 | const builder = Resources.build(/** @type {any} */(TEXT_OPTIONS)); 12 | return builder.from.apply(builder, arguments); 13 | } 14 | 15 | constructor(options) { 16 | if (arguments.length !== 1) { 17 | throw new Error(`Expected 1 parameter, got ${arguments.length}`); 18 | } 19 | checkType(options, Object, {name: 'parameter 1'}); 20 | super(Object.assign({}, TEXT_OPTIONS, options)); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/tabris/load-polyfill.js: -------------------------------------------------------------------------------- 1 | global.Promise = Promise; 2 | 3 | if (typeof window === 'undefined') { 4 | global.window = global; 5 | } 6 | 7 | if (!Object.assign) { 8 | Object.defineProperty(Object, 'assign', { 9 | enumerable: false, 10 | configurable: true, 11 | writable: true, 12 | value: assign 13 | }); 14 | } 15 | 16 | /** 17 | * Original code from 18 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign 19 | */ 20 | function assign(target) { 21 | if (target === undefined || target === null) { 22 | throw new TypeError('Cannot convert first argument to object'); 23 | } 24 | const to = Object(target); 25 | for (let i = 1; i < arguments.length; i++) { 26 | const source = arguments[i]; 27 | if (source === undefined || source === null) { 28 | continue; 29 | } 30 | const keys = Object.keys(Object(source)); 31 | for (const key of keys) { 32 | const desc = Object.getOwnPropertyDescriptor(source, key); 33 | if (desc !== undefined && desc.enumerable) { 34 | to[key] = source[key]; 35 | } 36 | } 37 | } 38 | return to; 39 | } 40 | -------------------------------------------------------------------------------- /src/tabris/symbols.ts: -------------------------------------------------------------------------------- 1 | export const equals: unique symbol = Symbol('equals'); 2 | export const creationAllowed: unique symbol = Symbol('creationAllowed'); 3 | export const bytes: unique symbol = Symbol('bytes'); 4 | export const nativeObject: unique symbol = Symbol('nativeObject'); 5 | export const toXML: unique symbol = Symbol('toXML'); 6 | export const notify: unique symbol = Symbol('notify'); 7 | export const data: unique symbol = Symbol('data'); 8 | export const originalComponent: unique symbol = Symbol('originalComponent'); 9 | export const proxyHandler: unique symbol = Symbol('proxyHandler'); 10 | export const setterTargetType: unique symbol = Symbol('setterTargetType'); 11 | export const observable: unique symbol = Symbol('observable'); 12 | export const nativeObservables: unique symbol = Symbol('nativeObservables'); 13 | export const jsxFactory: unique symbol = Symbol('jsxFactory'); 14 | export const jsxType: unique symbol = Symbol('jsxType'); 15 | -------------------------------------------------------------------------------- /src/tabris/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "alwaysStrict": true, 5 | "strict": true, 6 | "lib": ["es2017"], 7 | "checkJs": false, 8 | "allowJs": true, 9 | "typeRoots": [], 10 | "outDir": "../../build/tabris-transpiled" 11 | }, 12 | "include": [ 13 | "./**/*.js", 14 | "./**/*.ts" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /src/tabris/version.js: -------------------------------------------------------------------------------- 1 | import {error} from './Console'; 2 | 3 | export function checkVersion(tabrisVersionString, clientVersionString) { 4 | if (!clientVersionString) { 5 | return; 6 | } 7 | const tabrisVersion = tabrisVersionString.split('.'); 8 | const clientVersion = clientVersionString.split('.'); 9 | if (tabrisVersion[0] !== clientVersion[0] || tabrisVersion[1] !== clientVersion[1]) { 10 | error(`Version mismatch: JavaScript module "tabris" (version ${tabrisVersionString}) ` + 11 | `is incompatible with the native tabris platform (version ${clientVersionString}).`); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/tabris/widgets/ActivityIndicator.js: -------------------------------------------------------------------------------- 1 | import Widget from '../Widget'; 2 | import NativeObject from '../NativeObject'; 3 | 4 | export default class ActivityIndicator extends Widget { 5 | 6 | get _nativeType() { 7 | return 'tabris.ActivityIndicator'; 8 | } 9 | 10 | } 11 | 12 | NativeObject.defineProperties(ActivityIndicator.prototype, { 13 | tintColor: {type: 'ColorValue', default: 'initial'} 14 | }); 15 | -------------------------------------------------------------------------------- /src/tabris/widgets/CameraView.js: -------------------------------------------------------------------------------- 1 | import NativeObject from '../NativeObject'; 2 | import Widget from '../Widget'; 3 | import Camera from '../Camera'; 4 | 5 | export default class CameraView extends Widget { 6 | 7 | get _nativeType() { 8 | return 'tabris.CameraView'; 9 | } 10 | 11 | } 12 | 13 | NativeObject.defineProperties(CameraView.prototype, { 14 | camera: {type: Camera, default: null, nullable: true}, 15 | scaleMode: { 16 | type: 'string', 17 | choice: ['fit', 'fill'], 18 | default: 'fit' 19 | } 20 | }); 21 | -------------------------------------------------------------------------------- /src/tabris/widgets/ProgressBar.js: -------------------------------------------------------------------------------- 1 | import NativeObject from '../NativeObject'; 2 | import Widget from '../Widget'; 3 | import {types} from '../property-types'; 4 | 5 | export default class ProgressBar extends Widget { 6 | 7 | get _nativeType() { 8 | return 'tabris.ProgressBar'; 9 | } 10 | 11 | _getXMLAttributes() { 12 | return super._getXMLAttributes().concat([ 13 | ['selection', this.selection], 14 | ['minimum', this.minimum], 15 | ['maximum', this.maximum] 16 | ]); 17 | } 18 | 19 | } 20 | 21 | NativeObject.defineProperties(ProgressBar.prototype, { 22 | minimum: {type: types.integer, default: 0}, 23 | maximum: {type: types.integer, default: 100}, 24 | tintColor: {type: types.ColorValue, default: null}, 25 | selection: {type: types.integer, default: 0}, 26 | state: { 27 | type: types.string, 28 | choice: ['normal', 'paused', 'error'], 29 | default: 'normal' 30 | } 31 | }); 32 | -------------------------------------------------------------------------------- /src/tabris/widgets/RefreshComposite.js: -------------------------------------------------------------------------------- 1 | import Composite from './Composite'; 2 | import NativeObject from '../NativeObject'; 3 | 4 | export default class RefreshComposite extends Composite { 5 | 6 | get _nativeType() { 7 | return 'tabris.RefreshComposite'; 8 | } 9 | 10 | _listen(name, listening) { 11 | if (name === 'refresh') { 12 | this._nativeListen(name, listening); 13 | } else { 14 | super._listen(name, listening); 15 | } 16 | } 17 | 18 | } 19 | 20 | NativeObject.defineProperties(RefreshComposite.prototype, { 21 | 22 | refreshEnabled: { 23 | type: 'boolean', 24 | default: true 25 | }, 26 | refreshIndicator: { 27 | type: 'boolean', 28 | nocache: true 29 | }, 30 | refreshMessage: { 31 | type: 'string', 32 | default: '' 33 | } 34 | 35 | }); 36 | 37 | NativeObject.defineEvents(RefreshComposite.prototype, { 38 | refresh: {native: true} 39 | }); 40 | -------------------------------------------------------------------------------- /src/tabris/widgets/Slider.js: -------------------------------------------------------------------------------- 1 | import NativeObject from '../NativeObject'; 2 | import Widget from '../Widget'; 3 | 4 | export default class Slider extends Widget { 5 | 6 | get _nativeType() { 7 | return 'tabris.Slider'; 8 | } 9 | 10 | _getXMLAttributes() { 11 | return super._getXMLAttributes().concat([ 12 | ['selection', this.selection], 13 | ['minimum', this.minimum], 14 | ['maximum', this.maximum] 15 | ]); 16 | } 17 | 18 | } 19 | 20 | NativeObject.defineProperties(Slider.prototype, { 21 | minimum: {type: 'integer', default: 0}, 22 | maximum: {type: 'integer', default: 100}, 23 | selection: {type: 'integer', nocache: true}, 24 | tintColor: {type: 'ColorValue', default: 'initial'} 25 | }); 26 | 27 | NativeObject.defineEvents(Slider.prototype, { 28 | select: {native: true, changes: 'selection'} 29 | }); 30 | -------------------------------------------------------------------------------- /src/tabris/widgets/Switch.js: -------------------------------------------------------------------------------- 1 | import NativeObject from '../NativeObject'; 2 | import Widget from '../Widget'; 3 | 4 | export default class Switch extends Widget { 5 | 6 | get _nativeType() { 7 | return 'tabris.Switch'; 8 | } 9 | 10 | _getXMLAttributes() { 11 | return super._getXMLAttributes().concat([ 12 | ['text', this.text], 13 | ['checked', this.checked] 14 | ]); 15 | } 16 | 17 | } 18 | 19 | NativeObject.defineProperties(Switch.prototype, { 20 | checked: {type: 'boolean', nocache: true}, 21 | thumbOnColor: {type: 'ColorValue', default: 'initial'}, 22 | thumbOffColor: {type: 'ColorValue', default: 'initial'}, 23 | trackOnColor: {type: 'ColorValue', default: 'initial'}, 24 | trackOffColor: {type: 'ColorValue', default: 'initial'} 25 | }); 26 | 27 | NativeObject.defineEvents(Switch.prototype, { 28 | select: {native: true, changes: 'checked'} 29 | }); 30 | -------------------------------------------------------------------------------- /src/tabris/widgets/Tab.js: -------------------------------------------------------------------------------- 1 | import NativeObject from '../NativeObject'; 2 | import Composite from './Composite'; 3 | import TabFolder from './TabFolder'; 4 | import {toValueString} from '../Console'; 5 | 6 | export default class Tab extends Composite { 7 | 8 | get _nativeType() { 9 | return 'tabris.Tab'; 10 | } 11 | 12 | _setParent(parent, index) { 13 | if (parent && !(parent instanceof TabFolder)) { 14 | throw new Error(`Tab could not be appended to ${toValueString(parent)}`); 15 | } 16 | super._setParent(parent, index); 17 | } 18 | 19 | _getXMLAttributes() { 20 | return super._getXMLAttributes().concat([['title', this.title]]); 21 | } 22 | 23 | } 24 | 25 | NativeObject.defineProperties(Tab.prototype, { 26 | title: {type: 'string', default: ''}, 27 | image: {type: 'ImageValue', default: null}, 28 | selectedImage: {type: 'ImageValue', default: null}, 29 | badge: {type: 'natural', default: 0}, 30 | badgeColor: {type: 'ColorValue', default: 'initial'} 31 | }); 32 | 33 | NativeObject.defineEvents(Tab.prototype, { 34 | disappear: true, 35 | appear: true, 36 | select: true, 37 | reselect: true 38 | }); 39 | -------------------------------------------------------------------------------- /test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | }, 5 | "rules": { 6 | "prefer-arrow-callback": "off" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/boot/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "alwaysStrict": false, 5 | "strict": false, 6 | "checkJs": false, 7 | "allowJs": true, 8 | "noImplicitUseStrict": true, 9 | "lib": ["es2017"] 10 | }, 11 | "ts-node": { 12 | "files": true 13 | }, 14 | "include": [ 15 | "./*.ts", 16 | "../../src/boot/*.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /test/tabris-mock.js: -------------------------------------------------------------------------------- 1 | import NativeObjectRegistry from '../src/tabris/NativeObjectRegistry'; 2 | import NativeBridge from '../src/tabris/NativeBridge'; 3 | import Events from '../src/tabris/Events'; 4 | import {ConstraintLayout, LayoutQueue} from '../src/tabris/Layout'; 5 | import StackLayout from '../src/tabris/StackLayout'; 6 | import Tabris from '../src/tabris/Tabris'; 7 | 8 | export function mockTabris(client) { 9 | if (!client) { 10 | throw new Error('Cannot mock without a client'); 11 | } 12 | delete ConstraintLayout._default; 13 | delete LayoutQueue._instance; 14 | delete StackLayout._default; 15 | global.tabris = Object.assign({ 16 | Module: {getSourceMap() { return null; }}, 17 | flush: Tabris.prototype.flush, 18 | _notify: Tabris.prototype._notify, 19 | _client: client, 20 | _stackTraceStack: [], 21 | _nativeObjectRegistry: new NativeObjectRegistry(), 22 | started: true, 23 | device: {platform: 'test'} 24 | }, Events); 25 | global.tabris._nativeBridge = new NativeBridge(client); 26 | } 27 | -------------------------------------------------------------------------------- /test/tabris/CanvasContext.verify.js: -------------------------------------------------------------------------------- 1 | global.self = global; 2 | const tabris = require('../../build/tabris/'); 3 | const chai = require('chai'); 4 | const expect = chai.expect; 5 | const sinon = require('sinon'); 6 | const sandbox = sinon.sandbox.create(); 7 | const restore = sandbox.restore.bind(sandbox); 8 | const stub = sandbox.stub.bind(sandbox); 9 | const sinonChai = require('sinon-chai'); 10 | 11 | chai.use(sinonChai); 12 | 13 | describe('CanvasContext', function() { 14 | 15 | let context; 16 | 17 | beforeEach(function() { 18 | const client = stub({ 19 | call: () => {}, 20 | create: () => {}, 21 | get: () => {}, 22 | set: () => {} 23 | }); 24 | tabris._init(client); 25 | context = new tabris.Canvas().getContext('2d', 200, 200); 26 | }); 27 | 28 | afterEach(restore); 29 | 30 | describe('fillStyle', function() { 31 | 32 | it('has a default value', function() { 33 | expect(context.fillStyle).to.eql('rgba(0, 0, 0, 1)'); 34 | }); 35 | 36 | }); 37 | 38 | }); 39 | -------------------------------------------------------------------------------- /test/tabris/WebSocket.verify.js: -------------------------------------------------------------------------------- 1 | const tabris = require('../../build/tabris/'); 2 | const chai = require('chai'); 3 | const expect = chai.expect; 4 | const sinon = require('sinon'); 5 | const sandbox = sinon.sandbox.create(); 6 | const restore = sandbox.restore.bind(sandbox); 7 | const stub = sandbox.stub.bind(sandbox); 8 | const sinonChai = require('sinon-chai'); 9 | 10 | chai.use(sinonChai); 11 | 12 | describe('WebSocket', function() { 13 | 14 | let webSocket; 15 | let client; 16 | 17 | beforeEach(function() { 18 | client = stub({ 19 | call: () => {}, 20 | create: () => {}, 21 | get: () => {}, 22 | set: () => {}, 23 | listen: () => {} 24 | }); 25 | tabris._init(client); 26 | webSocket = new tabris.WebSocket('ws://url.com', 'chat-protocol'); 27 | }); 28 | 29 | afterEach(restore); 30 | 31 | it('calls send with string data', function() { 32 | tabris._notify(webSocket._nativeObject.cid, 'open', {}); 33 | 34 | webSocket.send('hello'); 35 | 36 | expect(client.call).to.have.been.calledWith(webSocket._nativeObject.cid, 'send', {data: 'hello'}); 37 | }); 38 | 39 | }); 40 | -------------------------------------------------------------------------------- /test/tabris/node.d.ts: -------------------------------------------------------------------------------- 1 | // Including the entire node type declarations in the tests 2 | // can cause conflicts. Declare only the few actually used 3 | // global variables 4 | 5 | declare function setTimeout(fn: Function, time?: number): any; 6 | -------------------------------------------------------------------------------- /test/typescript/$.test.ts: -------------------------------------------------------------------------------- 1 | import { WidgetCollection, TextView, NativeObject } from 'tabris'; 2 | 3 | // See also JSX.test.tsx 4 | 5 | let collection: WidgetCollection = $(null, [new TextView(), new TextView()]); 6 | collection = $(null, new TextView()); 7 | collection = $('#foo'); 8 | collection = $('*'); 9 | collection = $(); 10 | collection = $(TextView); 11 | collection = $((x: tabris.Widget) => x.cid === '$0'); 12 | let str: string = $(null, ['foo', 'bar']); 13 | str = $(null, 'foo bar'); 14 | str = $(null, [null, 'bar', 23, true]); 15 | str = $(null, 34); 16 | const nativeObject: NativeObject = $(0); 17 | -------------------------------------------------------------------------------- /test/typescript/ActionSheet.test.ts: -------------------------------------------------------------------------------- 1 | import {ActionSheetItem, ActionSheet, ImageValue, ActionSheetSelectEvent, ActionSheetCloseEvent, Properties} from 'tabris'; 2 | 3 | let widget: ActionSheet = new ActionSheet(); 4 | 5 | // Properties 6 | let title: string; 7 | let message: string; 8 | let actions: Array<{title: string, image?: ImageValue, style?: 'default'|'cancel'|'destructive'}>; 9 | 10 | title = widget.title; 11 | message = widget.message; 12 | actions = widget.actions; 13 | 14 | widget.title = title; 15 | widget.message = message; 16 | widget.actions = actions; 17 | 18 | let properties: Properties = {title, message, actions}; 19 | widget = new ActionSheet(properties); 20 | widget.set(properties); 21 | 22 | // Events 23 | let index: number, action: ActionSheetItem; 24 | let optionalIndex: number|null, optionalAction: ActionSheetItem|null; 25 | widget 26 | .onSelect((event: ActionSheetSelectEvent) => {index = event.index; action = event.action; }) 27 | .onClose((event: ActionSheetCloseEvent) => {optionalIndex = event.index; optionalAction = event.action; }); 28 | 29 | // open 30 | widget = widget.open(); 31 | const popup: ActionSheet = ActionSheet.open(widget); 32 | -------------------------------------------------------------------------------- /test/typescript/Blob.test.ts: -------------------------------------------------------------------------------- 1 | export default async function() { 2 | let blob: Blob = new Blob(); 3 | blob = new Blob([]); 4 | blob = new Blob(['', {}, new Uint8Array([])]); 5 | blob = new Blob([], {}); 6 | blob = new Blob([], {type: 'foo'}); 7 | const ab: ArrayBuffer = await blob.arrayBuffer(); 8 | let str: string = await blob.text(); 9 | str = blob.type; 10 | const num: number = blob.size; 11 | } 12 | -------------------------------------------------------------------------------- /test/typescript/Camera.test.ts: -------------------------------------------------------------------------------- 1 | import { Camera, device } from 'tabris'; 2 | 3 | type Resolution = {width: number, height: number}; 4 | 5 | const camera: Camera = device.cameras[0]; 6 | const resolution: Resolution|null = camera.captureResolution; 7 | const resolutions: Resolution[] = camera.availableCaptureResolutions; 8 | camera.captureResolution = resolution; 9 | const position: 'front' | 'back' | 'external' = camera.position; 10 | const cameraId: string = camera.cameraId; 11 | const active: boolean = camera.active; 12 | camera.active = active; 13 | const flash: 'auto' | 'on' | 'off' = 'on'; 14 | 15 | const capture: Promise = camera.captureImage({flash}); 16 | -------------------------------------------------------------------------------- /test/typescript/DateDialog.test.ts: -------------------------------------------------------------------------------- 1 | import { DateDialog, DateDialogSelectEvent, DateDialogCloseEvent, Properties } from 'tabris'; 2 | 3 | let dateDialog: DateDialog = new DateDialog(); 4 | 5 | // Properties 6 | let date: Date; 7 | let minDate: Date; 8 | let maxDate: Date; 9 | 10 | date = dateDialog.date; 11 | minDate = dateDialog.minDate; 12 | maxDate = dateDialog.maxDate; 13 | 14 | dateDialog.date = date; 15 | dateDialog.minDate = minDate; 16 | dateDialog.maxDate = maxDate; 17 | 18 | const properties: Properties = {date, minDate, maxDate}; 19 | dateDialog = new DateDialog(properties); 20 | dateDialog.set(properties); 21 | 22 | // Events 23 | const target: DateDialog = dateDialog; 24 | const timeStamp: number = 0; 25 | const type: string = 'foo'; 26 | 27 | const dateDialogSelectEvent: DateDialogSelectEvent = {target, timeStamp, type, date}; 28 | 29 | dateDialog 30 | .onSelect((event: DateDialogSelectEvent) => {}) 31 | .onClose((event: DateDialogCloseEvent) => {}); 32 | 33 | // open 34 | dateDialog = DateDialog.open(); 35 | dateDialog = DateDialog.open(new Date()); 36 | dateDialog = DateDialog.open(new DateDialog()); 37 | -------------------------------------------------------------------------------- /test/typescript/File.test.ts: -------------------------------------------------------------------------------- 1 | export default async function test() { 2 | let file: File = new File([], ''); 3 | file = new File(['', {}, new Uint8Array([])], ''); 4 | file = new File([], '', {}); 5 | file = new File([], '', {lastModified: 13}); 6 | file = new File([], '', {type: 'foo'}); 7 | const blob = file; 8 | const ab: ArrayBuffer = await file.arrayBuffer(); 9 | let str: string = await file.text(); 10 | str = file.type; 11 | let num: number = file.size; 12 | num = file.lastModified; 13 | } 14 | -------------------------------------------------------------------------------- /test/typescript/Headers.test.ts: -------------------------------------------------------------------------------- 1 | import 'tabris'; 2 | 3 | export default async function() { 4 | let str: string | null = ''; 5 | const headers: Headers = new Headers(); 6 | headers.append('foo', 'bar'); 7 | headers.set('foo', 'bar'); 8 | headers.delete('foo'); 9 | str = headers.get('foo'); 10 | const values: string[] = headers.getAll('foo'); 11 | const bool: boolean = headers.has('foo'); 12 | for (const entry of headers) { 13 | str = entry[0]; 14 | str = entry[1]; 15 | } 16 | for (const entry of headers.entries()) { 17 | str = entry[0]; 18 | str = entry[1]; 19 | } 20 | for (const value of headers.values()) { 21 | str = value; 22 | } 23 | for (const key of headers.keys()) { 24 | str = key; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/typescript/Layout.test.ts: -------------------------------------------------------------------------------- 1 | import {Layout, ConstraintLayout, StackLayout, Composite, BoxDimensions} from 'tabris'; 2 | 3 | let layout: Layout|null = ConstraintLayout.default 4 | let constraintLayout: ConstraintLayout = ConstraintLayout.default; 5 | let alignment: 'left'|'centerX'|'stretchX'|'right' = 'left'; 6 | constraintLayout = new ConstraintLayout(); 7 | let composite: Composite = new Composite({layout}); 8 | let stackLayout: StackLayout = StackLayout.default; 9 | stackLayout = new StackLayout({alignment}); 10 | 11 | layout = composite.layout; 12 | alignment = stackLayout.alignment; 13 | -------------------------------------------------------------------------------- /test/typescript/LocalStorage.test.ts: -------------------------------------------------------------------------------- 1 | import 'tabris'; 2 | 3 | let storage: Storage = localStorage; 4 | storage = secureStorage; 5 | 6 | storage.setItem('foo', 'bar'); 7 | storage.getItem('foo'); 8 | storage.removeItem('foo'); 9 | storage.clear(); 10 | const l: number = storage.length; 11 | const key: string = storage.key(0); 12 | -------------------------------------------------------------------------------- /test/typescript/Module.test.ts: -------------------------------------------------------------------------------- 1 | import { Module } from 'tabris'; 2 | 3 | let m: Module = new Module('my-module', null, {foo: 'bar'}); 4 | m = new Module('my-module', m, (a, b, c, d, e) => { 5 | const otherM: Module = a; 6 | const otherExports: {} = b; 7 | const otherRquire: (id: string) => unknown = c; 8 | const str1: string = d; 9 | const str2: string = e; 10 | }); 11 | 12 | let unknown: unknown = Module.getSourceMap('foo.js'); 13 | unknown = Module.execute('1+2;', 'foo.js'); 14 | unknown = Module.readJSON('foo.json'); 15 | unknown = Module.createRequire('/foo/bar')('./baz'); 16 | let str: string = Module.load('foo.js'); 17 | const loader = Module.createLoader('foo.js'); 18 | loader(m, {}, (x) => ({[x]: 'foo'}), 'foo.js', 'foo.js'); 19 | Module.define('/foo/bar', {}); 20 | Module.define('/foo/bar', null); 21 | Module.addPath('foo', ['foo']); 22 | Module.addPath({baseUrl: 'foo', paths: {foo: ['bar']}}); 23 | Module.addPath({paths: {foo: ['bar']}}); 24 | 25 | // global definitions 26 | 27 | m = module; 28 | unknown = require('tabris'); 29 | const obj: object = exports; 30 | str = __dirname; 31 | str = __filename; 32 | -------------------------------------------------------------------------------- /test/typescript/NavigationBar.test.ts: -------------------------------------------------------------------------------- 1 | import {NavigationBar, ColorValue, Properties, navigationBar} from 'tabris'; 2 | 3 | const object: NavigationBar = navigationBar; 4 | 5 | // Properties 6 | let background: ColorValue; 7 | let displayMode: 'default' | 'float' | 'hide'; 8 | let height: number; 9 | let theme: 'dark' | 'default' | 'light'; 10 | 11 | background = navigationBar.background; 12 | displayMode = navigationBar.displayMode; 13 | height = navigationBar.height; 14 | theme = navigationBar.theme; 15 | 16 | navigationBar.background = background; 17 | navigationBar.displayMode = displayMode; 18 | navigationBar.theme = theme; 19 | 20 | let properties: Properties = {background, displayMode}; 21 | navigationBar.set(properties); 22 | -------------------------------------------------------------------------------- /test/typescript/ObservableData.test.ts: -------------------------------------------------------------------------------- 1 | import {ObservableData, Observable, PropertyChangedEvent, } from 'tabris'; 2 | 3 | let data = {foo: 1, bar: 'baz'}; 4 | let observableData: ObservableData; 5 | let observable: Observable>; 6 | let extended: ObservableData & typeof data; 7 | 8 | observableData = new ObservableData(); 9 | observableData = new ObservableData({any: 'prop'}); 10 | observableData = ObservableData(); 11 | observableData = ObservableData({any: 'prop'}); 12 | data = ObservableData(data); 13 | extended = ObservableData(data); 14 | 15 | class MyData extends ObservableData { 16 | 17 | foo: number; 18 | bar: string; 19 | 20 | someMethod(value: string) { 21 | this.bar = value; 22 | } 23 | 24 | } 25 | 26 | const myData = new MyData(); 27 | myData.someMethod('foo'); 28 | extended = new MyData(); 29 | observable = myData[Symbol.observable](); 30 | observable.subscribe(ev => { 31 | if (ev.originalEvent && typeof ev.value === 'string') { 32 | ev.target.someMethod(ev.value); 33 | } 34 | }); 35 | -------------------------------------------------------------------------------- /test/typescript/Percent.test.ts: -------------------------------------------------------------------------------- 1 | import {Percent, PercentValue} from 'tabris'; 2 | 3 | let percentValue: PercentValue = new Percent(0); 4 | percentValue = '5%'; 5 | percentValue = {percent: 5}; 6 | 7 | let percent: Percent = new Percent(5); 8 | percent = Percent.from('foo'); 9 | percent = Percent.from({percent: 5}); 10 | percent = Percent.from(percent); 11 | percent = Percent.from(percentValue); 12 | percentValue = percent; 13 | 14 | let num: number; 15 | num = percent.percent; 16 | num = percent.valueOf(); 17 | 18 | let str: string; 19 | str = percent.toString(); 20 | 21 | let obj: object = {}; 22 | 23 | if (Percent.isValidPercentValue(obj)) { 24 | percentValue = obj; 25 | } 26 | -------------------------------------------------------------------------------- /test/typescript/Popover.test.ts: -------------------------------------------------------------------------------- 1 | import {EventObject, Popover, Widget, Properties, ContentView} from 'tabris'; 2 | 3 | let popover: Popover = new Popover(); 4 | 5 | // Properties 6 | let width: number | null; 7 | let height: number | null; 8 | let anchor: Widget; 9 | let contentView: ContentView; 10 | 11 | width = popover.width; 12 | height = popover.height; 13 | anchor = popover.anchor; 14 | contentView = popover.contentView; 15 | 16 | popover.width = width; 17 | popover.height = height; 18 | popover.anchor = anchor; 19 | 20 | let properties: Properties = {width, height, anchor}; 21 | popover = new Popover(properties); 22 | popover.set(properties); 23 | 24 | // Methods 25 | let thisReturnValue: Popover; 26 | 27 | thisReturnValue = popover.close(); 28 | thisReturnValue = popover.open(); 29 | 30 | // Events 31 | popover.onClose((event: EventObject) => {}); 32 | -------------------------------------------------------------------------------- /test/typescript/Request.test.ts: -------------------------------------------------------------------------------- 1 | import 'tabris'; 2 | 3 | declare type T = object; 4 | 5 | let result: Promise = fetch('URL'); 6 | result.then((response) => { 7 | let errorResponse: Response = Response.error(); 8 | let clonedResponse: Response = response.clone(); 9 | let redirectedResponse: Response = Response.redirect('url', 0); 10 | let arrayBuffer: Promise = response.arrayBuffer(); 11 | // let blob: Promise = response.blob(); 12 | // let formData: Promise = response.formData(); 13 | let json: Promise = response.json(); 14 | let json2: Promise = response.json(); 15 | let text: Promise = response.text(); 16 | let blob: Promise = response.blob(); 17 | }); 18 | 19 | let request: Request = new Request('input', {body: 'foo'}); 20 | request = new Request('input', {body: new Blob()}); 21 | request = new Request('input', {body: new FormData(), timeout: 400}); 22 | let fetchWithRequest: Promise = fetch(request); 23 | -------------------------------------------------------------------------------- /test/typescript/Response.test.ts: -------------------------------------------------------------------------------- 1 | import 'tabris'; 2 | 3 | declare type T = object; 4 | 5 | let response: Response = Response.error(); 6 | response = Response.redirect('url', 0); 7 | response = response.clone(); 8 | 9 | (async () => { 10 | const arrayBuffer: ArrayBuffer = await response.arrayBuffer(); 11 | const json: unknown = await response.json(); 12 | const json2: T = await response.json(); 13 | let text: Promise = response.text(); 14 | let blob: Promise = response.blob(); 15 | })(); -------------------------------------------------------------------------------- /test/typescript/StatusBar.test.ts: -------------------------------------------------------------------------------- 1 | import {StatusBar, ColorValue, statusBar} from 'tabris'; 2 | 3 | const object: StatusBar = statusBar; 4 | 5 | // Properties 6 | let background: ColorValue; 7 | let displayMode: 'default' | 'float' | 'hide'; 8 | let height: number; 9 | let theme: 'dark' | 'default' | 'light'; 10 | 11 | background = statusBar.background; 12 | displayMode = statusBar.displayMode; 13 | height = statusBar.height; 14 | theme = statusBar.theme; 15 | 16 | statusBar.background = background; 17 | statusBar.displayMode = displayMode; 18 | statusBar.theme = theme; 19 | -------------------------------------------------------------------------------- /test/typescript/Tabris.test.ts: -------------------------------------------------------------------------------- 1 | import { tabris, NativeObject, PropertyType } from 'tabris'; 2 | 3 | const nativeObject: NativeObject = tabris; 4 | const bool: boolean = tabris.started; 5 | const str: string = tabris.version; 6 | 7 | tabris._defineModule('my-module', () => {}); 8 | tabris._init({}, {headless: false}); 9 | tabris._init({}); 10 | tabris._notify('$0', 'event', {}); 11 | tabris.flush(); 12 | tabris.onFlush(() => {}); 13 | tabris.onLayout(() => {}); 14 | tabris.onStart(() => {}); 15 | tabris.onLog(({message, level}) => { 16 | const fn: Function = console[level]; 17 | const str2: string = message; 18 | }); 19 | 20 | const symbol: Symbol = tabris.symbols.equals; 21 | const types: {[type: string]: PropertyType} = tabris.propertyTypes; 22 | -------------------------------------------------------------------------------- /test/typescript/TimeDialog.test.ts: -------------------------------------------------------------------------------- 1 | import {TimeDialogCloseEvent, TimeDialog, Properties, TimeDialogSelectEvent} from 'tabris'; 2 | 3 | let timeDialog: TimeDialog = new TimeDialog(); 4 | 5 | // Properties 6 | let date: Date; 7 | 8 | date = timeDialog.date; 9 | 10 | timeDialog.date = date; 11 | 12 | let properties: Properties = {date}; 13 | timeDialog = new TimeDialog(properties); 14 | timeDialog.set(properties); 15 | 16 | // Events 17 | let target: TimeDialog = timeDialog; 18 | let timeStamp: number = 0; 19 | let type: string = 'foo'; 20 | 21 | let timeDialogSelectEvent: TimeDialogSelectEvent = {target, timeStamp, type, date}; 22 | 23 | timeDialog 24 | .onSelect((event: TimeDialogSelectEvent) => {}) 25 | .onClose((event: TimeDialogCloseEvent) => {}); 26 | 27 | // open 28 | timeDialog = TimeDialog.open(); 29 | timeDialog = TimeDialog.open(new Date()); 30 | timeDialog = TimeDialog.open(new TimeDialog()); 31 | -------------------------------------------------------------------------------- /test/typescript/Widgets/ActivityIndicator.test.ts: -------------------------------------------------------------------------------- 1 | import {ActivityIndicator, ColorValue, Properties} from 'tabris'; 2 | 3 | let widget: ActivityIndicator = new ActivityIndicator(); 4 | 5 | // Properties 6 | let tintColor: ColorValue; 7 | 8 | tintColor = widget.tintColor; 9 | 10 | widget.tintColor = tintColor; 11 | 12 | let properties: Properties = {tintColor}; 13 | widget = new ActivityIndicator(properties); 14 | widget.set(properties); 15 | 16 | class CustomComponent extends ActivityIndicator { 17 | public foo: string; 18 | constructor(props: Properties & Partial>) { super(props); } 19 | } 20 | 21 | new CustomComponent({foo: 'bar'}).set({foo: 'bar'}); 22 | -------------------------------------------------------------------------------- /test/typescript/Widgets/CameraView.test.ts: -------------------------------------------------------------------------------- 1 | import { Camera, CameraView, Properties } from 'tabris'; 2 | 3 | let widget: CameraView = new CameraView(); 4 | 5 | // Properties 6 | let camera: Camera; 7 | let scaleMode: 'fill' | 'fit'; 8 | 9 | scaleMode = widget.scaleMode; 10 | camera = widget.camera; 11 | 12 | widget.scaleMode = scaleMode; 13 | widget.camera = camera; 14 | 15 | let properties: Properties = { 16 | camera, 17 | scaleMode 18 | }; 19 | 20 | widget = new CameraView(properties); 21 | widget.set(properties); 22 | -------------------------------------------------------------------------------- /test/typescript/Widgets/Canvas.test.ts: -------------------------------------------------------------------------------- 1 | import {Canvas, CanvasContext, Properties} from 'tabris'; 2 | 3 | let canvas: Canvas = new Canvas(); 4 | 5 | // Methods 6 | let contextType: string = '2d'; 7 | let width: number = 42; 8 | let height: number = 42; 9 | 10 | let context: CanvasContext = canvas.getContext(contextType, width, height); 11 | canvas.toBlob((value: Blob) => null, 'image/png'); 12 | canvas.toBlob((value: Blob) => null, 'image/jpeg'); 13 | canvas.toBlob((value: Blob) => null, 'image/webp'); 14 | canvas.toBlob((value: Blob) => null, 'image/webp', 0.4); 15 | canvas.toBlob((value: Blob) => null); 16 | 17 | class CustomComponent extends Canvas { 18 | public foo: string; 19 | constructor(props: Properties & Partial>) { super(props); } 20 | } 21 | 22 | new CustomComponent({foo: 'bar'}).set({foo: 'bar'}); 23 | -------------------------------------------------------------------------------- /test/typescript/Widgets/Drawer.test.ts: -------------------------------------------------------------------------------- 1 | import {Drawer, drawer, EventObject, Properties, ContentView} from 'tabris'; 2 | 3 | const object: Drawer = drawer; 4 | const conentView: ContentView = drawer; 5 | 6 | // Propeties 7 | let enabled: boolean; 8 | 9 | enabled = drawer.enabled; 10 | 11 | drawer.enabled = enabled; 12 | 13 | let properties: Properties = {enabled}; 14 | drawer.set(properties); 15 | 16 | // Methods 17 | let thisReturnValue: Drawer; 18 | 19 | thisReturnValue = drawer.close(); 20 | thisReturnValue = drawer.open(); 21 | 22 | // Events 23 | let target: Drawer = drawer; 24 | let timeStamp: number = 0; 25 | let type: string = 'foo'; 26 | 27 | let drawerCloseEvent: EventObject = {target, timeStamp, type}; 28 | 29 | drawer.onClose((event: EventObject) => {}); 30 | -------------------------------------------------------------------------------- /test/typescript/Widgets/ProgressBar.test.ts: -------------------------------------------------------------------------------- 1 | import {ColorValue, ProgressBar, Properties} from 'tabris'; 2 | 3 | let widget: ProgressBar = new ProgressBar(); 4 | 5 | // Properties 6 | let maximum: number; 7 | let minimum: number; 8 | let tintColor: ColorValue; 9 | let selection: number; 10 | let state: 'error' | 'normal' | 'paused'; 11 | 12 | maximum = widget.maximum; 13 | minimum = widget.minimum; 14 | tintColor = widget.tintColor; 15 | selection = widget.selection; 16 | state = widget.state; 17 | 18 | widget.maximum = maximum; 19 | widget.minimum = minimum; 20 | widget.tintColor = tintColor; 21 | widget.selection = selection; 22 | widget.state = state; 23 | 24 | let properties: Properties = {maximum, minimum, tintColor, selection, state}; 25 | widget = new ProgressBar(properties); 26 | widget.set(properties); 27 | 28 | class CustomComponent extends ProgressBar { 29 | public foo: string; 30 | constructor(props: Properties & Partial>) { super(props); } 31 | } 32 | 33 | new CustomComponent({foo: 'bar'}).set({foo: 'bar'}); 34 | -------------------------------------------------------------------------------- /test/typescript/Widgets/Row.test.ts: -------------------------------------------------------------------------------- 1 | import {Composite, Row, RowLayout} from 'tabris'; 2 | 3 | let alignment: 'top' | 'centerY' | 'stretchY' | 'bottom' | 'baseline' = 'top' 4 | let widget: Row = new Row(); 5 | widget = new Row({padding: 2}); 6 | widget = new Row({padding: {left: 2, top: 2, right: 2, bottom: 2}}); 7 | widget = new Row({spacing: 2, alignment}); 8 | let composite: Composite = widget; 9 | let layout: RowLayout = widget.layout; 10 | let spacing: number = widget.spacing; 11 | alignment = widget.alignment; 12 | alignment = layout.alignment; 13 | -------------------------------------------------------------------------------- /test/typescript/Widgets/Stack.test.ts: -------------------------------------------------------------------------------- 1 | import {Composite, Stack, StackLayout} from 'tabris'; 2 | 3 | let alignment: 'left'|'centerX'|'stretchX'|'right' = 'left' 4 | let widget: Stack = new Stack(); 5 | widget = new Stack({padding: 2}); 6 | widget = new Stack({padding: {left: 2, top: 2, right: 2, bottom: 2}}); 7 | widget = new Stack({spacing: 2, alignment}); 8 | let composite: Composite = widget; 9 | let layout: StackLayout = widget.layout; 10 | let spacing: number = widget.spacing; 11 | alignment = widget.alignment; 12 | alignment = layout.alignment; 13 | -------------------------------------------------------------------------------- /test/typescript/authentication.test.ts: -------------------------------------------------------------------------------- 1 | import { authentication } from 'tabris'; 2 | 3 | // Properties 4 | let availableBiometrics: Array<'face' | 'fingerprint'>; 5 | 6 | availableBiometrics = authentication.availableBiometrics; 7 | 8 | // Methods 9 | authentication.canAuthenticate(); 10 | authentication.cancel(); 11 | authentication.authenticate().then((result: any) => { 12 | result.status = 'success'; 13 | result.status = 'canceled'; 14 | result.status = 'userCanceled'; 15 | result.status = 'limitExceeded'; 16 | result.status = 'lockout'; 17 | result.status = 'biometricsNotEnrolled'; 18 | result.status = 'credentialsNotEnrolled'; 19 | result.status = 'error'; 20 | }); 21 | -------------------------------------------------------------------------------- /test/typescript/console.test.ts: -------------------------------------------------------------------------------- 1 | console.log(1, 'foo', true, {}); 2 | console.debug(1, 'foo', true, {}); 3 | console.info(1, 'foo', true, {}); 4 | console.warn(1, 'foo', true, {}); 5 | console.error(1, 'foo', true, {}); 6 | console.group(1, 'foo', true, {}); 7 | console.groupEnd(); 8 | console.assert(true, 'foo', true, {}); 9 | console.assert(false, 'foo', true, {}); 10 | console.count(); 11 | console.count('foo'); 12 | console.countReset(); 13 | console.trace(); 14 | console.dirxml({}); 15 | -------------------------------------------------------------------------------- /test/typescript/devTools.test.ts: -------------------------------------------------------------------------------- 1 | import {devTools} from 'tabris'; 2 | 3 | let none: void; 4 | let bool: boolean; 5 | 6 | bool = devTools.showUi(); 7 | none = devTools.hideUi(); 8 | bool = devTools.isUiVisible(); 9 | -------------------------------------------------------------------------------- /test/typescript/device.test.ts: -------------------------------------------------------------------------------- 1 | import {Device, device, PropertyChangedEvent} from 'tabris'; 2 | 3 | type Orientation = 'landscape-primary' | 'landscape-secondary' | 'portrait-primary' | 'portrait-secondary'; 4 | // Properties 5 | let language: string; 6 | let model: string; 7 | let orientation: Orientation; 8 | let platform: 'Android' | 'iOS'; 9 | let scaleFactor: number; 10 | let screenHeight: number; 11 | let screenWidth: number; 12 | let version: string; 13 | let name: string; 14 | 15 | language = device.language; 16 | model = device.model; 17 | orientation = device.orientation; 18 | platform = device.platform; 19 | scaleFactor = device.scaleFactor; 20 | screenHeight = device.screenHeight; 21 | screenWidth = device.screenWidth; 22 | version = device.version; 23 | name = device.name; 24 | 25 | // Events 26 | let target: Device = device; 27 | let timeStamp: number = 0; 28 | let type: string = 'foo'; 29 | let value: Orientation = orientation; 30 | 31 | let orientationChangedEvent: PropertyChangedEvent = {target, timeStamp, type, value}; 32 | 33 | device.onOrientationChanged((event: PropertyChangedEvent) => {}); 34 | -------------------------------------------------------------------------------- /test/typescript/fetch.test.ts: -------------------------------------------------------------------------------- 1 | import 'tabris'; 2 | 3 | (async () => { 4 | let response: Response = await fetch('URL'); 5 | response = await fetch('URL', {}); 6 | response = await fetch('URL', {method: 'foo'}); 7 | response = await fetch('URL', {headers: new Headers()}); 8 | response = await fetch('URL', {headers: {foo: 'bar'}}); 9 | response = await fetch('URL', {headers: [['foo', 'bar'], ['foo2', 'bar2']]}); 10 | })(); 11 | -------------------------------------------------------------------------------- /test/typescript/fs.test.ts: -------------------------------------------------------------------------------- 1 | import {fs} from 'tabris'; 2 | 3 | let path: string; 4 | let data: ArrayBuffer | Blob; 5 | let text: string; 6 | let paths: string[]; 7 | let files: File[]; 8 | let none: void; 9 | let bool: boolean; 10 | 11 | async function test() { 12 | 13 | // Properties 14 | path = fs.filesDir; 15 | path = fs.cacheDir; 16 | 17 | // Methods 18 | data = await fs.readFile(path); 19 | text = await fs.readFile(path, 'utf-8'); 20 | paths = await fs.readDir(path); 21 | none = await fs.writeFile(path, data); 22 | none = await fs.writeFile(path, text, 'utf-8'); 23 | bool = await fs.appendToFile(path, data); 24 | bool = await fs.appendToFile(path, text, 'utf-8'); 25 | none = await fs.removeFile(path); 26 | none = await fs.removeDir(path); 27 | bool = await fs.createDir(path); 28 | bool = await fs.remove(path); 29 | files = await fs.openFile({type: 'image/png', quantity: 'multiple'}); 30 | bool = fs.isFile(path); 31 | bool = fs.isDir(path); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /test/typescript/globalTabrisObject.test.ts: -------------------------------------------------------------------------------- 1 | new tabris.TextView({text: 'foo'}).appendTo(tabris.contentView); 2 | -------------------------------------------------------------------------------- /test/typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tabris-typescript-test", 3 | "private": true, 4 | "dependencies": { 5 | "tabris": "../tabris", 6 | "typescript": "4.0.x" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/typescript/permission.test.ts: -------------------------------------------------------------------------------- 1 | import {permission} from 'tabris'; 2 | 3 | permission.getAuthorizationStatus('camera', 'foo'); 4 | permission.isAuthorizationPossible('camera', 'foo'); 5 | permission.isAuthorized('camera', 'foo'); 6 | permission.requestAuthorization('camera', 'foo').then((result) => { 7 | result = 'undetermined'; 8 | result = 'granted'; 9 | result = 'declined'; 10 | result = 'denied'; 11 | result = 'rejected'; 12 | }); 13 | let authorizationCallback = () => {} 14 | let errorCallback = (error: Error) => {} 15 | permission.withAuthorization('foo', authorizationCallback, authorizationCallback, errorCallback); -------------------------------------------------------------------------------- /test/typescript/promise.test.ts: -------------------------------------------------------------------------------- 1 | import 'tabris'; 2 | 3 | let promise1 = new Promise((resolve, reject) => { 4 | if (1 === 1) { 5 | resolve('result'); 6 | } else { 7 | reject('reason'); 8 | } 9 | }); 10 | 11 | promise1.then((result) => { 12 | return 'nextResult'; 13 | }).then((result) => { 14 | return 'nextResult'; 15 | }).catch((reason) => { 16 | // handle error 17 | }); 18 | 19 | let promise2 = new Promise((resolve, reject) => { 20 | if (1 === 1) { 21 | resolve('result'); 22 | } else { 23 | reject('reason'); 24 | } 25 | }); 26 | 27 | let allPromise: Promise = Promise.race([promise1, promise2]).then((results) => { 28 | let result1 = results[0]; 29 | let result2 = results[1]; 30 | }); 31 | 32 | let racePromise: Promise = Promise.race([promise1, promise2]).then((result) => { 33 | result.doSomething(); 34 | }); 35 | 36 | let rejectedPromise: Promise = Promise.reject('reason'); 37 | let resolvedPromise: Promise = Promise.resolve('value'); 38 | 39 | -------------------------------------------------------------------------------- /test/typescript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "lib": ["es6", "es2015.promise" ], 6 | "noImplicitAny": true, 7 | "noImplicitThis": true, 8 | "alwaysStrict": true, 9 | "strictNullChecks": true, 10 | "jsx": "react", 11 | "jsxFactory": "JSX.createElement", 12 | "typeRoots": [] 13 | }, 14 | "include": [ 15 | "**/*.test.ts", 16 | "**/*.test.tsx" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /test/typescript/utils.test.ts: -------------------------------------------------------------------------------- 1 | import {checkType, format} from 'tabris'; 2 | 3 | let value: unknown = {}; 4 | 5 | let date: Date = checkType(value, Date); 6 | const inferredString = checkType(value, String); 7 | let string: string = inferredString 8 | const inferredNumber = checkType(value, Number); 9 | let number: number = inferredNumber; 10 | const inferredBoolean = checkType(value, Boolean); 11 | let boolean: boolean = inferredBoolean; 12 | 13 | date = checkType(value, Date, {nullable: true}); 14 | date = checkType(value, Date, {name: 'date'}); 15 | let nothing: void = checkType(value, Date, checked => date = checked); 16 | nothing = checkType(value, String, checked => string = checked); 17 | nothing = checkType(value, Number, checked => number = checked); 18 | nothing = checkType(value, Boolean, checked => boolean = checked); 19 | 20 | string = format('foo'); 21 | string = format({}, new Date(), 23, null); 22 | string = format('baz', ['stuff']); 23 | -------------------------------------------------------------------------------- /tools/json-schema-to-typescript.js: -------------------------------------------------------------------------------- 1 | const {compile} = require('json-schema-to-typescript'); 2 | const fs = require('fs'); 3 | 4 | // Run this script to regenerate api-schema.d.ts after changing api-schema.json: 5 | // `node tools/json-schema-to-typescript.js` 6 | 7 | const schema = JSON.parse(fs.readFileSync(__dirname + '/api-schema.json')); 8 | // Workaround preventing nearly empty output, possibly related to: 9 | // https://github.com/bcherny/json-schema-to-typescript/issues/167 10 | delete schema.definitions.api.allOf; 11 | compile(schema, 'TabrisAPI') 12 | .then(ts => fs.writeFileSync(__dirname + '/api-schema.d.ts', ts)) 13 | .catch(ex => console.error(ex)); 14 | -------------------------------------------------------------------------------- /tools/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "lib": ["es6", "es2015.promise"] 6 | }, 7 | "include": [ 8 | "./*.ts", 9 | "./*.js" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "alwaysStrict": false, 5 | "strict": false, 6 | "checkJs": false, 7 | "allowJs": true, 8 | "noImplicitUseStrict": true, 9 | "lib": ["es2017"], 10 | "skipLibCheck": true, 11 | "moduleResolution": "node", 12 | "outDir": "build/dummy", 13 | "typeRoots": [], 14 | "types": [ 15 | "./node_modules/@types/chai", 16 | "./node_modules/@types/chai-as-promised", 17 | "./node_modules/@types/sinon", 18 | "./node_modules/@types/sinon-chai", 19 | "./node_modules/@types/mocha" 20 | ] 21 | }, 22 | "ts-node": { 23 | "files": true 24 | }, 25 | "exclude": [ 26 | "./test/typescript/**", 27 | "./test/boot/**", 28 | "./test/**/*.verify.js" 29 | ], 30 | "include": [ 31 | "./test/**/*.ts", 32 | "./test/**/*.js", 33 | "./src/tabris/**/*.ts", 34 | "./src/tabris/**/*.js" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /typings/global/ImageData.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Represents pixel data of a `Canvas` widget. 3 | */ 4 | declare class ImageData { 5 | 6 | constructor(data: Uint8ClampedArray, width: number, height?: number); 7 | constructor(width: number, height: number); 8 | 9 | /** 10 | * A one-dimensional array containing the data in RGBA order, with integer values between 0 and 255 (inclusive). 11 | */ 12 | readonly data: Uint8ClampedArray; 13 | 14 | /** 15 | * The actual height of the ImageData, in pixels. 16 | */ 17 | readonly width: number; 18 | 19 | /** 20 | * The actual height of the ImageData, in pixels. 21 | */ 22 | readonly height: number; 23 | 24 | } -------------------------------------------------------------------------------- /typings/global/Worker.d.ts: -------------------------------------------------------------------------------- 1 | interface WorkerEventMap { 2 | "message": MessageEvent; 3 | "error": Event; 4 | "messageerror": Event; 5 | } 6 | 7 | interface Worker extends EventTarget { 8 | onerror: (this: Worker, ev: Event) => any; 9 | onmessageerror: (this: Worker, ev: Event) => any; 10 | onmessage: (this: Worker, ev: MessageEvent) => any; 11 | onopen: (this: Worker, ev: Event) => any; 12 | readonly protocol: string; 13 | readonly readyState: number; 14 | readonly url: string; 15 | postMessage(data: any, transferList?: Array): void; 16 | terminate(): void; 17 | addEventListener(type: K, listener: (this: Worker, ev: WorkerEventMap[K]) => any, useCapture?: boolean): void; 18 | } 19 | 20 | declare var Worker: { 21 | prototype: Worker; 22 | new(scriptPath: string): Worker; 23 | }; 24 | -------------------------------------------------------------------------------- /typings/global/misc.d.ts: -------------------------------------------------------------------------------- 1 | declare var secureStorage: Storage; 2 | declare var device: tabris.Device; 3 | declare var createImageBitmap: typeof tabris.ImageBitmap.createImageBitmap; 4 | declare var __dirname: string; 5 | declare var __filename: string; 6 | declare var module: tabris.Module; 7 | declare var exports: object; 8 | declare var require: (request: string) => object; 9 | 10 | type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array; 11 | -------------------------------------------------------------------------------- /typings/reExports.d.ts: -------------------------------------------------------------------------------- 1 | 2 | declare var ImageDataConstructor: typeof ImageData; 3 | declare var StorageConstructor: typeof Storage; 4 | declare var WebSocketConstructor: typeof WebSocket; 5 | declare var XMLHttpRequestConstructor: typeof XMLHttpRequest; 6 | declare var CryptoConstructor: typeof Crypto; 7 | declare var cryptoObject: Crypto; 8 | declare var workerConstructor: typeof Worker; 9 | declare var RequestConstructor: typeof Request; 10 | declare var ResponseConstructor: typeof Response; 11 | declare var HeadersConstructor: typeof Headers; 12 | declare var fetchFunction: typeof fetch; 13 | declare var $Function: typeof $; 14 | 15 | export { 16 | ImageDataConstructor as ImageData, 17 | StorageConstructor as Storage, 18 | WebSocketConstructor as WebSocket, 19 | XMLHttpRequestConstructor as XMLHttpRequest, 20 | CryptoConstructor as Crypto, 21 | cryptoObject as crypto, 22 | RequestConstructor as Request, 23 | ResponseConstructor as Response, 24 | HeadersConstructor as Headers, 25 | fetchFunction as fetch, 26 | $Function as $, 27 | Setter as Set 28 | }; 29 | 30 | --------------------------------------------------------------------------------