Plugins

Last updated 3 months ago

Webix Jet provides predefined plugins and the ability to create custom plugins.

1. Default Plugins

View Plugins

These plugins are enabled for a specific view by view.use():

  • the Menu plugin

  • the UnloadGuard plugin

  • the Status plugin

  • the UrlParam plugin

App Plugins

These plugins are enabled for the whole app with app.use():

  • the User plugin

  • the Theme plugin

  • the Locale plugin

The Menu plugin simplifies your life if you plan to create a menu for navigation:

  • it sets subview URLs for menu options, buttons or other controls you plan to use for navigation;

  • it automatically highlights the right menu option after a page reload or change of the URL.

Using the Menu plugin in Webix Jet

The plugin must be enabled in the Jet view that contains the menu with view.use() (call it as this.use()). After the plugin name, you must specify the local ID of the Webix control or widget that you want to use as a menu:

// views/top.js
import {JetView, plugins} from "webix-jet";
export default class TopView extends JetView{
config(){
return {
rows:[
{
view:"menu", localId:"menu", data:[
{ id:"details", value:"Details" }, //show "/top/details"
{ id:"dash", value:"Dash" } //show "/top/dash"
]
},
{ $subview:true }
]
};
}
init(){
this.use(plugins.Menu, "menu");
}
}

Subview URLs are taken from menu option IDs or from values if there are no IDs. If you want to change some URL, you can add custom subview URLs in the plugin configuration:

// views/top.js
import {JetView} from "webix-jet";
export default class TopView extends JetView {
config(){
return {
rows:[
{
view:"menu", localId:"menu", data:[
{ id:"details", value:"Details"}, //show "/top/demo/details"
{ id:"dash", value:"Dash" } //show "/top/dash"
]
},
{ $subview:true }
]
};
}
init(){
this.use(plugins.Menu, {
id:"menu",
urls:{
details:"demo/details"
}
});
}
}

Check out the demo >>

UnloadGuard Plugin

The UnloadGuard plugin can be used to prevent users from leaving the view on some conditions. For example, this can be useful in the case of forms with unsaved or invalid data. The plugin can intercept the event of leaving the current view and e.g. show a confirmation dialogue.

Using the UnloadGuard plugin in Webix Jet

The syntax for using the plugin is this.use(plugin,handler).

// views/some.js
import {JetView, plugins} from "webix-jet";
...
init(){
this.use(plugins.UnloadGuard, function(){
//do something
});
}

this.use() takes two parameters:

  • the plugin name

  • the function that will define the behavior of the plugin

The UnloadGuard plugin can be used for form validation, for example. Let's have a look at a form with one input field that must not be empty:

// views/form.js
import {JetView, plugins} from "webix-jet";
export default class FormView extends JetView {
config(){
return {
view:"form", elements:[
{ view:"text", name:"email", required:true, label:"Email" },
{ view:"button", value:"save", click:() => this.show("details") }
]
};
}
}

Let's enable the UnloadGuard plugin and show a confirmation window if the input is invalid:

// views/form.js
...
init(){
this.use(plugins.UnloadGuard, () => {
if (this.getRoot().validate())
return true;
return new Promise((res, rej) => {
webix.confirm({
text: "Are you sure?",
callback: a => a ? res() : rej()
});
});
});
}

If the form input is not valid, the function returns a promise with a dialogue window. Depending on the answer, the promise either resolves and UnloadGuard lets the user go to the next view, or it rejects. No pasaran.

Check out the demo >>

Status Plugin

This plugin is useful if you want to show the status of data loading in case it takes time, to confirm success or to show an error message.

Using the Status plugin in Webix Jet

These are the status messages that you can see:

  • "Ok",

  • "Error",

  • "Connecting...".

Status is enabled with this.use() with two parameters:

  • the plugin name;

  • the plugin configuration (a string or an object).

The plugin configuration must contain at least the ID of the widget that will show the status. This is the simplest way to use the plugin to display the status of data loading into a datatable:

// views/data.js
import {JetView, plugins} from "webix-jet";
import {data} from "models/records";
export default class DataView extends JetView{
config(){
return {
rows:[
{ view:"datatable", autoConfig:true },
{ id:"app:status", view:"label" }
]
};
}
init(view){
view.parse(data);
this.use(plugins.Status, "app:status");
}
}

Status configuration can have several properties:

  • target (string) is the ID of the widget where you want to display the status message;

  • ajax (Boolean) enables asynchronous requests;

  • expire (number) defines the time after which the status message disappears (by default, 2000 ms). If you set it to 0, the status message will stay as long as the view is open;

  • data (string) defines the ID of the data component to track;

  • remote (Boolean) enables webix.remote - a protocol that allows the client component to call functions on the server directly.

// views/data.js
...
this.use(plugins.Status, {
target:"app:status",
ajax:true,
expire:5000
});

Check out the demo >>

UrlParam Plugin

The plugin allows using the URL fragments as parameters. It makes them accessible via view.getParam() and correctly weeds them out of the URL.

UrlParam is enabled with this.use() with two parameters:

  • the plugin name;

  • an array with parameter(s).

Let's consider a simple example with a parent view some and its child details:

// views/some.js
import {JetView} from "webix-jet";
export default class SomeView extends JetView{
config(){
return {
rows:[
{ $subview:true }
]
};
}
}
// views/details.js
const details = { template:"Details" };
export default details;

When loading the URL "/some/23/details", you need to treat 23 as a parameter of some. Enable the plugin the init() method of some:

// views/some.js
import {JetView,plugins} from "webix-jet";
export default class SomeView extends JetView{
...
init(){
this.use(plugins.UrlParam, ["id"])
// now when loading /some/23/details
var id = this.getParam("id");//id === 23
}
}

details will be rendered inside some, and the fragment 23 will be displayed in the address bar, but will not be resolved.

Check out the demo >>

User Plugin

The User plugin is useful for apps with authorization.

Enabling the User plugin in Webix Jet

Login through a Custom Script

This section contains guidelines for using the plugin with a custom script.

Related demos:

Enabling the Plugin

To enable the plugin, call app.use() with two parameters:

  • the plugin name,

  • the plugin configuration.

The plugin configuration must contain at least the session model:

// myapp.js
import {JetApp, plugins} from "webix-jet";
import session from "models/session";
...
app.use(plugins.User, { model: session });

The Session Model

The plugin uses a session model, check out an example. The model contains requests to php scripts for logging in, getting the current status, and logging out. The session model includes the following functions:

  • status() returns the status of the current user

// models/session.js
function status(){
return webix.ajax().post("server/login.php?status")
.then(a => a.json());
}
  • login() logs the user in, returns an object with his/her access right settings, a promise of this object or null if something went wrong. The parameters are:

    • user - username;

    • pass - password.

// models/session.js
function login(user, pass){
return webix.ajax().post("server/login.php", {
user, pass
}).then(a => a.json());
}
  • logout() logs the user out:

// models/session.js
function logout(){
return webix.ajax().post("server/login.php?logout")
.then(a => a.json());
}

Logging In

This is an example of a form for logging in:

// views/login.js
import {JetView} from "webix-jet";
export default class LoginView extends JetView{
config(){
return {
view:"form",
rows:[
{ view:"text", name:"login", label:"User Name", labelPosition:"top" },
{ view:"text", type:"password", name:"pass", label:"Password", labelPosition:"top" },
{ view:"button", value:"Login", click:()=>{
this.do_login(); //do_login() is implemented as a class method below
}, hotkey:"enter" }
],
rules:{
login:webix.rules.isNotEmpty,
pass:webix.rules.isNotEmpty
}
};
}

To implement logging in, you can use the login() method of the user service that is launched by the User plugin. login() must receive two parameters:

  • the username

  • the password

login() verifies them and if everything is fine, shows the afterLogin page (the start page by default). Otherwise, it shows an error message.

Let's define the do_login() method of LoginView that will call login():

// views/login.js
import {JetView} from "webix-jet";
export default class LoginView extends JetView{
...
do_login(){
const user = this.app.getService("user");
const form = this.getRoot();
if (form.validate()){
const data = form.getValues();
user.login(data.login, data.pass).catch(function(){
//error handler
});
}
}
...
}

Related demo:

Logging Out

The logout() method ends the current session and shows an afterLogout page (the login form by default).

Getting User Info & Checking the User Status

The getUser() method returns the data of the currently logged in user.

The getStatus() method returns the current status of the user. It can receive an optional Boolean parameter server: if it is set to true, the method will send an AJAX request to check the status.

The User service checks every 5 minutes the current user status and warns a user if the status has been changed. For example, if a user logged in and didn't perform any actions on the page during some time, the service will check the status and warn the user if it has been changed.

Plugin Configuration

Apart from the session model, the plugin configuration can include other settings:

  • login (string) is the URL of the login form, "/login" by default;

  • logout (string) is the URL for logging out, "/logout" by default;

  • afterLogin (string) is the URL shown after logging in, the start URL by default;

  • afterLogout (string) is the URL shown after logging out, "/login" by default;

  • ping (number) is the time interval for checking the current user status, 5 minutes by default;

Login with an external OAuth service ( Google, GitHub, etc. )

to be continued...

Theme plugin

This is a plugin for changing app themes.

Enabling the Plugin

This is how you can enable the plugin:

// myapp.js
import {JetApp, plugins} from "webix-jet";
...
app.use(plugins.Theme);
app.render();

The plugin has two methods:

  1. getTheme() returns the name of the current theme;

  2. setTheme(name) takes one obligatory parameter - the name of the theme - and sets the theme for the app.

Adding Stylesheets

The service locates links to stylesheets by their title attributes. Here are the stylesheets for the app, e.g.:

<!-- index.html -->
<link rel="stylesheet" title="flat" type="text/css" href="//cdn.webix.com/edge/webix.css">
<link rel="stylesheet" title="compact" type="text/css" href="//cdn.webix.com/edge/skins/compact.css">

Setting Themes

You need to provide a way for users to choose a theme. For example, let's add a segmented button:

// views/settings.js
import {JetView} from "webix-jet";
export default class SettingsView extends JetView {
config(){
return {
type:"space", rows:[
{ template:"Settings", type:"header" },
{ name:"skin", optionWidth: 120, view:"segmented", label:"Theme",
options:[
{ id:"flat-default", value:"Default" },
{ id:"flat-shady", value:"Shady" },
{ id:"compact-default", value:"Compact" }
], click:() => this.toggleTheme() /* not implemented yet, will be a method of this class */
}
{}
]
};
}
}

The option IDs of the segmented have two parts. The first part must be the same as the title attribute of the link to a stylesheet. The theme service gets the theme name from this part of the ID, locates the correct stylesheet and sets the theme.

Let's implement toggling themes as a method of the SettingsView class. The queryView locates the segmented by its name and gets the user's choice. After that, the service sets the chosen theme by adding a corresponding CSS class name to the body of the HTML page.

// views/settings.js
import {JetView} from "webix-jet";
export default class SettingsView extends JetView {
...
toggleTheme(){
const themes = this.app.getService("theme");
const value = this.getRoot().queryView({ name:"skin" }).getValue();
themes.setTheme(value);
}
}

Restoring The State of the Control

getTheme() can be used to restore the state of the segmented button after the new theme is applied. Let's get the current theme in config() and set the value of the segmented setting it to the correct value:

// views/settings.js
...
config(){
const theme = this.app.getService("theme").getTheme();
return {
...
{ name:"skin", optionWidth: 120, view:"segmented", label:"Theme", options:[
{id:"flat-default", value:"Default"},
{id:"flat-shady", value:"Shady"},
{id:"compact-default", value:"Compact"}
], click:() => this.toggleTheme(), value:theme }
...
};
}

Check out the demo >>

Locale plugin

This is a plugin for localizing apps.

Using the Locale plugin in Webix Jet

Enabling the Plugin

You can enable the Locale plugin before the app is rendered:

// myapp.js
import {JetApp, plugins} from "webix-jet";
...
app.use(plugins.Locale);
app.render();

You must create files with all the text labels in English and their translations in the locales folder. This is an example of the Spanish locale file:

// locales/es.js
export default {
"My Profile" : "Mi Perfil",
"My Account" : "Mi Cuenta",
"My Calendar" : "Mi Calendario"
};

Changing the Default Locale

The default locale is English. You can change it while enabling the plugin:

// app.js
app.use(plugins.Locale,{lang:"es"});

Applying the Locale

To translate all the text labels, you need to apply the _() method of the service to each label. The method takes one parameter - a text string. _() looks for the string in a locale file and returns the translation. E.g. this.app.getService\("locale"\).\_\("My Profile"\) will return "Mi Perfil" if Spanish is chosen.

For example, let's apply the _() method to a small menu:

// views/menu.js
import {JetView} from "webix-jet";
export default class MenuView extends JetView {
config(){
const _ = this.app.getService("locale")._;
return {
view:"menu", data:[
{ id:"profile", value:"My Profile" },
{ id:"account", value:"My Account" },
{ id:"calendar", value:"My Calendar" }
],
template:(obj)=>{
return _(obj.value)};
}
};
}
}

Dynamically Changing Locales

If you want your app to be multilingual and let the users to choose a language, you can add a control for that.

To set a new language, use the setLang() method of the locale service. setLocale() takes one parameter - the name of the locale file. When a user chooses a language, a locale file is located and the app language is changed.

Do not call setLang() in lifetime handlers of JetView! It calls app.refresh() that re-renders all the views, which will start an infinite loop.

Let's create a simple page for app settings with a segmented button that will be used to choose languages. Note that the IDs of the button options should be the same as the locale file names (e.g. "es", "en").

// views/settings.js
import {JetView} from "webix-jet";
export default class SettingsView extends JetView {
config(){
return {
type:"space", rows:[
{ template:"Settings", type:"header" },
{ name:"lang", optionWidth: 120, view:"segmented", label:"Language", options:[
{ id:"en", value:"English" },
{ id:"es", value:"Spanish" }
], click:() => this.toggleLanguage() }, //will be implemented as a method of this class
{}
]
};
}
}

toggleLanguage() is a class method that will:

  • get the value of the segmented button,

  • pass it to setLang() that will set the locale.

// views/settings.js
import {JetView} from "webix-jet";
export default class SettingsView extends JetView {
...
toggleLanguage(){
const langs = this.app.getService("locale");
const value = this.getRoot().queryView({ name:"lang" }).getValue();
langs.setLang(value);
}
}

Getting the Current Locale

To check the current language, use the getLang() method. It can be useful for restoring the value of the settings control, e.g.:

// views/settings.js
import {JetView} from "webix-jet";
export default class SettingsView extends JetView {
config(){
const lang = this.app.getService("locale").getLang();
return {
...
{ name:"lang", view:"segmented", label:_("Language"), options:[
{id:"en", value:"English"},
{id:"es", value:"Spanish"}
], click:() => this.toggleLanguage(), value:lang }
...
};
}
...
}

Check out the demo >>

Storing the Language

To restore the last chosen language when the app is opened again, set the storage setting of the plugin, e.g. you can choose the local storage:

// app.js
...
app.use(plugins.Locale, { storage:webix.storage.local });

Path for the Locale Plugin

You can also set path to a subfolder (subpath) inside the jet-locale folder, in which you want the plugin to look for translations:

// app.js
...
app.use(plugins.Locale, { path:"some" });

2. Custom Plugins

You can create a service and use it as an app-level plugin.

//helpers/state.js
export function State(app){
const service = {
getState(){
return this.state;
},
setState(state){
this.state = state;
},
state:0
};
app.setService("state", service);
}

Such services should be included into the application in the start file (e.g. myapp.js):

//myapp.js
import {state} from "helpers/state.js";
const app = new JetApp({...}).render();
app.use(state);

And any view will be able to use it as:

{ view:"button", value:"Add new", click:() => {
if(this.app.getService("state").getState())
//do something
}}