Checkpoint
gitea/hedera-web/pipeline/head This commit looks good Details

This commit is contained in:
Juan Ferrer 2022-05-24 23:11:12 +02:00
parent 546e67d6f6
commit dc0ba66257
47 changed files with 861 additions and 903 deletions

View File

@ -19,21 +19,23 @@ Hedera.AddressList = new Class
window.history.back();
}
,onSetDefaultClick: function() {
,onSetDefaultClick: function(event, addressId) {
if (event.defaultPrevented) return;
this.$('defaultAddress').value = addressId;
Htk.Toast.showMessage(_('DefaultAddressModified'));
}
,onRemoveAddressClick: function(button, form) {
,onRemoveAddressClick: function(form) {
if (confirm(_('AreYouSureDeleteAddress'))) {
form.set('isActive', false);
form.refresh();
}
}
,onEditAddressClick: function(button, form) {
,onEditAddressClick: function(id) {
this.hash.set({
form: 'account/address',
address: form.get('id')
address: id
});
}
});

View File

@ -25,7 +25,7 @@
<htk-bar-button
icon="add"
tip="_AddAddress"
on-click="onAddAddressClick"/>
on-click="this.onAddAddressClick()"/>
</div>
<div id="form" class="address-list">
<div class="box">
@ -33,40 +33,38 @@
id="default-address"
column="defaultAddressFk"
form="user-form"/>
<htk-repeater model="addresses" form-id="iter" class="htk-list">
<htk-repeater model="addresses" form-id="address" class="htk-list">
<custom>
<div class="address item" on-click="onSetDefaultClick">
<div class="address item" on-click="this.onSetDefaultClick($event, address.id)">
<div class="side">
<htk-radio
form="iter"
column="id"
radio-group="default-address"
tip="_SetAsDefault"/>
val="{{address.id}}"
tip="_SetAsDefault"
name="test"/>
</div>
<div class="content">
<p class="important">
{{iter.nickname}}
{{address.nickname}}
</p>
<p>
{{iter.street}}
{{address.street}}
</p>
<p>
{{iter.postalCode}}, {{iter.city}}
{{address.postalCode}}, {{address.city}}
</p>
</div>
<div class="actions">
<div
class="actions"
on-click="$event.preventDefault()">
<htk-button
form="iter"
column="id"
tip="_RemoveAddress"
icon="delete"
on-click="onRemoveAddressClick"/>
tip="_RemoveAddress"
on-click="this.onRemoveAddressClick($.address)"/>
<htk-button
form="iter"
column="id"
tip="_EditAddress"
icon="edit"
on-click="onEditAddressClick"/>
tip="_EditAddress"
on-click="this.onEditAddressClick(address.id)"/>
</div>
</div>
</custom>

View File

@ -8,9 +8,9 @@ Hedera.Address = new Class({
new Sql.Function({schema: 'account', name: 'myUser_getId'}));
},
onStatusChange: function(form) {
if (form.ready && this.$('address').value == 0)
form.insertRow();
onStatusChange: function() {
if (this.$('iter').ready && this.$('address').value == 0)
this.$('iter').insertRow();
},
onOperationsDone: function() {

View File

@ -1,10 +1,8 @@
.address
{
.address {
padding: 1em;
}
.address .box
{
.address .box {
max-width: 30em;
padding: 3em;
}

View File

@ -2,13 +2,13 @@
<vn-group>
<vn-param id="address"/>
<vn-hash-param key="address" param="address"/>
<db-form id="iter" on-status-changed="onStatusChange">
<db-form id="iter" on-status-changed="this.onStatusChange()">
<db-model
id="model"
property="model"
updatable="true"
mode="ON_DEMAND"
on-operations-done="onOperationsDone">
on-operations-done="this.onOperationsDone()">
SELECT a.id, a.street, a.nickname, a.city,
a.postalCode, a.provinceFk, p.countryFk
FROM myAddress a
@ -29,11 +29,11 @@
<htk-bar-button
icon="close"
tip="_Return"
on-click="onReturnClick"/>
on-click="this.onReturnClick()"/>
<htk-bar-button
icon="check"
tip="_Accept"
on-click="onAcceptClick"/>
on-click="this.onAcceptClick()"/>
</div>
<div id="form" class="address">
<div class="box">

View File

@ -1,23 +1,18 @@
.conf
{
.conf {
padding: 1em;
}
.conf .box
{
.conf .box {
max-width: 30em;
padding: 3em;
}
.pass-change
{
.pass-change {
max-width: 15em;
padding: 2.5em;
}
.pass-info
{
.pass-info {
width: 15em;
}
.pass-info ul
{
.pass-info ul {
list-style-type: none;
}

View File

@ -27,11 +27,11 @@
<htk-bar-button
icon="place"
tip="_Addresses"
on-click="onAddressesClick"/>
on-click="this.onAddressesClick()"/>
<htk-bar-button
icon="lock_reset"
tip="_Change password"
on-click="onPassChangeClick"/>
on-click="this.onPassChangeClick()"/>
</div>
<div id="form" class="conf">
<div class="box">
@ -98,10 +98,10 @@
placeholder="_Repeat password"/>
</div>
<div class="button-bar">
<button class="thin" on-click="onPassModifyClick">
<button class="thin" on-click="this.onPassModifyClick()">
<t>Modify</t>
</button>
<button class="thin" on-click="onPassInfoClick">
<button class="thin" on-click="this.onPassInfoClick()">
<t>Requirements</t>
</button>
<div class="clear"/>

View File

@ -1,6 +1,5 @@
Hedera.AccessLog = new Class
({
Hedera.AccessLog = new Class({
Extends: Hedera.Form
});

View File

@ -1,36 +1,29 @@
.access-log
{
.access-log {
padding: 1em;
}
.access-log .box
{
.access-log .box {
max-width: 25em;
margin: 0 auto;
}
.access-log .form
{
.access-log .form {
padding: 2em;
}
.access-log .form > p
{
.access-log .form > p {
font-size: 1.2em;
margin: .1em 0;
}
/* List */
.access-log .list
{
.access-log .list {
margin-top: 1em;
}
.access-log .item
{
.access-log .item {
display: block;
padding: 1em;
border-bottom: 1px solid #DDD;
}
.access-log .item > p
{
.access-log .item > p {
margin: .1em 0;
}

View File

@ -2,11 +2,13 @@
<vn-group>
<vn-param id="user"/>
<vn-hash-param key="user" param="user"/>
<db-form id="user-form">
<db-form id="userForm">
<db-model property="model">
<custom>
SELECT Id_Cliente, Cliente, Telefono, movil
FROM vn2008.Clientes WHERE Id_Cliente = #user
SELECT u.id, u.nickname, u.email, c.phone
FROM account.user u
LEFT JOIN vn.client c ON c.id = u.id
WHERE u.id = #user
</custom>
<sql-batch property="batch">
<custom>
@ -22,18 +24,10 @@
<div id="form" class="access-log">
<div class="box">
<div class="form">
<p>
<htk-text form="user-form" column="Id_Cliente"/>
</p>
<p>
<htk-text form="user-form" column="Cliente"/>
</p>
<p>
<htk-text form="user-form" column="Telefono"/>
</p>
<p>
<htk-text form="user-form" column="movil"/>
</p>
<p>#{{$.userForm.id}}</p>
<p>{{$.userForm.nickname}}</p>
<p>{{$.userForm.email}}</p>
<p>{{$.userForm.phone}}</p>
</div>
</div>
<div class="list box">
@ -58,12 +52,12 @@
<custom>
<div class="item">
<p>
<htk-text form="iter" column="stamp" format="_%a, %e %b %Y at %T"/>
{{Vn.Value.format(iter.stamp, _('%a, %e %b %Y at %T'))}}
</p>
<p>
<htk-text form="iter" column="platform"/> -
<htk-text form="iter" column="browser"/>
<htk-text form="iter" column="version"/>
{{iter.platform}} -
{{iter.browser}}
{{iter.version}}
</p>
</div>
</custom>

View File

@ -4,8 +4,8 @@ Hedera.Connections = new Class({
,_timeoutId: null
,onModelStatusChange: function(model) {
if (!model.ready)
,onModelStatusChange: function() {
if (!this.$('sessions').ready)
return;
if (this._timeoutId)
@ -22,15 +22,15 @@ Hedera.Connections = new Class({
this.$('sessions').refresh();
}
,onAccessLogClick: function(button, form) {
,onAccessLogClick: function(userId) {
this.hash.set({
form: 'admin/access-log'
,user: form.get('userId')
,user: userId
});
}
,onChangeUserClick: function(button, form) {
this.gui.supplantUser(form.get('user'),
,onChangeUserClick: function(userName) {
this.gui.supplantUser(userName,
this._onUserSupplant.bind(this));
}

View File

@ -1,14 +1,11 @@
.connections
{
.connections {
padding: 1em;
}
.connections .box
{
.connections .box {
max-width: 25em;
margin: 0 auto;
}
.action-bar .connections-sum
{
.action-bar .connections-sum {
padding: .4em;
background-color: #1e88e5;
border-radius: 0.1em;
@ -17,23 +14,19 @@
/* List */
.connections .item
{
.connections .item {
display: block;
padding: 1em;
border-bottom: 1px solid #DDD;
}
.connections .item > button
{
.connections .item > button {
float: right;
margin: 0;
}
.connections .item > p
{
.connections .item > p {
margin: .1em 0;
}
.connections .item > p.important
{
.connections .item > p.important {
font-size: 1.2em;
text-overflow: ellipsis;
white-space: nowrap;

View File

@ -6,7 +6,7 @@
<htk-bar-button
icon="refresh"
tip="_Refresh"
on-click="onRefreshClick"/>
on-click="this.onRefreshClick()"/>
<div class="connections-sum">
<htk-text>
<db-calc-sum
@ -20,7 +20,10 @@
<div id="form" class="connections">
<div class="box">
<htk-repeater form-id="iter">
<db-model property="model" id="sessions" on-status-changed="onModelStatusChange">
<db-model
property="model"
id="sessions"
on-status-changed="this.onModelStatusChange()">
<custom>
SELECT vu.userFk userId, vu.stamp, u.nickname, s.lastUpdate,
a.platform, a.browser, a.version, u.name user
@ -36,28 +39,25 @@
<custom>
<div class="item">
<htk-button
form="iter"
column="id"
tip="_Access log"
icon="history"
on-click="onAccessLogClick"/>
on-click="this.onAccessLogClick(iter.userId)"/>
<htk-button
form="iter"
column="id"
tip="_Supplant user"
icon="supervisor_account"
on-click="onChangeUserClick"/>
on-click="this.onChangeUserClick(iter.user)"/>
<p class="important">
{{iter.nickname}}
<htk-text form="iter" column="nickname"/>
</p>
<p>
<htk-text form="iter" column="stamp" format="%a, %T"/> -
<htk-text form="iter" column="lastUpdate" format="%T"/>
{{Vn.Value.format(iter.stamp, '%a, %T')}} -
{{Vn.Value.format(iter.lastUpdate, '%T')}}
</p>
<p>
<htk-text form="iter" column="platform"/> -
<htk-text form="iter" column="browser"/>
<htk-text form="iter" column="version"/>
{{iter.platform}} -
{{iter.browser}}
{{iter.version}}
</p>
</div>
</custom>

View File

@ -42,18 +42,16 @@
editable="true"
conn="conn"/>
<p class="concept">
<htk-text form="iter" column="longName"/>
{{iter.longName}}
</p>
<p class="tags">
<htk-text form="iter" column="value5"/>
<htk-text form="iter" column="value6"/>
<htk-text form="iter" column="value7"/>
{{iter.value5}} {{iter.value6}} {{iter.value7}}
</p>
<p>
#<htk-text form="iter" column="id"/>
{{iter.id}}
</p>
<p>
<htk-text form="iter" column="image"/>
{{iter.image}}
</p>
<div class="clear"/>
</div>

View File

@ -1,11 +1,5 @@
Hedera.Links = new Class
({
Hedera.Links = new Class({
Extends: Hedera.Form
,repeaterFunc: function (res, form)
{
res.$('link').href = form.get ('link');
}
});

View File

@ -4,7 +4,7 @@
</div>
<div id="form" class="cpanel">
<div class="box">
<htk-repeater form-id="iter" renderer="repeaterFunc">
<htk-repeater form-id="iter">
<db-model property="model">
<custom>
SELECT image, name, description, link FROM link
@ -12,17 +12,18 @@
</custom>
</db-model>
<custom>
<a id="link" class="item" target="_blank">
<a class="item"
href="{{iter.link}}"
target="_blank">
<htk-image
form="iter"
column="image"
value="{{iter.image}}"
directory="link"
subdir="full"/>
<p class="important">
<htk-text form="iter" column="name"/>
{{iter.name}}
</p>
<p>
<htk-text form="iter" column="description"/>
{{iter.description}}
</p>
</a>
</custom>

View File

@ -1,102 +1,91 @@
Hedera.Queries = new Class
({
Hedera.Queries = new Class({
Extends: Hedera.Form
,activate: function ()
{
,activate: function() {
this.$('result-index').value = 0;
}
,clean: function ()
{
if (this._grid)
{
this.$('grid-holder').removeChild (this._grid.node);
this._grid.unref ();
,clean: function() {
if (this._grid) {
this.$('grid-holder').removeChild(this._grid.node);
this._grid.unref();
this._grid = null;
}
}
,_onExecuteClick: function ()
{
this.clean ();
,onExecuteClick: function() {
this.clean();
var model = new Db.Model ({
var model = new Db.Model({
conn: this.conn,
query: this.$('sql').value,
resultIndex: this.$('result-index').value,
updatable: this.$('updatable').value
});
model.on ('status-changed', this._onModelChange, this);
model.on('status-changed', this.onModelChange, this);
}
,_onCleanClick: function ()
{
this.clean ();
,onCleanClick: function() {
this.clean();
}
,_onModelChange: function (model, status)
{
if (status !== Db.Model.Status.LOADING)
{
model.disconnect ('status-changed', this._onModelChange, this);
model.unref ();
,onModelChange: function(model, status) {
if (status !== Db.Model.Status.LOADING) {
model.disconnect('status-changed', this.onModelChange, this);
model.unref();
}
if (status !== Db.Model.Status.READY)
return;
Htk.Toast.showMessage (_('Query executed!'));
Htk.Toast.showMessage(_('Query executed!'));
var gridHolder = this.$('grid-holder');
if (gridHolder.firstChild)
gridHolder.removeChilds (gridHolder.firstChild);
gridHolder.removeChilds(gridHolder.firstChild);
var grid = new Htk.Grid ();
var grid = new Htk.Grid();
var columns = model.columns;
for (var i = 0; i < columns.length; i++)
{
for (var i = 0; i < columns.length; i++) {
var c = columns[i];
switch (c.type)
{
switch (c.type) {
case Db.Conn.Type.BOOLEAN:
var column = new Htk.ColumnCheck ();
var column = new Htk.ColumnCheck();
break;
case Db.Conn.Type.INTEGER:
var column = new Htk.ColumnSpin ();
var column = new Htk.ColumnSpin();
break;
case Db.Conn.Type.DOUBLE:
var column = new Htk.ColumnSpin ({digits: 2});
var column = new Htk.ColumnSpin({digits: 2});
break;
case Db.Conn.Type.DATE:
var column = new Htk.ColumnDate ({format: '%a, %e %b %Y'});
var column = new Htk.ColumnDate({format: '%a, %e %b %Y'});
break;
case Db.Conn.Type.DATE_TIME:
var column = new Htk.ColumnDate ({format: '%a, %e %b %Y, %T'});
var column = new Htk.ColumnDate({format: '%a, %e %b %Y, %T'});
break;
case Db.Conn.Type.STRING:
default:
var column = new Htk.ColumnText ();
var column = new Htk.ColumnText();
}
column.setProperties ({
column.setProperties({
title: c.name,
editable: this.$('updatable').value,
columnIndex: i
});
grid.appendColumn (column);
grid.appendColumn(column);
}
grid.model = model;
gridHolder.appendChild (grid.node);
gridHolder.appendChild(grid.node);
this._grid = grid;
}
});

View File

@ -1,25 +1,20 @@
.queries
{
.queries {
padding: 1em;
}
.queries .box
{
.queries .box {
max-width: 40em;
margin: 0 auto;
}
.queries .form
{
.queries .form {
box-sizing: border-box;
padding: 2em;
}
.queries textarea
{
.queries textarea {
display: block;
width: 100%;
height: 8em;
}
.queries .result
{
.queries .result {
margin-top: 1em;
overflow: auto;
}

View File

@ -6,11 +6,11 @@
<htk-bar-button
icon="ok"
tip="_Execute"
on-click="_onExecuteClick"/>
on-click="this.onExecuteClick()"/>
<htk-bar-button
icon="delete"
tip="_Clean"
on-click="_onCleanClick"/>
on-click="this.onCleanClick()"/>
</div>
<div id="form" class="queries">
<div class="box form">

View File

@ -1,32 +1,25 @@
.users
{
.users {
padding: 1em;
}
.users .box
{
.users .box {
max-width: 30em;
margin: 0 auto;
}
.users-box
{
.users-box {
padding: 1em;
border-bottom: 1px solid #DDD;
}
.users-box > button
{
.users-box > button {
float: right;
margin: 0;
}
.users-box > p
{
.users-box > p {
margin: .2em 0;
}
.users-box > p.important
{
.users-box > p.important {
font-size: 1.2em;
}
.users-box > .disabled
{
.users-box > .disabled {
float: right;
color: white;
background-color: #F66;
@ -38,8 +31,7 @@
/* Topbar */
.action-bar .htk-search-entry
{
.action-bar .htk-search-entry {
margin: .8em .6em;
}

View File

@ -31,18 +31,14 @@
<custom>
<div class="users-box">
<htk-button
form="iter"
column="id"
tip="_Access log"
icon="history"
on-click="onAccessLogClick"/>
tip="_Access log"
on-click="this.onAccessLogClick(iter.id)"/>
<htk-button
id="impersonate"
form="iter"
column="id"
tip="_Impersonate user"
icon="supervisor_account"
on-click="onChangeUserClick"/>
tip="_Impersonate user"
on-click="this.onChangeUserClick(iter.name)"/>
<span id="disabled" class="disabled">
<t>Disabled</t>
</span>

View File

@ -2,10 +2,10 @@
Hedera.Users = new Class({
Extends: Hedera.Form
,onAccessLogClick: function(button, form) {
,onAccessLogClick: function(userId) {
this.hash.set({
'form': 'admin/access-log'
,'user': form.get('id')
form: 'admin/access-log'
,user: userId
});
}
@ -17,8 +17,8 @@ Hedera.Users = new Class({
'block' : 'none';
}
,onChangeUserClick: function(button, form) {
this.gui.supplantUser(form.get('name'),
,onChangeUserClick: function(userName) {
this.gui.supplantUser(userName,
this.onUserSupplant.bind(this));
}

View File

@ -6,11 +6,11 @@
<htk-bar-button
icon="refresh"
tip="_Refresh"
on-click="onRefreshClick"/>
on-click="this.onRefreshClick()"/>
<htk-bar-button
icon="visibility"
tip="_Connections"
on-click="onSessionsClick"/>
on-click="this.onSessionsClick()"/>
</div>
<div id="form" class="visits">
<div class="box">

View File

@ -1,22 +1,18 @@
Hedera.Visits = new Class
({
Hedera.Visits = new Class({
Extends: Hedera.Form
,activate: function ()
{
this.$('from').value = new Date ();
this.$('to').value = new Date ();
,activate: function() {
this.$('from').value = new Date();
this.$('to').value = new Date();
}
,onRefreshClick: function ()
{
this.$('visits').refresh ();
,onRefreshClick: function() {
this.$('visits').refresh();
}
,onSessionsClick: function ()
{
this.hash.set ({'form': 'admin/connections'});
,onSessionsClick: function() {
this.hash.set({form: 'admin/connections'});
}
});

View File

@ -1,9 +1,5 @@
Hedera.Home = new Class({
Extends: Hedera.Form
,onStartOrderClick: function() {
this.hash.set({form: 'ecomerce/catalog'});
}
});

View File

@ -7,7 +7,7 @@
class="start-order"
icon="add_shopping_cart"
tip="_Start order"
on-click="onStartOrderClick"/>
on-click="this.hash.set({form: 'ecomerce/catalog'})"/>
</div>
<div id="form" class="home">
<div class="column mansonry" id="news-column">
@ -25,8 +25,7 @@
<htk-image
directory="news"
subdir="full"
form="iter"
column="image"
value="{{iter.image}}"
editable="false"
full-dir="full"/>
<div class="top">

View File

@ -54,9 +54,9 @@ Hedera.New = new Class({
this.editor.setContent(newHtml);
},
onStatusChange: function(form) {
onStatusChange: function() {
if (this.$('new-id').value == 0)
form.insertRow();
this.$('iter').insertRow();
},
onOperationsDone: function() {

View File

@ -1,23 +1,18 @@
.new
{
.new {
padding: 1em;
}
.new .box
{
.new .box {
max-width: 38em;
padding: 2em;
}
/* Form */
.new textarea
{
min-height: 20em;
.new textarea {
min-height: 500px;
}
.new .foot
{
.new .foot {
text-align: center;
margin-top: 1em;
}

View File

@ -2,12 +2,12 @@
<vn-group>
<vn-param id="new-id"/>
<vn-hash-param key="new" param="new-id"/>
<db-form id="iter" on-status-changed="onStatusChange">
<db-form id="iter" on-status-changed="this.onStatusChange()">
<db-model
id="model"
property="model"
updatable="true"
on-operations-done="onOperationsDone">
on-operations-done="this.onOperationsDone()">
<custom>
SELECT id, title, text, tag, priority
FROM news WHERE id = #new
@ -19,7 +19,7 @@
</sql-batch>
</db-model>
</db-form>
<db-param form="iter" column="text" on-changed="onBodyChange"/>
<db-param form="iter" column="text" on-changed="this.onBodyChange()"/>
</vn-group>
<div id="title">
<h1><t>AddEditNew</t></h1>
@ -28,11 +28,11 @@
<htk-bar-button
icon="close"
tip="_Return"
on-click="onReturnClick"/>
on-click="this.onReturnClick()"/>
<htk-bar-button
icon="check"
tip="_Accept"
on-click="onAcceptClick"/>
on-click="this.onAcceptClick()"/>
</div>
<div id="form" class="new">
<div class="box">

View File

@ -1,30 +1,25 @@
Hedera.News = new Class
({
Hedera.News = new Class({
Extends: Hedera.Form
,editNew: function (newId)
{
this.hash.set ({
'form': 'news/new'
,'new': newId
,editNew: function(newId) {
this.hash.set({
form: 'news/new',
new: newId
});
}
,onEditClick: function (button, form)
{
this.editNew (button.value);
,onEditClick: function(newId) {
this.editNew(newId);
}
,onDeleteClick: function (button, form)
{
if (confirm (_('ReallyDelete')))
form.deleteRow ();
,onDeleteClick: function(form) {
if (confirm(_('ReallyDelete')))
form.deleteRow();
}
,onAddClick: function ()
{
this.editNew (0);
,onAddClick: function() {
this.editNew(0);
}
});

View File

@ -6,7 +6,7 @@
<htk-bar-button
icon="add"
tip="_AddNew"
on-click="onAddClick"/>
on-click="this.onAddClick()"/>
</div>
<div id="form" class="news">
<div class="box">
@ -22,17 +22,13 @@
<custom>
<div class="item">
<htk-button
form="iter"
column="id"
tip="_EditNew"
icon="edit"
on-click="onEditClick"/>
tip="_EditNew"
on-click="this.onEditClick(iter.id)"/>
<htk-button
form="iter"
column="id"
tip="_Remove"
icon="delete"
on-click="onDeleteClick"/>
on-click="this.onDeleteClick($.iter)"/>
<htk-image
form="iter"
column="image"

View File

@ -1,23 +1,20 @@
Hedera.ItemsForm = new Class
({
Hedera.ItemsForm = new Class({
Extends: Hedera.Form
,activate: function ()
{
,activate: function() {
this.$('warehouse').value = 7;
this.$('realm').value = null;
}
,onPreviewClick: function ()
{
var batch = new Sql.Batch ();
batch.addValues ({
'warehouse': this.$('warehouse').value
,'realm': this.$('realm').value
,'rate': this.$('rate').value
,onPreviewClick: function() {
var batch = new Sql.Batch();
batch.addValues({
warehouse: this.$('warehouse').value
,realm: this.$('realm').value
,rate: this.$('rate').value
});
this.gui.openReport ('items-report', batch);
this.gui.openReport('items-report', batch);
}
});

View File

@ -6,7 +6,7 @@
<htk-bar-button
icon="print"
tip="_Preview"
on-click="onPreviewClick"/>
on-click="this.onPreviewClick()"/>
</div>
<div id="form" class="items">
<div class="box">

View File

@ -1,16 +1,13 @@
Hedera.Shelves = new Class
({
Hedera.Shelves = new Class({
Extends: Hedera.Form
,activate: function ()
{
this.$('date').value = new Date ();
,activate: function() {
this.$('date').value = new Date();
this.$('useIds').value = false;
}
,onConfigChange: function ()
{
,onConfigChange: function() {
var fields = [
'realm'
,'family'
@ -24,11 +21,10 @@ Hedera.Shelves = new Class
];
for (var i = 0; i < fields.length; i++)
this.$(fields[i]).value = this.$('config').get (fields[i]);
this.$(fields[i]).value = this.$('config').get(fields[i]);
}
,onPreviewClick: function ()
{
,onPreviewClick: function() {
var fields = [
'family'
,'warehouse'
@ -42,12 +38,12 @@ Hedera.Shelves = new Class
,'date'
];
var batch = new Sql.Batch ();
var batch = new Sql.Batch();
for (var i = 0; i < fields.length; i++)
batch.addValue (fields[i], this.$(fields[i]).value);
batch.addValue(fields[i], this.$(fields[i]).value);
this.gui.openReport ('shelves-report', batch);
this.gui.openReport('shelves-report', batch);
}
});

View File

@ -16,7 +16,7 @@
<htk-bar-button
icon="print"
tip="_Preview"
on-click="onPreviewClick"/>
on-click="this.onPreviewClick()"/>
</div>
<div id="form" class="shelves">
<div class="box">
@ -27,8 +27,8 @@
id="config"
placeholder="_Select config"
model="configs-model"
on-changed="onConfigChange"
on-ready="onConfigChange"/>
on-changed="this.onConfigChange()"
on-ready="this.onConfigChange()"/>
</div>
<div class="form-group">
<label><t>Date</t></label>

View File

@ -1,6 +1,5 @@
module.exports = new Class
({
module.exports = new Class({
Extends: Vn.Object
,isOpen: false
@ -31,28 +30,27 @@ module.exports = new Class
return;
var builder = new Vn.Builder();
builder.signalData = this;
builder.add('conn', this.conn);
builder.loadXml('forms/'+ this.formInfo.path +'/ui.xml');
builder.compileFile('forms/'+ this.formInfo.path +'/ui.xml');
var res = this.builder = builder.load();
this.node = res.$('form');
res.link(this);
var scope = this.builder = builder.load(null, this);
scope.link({conn: this.conn});
var models = res.getByTagName('db-model');
this.node = scope.$('form');
var models = scope.getByTagName('db-model');
for (var i = 0; i < models.length; i++)
models[i].conn = this.conn;
var queries = res.getByTagName('db-query');
var queries = scope.getByTagName('db-query');
for (var i = 0; i < queries.length; i++)
queries[i].conn = this.conn;
if (this.node) {
this.gui.setForm(this.node);
this.gui.setTitle(res.$('title'));
this.gui.setActions(res.$('actions'));
this.gui.setTitle(scope.$('title'));
this.gui.setActions(scope.$('actions'));
this.activate();
}

View File

@ -1,14 +1,12 @@
module.exports = new Class
({
module.exports = new Class({
Extends: Vn.Object
,initialize: function (moduleInfo, gui)
{
,initialize: function(moduleInfo, gui) {
this.info = moduleInfo;
this.gui = gui;
this.conn = gui.conn;
this.parent (null);
this.parent(null);
}
/**
@ -16,88 +14,80 @@ module.exports = new Class
*
* @param {string} objectId The object identifier
* @return {Object} The object, or %null if not found
**/
,$: function (objectId)
{
if (this.builderResult)
return this.builderResult.getById (objectId);
*/
,$: function(objectId) {
if (this.scope)
return this.scope.getById(objectId);
return null;
}
,open: function (batch)
{
,open: function(batch) {
this.batch = batch;
this.createWindow ();
this.createWindow();
}
,print: function ()
{
this.window.print ();
,print: function() {
this.window.print();
}
,includeCss: function (path)
{
,includeCss: function(path) {
var basePath = location.protocol +'//'+ location.host;
basePath += location.port ? ':'+ location.port : '';
basePath += location.pathname.substring (0,
location.pathname.lastIndexOf ('/'));
basePath += location.pathname.substring(0,
location.pathname.lastIndexOf('/'));
var link = this.doc.createElement ('link');
var link = this.doc.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = basePath +'/'+ path + Vn.getVersion ();
link.href = basePath +'/'+ path + Vn.getVersion();
var head = this.doc.getElementsByTagName ('head')[0];
head.appendChild (link);
var head = this.doc.getElementsByTagName('head')[0];
head.appendChild(link);
}
,createWindow: function ()
{
var reportWindow = window.open (
,createWindow: function() {
var reportWindow = window.open(
'js/hedera/report.html', '_blank',
'height=650, width=950, resizable=yes, fullscreen=no,'+
'titlebar=no, menubar=no, toolbar=no, location=no, scrollbars=yes'
);
if (!reportWindow)
{
Htk.Toast.showError (
if (!reportWindow) {
Htk.Toast.showError(
_('Please unlock popups and try again'));
return false;
}
reportWindow.addEventListener ('load',
this._onWindowLoad.bind (this));
reportWindow.addEventListener('load',
this._onWindowLoad.bind(this));
this.window = reportWindow;
return true;
}
,_onWindowLoad: function ()
{
,_onWindowLoad: function() {
this.doc = this.window.document
this.includeCss ('reports/'+ this.info.path +'/style.css');
this.includeCss('reports/'+ this.info.path +'/style.css');
var printButton = this.doc.getElementById ('print');
printButton.addEventListener ('click', this.print.bind (this));
Vn.Node.setText (printButton, _('Print'));
var printButton = this.doc.getElementById('print');
printButton.addEventListener('click', this.print.bind(this));
Vn.Node.setText(printButton, _('Print'));
this.onWindowCreate ();
this.onWindowCreate();
}
,onWindowCreate: function ()
{
var builder = new Vn.Builder ();
builder.signalData = this;
builder.add ('batch', this.batch);
builder.add ('conn', this.conn);
builder.loadXml ('reports/'+ this.info.path +'/ui.xml');
,onWindowCreate: function() {
var builder = new Vn.Builder();
builder.compileFile('reports/'+ this.info.path +'/ui.xml');
var res = this.builderResult = builder.load ();
res.link ();
var scope = this.scope = builder.load(this.doc, this);
scope.link({
batch: this.batch,
conn: this.conn
});
this.doc.body.appendChild (res.$('report'));
this.doc.body.appendChild(scope.$('report'));
}
});

View File

@ -1,49 +1,42 @@
var Widget = require ('./widget');
const Widget = require('./widget');
module.exports = new Class
({
module.exports = new Class({
Extends: Widget
,builder: null
,scope: null
,builderInit: function (path)
{
var builder = new Vn.Builder ();
builder.signalData = this;
builder.loadXml (path, this.doc);
this.builderResultInit (builder);
,builderInit: function(path) {
const builder = new Vn.Builder();
builder.compileFile(path);
this.builderResultInit(builder);
}
,builderInitString: function (xmlString)
{
var builder = new Vn.Builder ();
builder.signalData = this;
builder.loadFromString (xmlString, this.doc);
this.builderResultInit (builder);
,builderInitString: function(xmlString) {
const builder = new Vn.Builder();
builder.compileString(xmlString);
this.builderResultInit(builder);
}
,builderResultInit: function (builder)
{
var res = this.builder = builder.load ();
this._node = res.$('main');
res.link ();
,builderResultInit: function(builder) {
const scope = this.scope = builder.load(this.doc, this);
scope.link();
this._node = scope.$('main');
}
,$: function (id)
{
if (this.builder)
return this.builder.getById (id);
,$: function(id) {
if (this.scope)
return this.scope.getById(id);
return null;
}
,_destroy: function ()
{
if (this.builder)
this.builder.unref ();
,_destroy: function() {
if (this.scope)
this.scope.unref();
this.parent ();
this.parent();
}
});

View File

@ -1,75 +1,83 @@
var RadioGroup = require ('./radio-group');
var RadioGroup = require('./radio-group');
module.exports = new Class
({
module.exports = new Class({
Extends: Htk.Field
,Tag: 'htk-radio'
,Properties:
{
tip:
{
,Properties: {
tip: {
type: String
,set: function (x)
{
,set: function(x) {
if (x)
this.node.title = _(x);
}
},
radioGroup:
{
val: {
type: String
,get: function() {
return this._val;
}
,set: function(x) {
this._val = x;
this.node.value = !x ? '' : x;
this._onRadioGroupChange();
}
},
name: {
type: String
,get: function() {
return this.node.name;
}
,set: function(x) {
this.node.name = x;
}
},
radioGroup: {
type: RadioGroup
,set: function (x)
{
,get: function() {
return this._radioGroup;
}
,set: function(x) {
if (this._radioGroup)
this._radioGroup.removeButton (this);
this._radioGroup.removeButton(this);
this.link ({_radioGroup: x}, {'changed': this._onRadioGroupChange});
this.link({_radioGroup: x}, {'changed': this._onRadioGroupChange});
this.node.name = x.name;
x.buttons.push(this);
this._onRadioGroupChange ();
}
,get: function ()
{
return this._radioGroup;
this._onRadioGroupChange();
}
}
}
,_radioGroup: null
,render: function ()
{
var radio = Vn.Browser.createRadio ('', this.doc);
,render: function() {
var radio = Vn.Browser.createRadio('', this.doc);
radio.checked = false;
radio.addEventListener ('change', this._onChange.bind (this));
radio.addEventListener('change', this._onChange.bind(this));
this._node = radio;
}
,_onChange: function ()
{
,_onChange: function() {
console.log(this._val);
if (this.node.checked && this._radioGroup)
this._radioGroup.value = this.value;
this._radioGroup.value = this._val || this.value;
}
,_onRadioGroupChange: function ()
{
if (this._radioGroup.value && this._radioGroup.value == this.value)
this.node.checked = true;
else
this.node.checked = false;
,_onRadioGroupChange: function() {
const value = this._radioGroup.value;
this.node.checked =
value && (value == this._val || value == this.value);
}
,putValue: function (value)
{
,putValue: function(value) {
if (!value)
this.node.value = '';
else
this.node.value = value;
}
,setEditable: function (editable)
{
,setEditable: function(editable) {
this.node.disabled = !editable;
}
});

View File

@ -1,26 +1,22 @@
module.exports = new Class
({
module.exports = new Class({
Extends: Vn.Object
,doc: null
,initialize: function (props)
{
,initialize: function(props) {
this.doc = document;
this.parent (props);
this.parent(props);
}
,createElement: function (tagName)
{
return document.createElement (tagName);
,createElement: function(tagName) {
return document.createElement(tagName);
}
,createTextNode: function (text)
{
return document.createTextNode (text);
,createTextNode: function(text) {
return document.createTextNode(text);
}
,render: function () {}
,render: function() {}
});

View File

@ -9,13 +9,12 @@ module.exports = new Class({
{
/**
* The source data model.
**/
*/
model:
{
type: Db.Model
,set: function(x) {
this.link({_model: x},
{
this.link({_model: x}, {
'status-changed': this._onModelChange
,'row-deleted': this._onRowDelete
,'row-updated': this._onRowUpdate
@ -30,7 +29,7 @@ module.exports = new Class({
}
/**
* The identifier for internal iterator.
**/
*/
,formId:
{
type: String
@ -44,7 +43,7 @@ module.exports = new Class({
/**
* {Function (Vn.BuilderResult, Db.Form)} Function to call after every
* box rendering.
**/
*/
,renderer:
{
type: Function
@ -57,7 +56,7 @@ module.exports = new Class({
}
/**
* Wether to show the model status.
**/
*/
,showStatus:
{
type: Boolean
@ -71,7 +70,7 @@ module.exports = new Class({
}
/**
* Message that should be displayed when source model is not ready.
**/
*/
,emptyMessage:
{
type: String
@ -91,12 +90,12 @@ module.exports = new Class({
div.appendChild(this._container);
}
,loadXml: function(builderResult, node) {
this.parent(builderResult, node);
,loadXml: function(scope, node) {
this.parent(scope, node);
this._parentScope = scope;
var builder = this._builder = new Vn.Builder();
builder.setParent(builderResult);
builder.loadXmlFromNode(node.firstElementChild, null, [this._formId]);
builder.compileNode(node.firstElementChild, [this._formId]);
this._onModelChange();
}
@ -119,19 +118,20 @@ module.exports = new Class({
row: index
});
this._builder.add(this._formId, set);
var res = this._builder.load();
res.link(null, [set.getObject()]);
var scope = this._builder.load(this.doc, null, this._parentScope);
scope.link([set.getObject()], {
[this._formId]: set
});
this._childsData.push({
builder: res,
builder: scope,
set: set
});
if (this._renderer)
this._renderer(res, set);
this._renderer(scope, set);
return res.getMain();
return scope.getMain();
}
,_onModelChange: function() {

View File

@ -1,2 +1,3 @@
$color-primary: #8cc63f;
$color-hover-cd: rgba(255, 255, 255, .1);

View File

@ -1,36 +1,30 @@
var NodeBuilder = require ('./node-builder');
var NodeBuilder = require('./node-builder');
module.exports = new Class
({
module.exports = new Class({
Extends: NodeBuilder
,Properties:
{
/**
* Main HTML node that represents the widget
**/
node:
{
*/
node: {
type: Object
,get: function ()
{
this.renderBase ();
,get: function() {
this.renderBase();
return this._node;
}
},
/**
* CSS classes to be appendend to the node classes.
**/
class:
{
*/
class: {
type: String
,set: function (x)
{
,set: function(x) {
this._cssClass = x;
this._refreshClass ();
this._refreshClass();
}
,get: function ()
{
,get: function() {
return this._node.className;
}
}
@ -38,36 +32,31 @@ module.exports = new Class
,_node: null
,initialize: function (props)
{
,initialize: function(props) {
this.doc = document;
this.renderBase ();
this.parent (props);
this.renderBase();
this.parent(props);
}
,createRoot: function (tagName)
{
return this._node = this.createElement (tagName);
,createRoot: function(tagName) {
return this._node = this.createElement(tagName);
}
,renderBase: function ()
{
,renderBase: function() {
if (this._node)
return;
this.render ();
this._refreshClass ();
this.render();
this._refreshClass();
}
,_refreshClass: function ()
{
,_refreshClass: function() {
if (this._node && this._cssClass)
this._node.className = this._cssClass +' '+ this._node.className;
}
,remove: function ()
{
Vn.Node.remove (this._node);
,remove: function() {
Vn.Node.remove(this._node);
}
});

View File

@ -1,6 +1,6 @@
var Object = require ('./object');
var Value = require ('./value');
var Object = require('./object');
var Value = require('./value');
/**
* A map container for many Sql.Object
@ -14,12 +14,10 @@ module.exports = new Class
blocked:
{
type: Boolean
,set: function (x)
{
,set: function(x) {
this._blocked = x;
}
,get: function ()
{
,get: function() {
return this._blocked;
}
}
@ -28,75 +26,64 @@ module.exports = new Class
,objects: {}
,_blocked: false
,loadXml: function (builder, node)
{
this.parent (builder, node);
,loadXml: function(scope, node) {
this.parent(scope, node);
var childs = node.childNodes;
for (var i = 0; i < childs.length; i++)
if (childs[i].tagName && childs[i].tagName.toLowerCase () == 'item')
{
if (childs[i].tagName && childs[i].tagName.toLowerCase() == 'item') {
var object;
var id = childs[i].getAttribute ('name');
var id = childs[i].getAttribute('name');
if (id)
{
if (object = builder.getById (childs[i].getAttribute ('param')))
this.addParam (id, object);
else if (object = builder.getById (childs[i].getAttribute ('object')))
this.addObject (id, object);
if (id) {
if (object = scope.getById(childs[i].getAttribute('param')))
this.addParam(id, object);
else if (object = scope.getById(childs[i].getAttribute('object')))
this.addObject(id, object);
}
}
}
,get: function (id)
{
,get: function(id) {
if (this.objects[id])
return this.objects[id];
return null;
}
,add: function (id)
{
,add: function(id) {
if (!this.objects[id])
this.objects[id] = null;
}
,_addObject: function (id, object)
{
this.remove (id);
,_addObject: function(id, object) {
this.remove(id);
this.objects[id] = object;
object.on ('changed', this.emitChanged, this);
this.emitChanged ();
object.on('changed', this.emitChanged, this);
this.emitChanged();
}
,addObject: function (id, object)
{
this._addObject (id, object.ref ());
,addObject: function(id, object) {
this._addObject(id, object.ref());
}
,addValue: function (id, value)
{
this._addObject (id,
new Value ({value: value}));
,addValue: function(id, value) {
this._addObject(id,
new Value({value: value}));
}
,addValues: function (values)
{
,addValues: function(values) {
for (var id in values)
this.addValue (id, values[id]);
this.addValue(id, values[id]);
}
,addParam: function (id, param)
{
this._addObject (id,
new Value ({param: param}));
,addParam: function(id, param) {
this._addObject(id,
new Value({param: param}));
}
,getValue: function (id)
{
,getValue: function(id) {
var object = this.objects[id];
if (object instanceof Value)
@ -105,65 +92,54 @@ module.exports = new Class
return null;
}
,addParams: function (params)
{
,addParams: function(params) {
for (var id in params)
this.addParam (id, params[id]);
this.addParam(id, params[id]);
}
,remove: function (id)
{
if (this.objects[id])
{
this._unrefObject (this.objects[id]);
,remove: function(id) {
if (this.objects[id]) {
this._unrefObject(this.objects[id]);
delete this.objects[id];
}
}
,block: function ()
{
,block: function() {
this._blocked = true;
}
,unblock: function ()
{
,unblock: function() {
this._blocked = false;
}
,emitChanged: function ()
{
,emitChanged: function() {
if (!this._blocked)
this.signalEmit ('changed');
this.signalEmit('changed');
}
,changed: function ()
{
this.signalEmit ('changed');
,changed: function() {
this.signalEmit('changed');
}
,isReady: function ()
{
,isReady: function() {
for (var id in this.objects)
if (!(this.objects[id] && this.objects[id].isReady ()))
if (!(this.objects[id] && this.objects[id].isReady()))
return false;
return true;
}
,_unrefObject: function (object)
{
if (object)
{
object.disconnect ('changed', this.emitChanged, this);
object.unref ();
,_unrefObject: function(object) {
if (object) {
object.disconnect('changed', this.emitChanged, this);
object.unref();
}
}
,_destroy: function ()
{
,_destroy: function() {
for (var id in this.objects)
this._unrefObject (this.objects[id]);
this._unrefObject(this.objects[id]);
this.parent ();
this.parent();
}
});

View File

@ -1,100 +1,62 @@
var Object = require('./object');
const VnObject = require('./object');
const Scope = require('./scope');
const kebabToCamel = require('./string-util').kebabToCamel;
/**
* Creates a object from a XML specification.
*/
module.exports = new Class({
Extends: Object
,_addedMap: {}
Extends: VnObject
,_contexts: null
,add: function(id, object) {
this._addedMap[id] = object;
}
,setParent: function(parentResult) {
this._parentResult = parentResult;
if (parentResult && !this.signalData)
this.signalData = parentResult.builder.signalData;
}
,getMain: function(result) {
return result.objects[this._mainContext];
}
,getById: function(result, objectId) {
var index = this._contextMap[objectId];
if (index !== undefined)
return result.objects[index];
var object = this._addedMap[objectId];
if (object !== undefined)
return object;
if (this._parentResult)
return this._parentResult.getById(objectId);
return null;
}
,getByTagName: function(result, tagName) {
var tags = this._tags[tagName];
if (tags) {
var arr = new Array(tags.length);
for (var i = 0; i < tags.length; i++)
arr[i] = result.objects[tags[i]];
return arr;
}
return [];
}
/**
* Compiles an XML file.
*
* @path String The XML path
* @dstDocument Document The document used to create the nodes
* @return %true on success, %false othersise
* @param {String} path The XML path
* @return {Boolean} %true on success, %false othersise
*/
,loadXml: function(path, dstDocument) {
,compileFile: function(path) {
this._path = path;
return this.loadFromXmlDoc(Vn.getXml(path), dstDocument);
}
return this.compileDocument(Vn.getXml(path));
}
,loadFromString: function(xmlString, dstDocument) {
/**
* Compiles an XML string.
*
* @param {String} xmlString The XML string
* @return {Boolean} %true on success, %false othersise
*/
,compileString: function(xmlString) {
var parser = new DOMParser();
var xmlDoc = parser.parseFromString(xmlString, 'text/xml');
return this.loadFromXmlDoc(xmlDoc, dstDocument);
}
var doc = parser.parseFromString(xmlString, 'text/xml');
return this.compileDocument(doc);
}
,loadFromXmlDoc: function(xmlDoc, dstDocument, scope) {
if (!xmlDoc)
return false;
/**
* Compiles a XML document.
*
* @param {Document} doc The DOM document
* @return {Boolean} %true on success, %false othersise
*/
,compileDocument: function(doc, exprArgs) {
if (!doc)
return false;
this._compileInit(dstDocument, scope);
var docElement = xmlDoc.documentElement;
this._preCompile(exprArgs);
var docElement = doc.documentElement;
if (docElement.tagName !== 'vn') {
this._showError('Malformed XML');
this.showError('The toplevel tag should be named \'vn\'');
this._contexts = null;
return false;
}
var childs = docElement.childNodes;
if (childs)
for (var i = 0; i < childs.length; i++)
this._compileNode(childs[i]);
this._compile(childs[i]);
this._compileEnd();
this._postCompile();
return true;
}
@ -102,87 +64,171 @@ module.exports = new Class({
* Compiles a single DOM node.
*
* @path Node The DOM node
* @dstDocument Document The document used to create the nodes
* @return %true on success, %false othersise
*/
,loadXmlFromNode: function(node, dstDocument, scope) {
this._compileInit(dstDocument, scope);
this._mainContext = this._compileNode(node).id;
this._compileEnd();
,compileNode: function(node, exprArgs) {
this._preCompile(exprArgs);
this._mainContext = this._compile(node).id;
this._postCompile();
return true;
}
,load: function() {
/**
* Called before starting to compile nodes.
*/
,_preCompile: function(exprArgs) {
this._path = null;
this._tags = {};
this._contexts = [];
this._contextMap = {};
this._links = [];
this._mainContext = null;
this._baseExprArgs = ['_', '$'];
if (exprArgs)
this._baseExprArgs = this._baseExprArgs.concat(exprArgs);
this._baseEventArgs = this._baseExprArgs.concat(['$event']);
this._exprArgs = this._baseExprArgs.join(',');
this._eventArgs = this._baseEventArgs.join(',');
}
/**
* Called after all nodes have been compiled.
*/
,_postCompile: function() {}
/**
* Compiles a node.
*/
,_compile: function(node) {
let context = null;
let tagName = null;
const isElement = node.nodeType === Node.ELEMENT_NODE;
if (isElement)
tagName = node.tagName.toLowerCase();
else if (node.nodeType !== Node.TEXT_NODE
|| /^[\n\r\t]*$/.test(node.textContent))
return null;
context =
this.textCompile(node, tagName)
|| this.objectCompile(node, tagName)
|| this.elementCompile(node, tagName);
context.id = this._contexts.length;
if (isElement) {
var nodeId = node.getAttribute('id');
if (nodeId)
this._contextMap[kebabToCamel(nodeId)] = context.id;
var tags = this._tags[tagName];
if (!tags)
this._tags[tagName] = tags = [];
tags.push(context.id);
}
this._contexts.push(context);
return context;
}
,getMain: function(scope) {
return scope.objects[this._mainContext];
}
,getByTagName: function(scope, tagName) {
var tags = this._tags[tagName];
if (tags) {
var arr = new Array(tags.length);
for (var i = 0; i < tags.length; i++)
arr[i] = scope.objects[tags[i]];
return arr;
}
return [];
}
,load: function(dstDocument, thisArg, parentScope) {
if (this._contexts === null)
return null;
var contexts = this._contexts;
var len = contexts.length;
var objects = new Array(len);
const contexts = this._contexts;
const len = contexts.length;
const objects = new Array(len);
const doc = dstDocument ? dstDocument : document;
for (var i = 0; i < len; i++) {
var context = contexts[i];
if (context.tagName)
objects[i] = this.elementInstantiate(context);
objects[i] = this.elementInstantiate(doc, context);
else if (context.klass)
objects[i] = this.objectInstantiate(context);
objects[i] = this.objectInstantiate(doc, context);
else
objects[i] = this.textInstantiate(context);
objects[i] = this.textInstantiate(doc, context);
}
return new BuilderResult(this, objects);
return new Scope(this, objects, thisArg, parentScope);
}
,link: function(result, self, scope) {
var objects = result.objects;
,link: function(scope, exprScope) {
const objects = scope.objects;
const links = this._links;
for (var i = this._links.length - 1; i >= 0; i--) {
var l = this._links[i];
var addedObject = this._addedMap[l.objectId];
// Pre-link
if (addedObject) {
if (l.prop)
objects[l.context.id][l.prop] = addedObject;
else
objects[l.context.id].appendChild(addedObject);
} else
this._showError('Referenced unexistent object with id \'%s\'',
l.objectId);
for (var i = links.length - 1; i >= 0; i--) {
const link = links[i];
const object = objects[link.context.id];
const objectRef = scope._$[link.objectId];
if (objectRef === undefined) {
this.showError('Referenced unexistent object with id \'%s\'',
link.objectId);
continue;
}
if (link.prop)
object[link.prop] = objectRef;
else
object.appendChild(objectRef);
}
this.linkExpr(result, self, scope);
// Post-link
var contexts = this._contexts;
const baseExprScope = [
_,
scope._$
].concat(exprScope);
this.linkExpr(scope, baseExprScope);
const contexts = this._contexts;
for (var i = 0; i < contexts.length; i++) {
var context = contexts[i];
var object = objects[i];
const context = contexts[i];
const object = objects[i];
if (context.tagName)
this.elementLink(context, object, objects, result);
this.elementLink(context, object, objects, scope, baseExprScope);
else if (context.klass)
this.objectLink(context, object, objects, result);
this.objectLink(context, object, objects, scope, baseExprScope);
}
}
,fnExpr(expr) {
return new Function(this._scopeArgs,
'"use strict"; return ' + expr + ';'
);
}
,matchExpr(value) {
const match = /^{{(.*)}}$/.exec(value);
if (!match) return null;
return this.fnExpr(match[1]);
}
,linkExpr(result, self, scope) {
,linkExpr(scope, baseScope, exprScope) {
const contexts = this._contexts;
const objects = result.objects;
let args = [_]
const objects = scope.objects;
if (scope) args = args.concat(scope);
exprScope = baseScope.concat(exprScope);
for (let i = 0; i < contexts.length; i++) {
const context = contexts[i];
@ -193,7 +239,7 @@ module.exports = new Class({
for (expr of context.exprs) {
let value = undefined;
try {
value = expr.apply(self, args);
value = expr.apply(scope.thisArg, exprScope);
} catch (e) {
console.warn('Expression error:', e.message);
continue;
@ -212,7 +258,7 @@ module.exports = new Class({
for (const prop in dynProps) {
let value = undefined;
try {
value = dynProps[prop].apply(self, args);
value = dynProps[prop].apply(scope.thisArg, exprScope);
} catch (e) {
console.warn('Expression error:', e.message);
continue;
@ -227,82 +273,80 @@ module.exports = new Class({
}
}
,_compileInit: function(dstDocument, scope) {
this._path = null;
this._tags = {};
this._contexts = [];
this._contextMap = {};
this._links = [];
this._mainContext = null;
this._doc = dstDocument ? dstDocument : document;
,showError: function(error) {
var path = this._path ? this._path : 'Node';
var logArgs = ['Vn.Builder: %s: '+ error, path];
this._scope = ['_'];
if (scope)
this._scope = this._scope.concat(scope);
this._scopeArgs = this._scope.join(',');
for (var i = 1; i < arguments.length; i++)
logArgs.push(arguments[i]);
console.warn.apply(null, logArgs);
}
,_compileEnd: function() {
for (var i = this._links.length - 1; i >= 0; i--) {
var l = this._links[i];
var contextId = this._contextMap[l.objectId];
,_addLink: function(context, prop, objectId) {
this._links.push({
context
,prop
,objectId: kebabToCamel(objectId)
});
}
if (contextId != undefined) {
if (l.prop)
l.context.objectProps[l.prop] = contextId;
else
l.context.childs.push(contextId);
,fnExpr(expr) {
return new Function(this._exprArgs,
'"use strict"; return ' + expr + ';'
);
}
this._links.splice(i, 1);
} else {
var object = this._addedMap[l.objectId];
,matchExpr(value) {
const match = /^{{(.*)}}$/.exec(value);
if (!match) return null;
return this.fnExpr(match[1]);
}
if (!object && this._parentResult)
object = this._parentResult.getById(l.objectId);
,_translateValue: function(value) {
var chr = value.charAt(0);
if (object) {
l.context.props[l.prop] = object;
this._links.splice(i, 1);
}
if (chr === '_')
return _(value.substr(1));
else if (chr === '\\' && value.charAt(1) === '_')
return value.substr(1);
return value;
}
,_getMethod: function(value) {
let method;
if (this.isIdentifier(value)) {
// XXX: Compatibility with old events
method = value;
} else {
try {
method = new Function(this._eventArgs,
'"use strict"; return ' + value + ';'
);
} catch (err) {
this.showError(`Method: ${err.message}: ${value}`);
}
}
return method;
}
,_compileNode: function(node) {
var context = null;
var tagName = null;
if (node.nodeType === Node.ELEMENT_NODE)
tagName = node.tagName.toLowerCase();
else if (node.nodeType !== Node.TEXT_NODE
|| /^[\n\r\t]*$/.test(node.textContent))
return null;
var context =
this.textCompile(node, tagName)
|| this.objectCompile(node, tagName)
|| this.elementCompile(node, tagName);
context.id = this._contexts.length;
if (tagName) {
var nodeId = node.getAttribute('id');
if (nodeId)
this._contextMap[nodeId] = context.id;
var tags = this._tags[tagName];
if (!tags)
this._tags[tagName] = tags = [];
tags.push(context.id);
}
this._contexts.push(context);
return context;
,_isEvent: function(attribute) {
return /^on-\w+/.test(attribute);
}
,isIdentifier: function(value) {
return /^[a-zA-Z_$][\w$]*$/.test(value);
}
,_replaceFunc: function(token) {
return token.charAt(1).toUpperCase();
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ TextNode
/**
* Creates a text node context.
*/
@ -328,10 +372,12 @@ module.exports = new Class({
return null;
}
,textInstantiate: function(context) {
return this._doc.createTextNode(context.exprs ? '' : context.text);
,textInstantiate: function(doc, context) {
return doc.createTextNode(context.exprs ? '' : context.text);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Vn.Object
/**
* Creates a object context.
*/
@ -342,7 +388,6 @@ module.exports = new Class({
return null;
var props = {};
var dynProps = {};
var objectProps = {};
var childs = [];
var events = {};
@ -350,7 +395,8 @@ module.exports = new Class({
var context = {
klass: klass,
props: props,
dynProps: dynProps,
dynProps: {},
funcProps: {},
objectProps: objectProps,
childs: childs,
events: events,
@ -369,7 +415,7 @@ module.exports = new Class({
if (handler)
events[attribute.substr(3)] = handler;
} else if (!/^(id|property)$/.test(attribute)) {
this.propCompile(context, klass, props, dynProps,
this.propCompile(context, klass, props,
node, attribute, value);
}
}
@ -387,7 +433,7 @@ module.exports = new Class({
this._addLink(context, null, child.getAttribute('object'));
} else if (childTagName === 'custom') {
context.custom = child;
} else if (childContext = this._compileNode(child)) {
} else if (childContext = this._compile(child)) {
var prop = isElement ? child.getAttribute('property') : null;
if (prop) {
@ -401,19 +447,20 @@ module.exports = new Class({
return context;
}
,propCompile: function(context, klass, props, dynProps, node, attribute, value) {
var isLink = false;
var newValue = null;
var propName = attribute.replace(/-./g, this._replaceFunc);
var propInfo = klass.Properties[propName];
,propCompile: function(context, klass, props, node, attribute, value) {
let isLink = false;
let propError = false;
let newValue = null;
const propName = attribute.replace(/-./g, this._replaceFunc);
const propInfo = klass.Properties[propName];
if (!propInfo) {
this._showError('Attribute \'%s\' not valid for tag \'%s\'',
this.showError('Attribute \'%s\' not valid for tag \'%s\'',
attribute, node.tagName);
return;
}
if (!value) {
this._showError('Attribute \'%s\' empty on tag \'%s\'',
this.showError('Attribute \'%s\' empty on tag \'%s\'',
attribute, node.tagName);
return;
}
@ -421,7 +468,7 @@ module.exports = new Class({
const expr = this.matchExpr(value);
if (expr) {
dynProps[propName] = expr;
context.dynProps[propName] = expr;
} else {
switch (propInfo.type) {
case Boolean:
@ -434,49 +481,89 @@ module.exports = new Class({
newValue = this._translateValue(value);
break;
case Function:
var method = this._getMethod(value);
newValue = method ? method.bind(this.signalData) : null;
context.funcProps[propName] = this._getMethod(value);
break;
default:
if (propInfo.enumType)
newValue = propInfo.enumType[value];
else if (propInfo.type instanceof Function)
isLink = true;
else
propError = true;
}
if (isLink)
this._addLink(context, propName, value);
else if (newValue !== null && newValue !== undefined)
props[propName] = newValue;
else
this._showError('Attribute \'%s\' invalid for tag \'%s\'',
else if (propError)
this.showError('Attribute \'%s\' invalid for tag \'%s\'',
attribute, node.tagName);
}
}
,objectInstantiate: function(context) {
,objectInstantiate: function(doc, context) {
return new context.klass();
}
,objectLink: function(context, object, objects, res) {
,objectLink: function(context, object, objects, scope, exprScope) {
object.setProperties(context.props);
var objectProps = context.objectProps;
for (var prop in objectProps)
const objectProps = context.objectProps;
for (const prop in objectProps)
object[prop] = objects[objectProps[prop]];
var childs = context.childs;
for (var i = 0; i < childs.length; i++)
const childs = context.childs;
for (let i = 0; i < childs.length; i++)
object.appendChild(objects[childs[i]]);
var events = context.events;
for (var event in events)
object.on(event, events[event], this.signalData);
const funcProps = context.funcProps;
for (const prop in funcProps) {
let method;
const handler = funcProps[prop];
if (typeof handler === 'string') {
// XXX: Compatibility with old expressions
method = scope.thisArg[handler];
if (!method)
this.showError(`Function '${handler}' not found`);
method = method.bind(scope.thisArg);
} else {
method = function() {
handler.apply(scope.thisArg, exprScope);
};
}
if (method)
object[prop] = method;
}
const events = context.events;
for (const event in events) {
let listener;
const handler = events[event];
if (typeof handler === 'string') {
// XXX: Compatibility with old expressions
listener = scope.thisArg[handler];
if (!listener)
this.showError(`Function '${handler}' not found`);
} else {
listener = function() {
handler.apply(scope.thisArg, exprScope.concat(arguments));
};
}
if (listener)
object.on(event, listener, scope.thisArg);
}
if (context.custom)
object.loadXml(res, context.custom);
object.loadXml(scope, context.custom);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Element
/**
* Creates a HTML node context.
*/
@ -492,17 +579,17 @@ module.exports = new Class({
for (var i = 0; i < a.length; i++) {
var attribute = a[i].nodeName;
var value = a[i].nodeValue;
const expr = this.matchExpr(value);
if (expr) {
dynProps[attribute] = expr;
} else if (this._isEvent(attribute)) {
if (this._isEvent(attribute)) {
var handler = this._getMethod(value);
if (handler)
events[attribute.substr(3)] = handler;
} else if (attribute !== 'id')
attributes[attribute] = this._translateValue(value);
if (handler) events[attribute.substr(3)] = handler;
} else if (attribute !== 'id') {
const expr = this.matchExpr(value);
if (expr)
dynProps[attribute] = expr;
else
attributes[attribute] = this._translateValue(value);
}
}
var childContext;
@ -510,7 +597,7 @@ module.exports = new Class({
if (childNodes)
for (var i = 0; i < childNodes.length; i++)
if (childContext = this._compileNode(childNodes[i]))
if (childContext = this._compile(childNodes[i]))
childs.push(childContext.id);
return {
@ -522,18 +609,18 @@ module.exports = new Class({
};
}
,elementInstantiate: function(context) {
return this._doc.createElement(context.tagName);
,elementInstantiate: function(doc, context) {
return doc.createElement(context.tagName);
}
,elementLink: function(context, object, objects) {
var attributes = context.attributes;
for (var attribute in attributes)
,elementLink: function(context, object, objects, scope, exprScope) {
const attributes = context.attributes;
for (const attribute in attributes)
object.setAttribute(attribute, attributes[attribute]);
var childs = context.childs;
const childs = context.childs;
for (var i = 0; i < childs.length; i++) {
var child = objects[childs[i]];
let child = objects[childs[i]];
if (child instanceof Htk.Widget)
child = child.node;
@ -541,98 +628,24 @@ module.exports = new Class({
object.appendChild(child);
}
var events = context.events;
for (var event in events)
object.addEventListener(event,
events[event].bind(this.signalData));
}
const events = context.events;
for (const event in events) {
let listener;
const handler = events[event];
if (typeof handler === 'string') {
// XXX: Compatibility with old expressions
listener = scope.thisArg[handler];
if (!listener)
this.showError(`Function '${handler}' not found`);
listener = listener.bind(scope.thisArg);
} else {
listener = function(e) {
handler.apply(scope.thisArg, exprScope.concat(e));
};
}
,_showError: function(error) {
var path = this._path ? this._path : 'Node';
var logArgs = ['Vn.Builder: %s: '+ error, path];
for (var i = 1; i < arguments.length; i++)
logArgs.push(arguments[i]);
console.warn.apply(null, logArgs);
}
,_addLink: function(context, prop, objectId) {
this._links.push({
context: context
,prop: prop
,objectId: objectId
});
}
,_translateValue: function(value) {
var chr = value.charAt(0);
if (chr === '_')
return _(value.substr(1));
else if (chr === '\\' && value.charAt(1) === '_')
return value.substr(1);
return value;
}
,_getMethod: function(value) {
if (this.signalData)
var method = this.signalData[value];
else
var method = window[value];
if (method === undefined)
this._showError('Function \'%s\' not found', value);
return method;
}
,_isEvent: function(attribute) {
return /^on-\w+/.test(attribute);
}
,_replaceFunc: function(token) {
return token.charAt(1).toUpperCase();
if (listener)
object.addEventListener(event, listener);
}
}
});
var BuilderResult = new Class({
Extends: Object
,initialize: function(builder, objects) {
this.builder = builder;
this.objects = objects;
}
,getMain: function() {
return this.builder.getMain(this);
}
,$: function(objectId) {
return this.builder.getById(this, objectId);
}
,getById: function(objectId) {
return this.builder.getById(this, objectId);
}
,getByTagName: function(tagName) {
return this.builder.getByTagName(this, tagName);
}
,link: function(self, scope) {
this.builder.link(this, self, scope);
}
,_destroy: function() {
var objects = this.objects;
for (var i = 0; i < objects.length; i++)
if (objects[i] instanceof Object)
objects[i].unref();
this.parent();
}
});

60
js/vn/scope.js Normal file
View File

@ -0,0 +1,60 @@
const VnObject = require('./object');
const kebabToCamel = require('./string-util').kebabToCamel;
module.exports = new Class({
Extends: VnObject
,initialize: function(builder, objects, thisArg, parentScope) {
this.builder = builder;
this.objects = objects;
this.thisArg = thisArg;
this.parentScope = parentScope;
if (!thisArg && parentScope)
this.thisArg = parentScope.thisArg;
}
,link: function(exprScope, extraObjects) {
var contextMap = this.builder._contextMap;
var objectMap = this.parentScope ? Object.create(this.parentScope._$) : {};
this._$ = objectMap;
for (var id in extraObjects)
objectMap[id] = extraObjects[id];
for (var id in contextMap)
objectMap[id] = this.objects[contextMap[id]];
this.builder.link(this, exprScope);
}
,getMain: function() {
return this.builder.getMain(this);
}
,$: function(objectId) {
if (!objectId) return null;
return this._$[kebabToCamel(objectId)];
}
,getById: function(objectId) {
return this.$(objectId);
}
,getByTagName: function(tagName) {
return this.builder.getByTagName(this, tagName);
}
,getHtmlId: function(nodeId) {
return 'vn-'+ this.uid +'-'+ nodeId;
}
,_destroy: function() {
var objects = this.objects;
for (var i = 0; i < objects.length; i++)
if (objects[i] instanceof VnObject)
objects[i].unref();
this.parent();
}
});

27
js/vn/string-util.js Normal file
View File

@ -0,0 +1,27 @@
module.exports = {
kebabToCamel: kebabToCamel,
kebabToPascal: kebabToPascal
};
/**
* Converts a kebab-case (hyphenized) string to camelCase (lowerCamelCase).
*
* @param {String} string The kebab-case string
* @return {String} The string parsed to camelCase
*/
function kebabToCamel(string) {
function replaceFunc(token) {
return token.charAt(1).toUpperCase();
}
return string.replace(/-./g, replaceFunc);
}
/**
* Converts a kebab-case (hyphenized) string to PascalCase (UpperCamelCase).
*
* @param {String} string The kebab-case string
* @return {String} The string parsed to PascalCase
*/
function kebabToPascal(string) {
string = string.charAt(0).toUpperCase() + string.substr(1);
return kebabToCamel(string);
}