├── .travis.yml ├── babel.config.js ├── lerna.json ├── demo ├── bulma │ ├── images │ │ └── no-image.png │ ├── scripts │ │ ├── mixins │ │ │ └── demo-page.mixin.js │ │ ├── app.js │ │ ├── components │ │ │ ├── about │ │ │ │ └── demo-about.component.js │ │ │ ├── base │ │ │ │ └── demo-base.component.js │ │ │ ├── home │ │ │ │ ├── demo-home.component.js │ │ │ │ └── demo-description.component.js │ │ │ ├── widgets │ │ │ │ ├── demo-input.component.js │ │ │ │ ├── demo-user.component.js │ │ │ │ ├── demo-select.component.js │ │ │ │ ├── demo-widgets.component.js │ │ │ │ ├── demo-grid.component.js │ │ │ │ └── demo-todo.component.js │ │ │ ├── demo-layout.component.js │ │ │ ├── demo-header.component.js │ │ │ └── demo-menu.component.js │ │ └── services │ │ │ └── todo.service.js │ ├── css │ │ └── main.css │ └── index.html └── bootstrap-ui │ ├── scripts │ ├── app.js │ └── components │ │ ├── bootstrap-ui-header.component.js │ │ └── bootstrap-ui-layout.component.js │ └── index.html ├── packages ├── core │ ├── package-lock.json │ ├── src │ │ ├── asset-types │ │ │ ├── class.js │ │ │ ├── mixin.js │ │ │ └── base.js │ │ ├── statics │ │ │ ├── binder │ │ │ │ ├── reserved-keys.js │ │ │ │ ├── observable.js │ │ │ │ ├── util.js │ │ │ │ ├── binding.js │ │ │ │ ├── view.js │ │ │ │ ├── parser.js │ │ │ │ ├── observableArray.js │ │ │ │ └── index.js │ │ │ ├── events.js │ │ │ └── dom.js │ │ ├── utils │ │ │ ├── object.js │ │ │ ├── string.js │ │ │ └── array.js │ │ └── index.js │ ├── rollup.config.js │ ├── __tests__ │ │ ├── binders │ │ │ ├── value.test.js │ │ │ ├── text.test.js │ │ │ ├── if.test.js │ │ │ ├── ifnot.test.js │ │ │ ├── attr.test.js │ │ │ ├── visible.test.js │ │ │ └── interpolation.test.js │ │ ├── core.test.js │ │ └── components │ │ │ └── components.test.js │ ├── package.json │ └── README.md ├── http │ ├── __tests__ │ │ └── http.test.js │ ├── package-lock.json │ ├── src │ │ ├── response.js │ │ ├── constants.js │ │ ├── request.js │ │ ├── index.js │ │ └── factory.js │ ├── rollup.config.js │ ├── README.md │ └── package.json └── bootstrap-ui │ ├── __tests__ │ └── bootstrap-ui.test.js │ ├── __mocks__ │ └── jquery.js │ ├── src │ ├── index.js │ ├── components │ │ ├── ui-button-toolbar.component.js │ │ ├── ui-button-group.component.js │ │ ├── index.js │ │ ├── ui-collapse.component.js │ │ ├── ui-breadcrumb.component.js │ │ ├── ui-progress.component.js │ │ ├── ui-select.component.js │ │ ├── ui-form.component.js │ │ ├── ui-button.component.js │ │ ├── ui-alert.component.js │ │ ├── ui-grid.component.js │ │ ├── ui-navbar.component.js │ │ ├── ui-input-group.component.js │ │ ├── ui-carousel.component.js │ │ ├── ui-container.component.js │ │ ├── ui-card.component.js │ │ ├── ui-dropdown.component.js │ │ ├── ui-list-group.component.js │ │ ├── ui-input.component.js │ │ ├── ui-nav.component.js │ │ └── ui-modal.component.js │ ├── mixins │ │ └── form-field.mixin.js │ └── base │ │ └── ui-base.component.js │ ├── rollup.config.js │ ├── package-lock.json │ ├── package.json │ └── README.md ├── .gitignore ├── .eslintrc.json ├── .github └── ISSUE_TEMPLATE │ └── bug_report.md ├── scripts └── rollup-common.config.js ├── LICENSE ├── package.json ├── PACKAGES.md ├── CONTRIBUTING.md └── README.md /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "lts/*" -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ "@babel/preset-env"] 3 | } -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "packages/*" 4 | ], 5 | "version": "2.1.5" 6 | } 7 | -------------------------------------------------------------------------------- /demo/bulma/images/no-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProticM/plazar-js/HEAD/demo/bulma/images/no-image.png -------------------------------------------------------------------------------- /packages/core/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@plazarjs/core", 3 | "version": "2.1.4", 4 | "lockfileVersion": 1 5 | } 6 | -------------------------------------------------------------------------------- /packages/core/src/asset-types/class.js: -------------------------------------------------------------------------------- 1 | const cls = { 2 | type: 'class' 3 | // common 4 | }; 5 | 6 | export default cls; -------------------------------------------------------------------------------- /demo/bulma/scripts/mixins/demo-page.mixin.js: -------------------------------------------------------------------------------- 1 | pz.define('page-mixin', { 2 | ownerType: 'mixin', 3 | autoLoad: true 4 | }); -------------------------------------------------------------------------------- /packages/core/src/asset-types/mixin.js: -------------------------------------------------------------------------------- 1 | const mixin = { 2 | type: 'mixin' 3 | // common 4 | }; 5 | 6 | export default mixin; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/**/* 2 | .vscode/**/* 3 | /packages/*/node_modules 4 | /packages/*/dist 5 | /packages/*/LICENSE 6 | *.log 7 | *.cache -------------------------------------------------------------------------------- /demo/bulma/scripts/app.js: -------------------------------------------------------------------------------- 1 | pz.defineApplication({ 2 | name: 'Demo App', 3 | namespace: 'demoApp', 4 | components: ['layout-component'], 5 | init: function() { 6 | console.log('App Initialized'); 7 | } 8 | }); -------------------------------------------------------------------------------- /demo/bulma/scripts/components/about/demo-about.component.js: -------------------------------------------------------------------------------- 1 | pz.define('about-component', { 2 | ownerType: 'base-component', 3 | mixins: ['page-mixin'], 4 | template: '

Demo Application

', 5 | renderTo: 'section.app-body' 6 | }); -------------------------------------------------------------------------------- /packages/core/src/statics/binder/reserved-keys.js: -------------------------------------------------------------------------------- 1 | const reservedKeys = { 2 | idx: '$index', 3 | current: '$current', 4 | root: '$root', 5 | as: ' as ', 6 | observed: '$observed', 7 | view: '$view' 8 | }; 9 | 10 | export default reservedKeys; -------------------------------------------------------------------------------- /packages/http/__tests__/http.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import http from '../src'; 4 | 5 | describe('http', () => { 6 | it('should have an initialization function defined', () => { 7 | expect(http.init).toBeDefined(); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /packages/bootstrap-ui/__tests__/bootstrap-ui.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import bootstrapUi from '../src'; 4 | 5 | describe('bootstrap-ui', () => { 6 | it('should have an initialization function defined', () => { 7 | expect(bootstrapUi.init).toBeDefined(); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /demo/bootstrap-ui/scripts/app.js: -------------------------------------------------------------------------------- 1 | pz.defineApplication({ 2 | name: 'Bootstrap UI Demo App', 3 | namespace: 'bootstrapUIDemoApp', 4 | components: ['bootstrap-ui-layout-component', 'bootstrap-ui-header-component'], 5 | init: function() { 6 | console.log('App Initialized'); 7 | } 8 | }); -------------------------------------------------------------------------------- /packages/bootstrap-ui/__mocks__/jquery.js: -------------------------------------------------------------------------------- 1 | // Taken from the jquery module. Add method mocks when required 2 | const jQuery = function(selector, context) { 3 | return new jQuery.fn(selector, context); 4 | }; 5 | 6 | jQuery.fn = jQuery.prototype = { 7 | constructor: jQuery 8 | }; 9 | 10 | export default jQuery; -------------------------------------------------------------------------------- /packages/http/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@plazarjs/http", 3 | "version": "2.1.4", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@plazarjs/core": { 8 | "version": "2.1.4", 9 | "resolved": "https://registry.npmjs.org/@plazarjs/core/-/core-2.1.4.tgz", 10 | "integrity": "sha512-F9H2HY4MTgG10765hP9e9aKhGoofc/wOM4Enh8+Hv+45YWEJmLVFWJGWn9Vxkcnxy/7O5QKWncXO3/1Sr/Ztdg==" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/bootstrap-ui/src/index.js: -------------------------------------------------------------------------------- 1 | import base from './base/ui-base.component'; 2 | import * as components from './components'; 3 | import pz from '@plazarjs/core'; 4 | 5 | const bootstrapUi = { 6 | init: () => { 7 | pz.storeDefinition(base.$type, base); 8 | for(let component in components) { 9 | let def = components[component]; 10 | pz.storeDefinition(def.$type, def); 11 | }; 12 | } 13 | }; 14 | 15 | export default bootstrapUi; -------------------------------------------------------------------------------- /packages/http/src/response.js: -------------------------------------------------------------------------------- 1 | import pz from '@plazarjs/core'; 2 | import { types, requestStatus } from './constants'; 3 | 4 | class response { 5 | constructor(request, dataType) { 6 | this.request = request; 7 | let dt = request.status == requestStatus.ok && !pz.isEmpty(dataType) ? dataType.toLowerCase() : 'text'; 8 | this.data = (dt == types.data.json ? pz.toJSON(request.responseText) : request.responseText); 9 | this.dataType = dt; 10 | } 11 | } 12 | 13 | export default response; -------------------------------------------------------------------------------- /packages/core/rollup.config.js: -------------------------------------------------------------------------------- 1 | import commonRollup from '../../scripts/rollup-common.config'; 2 | import path from 'path'; 3 | import pck from './package.json'; 4 | 5 | const src = path.resolve(__dirname, 'src') 6 | const dist = path.resolve(__dirname, 'dist'); 7 | const config = Object.assign({}, commonRollup.config); 8 | 9 | config.input = path.resolve(src, 'index.js'); 10 | config.output.name = pck.rollupName; 11 | config.output.banner = commonRollup.buildBanner(pck); 12 | config.output.file = path.resolve(dist, (pck.rollupFileName + '.js')); 13 | 14 | export default config; -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true 5 | }, 6 | "extends": "eslint:recommended", 7 | "parserOptions": { 8 | "ecmaVersion": 2015, 9 | "sourceType": "module" 10 | }, 11 | "rules": { 12 | "indent": [ 13 | "error", 14 | "tab" 15 | ], 16 | "linebreak-style": [ 17 | "error", 18 | "windows" 19 | ], 20 | "quotes": [ 21 | "error", 22 | "single" 23 | ], 24 | "semi": [ 25 | "error", 26 | "always" 27 | ] 28 | } 29 | } -------------------------------------------------------------------------------- /demo/bulma/scripts/components/base/demo-base.component.js: -------------------------------------------------------------------------------- 1 | pz.define('base-component', { 2 | ownerType: 'component', 3 | changeView: function(componentType) { 4 | var oldC, layoutC = pz.getInstanceOf('layout-component'); 5 | if(pz.isEmpty(componentType) || componentType == layoutC.currentView) { 6 | return; 7 | }; 8 | 9 | oldC = pz.getInstanceOf(layoutC.currentView); 10 | if(!pz.isEmpty(oldC)) { 11 | oldC.destroy(); 12 | }; 13 | 14 | layoutC.currentView = componentType; 15 | layoutC.addChild({ 16 | type: componentType 17 | }); 18 | } 19 | }); -------------------------------------------------------------------------------- /packages/http/rollup.config.js: -------------------------------------------------------------------------------- 1 | import commonRollup from '../../scripts/rollup-common.config'; 2 | import path from 'path'; 3 | import pck from './package.json'; 4 | 5 | const src = path.resolve(__dirname, 'src') 6 | const dist = path.resolve(__dirname, 'dist'); 7 | const config = Object.assign({}, commonRollup.config); 8 | 9 | config.input = path.resolve(src, 'index.js'); 10 | config.output.name = pck.rollupName; 11 | config.output.banner = commonRollup.buildBanner(pck); 12 | config.output.file = path.resolve(dist, (pck.rollupFileName + '.js')); 13 | config.external = ['@plazarjs/core']; 14 | config.output.globals = { 15 | '@plazarjs/core': 'pz' 16 | }; 17 | export default config; -------------------------------------------------------------------------------- /packages/core/__tests__/binders/value.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import pz from '../../src'; 4 | 5 | describe('value binder', () => { 6 | let componentDef, component; 7 | 8 | beforeAll(() => { 9 | componentDef = pz.define('test-component', { 10 | ownerType: 'component', 11 | renderTo: 'body', 12 | template: '', 13 | autoLoad: true, 14 | viewModel: { 15 | name: 'foo' 16 | } 17 | }); 18 | component = componentDef.create(); 19 | }); 20 | 21 | it('should check if value is foo', () => { 22 | expect(component.html.value).toBe('foo'); 23 | }); 24 | }); -------------------------------------------------------------------------------- /packages/core/src/utils/object.js: -------------------------------------------------------------------------------- 1 | import pz from '../core'; 2 | 3 | const objectUtil = { 4 | assignTo: (target, source, clone) => { 5 | return pz.assignTo(target, source, clone); 6 | }, 7 | 8 | clone: function (obj) { 9 | return this.assignTo({}, obj); 10 | }, 11 | 12 | getKeys: Object.keys, // create polyfill? 13 | 14 | getValues: (obj) => { 15 | 16 | let vals = [], prop, 17 | valuesSupported = ('values' in Object); 18 | 19 | if (valuesSupported) { 20 | return Object.values(obj); 21 | } 22 | 23 | for (prop in obj) { 24 | if (obj.hasOwnProperty(prop)) { 25 | vals.push(obj[prop]); 26 | } 27 | } 28 | 29 | return vals; 30 | } 31 | }; 32 | 33 | export default objectUtil; -------------------------------------------------------------------------------- /packages/core/__tests__/binders/text.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import pz from '../../src'; 4 | 5 | describe('text binder', () => { 6 | let componentDef, component; 7 | 8 | beforeAll(() => { 9 | componentDef = pz.define('test-component', { 10 | ownerType: 'component', 11 | renderTo: 'body', 12 | template: '', 13 | autoLoad: true, 14 | viewModel: { 15 | message: 'foo' 16 | } 17 | }); 18 | component = componentDef.create(); 19 | }); 20 | 21 | it('should check if text is foo', () => { 22 | expect(component.html.innerHTML).toBe('foo'); 23 | }); 24 | }); -------------------------------------------------------------------------------- /packages/core/__tests__/binders/if.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import pz from '../../src'; 4 | 5 | describe('if binder', () => { 6 | let componentDef, component; 7 | 8 | beforeAll(() => { 9 | componentDef = pz.define('test-component', { 10 | ownerType: 'component', 11 | renderTo: 'body', 12 | template: '
{message}
', 13 | autoLoad: true, 14 | viewModel: { 15 | ok: true, 16 | message: 'foo' 17 | } 18 | }); 19 | component = componentDef.create(); 20 | }); 21 | 22 | it('should check if span is rendered', () => { 23 | expect(component.html.innerHTML).toBe('foo'); 24 | }); 25 | }); -------------------------------------------------------------------------------- /packages/core/__tests__/binders/ifnot.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import pz from '../../src'; 4 | 5 | describe('ifnot binder', () => { 6 | let componentDef, component; 7 | 8 | beforeAll(() => { 9 | componentDef = pz.define('test-component', { 10 | ownerType: 'component', 11 | renderTo: 'body', 12 | template: '
{message}
', 13 | autoLoad: true, 14 | viewModel: { 15 | ok: false, 16 | message: 'foo' 17 | } 18 | }); 19 | component = componentDef.create(); 20 | }); 21 | 22 | it('should check if span is rendered', () => { 23 | expect(component.html.innerHTML).toBe('foo'); 24 | }); 25 | }); -------------------------------------------------------------------------------- /packages/core/src/index.js: -------------------------------------------------------------------------------- 1 | import pz from './core'; 2 | import base from './asset-types/base'; 3 | import cls from './asset-types/class'; 4 | import component from './asset-types/component'; 5 | import mixin from './asset-types/mixin'; 6 | import binder from './statics/binder'; 7 | import dom from './statics/dom'; 8 | import events from './statics/events'; 9 | import objectUtils from './utils/object'; 10 | import arrayUtils from './utils/array'; 11 | import stringUtils from './utils/string'; 12 | 13 | pz.obj = objectUtils; 14 | pz.arr = arrayUtils; 15 | pz.str = stringUtils; 16 | pz.binder = binder; 17 | pz.dom = dom(); 18 | pz.events = events(); 19 | pz.base = base; 20 | pz.component = base.extend(component); 21 | pz.class = base.extend(cls); 22 | pz.mixin = base.extend(mixin); 23 | 24 | export default pz; -------------------------------------------------------------------------------- /packages/core/src/statics/events.js: -------------------------------------------------------------------------------- 1 | const events = () => { 2 | let _subscriptions = {}; 3 | let _hasOwn = _subscriptions.hasOwnProperty; 4 | 5 | return { 6 | subscribe: (name, listener) => { 7 | let index; 8 | 9 | if (!_hasOwn.call(_subscriptions, name)) { 10 | _subscriptions[name] = []; 11 | } 12 | 13 | index = _subscriptions[name].push(listener) - 1; 14 | 15 | return { 16 | remove: () => { 17 | delete _subscriptions[name][index]; 18 | } 19 | }; 20 | }, 21 | publish: (name, args) => { 22 | 23 | if (!_hasOwn.call(_subscriptions, name)) { 24 | return; 25 | } 26 | 27 | _subscriptions[name].forEach((subscription) => { 28 | subscription((args != undefined ? args : null)); 29 | }); 30 | } 31 | }; 32 | 33 | }; 34 | 35 | export default events; -------------------------------------------------------------------------------- /packages/bootstrap-ui/rollup.config.js: -------------------------------------------------------------------------------- 1 | import commonRollup from '../../scripts/rollup-common.config'; 2 | import path from 'path'; 3 | import pck from './package.json'; 4 | 5 | const src = path.resolve(__dirname, 'src') 6 | const dist = path.resolve(__dirname, 'dist'); 7 | const config = Object.assign({}, commonRollup.config); 8 | 9 | config.input = path.resolve(src, 'index.js'); 10 | config.output.name = pck.rollupName; 11 | config.output.banner = commonRollup.buildBanner(pck); 12 | config.output.file = path.resolve(dist, (pck.rollupFileName + '.js')); 13 | config.external = ['jquery', '@plazarjs/core']; // Include only jquery and @plazarjs/core into dist as external. popper.js and bootstrap are expected to be added later 14 | config.output.globals = { 15 | 'jquery': '$', 16 | '@plazarjs/core': 'pz' 17 | }; 18 | export default config; -------------------------------------------------------------------------------- /packages/http/README.md: -------------------------------------------------------------------------------- 1 | # plazarjs/http 2 | 3 | > PlazarJS http/ajax helper methods. 4 | 5 | ## Usage - es 6 | 7 | ```javascript 8 | $ npm install @plazarjs/http 9 | ``` 10 | 11 | Create a folder called `plugins`. Inside of it create a file called `http.js` and copy the following snippet: 12 | 13 | ```javascript 14 | import pz from '@plazarjs/core'; 15 | import pzHttp from '@plazarjs/http'; 16 | pz.plugin(pzHttp); 17 | ``` 18 | 19 | ## Usage - cdn 20 | 21 | ```html 22 | // include the required scripts before closing the body tag 23 | 24 | 25 | 26 | // initialize the plugin 27 | 30 | ``` 31 | 32 | Detailed documentation can be found here. -------------------------------------------------------------------------------- /packages/core/__tests__/binders/attr.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import pz from '../../src'; 4 | 5 | describe('attr binder', () => { 6 | let componentDef, component; 7 | 8 | beforeAll(() => { 9 | componentDef = pz.define('test-component', { 10 | ownerType: 'component', 11 | renderTo: 'body', 12 | template: '', 13 | autoLoad: true, 14 | viewModel: { 15 | url: 'https://www.plazarjs.com', 16 | id: 'my-link' 17 | } 18 | }); 19 | component = componentDef.create(); 20 | }); 21 | 22 | it('should check the attribute value', () => { 23 | expect(component.html.getAttribute('href')).toBe('https://www.plazarjs.com'); 24 | expect(component.html.getAttribute('data-id')).toBe('my-link'); 25 | }); 26 | }); -------------------------------------------------------------------------------- /packages/http/src/constants.js: -------------------------------------------------------------------------------- 1 | 2 | const minConfigNotProfided = 'Minimal configuration for ajax call was not provided. Please check you setup for following options [url], [method]', 3 | requestStates = { 4 | done: 4 5 | }, requestStatus = { 6 | abort: 0, 7 | ok: 200 8 | }, types = { 9 | post: 'POST', 10 | get: 'GET', 11 | put: 'PUT', 12 | delete: 'DELETE', 13 | data: { 14 | json: 'json', 15 | html: 'html' 16 | } 17 | }, 18 | optionsRequred = 'Can not instantiate http request without options defined', 19 | notAnObject = '{0} property must be an object containing key/value pairs.'; 20 | 21 | let requests = {}; 22 | 23 | export { 24 | minConfigNotProfided, 25 | requestStates, 26 | requestStatus, 27 | types, 28 | optionsRequred, 29 | notAnObject, 30 | requests 31 | } -------------------------------------------------------------------------------- /demo/bulma/scripts/components/home/demo-home.component.js: -------------------------------------------------------------------------------- 1 | pz.define('home-component', { 2 | ownerType: 'base-component', 3 | mixins: ['page-mixin'], 4 | template: '
Welcome to PlazarJS Demo Application. This demo uses Bulma CSS Framework ' + 5 | 'for styling therefore make sure that your browser supports ' + 6 | 'Flexbox. Note that usage of this framework is not required and it\'\s used to simplify this demo while focusing on PlazarJS features. ' + 7 | 'We built this demo by using inline and pre rendered templates, but every template can be loaded asynchronously from the server while initializing component.' + 8 | '
', 9 | renderTo: 'section.app-body' 10 | }); -------------------------------------------------------------------------------- /packages/core/__tests__/binders/visible.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import pz from '../../src'; 4 | 5 | describe('visible binder', () => { 6 | let componentDef, component; 7 | 8 | beforeAll(() => { 9 | componentDef = pz.define('test-component', { 10 | ownerType: 'component', 11 | renderTo: 'body', 12 | template: '
{message}
', 13 | autoLoad: true, 14 | viewModel: { 15 | ok: true, 16 | message: 'foo' 17 | } 18 | }); 19 | component = componentDef.create(); 20 | }); 21 | 22 | it('should check if span is visible', () => { 23 | expect(component.html.innerHTML).toBe('foo'); 24 | component.viewModel.ok = false; 25 | expect(component.html.innerHTML).toBe('foo'); 26 | }); 27 | }); -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve PlazarJS 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | 1. Describe the steps how to reproduce the behavior 15 | 2. If applicable, create a JSFiddle 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Desktop (please complete the following information):** 24 | - OS: [e.g. iOS] 25 | - Browser [e.g. chrome, safari] 26 | - Version [e.g. 22] 27 | 28 | **Smartphone (please complete the following information):** 29 | - Device: [e.g. iPhone6] 30 | - OS: [e.g. iOS8.1] 31 | - Browser [e.g. stock browser, safari] 32 | - Version [e.g. 22] 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /packages/core/__tests__/core.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import pz from '../src/core'; 4 | 5 | describe('core', function() { 6 | let obj = {}, fn = () => {}, array = [], und = undefined, 7 | n = null, emptyStr = '', str = 'test'; 8 | 9 | it('should be object', () => { 10 | expect(pz.isObject(obj)).toBe(true); 11 | }); 12 | 13 | it('should be function', () => { 14 | expect(pz.isFunction(fn)).toBe(true); 15 | }); 16 | 17 | it('should be array', () => { 18 | expect(pz.isArray(array)).toBe(true); 19 | }); 20 | 21 | it('should be string', () => { 22 | expect(pz.isString(str)).toBe(true); 23 | }); 24 | 25 | it('should be empty', () => { 26 | expect(pz.isEmpty(und)).toBe(true); 27 | expect(pz.isEmpty(n)).toBe(true); 28 | expect(pz.isEmpty(emptyStr)).toBe(true); 29 | }); 30 | 31 | it('should not be empty', () => { 32 | expect(pz.isEmpty(emptyStr, true)).toBe(false); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /demo/bulma/scripts/components/home/demo-description.component.js: -------------------------------------------------------------------------------- 1 | pz.define('description-component', { 2 | ownerType: 'base-component', 3 | mixins: ['page-mixin'], 4 | template: '
PlazarJS is a versatile framework built to enrich the developer experience in terms of simplicity and speed of application development. The framework itself has no dependencies and by leaning on Object-Oriented-Principles (OOP) it can easily be used to create a large Single-Page Application or it can be integrated to a portion of a web page where dynamic workflow is required. It is written in plain JavaScript and built to be flexible. For example, in ReactJS everything is JavaScript, and Angular has a forceful opinion about how your application should be constructed. PlazarJS is designed to help you build the application the way you want it without forcing you to follow a path you do not think is suitable for the application you are developing. The main focus is on good old trio, HTML, CSS and JavaScript.
', 5 | renderTo: 'section.app-body' 6 | }); -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@plazarjs/core", 3 | "rollupName": "pz", 4 | "rollupFileName": "core", 5 | "version": "2.1.5", 6 | "description": "PlazarJS core package", 7 | "keywords": [ 8 | "javascript", 9 | "plazarjs", 10 | "core", 11 | "framework", 12 | "components", 13 | "oop" 14 | ], 15 | "author": "Miloš Protić (https://github.com/ProticM)", 16 | "homepage": "http://www.plazarjs.com/", 17 | "license": "MIT", 18 | "main": "dist/core.js", 19 | "directories": { 20 | "lib": "dist", 21 | "test": "__tests__" 22 | }, 23 | "files": [ 24 | "dist" 25 | ], 26 | "repository": { 27 | "type": "git", 28 | "url": "https://github.com/ProticM/plazar-js" 29 | }, 30 | "scripts": { 31 | "uglify": "uglifyjs --mangle --comments /^!/ --output dist/core.min.js dist/core.js" 32 | }, 33 | "bugs": { 34 | "url": "https://github.com/ProticM/plazar-js/issues" 35 | }, 36 | "publishConfig": { 37 | "access": "public" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /scripts/rollup-common.config.js: -------------------------------------------------------------------------------- 1 | import resolve from 'rollup-plugin-node-resolve'; 2 | import commonjs from 'rollup-plugin-commonjs'; 3 | import babel from 'rollup-plugin-babel'; 4 | 5 | export default { 6 | config: { 7 | input: '', 8 | output: { 9 | name: '', 10 | file: '', 11 | format: 'umd' 12 | }, 13 | plugins: [ 14 | resolve(), 15 | commonjs(), 16 | babel({ 17 | exclude: ['node_modules/**'], 18 | presets: ['@babel/preset-env'] 19 | }) 20 | ] 21 | }, 22 | buildBanner: (pck) => { 23 | return [ 24 | '/*!', 25 | '* PlazarJS ' + pck.rollupFileName + ' v' + pck.version, 26 | '* Copyright ' + pck.author + ' and other contributors', 27 | '* Licensed under ' + pck.license + ' (https://github.com/ProticM/plazar-js/blob/master/LICENSE)', 28 | '*/' 29 | ].join('\n'); 30 | } 31 | }; -------------------------------------------------------------------------------- /demo/bulma/scripts/components/widgets/demo-input.component.js: -------------------------------------------------------------------------------- 1 | pz.define('input-component', function() { 2 | 3 | var _buildTemplate = function(me) { 4 | var showLabel = !pz.isEmpty(me.label); 5 | var hasPlaceHolder = !pz.isEmpty(me.placeholder); 6 | var hasLabelText = showLabel && !pz.isEmpty(me.label.text); 7 | var field = '
'; 9 | 10 | if(showLabel) { 11 | pz.dom.append(me.html, ''); 13 | }; 14 | 15 | pz.dom.append(me.html, field); 16 | }; 17 | 18 | return { 19 | ownerType: 'base-component', 20 | template: '
', 21 | label: null, 22 | render: function() { 23 | this.base(arguments); 24 | _buildTemplate(this); 25 | } 26 | }; 27 | 28 | }); -------------------------------------------------------------------------------- /packages/http/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@plazarjs/http", 3 | "rollupName": "pzHttp", 4 | "rollupFileName": "http", 5 | "version": "2.1.5", 6 | "description": "PlazarJS http package", 7 | "keywords": [ 8 | "javascript", 9 | "js", 10 | "plazarjs", 11 | "http", 12 | "ajax" 13 | ], 14 | "author": "Miloš Protić (https://github.com/ProticM)", 15 | "homepage": "http://www.plazarjs.com/", 16 | "license": "MIT", 17 | "main": "dist/http.js", 18 | "directories": { 19 | "lib": "dist", 20 | "test": "__tests__" 21 | }, 22 | "files": [ 23 | "dist" 24 | ], 25 | "repository": { 26 | "type": "git", 27 | "url": "https://github.com/ProticM/plazar-js" 28 | }, 29 | "scripts": { 30 | "uglify": "uglifyjs --mangle --comments /^!/ --output dist/http.min.js dist/http.js" 31 | }, 32 | "bugs": { 33 | "url": "https://github.com/ProticM/plazar-js/issues" 34 | }, 35 | "publishConfig": { 36 | "access": "public" 37 | }, 38 | "dependencies": { 39 | "@plazarjs/core": "^2.1.5" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/core/__tests__/binders/interpolation.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import pz from '../../src'; 4 | 5 | describe('interpolation', () => { 6 | let componentDef, component; 7 | 8 | beforeAll(() => { 9 | componentDef = pz.define('test-component', { 10 | ownerType: 'component', 11 | renderTo: 'body', 12 | template: '
{message}{fnMessage}
', 13 | autoLoad: true, 14 | viewModel: { 15 | fnMessage: function() { 16 | return 'foo from fn' 17 | }, 18 | message: 'foo' 19 | } 20 | }); 21 | component = componentDef.create(); 22 | }); 23 | 24 | it('should check if span text is replaced', () => { 25 | expect(component.html.innerHTML).toBe('foofoo from fn'); 26 | component.viewModel.message = 'bar'; 27 | expect(component.html.innerHTML).toBe('barfoo from fn'); 28 | }); 29 | }); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Miloš Protić 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /demo/bulma/scripts/components/demo-layout.component.js: -------------------------------------------------------------------------------- 1 | pz.define('layout-component', { 2 | ownerType: 'base-component', 3 | templateSelector: 'main.layout-component', 4 | autoLoad: true, 5 | currentView: 'home-component', 6 | components: [{ 7 | type: 'header-component' 8 | }, { 9 | type: 'home-component' 10 | }, { 11 | type: 'menu-component', 12 | renderTo: '.side-menu', 13 | alias: 'sideMenu', 14 | items: [{ 15 | text: 'Home', 16 | view: 'home-component', 17 | isActive: true, 18 | components: [{ 19 | type: 'menu-component', 20 | items: [{ 21 | text: 'What is PlazarJS?', 22 | view: 'description-component', 23 | }] 24 | }] 25 | }, { 26 | text: 'Todo', 27 | view: 'todo-component' 28 | }, { 29 | text: 'Example Widgets', 30 | view: 'widgets-component' 31 | }, { 32 | text: 'About', 33 | view: 'about-component' 34 | }] 35 | }] 36 | }); -------------------------------------------------------------------------------- /packages/bootstrap-ui/src/components/ui-button-toolbar.component.js: -------------------------------------------------------------------------------- 1 | import pz from '@plazarjs/core'; 2 | import uiBase from '../base/ui-base.component'; 3 | 4 | const buttonToolbar = () => { 5 | 6 | let _parseTemplate = function() { 7 | this.html.setAttribute('aria-label', 'label_' + this.id); 8 | }; 9 | 10 | return { 11 | type: 'ui-bootstrap-button-toolbar', 12 | ownerType: 'ui-bootstrap-component', 13 | groups: [], 14 | init: function() { 15 | 16 | let groups = pz.arr.map((group) => { 17 | return pz.isEmpty(group.type) ? 18 | pz.assignTo(group, { type: 'ui-bootstrap-button-group' }, false) : group; 19 | }, this.groups); 20 | 21 | this.components = pz.arr.merge(this.components || [], groups); 22 | 23 | pz.arr.clear(this.groups); 24 | delete this.groups; 25 | 26 | this.base(arguments); 27 | }, 28 | template: '', 29 | parseTemplate: _parseTemplate 30 | }; 31 | }; 32 | 33 | export default uiBase.extend(buttonToolbar); 34 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "plazarjs", 3 | "private": true, 4 | "license": "MIT", 5 | "scripts": { 6 | "clean": "lerna exec --parallel -- rimraf dist", 7 | "rollup": "lerna exec --parallel -- rollup -c", 8 | "buildModules": "lerna run buildESModules", 9 | "uglifyAll": "lerna run uglify", 10 | "build": "npm run clean & npm run rollup & npm run buildModules & npm run uglifyAll", 11 | "prepublishOnly": "npm run build", 12 | "test": "jest" 13 | }, 14 | "author": "Miloš Protić (https://github.com/ProticM)", 15 | "dependencies": {}, 16 | "devDependencies": { 17 | "@babel/cli": "^7.7.7", 18 | "@babel/core": "^7.7.7", 19 | "@babel/preset-env": "^7.7.7", 20 | "babel-core": "^7.0.0-bridge.0", 21 | "babel-jest": "^24.9.0", 22 | "eslint": "^6.8.0", 23 | "jest": "^24.9.0", 24 | "lerna": "^3.20.2", 25 | "rimraf": "^3.0.0", 26 | "rollup": "^1.29.0", 27 | "rollup-plugin-babel": "^4.3.3", 28 | "rollup-plugin-commonjs": "^10.1.0", 29 | "rollup-plugin-node-resolve": "^5.2.0", 30 | "uglify-js": "^3.7.4" 31 | }, 32 | "jest": { 33 | "moduleNameMapper": { 34 | "@plazarjs/core": "/packages/core/src/index" 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /demo/bootstrap-ui/scripts/components/bootstrap-ui-header.component.js: -------------------------------------------------------------------------------- 1 | pz.define('bootstrap-ui-header-component', { 2 | ownerType: 'ui-bootstrap-navbar', 3 | renderTo: 'header', 4 | replace: true, 5 | position: 'top', 6 | autoLoad: true, 7 | theme: 'dark', 8 | brand: { 9 | type: 'text', 10 | value: 'Company Name' 11 | }, 12 | menu: { 13 | items: [{ 14 | text: 'Menu Item 1' 15 | },{ 16 | text: 'Menu Item 2' 17 | }, { 18 | type: 'ui-bootstrap-dropdown', 19 | inNav: true, 20 | text: 'Menu Item 3', 21 | menuItems: [{ 22 | text: 'Menu Item 3.1' 23 | },{ 24 | text: 'Menu Item 3.2' 25 | }] 26 | }] 27 | }, 28 | components: [{ 29 | type: 'ui-bootstrap-form', 30 | css: ['form-inline'], 31 | renderTo: 'div.navbar-collapse', 32 | button: { 33 | appearance: 'outline-success' 34 | }, 35 | components: [{ 36 | type: 'ui-bootstrap-input', 37 | css: ['mr-1'] 38 | }] 39 | }] 40 | }); -------------------------------------------------------------------------------- /packages/bootstrap-ui/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@plazarjs/bootstrap-ui", 3 | "version": "2.1.5", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@plazarjs/core": { 8 | "version": "2.1.5", 9 | "resolved": "https://registry.npmjs.org/@plazarjs/core/-/core-2.1.5.tgz", 10 | "integrity": "sha512-ZjzjU5dB+6+W3st3Eg/hcT0q7rblP5Gp7Rz26wNZdbbpwycyreoWcb7vG7fQOPBmsp3NcqBFTICTNKeMl3jQJw==" 11 | }, 12 | "bootstrap": { 13 | "version": "4.3.1", 14 | "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.3.1.tgz", 15 | "integrity": "sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag==" 16 | }, 17 | "jquery": { 18 | "version": "3.5.0", 19 | "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.0.tgz", 20 | "integrity": "sha512-Xb7SVYMvygPxbFMpTFQiHh1J7HClEaThguL15N/Gg37Lri/qKyhRGZYzHRyLH8Stq3Aow0LsHO2O2ci86fCrNQ==" 21 | }, 22 | "popper.js": { 23 | "version": "1.15.0", 24 | "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.15.0.tgz", 25 | "integrity": "sha512-w010cY1oCUmI+9KwwlWki+r5jxKfTFDVoadl7MSrIujHU5MJ5OR6HTDj6Xo8aoR/QsA56x8jKjA59qGH4ELtrA==" 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/bootstrap-ui/src/mixins/form-field.mixin.js: -------------------------------------------------------------------------------- 1 | const formFieldMixin = () => { 2 | 3 | let _getHtml = (me) => { 4 | return me.inputType == 'text' ? (pz.dom.findElement(me.html, 'input') || me.html) 5 | : me.html; 6 | }; 7 | 8 | let _setAttr = (me, name, value) => { 9 | let html = _getHtml(me); 10 | html.setAttribute(name, value); 11 | }; 12 | 13 | return { 14 | type: 'ui-bootstrap-form-field-mix', 15 | ownerType: 'mixin', 16 | getValue: function() { 17 | let html = _getHtml(this); 18 | return html.value; 19 | }, 20 | setValue: function(value) { 21 | let html = _getHtml(this); 22 | html.value = value; 23 | }, 24 | setRequired: function(value) { 25 | _setAttr(this, 'required', (value || true)); 26 | }, 27 | setDisabled: function(value) { 28 | _setAttr(this, 'disabled', (value || true)); 29 | }, 30 | setReadonly: function(value) { 31 | _setAttr(this, 'readonly', (value || true)); 32 | } 33 | }; 34 | }; 35 | 36 | export default formFieldMixin(); -------------------------------------------------------------------------------- /packages/core/src/utils/string.js: -------------------------------------------------------------------------------- 1 | import pz from '../core'; 2 | 3 | const stringUtil = { 4 | camelize: (str) => { 5 | if (pz.isEmpty(str)) { 6 | return ''; 7 | } 8 | 9 | return str.replace(/^([A-Z])|[\s-_](\w)/g, function (match, p1, p2, offset) { 10 | if (p2) return p2.toUpperCase(); 11 | return p1.toLowerCase(); 12 | }); 13 | }, 14 | 15 | capitalize: (str) => { 16 | if (pz.isEmpty(str)) { 17 | return ''; 18 | } 19 | 20 | let result = str.charAt(0).toUpperCase() + str.substr(1); 21 | return result || ''; 22 | }, 23 | 24 | contains: (str, value) => { 25 | return pz.isEmpty(str) || pz.isEmpty(value) ? false : 26 | str.indexOf(value) != -1; 27 | }, 28 | 29 | format: function () { 30 | let args = Array.prototype.slice.call(arguments); 31 | let baseString = args[0]; 32 | let params = args.splice(1), result = ''; 33 | 34 | if (pz.isEmpty(baseString) || pz.isEmpty(params)) { 35 | return result; 36 | } 37 | 38 | pz.forEach(params, function (param, idx) { 39 | result = pz.isEmpty(result) ? baseString.replace('{' + idx + '}', param) : 40 | result.replace('{' + idx + '}', param); 41 | }); 42 | 43 | return result; 44 | } 45 | }; 46 | 47 | export default stringUtil; -------------------------------------------------------------------------------- /demo/bulma/css/main.css: -------------------------------------------------------------------------------- 1 | * { 2 | border-radius: 0!important; 3 | } 4 | html, body, .h-100perc { 5 | height: 100%; 6 | } 7 | .d-inline-block { 8 | display: inline-block; 9 | vertical-align: top 10 | } 11 | .b-1 { 12 | border: 1px solid #dbdbdb 13 | } 14 | .bl-0 { 15 | border-left: 0!important 16 | } 17 | .br-0 { 18 | border-right: 0!important 19 | } 20 | .bt-0 { 21 | border-top: 0!important 22 | } 23 | .mb-1 { 24 | margin-bottom: 0.5rem 25 | } 26 | .p-1{ 27 | padding: 0.5rem 28 | } 29 | .has-background-dark-blue { 30 | background-color: #32404e 31 | } 32 | a.menu-item:hover{ 33 | background-color:#46535f 34 | } 35 | a.menu-item.is-active{ 36 | background-color:#46535f 37 | } 38 | .message-header+.message-body{ 39 | background-color: #fff 40 | } 41 | header.main-navbar > nav { 42 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); 43 | -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); 44 | -ms-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); 45 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); 46 | } 47 | .has-text-lightblue { 48 | color: #3273dc!important 49 | } 50 | .panel-heading-widget { 51 | background-color: #35baf6; 52 | color: #fff; 53 | } 54 | .cursor-pointer { 55 | cursor: pointer; 56 | } -------------------------------------------------------------------------------- /packages/bootstrap-ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@plazarjs/bootstrap-ui", 3 | "rollupName": "pzBootstrap", 4 | "rollupFileName": "bootstrap-ui", 5 | "version": "2.1.5", 6 | "description": "PlazarJS bootstrap integration", 7 | "keywords": [ 8 | "javascript", 9 | "plazarjs", 10 | "bootstrap", 11 | "ui", 12 | "components", 13 | "framework" 14 | ], 15 | "author": "Miloš Protić (https://github.com/ProticM)", 16 | "homepage": "http://www.plazarjs.com/", 17 | "license": "MIT", 18 | "main": "dist/bootstrap-ui.js", 19 | "directories": { 20 | "lib": "dist", 21 | "test": "__tests__" 22 | }, 23 | "files": [ 24 | "dist" 25 | ], 26 | "repository": { 27 | "type": "git", 28 | "url": "https://github.com/ProticM/plazar-js" 29 | }, 30 | "scripts": { 31 | "uglify": "uglifyjs --mangle --comments /^!/ --output dist/bootstrap-ui.min.js dist/bootstrap-ui.js", 32 | "buildESModules": "babel src --out-dir ./dist/esmodules" 33 | }, 34 | "bugs": { 35 | "url": "https://github.com/ProticM/plazar-js/issues" 36 | }, 37 | "publishConfig": { 38 | "access": "public" 39 | }, 40 | "dependencies": { 41 | "@plazarjs/core": "^2.1.5", 42 | "bootstrap": "^4.3.1", 43 | "jquery": "^3.4.1", 44 | "popper.js": "^1.15.0" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /demo/bulma/scripts/components/widgets/demo-user.component.js: -------------------------------------------------------------------------------- 1 | pz.define('user-component', { 2 | ownerType: 'base-component', 3 | autoLoad: true, 4 | template: '
' + 5 | '' + 9 | '' + 15 | '
', 16 | renderTo: 'root' // default renderTo, this can be overridden when adding this component as a child 17 | }); -------------------------------------------------------------------------------- /packages/core/src/utils/array.js: -------------------------------------------------------------------------------- 1 | import pz from '../core'; 2 | 3 | const arr = { 4 | clear: (array) => { 5 | if (pz.isEmpty(array)) { 6 | return; 7 | } 8 | 9 | return array.splice(0, array.length); 10 | }, 11 | 12 | find: (callback, arr, scope) => { 13 | return pz.find(callback, arr, scope); 14 | }, 15 | 16 | contains: (array, item, fromIndex) => { 17 | let isFunction = pz.isFunction(item); 18 | 19 | return isFunction ? (() => { 20 | let el = pz.arr.find(item, array); 21 | return !pz.isEmpty(el); 22 | })() : pz.isEmpty(array) ? false : array.indexOf(item, fromIndex) != -1; 23 | }, 24 | 25 | filter: (callback, array) => { 26 | let res = array.filter(callback); 27 | callback = null; 28 | return res; 29 | }, 30 | 31 | merge: function () { 32 | let args = Array.prototype.slice.call(arguments), 33 | resultArray = []; 34 | 35 | pz.forEach(args, (array) => { 36 | resultArray = resultArray.concat(array); 37 | }); 38 | 39 | return resultArray; 40 | }, 41 | 42 | map: (callback, array, scope) => { 43 | let result = array.map(callback, scope); 44 | callback = null; 45 | return result; 46 | }, 47 | 48 | removeAt: (array, index) => { 49 | if (pz.isEmpty(array) || pz.isEmpty(index)) { 50 | return; 51 | } 52 | 53 | array.splice(index, 1); 54 | } 55 | }; 56 | 57 | export default arr; -------------------------------------------------------------------------------- /PACKAGES.md: -------------------------------------------------------------------------------- 1 | ## Available Packages 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 14 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 34 | 35 | 36 | 39 | 42 | 43 | 44 | 45 | 48 | 49 | 50 | 51 | 54 | 55 | 56 |
7 | @plazarjs/bootstrap-ui 8 |
12 | NPM 13 | 15 | $ npm install @plazarjs/bootstrap-ui 16 |
CDN 21 | 22 |
Dependencies 27 | @plazarjs/core, jquery, bootstrap, popper.js 28 |
32 | @plazarjs/http 33 |
37 | NPM 38 | 40 | $ npm install @plazarjs/http 41 |
CDN 46 | 47 |
Dependencies 52 | @plazarjs/core 53 |
57 | -------------------------------------------------------------------------------- /packages/bootstrap-ui/src/components/ui-button-group.component.js: -------------------------------------------------------------------------------- 1 | import pz from '@plazarjs/core'; 2 | import uiBase from '../base/ui-base.component'; 3 | 4 | const buttonGroup = () => { 5 | 6 | let _parseTemplate = function() { 7 | let sizeCls = !pz.isEmpty(this.size) ? 'btn-group-' + this.size : ''; 8 | this.addCss((this.vertical ? 'btn-group-vertical ' + sizeCls : 'btn-group ' + sizeCls)); 9 | this.html.setAttribute('aria-label', 'label_' + this.id); 10 | this.html.setAttribute('role', this.renderAs); 11 | }; 12 | 13 | return { 14 | type: 'ui-bootstrap-button-group', 15 | ownerType: 'ui-bootstrap-component', 16 | buttons: [], 17 | renderAs: 'group', 18 | init: function() { 19 | 20 | let buttons = pz.arr.map((button) => { 21 | return pz.isEmpty(button.type) ? 22 | pz.assignTo(button, { type: 'ui-bootstrap-button' }, false) : button; 23 | }, this.buttons); 24 | 25 | this.components = pz.arr.merge(this.components || [], buttons); 26 | 27 | pz.arr.clear(this.buttons); 28 | delete this.buttons; 29 | this.base(arguments); 30 | }, 31 | vertical: false, 32 | template: '
', 33 | parseTemplate: _parseTemplate 34 | }; 35 | }; 36 | 37 | export default uiBase.extend(buttonGroup); 38 | -------------------------------------------------------------------------------- /packages/core/README.md: -------------------------------------------------------------------------------- 1 | # plazarjs/core 2 | 3 | > PlazarJS standalone package. This package holds the core implementation of the framework and it's all you need to build your app if no predefined UI components are required. 4 | 5 | ## Usage 6 | 7 | ```javascript 8 | // define the component 9 | import pz from '@plazarjs/core'; 10 | 11 | const helloWorld = { 12 | ownerType: 'component', 13 | template: '
Hello from {fw}
', 14 | renderTo: 'body', 15 | autoLoad: true, 16 | viewModel: { 17 | fw: 'plazarjs' 18 | } 19 | }; 20 | 21 | export default pz.define('hello-world', helloWorld); 22 | 23 | // create the component where required 24 | import helloWorld from 'my-path/helloWorld'; 25 | helloWorld.create(); 26 | ``` 27 | 28 | The equivalent of the code above written with the extend API, which is recommended when in modular environments, looks like this: 29 | 30 | ```javascript 31 | // define the component 32 | import pz from '@plazarjs/core'; 33 | 34 | const helloWorld = { 35 | type: 'hello-world', 36 | template: '
Hello from {fw}
', 37 | renderTo: 'body', 38 | autoLoad: true, 39 | viewModel: { 40 | fw: 'plazarjs' 41 | } 42 | }; 43 | 44 | export default pz.component.extend(helloWorld); 45 | 46 | // create the component where required 47 | import helloWorld from 'my-path/helloWorld'; 48 | helloWorld.create(); 49 | ``` 50 | 51 | Detailed documentation can be found here. -------------------------------------------------------------------------------- /packages/bootstrap-ui/src/components/index.js: -------------------------------------------------------------------------------- 1 | import alert from './ui-alert.component'; 2 | import breadcrumb from './ui-breadcrumb.component'; 3 | import buttonGroup from './ui-button-group.component'; 4 | import buttonToolbar from './ui-button-toolbar.component'; 5 | import button from './ui-button.component'; 6 | import card from './ui-card.component'; 7 | import carousel from './ui-carousel.component'; 8 | import collapse from './ui-collapse.component'; 9 | import container from './ui-container.component'; 10 | import dropdown from './ui-dropdown.component'; 11 | import form from './ui-form.component'; 12 | import grid from './ui-grid.component'; 13 | import inputGroup from './ui-input-group.component'; 14 | import input from './ui-input.component'; 15 | import listGroup from './ui-list-group.component'; 16 | import modal from './ui-modal.component'; 17 | import nav from './ui-nav.component'; 18 | import navbar from './ui-navbar.component'; 19 | import progress from './ui-progress.component'; 20 | import select from './ui-select.component'; 21 | 22 | export { 23 | alert, 24 | breadcrumb, 25 | buttonGroup, 26 | buttonToolbar, 27 | button, 28 | card, 29 | carousel, 30 | collapse, 31 | container, 32 | dropdown, 33 | form, 34 | grid, 35 | inputGroup, 36 | input, 37 | listGroup, 38 | modal, 39 | nav, 40 | navbar, 41 | progress, 42 | select 43 | } -------------------------------------------------------------------------------- /demo/bulma/scripts/services/todo.service.js: -------------------------------------------------------------------------------- 1 | pz.define('todo-service', function() { 2 | 3 | var _todos = [{ 4 | id: 1, 5 | title: 'Kids', 6 | text: 'Pick up kids from kindergarten', 7 | isCompleted: true 8 | }, { 9 | id: 2, 10 | title: 'Happy wife', 11 | text: 'Buy flowers', 12 | isCompleted: false 13 | }]; 14 | 15 | var _get = function(isCompleted) { 16 | return pz.arr.filter(function(todo) { 17 | return (isCompleted == todo.isCompleted) ? true : false; 18 | }, _todos); 19 | }; 20 | 21 | return { 22 | ownerType: 'class', 23 | get: function() { 24 | return _todos; 25 | }, 26 | put: function(todo) { 27 | var json = pz.binder.toJSON(todo); 28 | _todos.push(json); 29 | }, 30 | delete: function(idx) { 31 | pz.arr.removeAt(_todos, idx); 32 | }, 33 | clear: function() { 34 | pz.arr.clear(_todos); 35 | }, 36 | update: function(todo) { 37 | var jTodo = pz.binder.toJSON(todo); 38 | pz.arr.find(function(item) { 39 | return item.id == jTodo.id; 40 | }, _todos).isCompleted = jTodo.isCompleted; 41 | }, 42 | getCompleted: function() { 43 | return _get(true); 44 | }, 45 | getUnCompleted: function() { 46 | return _get(false); 47 | } 48 | } 49 | }); -------------------------------------------------------------------------------- /packages/bootstrap-ui/src/components/ui-collapse.component.js: -------------------------------------------------------------------------------- 1 | import pz from '@plazarjs/core'; 2 | import $ from 'jquery'; 3 | import uiBase from '../base/ui-base.component'; 4 | 5 | const collapse = () => { 6 | 7 | let _setIfNotEmpty = (me, propName) => { 8 | if (!pz.isEmpty(me[propName])) { 9 | me.html.setAttribute(('data-' + propName), me[propName]); 10 | }; 11 | }; 12 | 13 | let _setVisibility = (me, value) => { 14 | $(me.html).collapse(value); 15 | }; 16 | 17 | return { 18 | type: 'ui-bootstrap-collapse', 19 | ownerType: 'ui-bootstrap-button', 20 | parseTemplate: function() { 21 | this.base(arguments); 22 | this.html.setAttribute('data-toggle', 'collapse'); 23 | 24 | _setIfNotEmpty(this, 'target'); 25 | _setIfNotEmpty(this, 'parent'); 26 | }, 27 | target: '', 28 | parent: '', 29 | init: function() { 30 | pz.arr.clear(this.handlers); 31 | this.base(arguments); 32 | }, 33 | toggle: function() { 34 | $(this.html).collapse('toggle'); 35 | }, 36 | destroy: function() { 37 | $(this.html).collapse('dispose'); 38 | this.base(arguments); 39 | }, 40 | show: function() { 41 | _setVisibility(this, 'show'); 42 | }, 43 | hide: function() { 44 | _setVisibility(this, 'hide'); 45 | } 46 | }; 47 | }; 48 | 49 | export default uiBase.extend(collapse); 50 | -------------------------------------------------------------------------------- /packages/bootstrap-ui/src/components/ui-breadcrumb.component.js: -------------------------------------------------------------------------------- 1 | import pz from '@plazarjs/core'; 2 | import uiBase from '../base/ui-base.component'; 3 | 4 | const breadcrumb = () => { 5 | 6 | let _createCrumbs = (me, crumbs) => { 7 | let ul = pz.dom.findElement(me.html, 'ol.breadcrumb'); 8 | pz.forEach(crumbs, (crumb) => { 9 | let cls = crumb.isActive ? 'breadcrumb-item active' : 'breadcrumb-item'; 10 | let attr = crumb.isActive ? ' aria-current="page"' : ''; 11 | let text = crumb.asLink ? '' + crumb.text + '' : crumb.text; 12 | 13 | pz.dom.append(ul, '
  • ' + text + '
  • '); 14 | }); 15 | }; 16 | 17 | let _parseTemplate = function() { 18 | _createCrumbs(this, this.crumbs); 19 | }; 20 | 21 | return { 22 | type: 'ui-bootstrap-breadcrumb', 23 | ownerType: 'ui-bootstrap-component', 24 | template: '', 25 | parseTemplate: _parseTemplate, 26 | crumbs: [], 27 | addCrumbs: function(crumb) { 28 | let isArray, method; 29 | 30 | if (pz.isEmpty(crumb)) { 31 | return; 32 | }; 33 | 34 | isArray = pz.isArray(crumb); 35 | method = isArray ? 'concat' : 'push'; 36 | this.crumbs = this.crumbs[method](crumb); 37 | _createCrumbs(this, isArray ? crumb : [crumb]); 38 | } 39 | }; 40 | }; 41 | 42 | export default uiBase.extend(breadcrumb); 43 | -------------------------------------------------------------------------------- /demo/bulma/scripts/components/widgets/demo-select.component.js: -------------------------------------------------------------------------------- 1 | pz.define('select-component', function() { 2 | var _buildTemplate = function(me) { 3 | var showLabel = !pz.isEmpty(me.label); 4 | var showHelpText = !pz.isEmpty(me.helpText); 5 | var hasLabelText = showLabel && !pz.isEmpty(me.label.text); 6 | var field = '
    ', select; 7 | if(showLabel) { 8 | pz.dom.append(me.html, ''); 10 | }; 11 | 12 | pz.dom.append(me.html, field); 13 | select = pz.dom.findElement(me.html, 'select'); 14 | pz.forEach(me.options, function(option) { 15 | pz.dom.append(select, ''); 16 | }); 17 | 18 | if(showHelpText) { 19 | pz.dom.append(me.html, '

    ' + me.helpText + '

    '); 20 | }; 21 | 22 | }; 23 | 24 | return { 25 | ownerType: 'base-component', 26 | template: '
    ', 27 | label: null, 28 | helpText: null, 29 | options: [], 30 | init: function() { 31 | this.base(arguments); 32 | this.handle({ 33 | on: 'change', 34 | fn: 'onChange', 35 | selector: 'select' 36 | }); 37 | }, 38 | render: function() { 39 | this.base(arguments); 40 | _buildTemplate(this); 41 | }, 42 | onChange: function() { } 43 | }; 44 | 45 | }); -------------------------------------------------------------------------------- /demo/bootstrap-ui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Plazar JS Demo Application 8 | 10 | 11 | 12 | 13 |
    14 |
    15 | 16 | 19 | 22 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /packages/http/src/request.js: -------------------------------------------------------------------------------- 1 | import pz from '@plazarjs/core'; 2 | import factory from './factory'; 3 | import { notAnObject } from './constants'; 4 | 5 | class request { 6 | constructor(options) { 7 | this.id = pz.guid(); 8 | this.aborted = false; 9 | this.options = options; 10 | this.xhr = factory.createXHR(); 11 | } 12 | abort() { 13 | this.xhr.abort(); 14 | this.xhr = null; 15 | this.aborted = true; 16 | } 17 | setHeaders(headers) { 18 | let h = pz.isEmpty(headers) ? this.options.headers : headers; 19 | 20 | if(pz.isEmpty(h)) { 21 | return; 22 | }; 23 | 24 | if(!pz.isObject(h)) { 25 | throw new Error(pz.str.format(notAnObject, '[headers]')); 26 | }; 27 | 28 | let headerKeys = Object.keys(h); 29 | pz.forEach(headerKeys, (key) => { 30 | this.xhr.setRequestHeader(key, h[key]); 31 | }); 32 | } 33 | setXHROptions(options) { 34 | let o = pz.isEmpty(options) ? this.options : options; 35 | 36 | this.xhr.withCredentials = o.withCredentials || false; 37 | this.xhr.timeout = o.timeout || 0; 38 | } 39 | parseUrlParams(params) { 40 | let p = pz.isEmpty(params) ? this.options.params : params; 41 | 42 | if(pz.isEmpty(p)) { 43 | return; 44 | }; 45 | 46 | if(!pz.isObject(p)) { 47 | throw new Error(pz.str.format(notAnObject, '[params]')); 48 | }; 49 | 50 | this.options.url = this.options.url.replace(/\{(.*?)\}/g, (pattern, value) => { 51 | return encodeURIComponent(p[value]); 52 | }); 53 | } 54 | } 55 | 56 | export default request; -------------------------------------------------------------------------------- /packages/bootstrap-ui/src/components/ui-progress.component.js: -------------------------------------------------------------------------------- 1 | import pz from '@plazarjs/core'; 2 | import uiBase from '../base/ui-base.component'; 3 | 4 | const progress = () => { 5 | 6 | let _parseTemplate = function() { 7 | let progressBar = pz.dom.findElement(this.html, 'div.progress-bar'), 8 | hasAppearance = !pz.isEmpty(this.appearance), 9 | hasNowValue = !pz.isEmpty(this.values.now) && this.values.now > 0, 10 | max = this.values.max || 100, 11 | min = this.values.min || 0, val; 12 | 13 | this.html.setAttribute('aria-valuemin', min); 14 | this.html.setAttribute('aria-valuemax', max); 15 | 16 | this.addCss((hasAppearance ? ('bg-' + this.appearance) : ''), progressBar); 17 | this.addCss((this.animated ? ('progress-bar-striped progress-bar-animated') : ''), progressBar); 18 | 19 | if (hasNowValue) { 20 | this.addStyle(('width:' + this.values.now + '%'), progressBar); 21 | this.html.setAttribute('aria-valuenow', this.values.now); 22 | }; 23 | 24 | if (this.showValue && hasNowValue) { 25 | progressBar.innerText = (this.values.now + '%'); 26 | }; 27 | }; 28 | 29 | return { 30 | type: 'ui-bootstrap-progress', 31 | ownerType: 'ui-bootstrap-component', 32 | template: '
    ', 33 | showValue: true, 34 | animated: false, 35 | values: { 36 | min: 0, 37 | now: 25, 38 | max: 100 39 | }, 40 | parseTemplate: _parseTemplate, 41 | setValues: function(values) { 42 | if (pz.isEmpty(values)) { 43 | return; 44 | }; 45 | 46 | this.values = values; 47 | this.parseTemplate(); 48 | } 49 | }; 50 | }; 51 | 52 | export default uiBase.extend(progress); -------------------------------------------------------------------------------- /packages/bootstrap-ui/src/components/ui-select.component.js: -------------------------------------------------------------------------------- 1 | import formFieldMixin from '../mixins/form-field.mixin'; 2 | import pz from '@plazarjs/core'; 3 | import uiBase from '../base/ui-base.component'; 4 | 5 | const select = () => { 6 | let _parseTemplate = function() { 7 | let hasSize = !pz.isEmpty(this.size); 8 | let css = (this.custom ? (hasSize ? ('custom-select custom-select-' + this.size) : 'custom-select') : 9 | (hasSize ? ('form-control form-control-' + this.size) : 'form-control')); 10 | this.addCss(css); 11 | if (this.multiple) { 12 | this.html.setAttribute('multiple', true); 13 | }; 14 | 15 | pz.forEach(this.dataSource, (item) => { 16 | let valField = item[this.valueField], 17 | disField = item[this.displayField], 18 | option = pz.dom.createElement('option'); 19 | 20 | option.innerText = disField; 21 | option.setAttribute('value', valField); 22 | pz.dom.append(this.html, option); 23 | option = null; 24 | }, this); 25 | }; 26 | 27 | return { 28 | type: 'ui-bootstrap-select', 29 | ownerType: 'ui-bootstrap-component', 30 | labelText:'', 31 | template: '', 32 | mixins: [formFieldMixin], 33 | dataSource: [], 34 | custom: false, 35 | multiple: false, 36 | valueField: 'id', 37 | displayField: 'value', 38 | parseTemplate: _parseTemplate, 39 | handlers: [{ 40 | on: 'change', 41 | fn: 'onChange' 42 | }], 43 | onChange: () => { }, 44 | setDataSource: function(data) { 45 | if (pz.isEmpty(data) || pz.isEmpty(this.html)) { 46 | return; 47 | }; 48 | 49 | this.dataSource = data; 50 | this.parseTemplate(); 51 | } 52 | }; 53 | }; 54 | 55 | export default uiBase.extend(select); -------------------------------------------------------------------------------- /packages/core/src/statics/binder/observable.js: -------------------------------------------------------------------------------- 1 | import pz from '../../core'; 2 | 3 | class observable { 4 | _defineReactive(obj, key) { 5 | let me = this; 6 | 7 | delete obj[key]; 8 | Object.defineProperty(obj, key, { 9 | configurable: true, 10 | enumerable: true, 11 | set: function (newValue) { 12 | let val = newValue.value != null || newValue.value != undefined ? newValue.value : newValue; 13 | let shouldNotify = val != me.value && me.notify != undefined; 14 | me.value = val; 15 | if (shouldNotify) { 16 | me.notify(); 17 | } 18 | }, 19 | get: function () { 20 | let get = () => { 21 | return me.value; 22 | }; 23 | 24 | get.subscribe = (callback, bindingId) => { 25 | me.subscribe.call(me, callback, bindingId); 26 | }; 27 | 28 | get.unsubscribe = (bindingId) => { 29 | me.unsubscribe.call(me, bindingId); 30 | }; 31 | 32 | return get; 33 | } 34 | }); 35 | } 36 | constructor(obj, key) { 37 | this.value = obj[key]; 38 | this.prop = key; 39 | this.subscriptions = []; 40 | this._defineReactive(obj, key); 41 | return this; 42 | } 43 | notify() { 44 | if (this.subscriptions.length == 0) { 45 | return; 46 | } 47 | 48 | pz.forEach(this.subscriptions, function (subscription) { 49 | subscription.update.call(this, this.value); 50 | }, this); 51 | } 52 | subscribe(callback, bindingId) { 53 | let length = this.subscriptions.length; 54 | this.subscriptions.push({ 55 | id: bindingId || length++, 56 | update: callback 57 | }); 58 | } 59 | unsubscribe(bindingId) { 60 | let bindingSubs = this.subscriptions.filter(function (sub) { 61 | return sub.id == bindingId; 62 | }); 63 | 64 | pz.forEach(bindingSubs, function (sub) { 65 | let idx = this.subscriptions.indexOf(sub); 66 | this.subscriptions.splice(idx, 1); 67 | }, this); 68 | } 69 | static create(obj, key) { 70 | return new observable(obj, key); 71 | } 72 | } 73 | 74 | export default observable; -------------------------------------------------------------------------------- /demo/bulma/scripts/components/demo-header.component.js: -------------------------------------------------------------------------------- 1 | pz.define('header-component', { 2 | ownerType: 'base-component', 3 | autoLoad: true, 4 | renderTo: 'header.main-navbar', 5 | template: '' 47 | }); -------------------------------------------------------------------------------- /packages/core/src/statics/binder/util.js: -------------------------------------------------------------------------------- 1 | import pz from '../../core'; 2 | import reservedKeys from './reserved-keys'; 3 | 4 | let pathRegex = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g, 5 | backslashRegex = /\\(\\)?/g; // these are used by lodash to parse the path 6 | 7 | let getAliasRegex = (keys) => { // alias regex 8 | return new RegExp('\\b' + keys.join('|') + '\\b', 'gi'); 9 | }; 10 | 11 | let pathToParts = (keypath) => { 12 | let result = []; 13 | keypath.replace(pathRegex, (match, num, quote, str) => { 14 | result.push(!pz.isEmpty(quote) ? str.replace(backslashRegex, '$1') : (num || match)); 15 | }); 16 | return result; 17 | }; 18 | 19 | let parseKeyPath = (parts, target) => { 20 | let globalScope = pz.getGlobal(), result, p; 21 | 22 | if (parts.length == 1) { 23 | return ((!pz.isEmpty(target) && 24 | !pz.isEmpty(target[parts[0]])) || 25 | pz.arr.contains([reservedKeys.idx, reservedKeys.current], parts[0])) ? 26 | target : null; 27 | } 28 | 29 | p = parts.slice(); 30 | p.pop(); 31 | result = p.reduce((previous, current) => { 32 | let isString = pz.isString(previous); 33 | return isString ? globalScope[previous][current] : 34 | (pz.isEmpty(previous) ? null : previous[current]); 35 | }, target); 36 | 37 | return result; 38 | }; 39 | 40 | let buildContext = (keypath, view) => { 41 | let ctx = view.ctx, vm = view.vm; 42 | let aliases = Object.keys(view.alias), hasAlias = aliases.length > 0, 43 | isPath = pathRegex.test(keypath), 44 | fromRoot = isPath && keypath.indexOf(reservedKeys.root) != -1, 45 | parts, aliasRegex; 46 | 47 | keypath = fromRoot ? keypath.replace((reservedKeys.root), '') : keypath; 48 | if (hasAlias) { 49 | aliasRegex = getAliasRegex(aliases); 50 | keypath = keypath.replace(aliasRegex, (matched) => { 51 | return view.alias[matched]; 52 | }); 53 | } 54 | parts = pathToParts(keypath); 55 | return parseKeyPath(parts, ctx) || parseKeyPath(parts, vm); 56 | }; 57 | 58 | export { 59 | buildContext, 60 | parseKeyPath, 61 | pathToParts, 62 | pathRegex 63 | }; -------------------------------------------------------------------------------- /packages/bootstrap-ui/src/components/ui-form.component.js: -------------------------------------------------------------------------------- 1 | import pz from '@plazarjs/core'; 2 | import uiBase from '../base/ui-base.component'; 3 | 4 | const form = () => { 5 | 6 | let _parseTemplate = function() { 7 | let hasAction = !pz.isEmpty(this.action), hasMethod = !pz.isEmpty(this.method); 8 | 9 | if (hasAction) { 10 | this.setAttribute('action', this.action); 11 | }; 12 | 13 | if (hasMethod) { 14 | this.setAttribute('method', this.method); 15 | }; 16 | 17 | this.addCss((this.inline ? 'form-inline' : '')); 18 | }; 19 | 20 | return { 21 | type: 'ui-bootstrap-form', 22 | ownerType: 'ui-bootstrap-component', 23 | template: '
    ', 24 | inline: false, 25 | components: [], 26 | button: { 27 | text: 'Submit', 28 | appearance: 'primary', 29 | type: 'submit', 30 | align: 'right', 31 | css: [] 32 | }, 33 | init: function() { 34 | 35 | pz.forEach(this.components, (component) => { 36 | component.inForm = component.type == 'ui-bootstrap-input'; 37 | }, this); 38 | 39 | if (!pz.isEmpty(this.button)) { 40 | let button = { 41 | type: 'ui-bootstrap-button', 42 | text: this.button.text || 'Submit', 43 | appearance: this.button.appearance || 'primary', 44 | buttonType: this.button.type || 'submit', 45 | css: this.button.css || [], 46 | align: this.button.align || 'right' 47 | }; 48 | 49 | if (pz.isFunction(this.button.onClick)) { 50 | button.onClick = this.button.onClick; 51 | }; 52 | 53 | this.components.push(button); 54 | }; 55 | 56 | this.base(arguments); 57 | }, 58 | parseTemplate: _parseTemplate, 59 | validate: function() { 60 | 61 | } 62 | }; 63 | }; 64 | 65 | export default uiBase.extend(form); -------------------------------------------------------------------------------- /demo/bulma/scripts/components/demo-menu.component.js: -------------------------------------------------------------------------------- 1 | pz.define('menu-component', function() { 2 | 3 | var _preInit = function(me) { 4 | pz.forEach(me.items, function(item, idx) { 5 | var cls = item.isActive ? 'menu-item is-active' : 'menu-item'; 6 | var liCls = 'li-menu-item-' + idx; 7 | var link = pz.dom.parseTemplate('' + item.text + ''); 8 | 9 | if(!pz.isEmpty(item.view)) { 10 | this.addAttr({ 11 | name: 'data-view', 12 | value: item.view 13 | }, link); 14 | }; 15 | 16 | var el = pz.dom.parseTemplate('
  • '); 17 | 18 | pz.dom.append(el, link); 19 | pz.dom.append(this.html, el); 20 | 21 | if(!pz.isEmpty(item.components)) { 22 | this.components = pz.arr.map(function(comp) { 23 | var c = pz.obj.assignTo({}, comp); 24 | c.renderTo = 'li.li-menu-item-' + idx; 25 | return c; 26 | }, item.components); 27 | } 28 | }, me); 29 | }; 30 | 31 | var _toggleActiveState = function(el) { 32 | var links = document.querySelectorAll('a.menu-item'); 33 | pz.forEach(links, function(link) { 34 | link.classList.remove('is-active'); 35 | }); 36 | el.classList.add('is-active'); 37 | }; 38 | 39 | return { 40 | ownerType: 'base-component', 41 | autoLoad: true, 42 | template: '
      ', 43 | css: ['menu-list'], 44 | items: [], 45 | init: function() { 46 | _preInit(this); 47 | this.base(arguments); 48 | }, 49 | handlers: [{ 50 | on: 'click', 51 | selector: 'a.menu-item', 52 | fn: 'itemClick' 53 | }], 54 | itemClick: function (el) { 55 | var view = el.getAttribute('data-view'); 56 | _toggleActiveState(el); 57 | this.changeView(view); 58 | } 59 | }; 60 | 61 | }); -------------------------------------------------------------------------------- /demo/bulma/scripts/components/widgets/demo-widgets.component.js: -------------------------------------------------------------------------------- 1 | pz.define('widgets-component', { 2 | ownerType: 'base-component', 3 | mixins: ['page-mixin'], 4 | template: '

      ' + 5 | 'Example widgets are built in purpose of this demo. Hopefully PlazarJS will grow and we will build set of controls to be supported out of the box.

      ' + 6 | '
      ' + 7 | '
      ' + 8 | '
      ' + 9 | '
      ' + 10 | '
      ' + 11 | '
      ', 12 | renderTo: 'section.app-body', 13 | components: [{ 14 | type: 'todo-component', 15 | renderTo: 'div.todo', 16 | mixins: [] 17 | }, { 18 | type: 'grid-component', 19 | renderTo: 'div.grid', 20 | mixins: [], 21 | columns: [{ 22 | text: '№', 23 | dataIndex: 'id' 24 | }, { 25 | text: 'Title', 26 | dataIndex: 'title' 27 | },{ 28 | text: 'Description', 29 | dataIndex: 'text' 30 | }], 31 | data: [] 32 | }, { 33 | type: 'user-component', 34 | renderTo: 'div.user' 35 | }, { 36 | type: 'input-component', 37 | renderTo: 'div.grid', 38 | alias: 'nameField', 39 | label: { 40 | text: 'Name:' 41 | }, 42 | placeholder: 'Enter name' 43 | }, { 44 | type: 'input-component', 45 | renderTo: 'div.grid', 46 | alias: 'surnameField', 47 | label: { 48 | text: 'Surname:' 49 | }, 50 | placeholder: 'Enter surname' 51 | }, { 52 | type: 'select-component', 53 | renderTo: 'div.grid', 54 | label: { 55 | text: 'City:' 56 | }, 57 | options: [{ 58 | value: 1, 59 | text: 'New York' 60 | },{ 61 | value: 2, 62 | text: 'San Francisco' 63 | }], 64 | helpText: 'Some help from this text', 65 | onChange: function(el) { 66 | alert(el.value); 67 | } 68 | }] 69 | }); -------------------------------------------------------------------------------- /demo/bulma/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Plazar JS Demo Application 7 | 8 | 9 | 10 | 11 |
      12 | 13 |
      14 |
      15 | 16 |
      17 |
      18 |
      19 |
      20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /packages/bootstrap-ui/src/components/ui-button.component.js: -------------------------------------------------------------------------------- 1 | import pz from '@plazarjs/core'; 2 | import $ from 'jquery'; 3 | import uiBase from '../base/ui-base.component'; 4 | 5 | const button = () => { 6 | 7 | let _parseTemplate = function() { 8 | let hasSize = !pz.isEmpty(this.size), hasHref = !pz.isEmpty(this.href); 9 | this.html.innerHTML = this.text; 10 | this.addCss(('btn-' + this.appearance + (hasSize ? ' btn-' + this.size : ''))); 11 | this.addCss((!pz.isEmpty(this.align) ? 'float-' + this.align : '')); 12 | this.html.setAttribute((hasHref ? 'href' : 'type'), (hasHref ? this.href : this.buttonType)); 13 | }; 14 | 15 | return { 16 | type: 'ui-bootstrap-button', 17 | ownerType: 'ui-bootstrap-component', 18 | appearance: 'primary', 19 | text: 'Button', 20 | buttonType: 'button', 21 | template: '', 22 | load: function() { 23 | if (!pz.isEmpty(this.href)) { 24 | this.template = this.template.replace('', 'a>'); 25 | }; 26 | this.base(arguments) 27 | }, 28 | init: function() { 29 | if (pz.isEmpty(this.href)) { 30 | this.handle({ 31 | on: 'click', 32 | fn: 'onClick' 33 | }); 34 | }; 35 | this.base(arguments); 36 | }, 37 | parseTemplate: _parseTemplate, 38 | onClick: function() { }, 39 | toggle: function() { 40 | $(this.html).button('toggle'); 41 | }, 42 | destroy: function() { 43 | $(this.html).button('dispose'); 44 | this.base(arguments); 45 | }, 46 | setDisabled: function(value) { 47 | // TODO: link disable 48 | if (pz.isEmpty(value) || value == true) { 49 | this.html.setAttribute('disabled', ''); 50 | } else { 51 | this.html.removeAttribute('disabled'); 52 | }; 53 | }, 54 | setText: function(value) { 55 | 56 | if (pz.isEmpty(value)) { 57 | return; 58 | }; 59 | 60 | this.html.innerHTML = value; 61 | } 62 | }; 63 | }; 64 | 65 | export default uiBase.extend(button); -------------------------------------------------------------------------------- /packages/bootstrap-ui/src/components/ui-alert.component.js: -------------------------------------------------------------------------------- 1 | import pz from '@plazarjs/core'; 2 | import $ from 'jquery'; 3 | import uiBase from '../base/ui-base.component'; 4 | 5 | const alert = () => { 6 | 7 | let _parseTemplate = function() { 8 | 9 | this.addCss('alert-'.concat(this.appearance)); 10 | 11 | let renderLink = !pz.isEmpty(this.link), animation; 12 | let renderHeading = !pz.isEmpty(this.heading); 13 | 14 | if (renderHeading) { 15 | pz.dom.append(this.html, '' + 16 | this.heading.text + ''); 17 | }; 18 | 19 | if (renderLink) { 20 | this.text = this.text.replace(this.linkPlaceHolder, 21 | '' + this.link.text + ''); 22 | }; 23 | 24 | this.html.innerHTML += this.text; 25 | 26 | if (this.dismissible) { 27 | animation = this.dismissible.animation; 28 | this.addCss((!animation ? 'alert-dismissible' : 'alert-dismissible fade show')); 29 | pz.dom.append(this.html, ''); 30 | }; 31 | }; 32 | 33 | return { 34 | type: 'ui-bootstrap-alert', 35 | ownerType: 'ui-bootstrap-component', 36 | template: '