ExtJS i razvoj modernih korisničkih interfejsa
U današnje vreme se sve više i više razvijaju aplikacije koje rade na svim platformama (Windows, Linux, Mac OS). Jedan način na koji je to moguće postići je upotreba Web tehnologije za razvoj aplikacija. Koncept korišćenja Web tehnologija za razvoj aplikacija je osmišljen tako da se jednom napiše a koristi svuda. Kada sa napravi aplikacija na ovakav način, postavi se u kontejner (container) kao što je Electron ili možda sam Chromium i na taj način je dovoljno da aplikacija koja radi na Web pretraživačima može da se koristi i kao desktop aplikacija. Jedan od okvira (framework-a) koji se koriste je ExtJS razvijen od strane kompanije Sencha i služi za pravljenje profesionalnih aplikacija.
ExtJS olakšava razvoj aplikacija za rad sa velikim količinama podataka za desktop, tablet i smart uređaje. Razvijen je u programskom jeziku Javascript i sastoji se iz dva dela:
- Sencha CMD – aplikacija za upravljanje ExtJS projektima kroz komandnu liniju,
- ExtJS framework – sam framework koji je potreban Sencha CMD aplikaciji da bi operisala projektima.
Sadržaj
Sencha CMD
Sencha CMD se bavi upravljanjem životnog ciklusa projekta, minimizacijom kôda, pretvaranjem kôda iz ES6 u ES koji svaki Web pretraživač podržava, dinamičko učitavanje paketa, generisanje build-ova za progresivne Web aplikacije, itd.
Preuzimanje
Sencha CMD se preuzima sa linka: https://www.sencha.com/products/extjs/cmd-download/.
Postoje dve verzije instalacije:
- Sa JRE-om – izaberite ovu verziju u slucaju da nemate JRE ili JDK
- Bez JRE-a – izaberite ovu verziju u slucaju da imate JRE ili JDK
Instaliranje
Instalacija je jednostavna i intuitivna, samo je potrebno pratiti uputstva u toku same instalacije i neće biti nikakvih problema.
Osnovne komande
Neke od osnovnih komandi su:
- Generisanje ExtJS projekta/aplikacije
sencha -sdk generate app
- Pokretanje razvojne verzije aplikacije (potrebno je biti u direktorijumu aplikacije)
sencha app watch
- Kreiranje radne verzije aplikacije (potrebno je biti u direktorijumu aplikacije)
sencha app build
ExtJS framework
ExtJS framework sadrži preko 115 integrisanih komponenti, a neke od komponenti su: kalendar, tabele, grafikoni… Tabele i grafikoni mogu da obrade milione podataka sa lakoćom. Framework sadrži i robustan paket za podatke koji može da pribavi podatke sa bilo kog standardnog izvora. Takođe pruža mogućnost vizualizacije i analize podataka korišćenjem Sencha Pivot tabele i D3 adapter-a.
Preuzimanje
Besplatna verzija ExtJS framework-a (GPLv3) se preuzima sa linka: https://www.sencha.com/legal/gpl/
Instaliranje
Instalacija se vrši tako što se putanja ka raspakovanom ExtJS framework-u navede pri generisanju novog projekta/aplikacije
Struktura projekta
.sencha/ # Sencha-specific files (primarily configuration) app/ # Application-specific content sencha.cfg # Application configuration file for Sencha Cmd Boot.js # Private, low-level dynamic loader for JS and CSS Microloader.js # Loads app based on app.json content build-impl.xml # Standard application build script *-impl.xml # Implementations of various build phases defaults.properties # Default values and docs for build properties ext.properties # Build property values specific to Ext JS *.defaults.properties # Build properties by environment (e.g. "testing") plugin.xml # Application-level plugin for Sencha Cmd codegen.json # Data for merging generated code during upgrade workspace/ # Workspace-specific content (see below) sencha.cfg # Workspace configuration file for Sencha Cmd plugin.xml # Workspace-level plugin for Sencha Cmd` ext/ # A copy of the Ext JS SDK cmd/ # Framework-specific content for Sencha Cmd sencha.cfg # Framework configuration file for Sencha Cmd classic/ # Packages related to the Classic Toolkit classic/ # Ext JS Classic Toolkit package theme-neptune/ # Classic Toolkit Theme Package for Neptune theme-triton/ # Classic Toolkit Theme Package for Triton ... modern/ # Packages related to the Modern Toolkit modern/ # Ext JS Modern Toolkit package theme-neptune/ # Modern Toolkit Theme Package for Neptune theme-triton/ # Modern Toolkit Theme Package for Triton ... packages/ # Framework supplied packages charts/ # Charts package ux/ # Contents of "Ext.ux" namespace ... index.html # The entry point to your application app.json # Application manifest app.js # Launches the Application class app/ # Your application's source code in MVC structure model/ # Folder for application model classes store/ # Folder for application stores view/ # Folder for application view classes main/ # Folder for the classes implementing the Main View Main.js # The Main View MainModel.js # The `Ext.app.ViewModel` for the Main View MainController.js # The `Ext.app.ViewController` for the Main View Application.js # The `Ext.app.Application` class packages/ # Sencha Cmd packages workspace.json # Workspace JSON descriptor build/ # The folder where build output is placed
Razvoj aplikacije i razvojni šablon
Sam razvoj je moguć u tri direktorijuma:
app/
– razvoj za classic i modern verzijeclassic/
– razvoj samo za classic verzijumodern/
– razvoj samo za modern verziju
Aplikaciju je moguće razvijati koristeći MVC i/ili MVVM razvojni šablon.
Dokumentacija
Dokumentacija se nalazi na linku: https://docs.sencha.com
U okviru dokumentacije su detaljno objašnjeni i Sencha CMD i ExtJS framework. U ExtJS dokumentaciji se takođe nalaze primeri za svaku komponentu.
Primer – Kalkulator
Kao primer korišćenja ovog framework-a ćemo napraviti aplikaciju pod nazivom Kalkulator. U okviru ove aplikacije ćemo iskoristiti Viewport
, Window
, Button
, View
, ViewModel
, ViewController
i Table Layout
. Na početku generišemo novu aplikaciju koristeći komandu navedenu u prethodnom poglavlju. Nazvaćemo je Calculator u našem slučaju.
U direktorijumu classic/src/view
ćemo napraviti novu klasu Viewport
koja proširuje Ext.container.Viewport
i u njoj ćemo za početak da imamo samo osnovnu konfiguraciju:
Ext.define('Calculator.view.Viewport', { extend: 'Ext.container.Viewport',` requires: ['Calculator.view.main.Main'], items: [{ xtype: 'main' }] });
Items
konfiguracija služi da se navedu komponente koje će se nalaziti na ovom Viewport
-u, a xtype
je naziv komponente, u našem slučaju main
. Nakon što smo napravili Viewport
klasu, potrebno je izmeniti Main
klasu u direktorijumu classic/src/view/main
tako da izgleda ovako:
Ext.define('Calculator.view.main.Main', { extend: 'Ext.window.Window', xtype: 'main',` requires: [ 'Calculator.view.main.MainModel' ], autoShow: true, controller: 'main', resizable: false, viewModel: { type: 'main' }, width: 200, height: 200 });
Ova klasa nam je Window
(proširuje Window
klasu od ExtJS framework-a) i veličine je 200×200. Da bi ovo sve do što smo do sada uradili zapravo bilo vidljivo, potrebno je dodati Viewport
klasu u app.js
koji se nalazi u samom direktorijumu aplikacije. Ovaj fajl bi trebalo da izgleda ovako:
/* * This file is generated and updated by Sencha Cmd. You can edit this file as * needed for your application, but these edits will have to be merged by * Sencha Cmd when upgrading. */ Ext.application({ name: 'Calculator', extend: 'Calculator.Application', requires: [ 'Calculator.view.Viewport' ], // The name of the initial view to create. With the classic toolkit this class // will gain a "viewport" plugin if it does not extend Ext.Viewport. With the // modern toolkit, the main view will be added to the Viewport. // mainView: 'Calculator.view.Viewport' //------------------------------------------------------------------------- // Most customizations should be made to Calculator.Application. If you need to // customize this file, doing so below this section reduces the likelihood // of merge conflicts when upgrading to new versions of Sencha Cmd. //------------------------------------------------------------------------- });
Aplikacija trenutno izgleda ovako:
Ovo kaže našoj aplikaciji koji je početni View
koji se učitava. Dalje je potrebno da dovršimo izgled Kalkulatora. U našoj Main
klasi ćemo dodati komponente koje su nam potrebne (Button
-i, Header
) i da postavimo odgovarajući Layout
(raspored). Pored komponenti, imamo Defaults
konfiguraciju, koja označava vrednosti konfiguracija za ostale komponente koje koristimo. U našem slučaju smo rekli da su sve komponente dimenzija 50×50, da imaju CSS klasu btn
i da imaju onClickNumber
handler (funkcija koja se poziva kada se klikne na Button
). konfiguracije koje su postavljene kao default (podrazumevane) mogu da se izmene u okviru same komponente (na primer button-i za operacije imaju drugi handler i drugu CSS klasu). Nakon svih izmena naša klasa bi trebalo da izgleda ovako:
Ext.define('Calculator.view.main.Main', { extend: 'Ext.window.Window', xtype: 'main',` requires: [ 'Calculator.view.main.MainModel' ], autoShow: true, controller: 'main', defaults: { width: 50, height: 50, cls: 'btn', handler: 'onClickNumber' }, defaultType: 'button', header: { items: [{ xtype: 'displayfield', bind: { value: '{display}' }, cls: 'display', colspan: 4, height: 60, padding: 0, width: 200 }] }, layout: { type: 'table', columns: 4 }, resizable: false, viewModel: { type: 'main' }, items: [{ cls: 'btn-green', colspan: 2, handler: 'onClickClear', text: 'C', width: 100 }, { cls: 'btn-green', handler: 'onClickChangeSign', text: '+/-' }, { cls: 'btn-orange', handler: 'onClickOp', text: '÷' }, { text: '7' }, { text: '8' }, { text: '9' }, { cls: 'btn-orange', handler: 'onClickOp', text: '×' }, { text: '4' }, { text: '5' }, { text: '6' }, { cls: 'btn-orange', handler: 'onClickOp', text: '-' }, { text: '1' }, { text: '2' }, { text: '3' }, { cls: 'btn-orange', handler: 'onClickOp', text: '+' }, { colspan: 2, text: '0', width: 100 }, { handler: 'onClickDot', text: '.' }, { cls: 'btn-orange', handler: 'onClickOp', text: '=' }] });
Nakon Main View
-a, prelazimo na ViewModel
koji nam služi za dvosmerno povezivanje podataka koji se prikazuju korisniku sa View
-om. ViewModel
se nalazi u direktorijumu app/view/main
, pod nazivom MainModel
. U njemu ćemo da definišemo samo promenljivu za rezultat koja će da se prikaže korisniku. On bi trebalo ovako da izgleda ovako:
Ext.define('Calculator.view.main.MainModel', { extend: 'Ext.app.ViewModel', alias: 'viewmodel.main', data: { display: 0.0 } });
Najzad nam je ostao još samo ViewController
, odnosno kreiranje svih onih handler funkcija koje smo naveli u Main View
-u. ViewController
se nalazi u direktorijumu app/view/main
pod nazivom MainController
. U okviru njega ćemo da definišemo našu konfiguraciju State
, koja će pamtiti trenutno stanje (trenutna operacija, trenutni rezultat, operande…) i funkcije. On bi trebao da ovako da izgleda:
Ext.define('Calculator.view.main.MainController', { extend: 'Ext.app.ViewController', alias: 'controller.main', state: { operatorClicked: false, selectedOperator: null, dotClicked: false, op1: 0, numberClicked: false, sign: true, decimal: false }, onClickClear: function(){ var vm = this.getViewModel(); vm.set('display', '0'); this.state.selectedOperator = null; this.state.op1 = 0; this.state.isPositive = true; this.state.decimal = false; this.state.sign = true; }, onClickChangeSign: function(){ var vm = this.getViewModel(); var cur = vm.get('display'); if (cur != '0') { if (this.state.sign === true) { vm.set('display', '-' + cur); } else { vm.set('display', cur.toString().substring(1)); } } this.state.sign = !this.state.sign; }, onClickOp: function(btn){ if (this.state.selectedOperator != null && this.state.numberClicked === true) { var vm = this.getViewModel(); var op2 = parseFloat(vm.get('display')); var op1 = parseFloat(this.state.op1); var result = 0; switch (this.state.selectedOperator) { case '+': result = op1 + op2; break; case '-': result = op1 - op2; break; case '×': result = op1 * op2; break; case '÷': result = op1 / op2; break; } vm.set('display', Math.round(result * 100) / 100); this.state.selectedOperator = null; } if (btn.text != '=') { this.state.operatorClicked = true; } this.state.selectedOperator = btn.text; this.state.numberClicked = false; }, onClickDot: function(btn){ if (this.state.decimal === false) { var vm = this.getViewModel(); vm.set('display', vm.get('display') + '.'); } }, onClickNumber: function(btn){ this.state.numberClicked = true; if (this.state.selectedOperator === '=') { this.onClickClear(); } var vm = this.getViewModel(); if (this.state.operatorClicked === true) { this.state.op1 = vm.get('display'); vm.set('display', btn.text); this.state.operatorClicked = false; } else { var cur = vm.get('display'); if (cur == '0') { cur = ''; } vm.set('display', cur + btn.text); } } });
Aplikacija trenutno izgleda ovako:
Nakon svega ovoga smo napravili Kalkulator koji ne izgleda baš najbolje (trenutno je potpuno plav ako ga pokrenete sa Sencha CMD). Da bismo poboljšali izgled, dodaćemo CSS (u slučaju ExtJS framework-a, koristi se SASS). SASS fajl koji nama treba za aplikaciju se nalazi u direktorijumu classic/sass/src/view/main
pod nazivom Main
. Pošto cilj ovog članka nije CSS/SASS, neće biti dato objašnjenja za ovaj deo. Ovaj fajl bi trebao da izgleda ovako:
.btn:hover { background-color: #C7C7C7 !important; } .btn-orange:hover { background-color: #D07B32 !important; } .btn-green:hover { background-color: #A1C9AC !important; } .btn, .btn.x-btn-focus.x-btn-default-small { background-color: #E0E0E0; } .btn-orange, .btn-orange.x-btn-focus.x-btn-default-small { background-color: #F5923E; } .btn-green, .btn-green.x-btn-focus.x-btn-default-small { background-color: #AFDCBB; } .x-btn-focus.x-btn-default-small, .x-btn-focus.x-btn-over.x-btn-default-small { box-shadow: none; } .btn-orange span, .display div { color: #FFFFFF !important; } .display { background-color: #69787F; padding: 0px !important; } .btn span, .btn-orange span, .btn-green span { font-size: 18px; line-height: 22px; color: #000000; } .btn-orange, .btn, .display, .btn-green { border-radius: 0; border-color: #89898C; border-width: 0.5px; } .display div { font-size: 24px; line-height: 32px; text-align: right; padding-right: 5px; padding-top: 10px; } td div { margin-bottom: 0px !important; } .x-window-header-default-top { padding: 0px !important; top: 0px !important; left: 0px !important; }
Preuzimanje
Urađenu aplikaciju možete da preuzmete sa linka Calculator.tar.gz