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(); window.history.back();
} }
,onSetDefaultClick: function() { ,onSetDefaultClick: function(event, addressId) {
if (event.defaultPrevented) return;
this.$('defaultAddress').value = addressId;
Htk.Toast.showMessage(_('DefaultAddressModified')); Htk.Toast.showMessage(_('DefaultAddressModified'));
} }
,onRemoveAddressClick: function(button, form) { ,onRemoveAddressClick: function(form) {
if (confirm(_('AreYouSureDeleteAddress'))) { if (confirm(_('AreYouSureDeleteAddress'))) {
form.set('isActive', false); form.set('isActive', false);
form.refresh(); form.refresh();
} }
} }
,onEditAddressClick: function(button, form) { ,onEditAddressClick: function(id) {
this.hash.set({ this.hash.set({
form: 'account/address', form: 'account/address',
address: form.get('id') address: id
}); });
} }
}); });

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,11 +2,13 @@
<vn-group> <vn-group>
<vn-param id="user"/> <vn-param id="user"/>
<vn-hash-param key="user" param="user"/> <vn-hash-param key="user" param="user"/>
<db-form id="user-form"> <db-form id="userForm">
<db-model property="model"> <db-model property="model">
<custom> <custom>
SELECT Id_Cliente, Cliente, Telefono, movil SELECT u.id, u.nickname, u.email, c.phone
FROM vn2008.Clientes WHERE Id_Cliente = #user FROM account.user u
LEFT JOIN vn.client c ON c.id = u.id
WHERE u.id = #user
</custom> </custom>
<sql-batch property="batch"> <sql-batch property="batch">
<custom> <custom>
@ -22,18 +24,10 @@
<div id="form" class="access-log"> <div id="form" class="access-log">
<div class="box"> <div class="box">
<div class="form"> <div class="form">
<p> <p>#{{$.userForm.id}}</p>
<htk-text form="user-form" column="Id_Cliente"/> <p>{{$.userForm.nickname}}</p>
</p> <p>{{$.userForm.email}}</p>
<p> <p>{{$.userForm.phone}}</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>
</div> </div>
</div> </div>
<div class="list box"> <div class="list box">
@ -58,12 +52,12 @@
<custom> <custom>
<div class="item"> <div class="item">
<p> <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>
<p> <p>
<htk-text form="iter" column="platform"/> - {{iter.platform}} -
<htk-text form="iter" column="browser"/> {{iter.browser}}
<htk-text form="iter" column="version"/> {{iter.version}}
</p> </p>
</div> </div>
</custom> </custom>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,23 +1,20 @@
Hedera.ItemsForm = new Class Hedera.ItemsForm = new Class({
({
Extends: Hedera.Form Extends: Hedera.Form
,activate: function () ,activate: function() {
{
this.$('warehouse').value = 7; this.$('warehouse').value = 7;
this.$('realm').value = null; this.$('realm').value = null;
} }
,onPreviewClick: function () ,onPreviewClick: function() {
{ var batch = new Sql.Batch();
var batch = new Sql.Batch (); batch.addValues({
batch.addValues ({ warehouse: this.$('warehouse').value
'warehouse': this.$('warehouse').value ,realm: this.$('realm').value
,'realm': this.$('realm').value ,rate: this.$('rate').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 <htk-bar-button
icon="print" icon="print"
tip="_Preview" tip="_Preview"
on-click="onPreviewClick"/> on-click="this.onPreviewClick()"/>
</div> </div>
<div id="form" class="items"> <div id="form" class="items">
<div class="box"> <div class="box">

View File

@ -1,16 +1,13 @@
Hedera.Shelves = new Class Hedera.Shelves = new Class({
({
Extends: Hedera.Form Extends: Hedera.Form
,activate: function () ,activate: function() {
{ this.$('date').value = new Date();
this.$('date').value = new Date ();
this.$('useIds').value = false; this.$('useIds').value = false;
} }
,onConfigChange: function () ,onConfigChange: function() {
{
var fields = [ var fields = [
'realm' 'realm'
,'family' ,'family'
@ -24,11 +21,10 @@ Hedera.Shelves = new Class
]; ];
for (var i = 0; i < fields.length; i++) 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 = [ var fields = [
'family' 'family'
,'warehouse' ,'warehouse'
@ -42,12 +38,12 @@ Hedera.Shelves = new Class
,'date' ,'date'
]; ];
var batch = new Sql.Batch (); var batch = new Sql.Batch();
for (var i = 0; i < fields.length; i++) 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 <htk-bar-button
icon="print" icon="print"
tip="_Preview" tip="_Preview"
on-click="onPreviewClick"/> on-click="this.onPreviewClick()"/>
</div> </div>
<div id="form" class="shelves"> <div id="form" class="shelves">
<div class="box"> <div class="box">
@ -27,8 +27,8 @@
id="config" id="config"
placeholder="_Select config" placeholder="_Select config"
model="configs-model" model="configs-model"
on-changed="onConfigChange" on-changed="this.onConfigChange()"
on-ready="onConfigChange"/> on-ready="this.onConfigChange()"/>
</div> </div>
<div class="form-group"> <div class="form-group">
<label><t>Date</t></label> <label><t>Date</t></label>

View File

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

View File

@ -1,14 +1,12 @@
module.exports = new Class module.exports = new Class({
({
Extends: Vn.Object Extends: Vn.Object
,initialize: function (moduleInfo, gui) ,initialize: function(moduleInfo, gui) {
{
this.info = moduleInfo; this.info = moduleInfo;
this.gui = gui; this.gui = gui;
this.conn = gui.conn; this.conn = gui.conn;
this.parent (null); this.parent(null);
} }
/** /**
@ -16,88 +14,80 @@ module.exports = new Class
* *
* @param {string} objectId The object identifier * @param {string} objectId The object identifier
* @return {Object} The object, or %null if not found * @return {Object} The object, or %null if not found
**/ */
,$: function (objectId) ,$: function(objectId) {
{ if (this.scope)
if (this.builderResult) return this.scope.getById(objectId);
return this.builderResult.getById (objectId);
return null; return null;
} }
,open: function (batch) ,open: function(batch) {
{
this.batch = batch; this.batch = batch;
this.createWindow (); this.createWindow();
} }
,print: function () ,print: function() {
{ this.window.print();
this.window.print ();
} }
,includeCss: function (path) ,includeCss: function(path) {
{
var basePath = location.protocol +'//'+ location.host; var basePath = location.protocol +'//'+ location.host;
basePath += location.port ? ':'+ location.port : ''; basePath += location.port ? ':'+ location.port : '';
basePath += location.pathname.substring (0, basePath += location.pathname.substring(0,
location.pathname.lastIndexOf ('/')); location.pathname.lastIndexOf('/'));
var link = this.doc.createElement ('link'); var link = this.doc.createElement('link');
link.rel = 'stylesheet'; link.rel = 'stylesheet';
link.type = 'text/css'; link.type = 'text/css';
link.href = basePath +'/'+ path + Vn.getVersion (); link.href = basePath +'/'+ path + Vn.getVersion();
var head = this.doc.getElementsByTagName ('head')[0]; var head = this.doc.getElementsByTagName('head')[0];
head.appendChild (link); head.appendChild(link);
} }
,createWindow: function () ,createWindow: function() {
{ var reportWindow = window.open(
var reportWindow = window.open (
'js/hedera/report.html', '_blank', 'js/hedera/report.html', '_blank',
'height=650, width=950, resizable=yes, fullscreen=no,'+ 'height=650, width=950, resizable=yes, fullscreen=no,'+
'titlebar=no, menubar=no, toolbar=no, location=no, scrollbars=yes' 'titlebar=no, menubar=no, toolbar=no, location=no, scrollbars=yes'
); );
if (!reportWindow) if (!reportWindow) {
{ Htk.Toast.showError(
Htk.Toast.showError (
_('Please unlock popups and try again')); _('Please unlock popups and try again'));
return false; return false;
} }
reportWindow.addEventListener ('load', reportWindow.addEventListener('load',
this._onWindowLoad.bind (this)); this._onWindowLoad.bind(this));
this.window = reportWindow; this.window = reportWindow;
return true; return true;
} }
,_onWindowLoad: function () ,_onWindowLoad: function() {
{
this.doc = this.window.document 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'); var printButton = this.doc.getElementById('print');
printButton.addEventListener ('click', this.print.bind (this)); printButton.addEventListener('click', this.print.bind(this));
Vn.Node.setText (printButton, _('Print')); Vn.Node.setText(printButton, _('Print'));
this.onWindowCreate (); this.onWindowCreate();
} }
,onWindowCreate: function () ,onWindowCreate: function() {
{ var builder = new Vn.Builder();
var builder = new Vn.Builder (); builder.compileFile('reports/'+ this.info.path +'/ui.xml');
builder.signalData = this;
builder.add ('batch', this.batch);
builder.add ('conn', this.conn);
builder.loadXml ('reports/'+ this.info.path +'/ui.xml');
var res = this.builderResult = builder.load (); var scope = this.scope = builder.load(this.doc, this);
res.link (); 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 Extends: Widget
,builder: null ,scope: null
,builderInit: function (path) ,builderInit: function(path) {
{ const builder = new Vn.Builder();
var builder = new Vn.Builder (); builder.compileFile(path);
builder.signalData = this; this.builderResultInit(builder);
builder.loadXml (path, this.doc);
this.builderResultInit (builder);
} }
,builderInitString: function (xmlString) ,builderInitString: function(xmlString) {
{ const builder = new Vn.Builder();
var builder = new Vn.Builder (); builder.compileString(xmlString);
builder.signalData = this; this.builderResultInit(builder);
builder.loadFromString (xmlString, this.doc);
this.builderResultInit (builder);
} }
,builderResultInit: function (builder) ,builderResultInit: function(builder) {
{ const scope = this.scope = builder.load(this.doc, this);
var res = this.builder = builder.load (); scope.link();
this._node = res.$('main');
res.link (); this._node = scope.$('main');
} }
,$: function (id) ,$: function(id) {
{ if (this.scope)
if (this.builder) return this.scope.getById(id);
return this.builder.getById (id);
return null; return null;
} }
,_destroy: function () ,_destroy: function() {
{ if (this.scope)
if (this.builder) this.scope.unref();
this.builder.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 Extends: Htk.Field
,Tag: 'htk-radio' ,Tag: 'htk-radio'
,Properties: ,Properties: {
{ tip: {
tip:
{
type: String type: String
,set: function (x) ,set: function(x) {
{
if (x) if (x)
this.node.title = _(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 type: RadioGroup
,set: function (x) ,get: function() {
{ return this._radioGroup;
}
,set: function(x) {
if (this._radioGroup) 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; this.node.name = x.name;
x.buttons.push(this); x.buttons.push(this);
this._onRadioGroupChange (); this._onRadioGroupChange();
}
,get: function ()
{
return this._radioGroup;
} }
} }
} }
,_radioGroup: null ,_radioGroup: null
,render: function () ,render: function() {
{ var radio = Vn.Browser.createRadio('', this.doc);
var radio = Vn.Browser.createRadio ('', this.doc);
radio.checked = false; radio.checked = false;
radio.addEventListener ('change', this._onChange.bind (this)); radio.addEventListener('change', this._onChange.bind(this));
this._node = radio; this._node = radio;
} }
,_onChange: function () ,_onChange: function() {
{ console.log(this._val);
if (this.node.checked && this._radioGroup) if (this.node.checked && this._radioGroup)
this._radioGroup.value = this.value; this._radioGroup.value = this._val || this.value;
} }
,_onRadioGroupChange: function () ,_onRadioGroupChange: function() {
{ const value = this._radioGroup.value;
if (this._radioGroup.value && this._radioGroup.value == this.value) this.node.checked =
this.node.checked = true; value && (value == this._val || value == this.value);
else
this.node.checked = false;
} }
,putValue: function (value) ,putValue: function(value) {
{
if (!value) if (!value)
this.node.value = ''; this.node.value = '';
else else
this.node.value = value; this.node.value = value;
} }
,setEditable: function (editable) ,setEditable: function(editable) {
{
this.node.disabled = !editable; this.node.disabled = !editable;
} }
}); });

View File

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

View File

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

View File

@ -1,2 +1,3 @@
$color-hover-cd: rgba(255, 255, 255, .1); $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 Extends: NodeBuilder
,Properties: ,Properties:
{ {
/** /**
* Main HTML node that represents the widget * Main HTML node that represents the widget
**/ */
node: node: {
{
type: Object type: Object
,get: function () ,get: function() {
{ this.renderBase();
this.renderBase ();
return this._node; return this._node;
} }
}, },
/** /**
* CSS classes to be appendend to the node classes. * CSS classes to be appendend to the node classes.
**/ */
class: class: {
{
type: String type: String
,set: function (x) ,set: function(x) {
{
this._cssClass = x; this._cssClass = x;
this._refreshClass (); this._refreshClass();
} }
,get: function () ,get: function() {
{
return this._node.className; return this._node.className;
} }
} }
@ -38,36 +32,31 @@ module.exports = new Class
,_node: null ,_node: null
,initialize: function (props) ,initialize: function(props) {
{
this.doc = document; this.doc = document;
this.renderBase (); this.renderBase();
this.parent (props); this.parent(props);
} }
,createRoot: function (tagName) ,createRoot: function(tagName) {
{ return this._node = this.createElement(tagName);
return this._node = this.createElement (tagName);
} }
,renderBase: function () ,renderBase: function() {
{
if (this._node) if (this._node)
return; return;
this.render (); this.render();
this._refreshClass (); this._refreshClass();
} }
,_refreshClass: function () ,_refreshClass: function() {
{
if (this._node && this._cssClass) if (this._node && this._cssClass)
this._node.className = this._cssClass +' '+ this._node.className; this._node.className = this._cssClass +' '+ this._node.className;
} }
,remove: function () ,remove: function() {
{ Vn.Node.remove(this._node);
Vn.Node.remove (this._node);
} }
}); });

View File

@ -1,6 +1,6 @@
var Object = require ('./object'); var Object = require('./object');
var Value = require ('./value'); var Value = require('./value');
/** /**
* A map container for many Sql.Object * A map container for many Sql.Object
@ -14,12 +14,10 @@ module.exports = new Class
blocked: blocked:
{ {
type: Boolean type: Boolean
,set: function (x) ,set: function(x) {
{
this._blocked = x; this._blocked = x;
} }
,get: function () ,get: function() {
{
return this._blocked; return this._blocked;
} }
} }
@ -28,75 +26,64 @@ module.exports = new Class
,objects: {} ,objects: {}
,_blocked: false ,_blocked: false
,loadXml: function (builder, node) ,loadXml: function(scope, node) {
{ this.parent(scope, node);
this.parent (builder, node);
var childs = node.childNodes; var childs = node.childNodes;
for (var i = 0; i < childs.length; i++) 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 object;
var id = childs[i].getAttribute ('name'); var id = childs[i].getAttribute('name');
if (id) if (id) {
{ if (object = scope.getById(childs[i].getAttribute('param')))
if (object = builder.getById (childs[i].getAttribute ('param'))) this.addParam(id, object);
this.addParam (id, object); else if (object = scope.getById(childs[i].getAttribute('object')))
else if (object = builder.getById (childs[i].getAttribute ('object'))) this.addObject(id, object);
this.addObject (id, object);
} }
} }
} }
,get: function (id) ,get: function(id) {
{
if (this.objects[id]) if (this.objects[id])
return this.objects[id]; return this.objects[id];
return null; return null;
} }
,add: function (id) ,add: function(id) {
{
if (!this.objects[id]) if (!this.objects[id])
this.objects[id] = null; this.objects[id] = null;
} }
,_addObject: function (id, object) ,_addObject: function(id, object) {
{ this.remove(id);
this.remove (id);
this.objects[id] = object; this.objects[id] = object;
object.on ('changed', this.emitChanged, this); object.on('changed', this.emitChanged, this);
this.emitChanged (); this.emitChanged();
} }
,addObject: function (id, object) ,addObject: function(id, object) {
{ this._addObject(id, object.ref());
this._addObject (id, object.ref ());
} }
,addValue: function (id, value) ,addValue: function(id, value) {
{ this._addObject(id,
this._addObject (id, new Value({value: value}));
new Value ({value: value}));
} }
,addValues: function (values) ,addValues: function(values) {
{
for (var id in values) for (var id in values)
this.addValue (id, values[id]); this.addValue(id, values[id]);
} }
,addParam: function (id, param) ,addParam: function(id, param) {
{ this._addObject(id,
this._addObject (id, new Value({param: param}));
new Value ({param: param}));
} }
,getValue: function (id) ,getValue: function(id) {
{
var object = this.objects[id]; var object = this.objects[id];
if (object instanceof Value) if (object instanceof Value)
@ -105,65 +92,54 @@ module.exports = new Class
return null; return null;
} }
,addParams: function (params) ,addParams: function(params) {
{
for (var id in params) for (var id in params)
this.addParam (id, params[id]); this.addParam(id, params[id]);
} }
,remove: function (id) ,remove: function(id) {
{ if (this.objects[id]) {
if (this.objects[id]) this._unrefObject(this.objects[id]);
{
this._unrefObject (this.objects[id]);
delete this.objects[id]; delete this.objects[id];
} }
} }
,block: function () ,block: function() {
{
this._blocked = true; this._blocked = true;
} }
,unblock: function () ,unblock: function() {
{
this._blocked = false; this._blocked = false;
} }
,emitChanged: function () ,emitChanged: function() {
{
if (!this._blocked) if (!this._blocked)
this.signalEmit ('changed'); this.signalEmit('changed');
} }
,changed: function () ,changed: function() {
{ this.signalEmit('changed');
this.signalEmit ('changed');
} }
,isReady: function () ,isReady: function() {
{
for (var id in this.objects) 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 false;
return true; return true;
} }
,_unrefObject: function (object) ,_unrefObject: function(object) {
{ if (object) {
if (object) object.disconnect('changed', this.emitChanged, this);
{ object.unref();
object.disconnect ('changed', this.emitChanged, this);
object.unref ();
} }
} }
,_destroy: function () ,_destroy: function() {
{
for (var id in this.objects) 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 @@
const VnObject = require('./object');
var Object = require('./object'); const Scope = require('./scope');
const kebabToCamel = require('./string-util').kebabToCamel;
/** /**
* Creates a object from a XML specification. * Creates a object from a XML specification.
*/ */
module.exports = new Class({ module.exports = new Class({
Extends: Object Extends: VnObject
,_addedMap: {}
,_contexts: null ,_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. * Compiles an XML file.
* *
* @path String The XML path * @param {String} path The XML path
* @dstDocument Document The document used to create the nodes * @return {Boolean} %true on success, %false othersise
* @return %true on success, %false othersise
*/ */
,loadXml: function(path, dstDocument) { ,compileFile: function(path) {
this._path = 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 parser = new DOMParser();
var xmlDoc = parser.parseFromString(xmlString, 'text/xml'); var doc = parser.parseFromString(xmlString, 'text/xml');
return this.loadFromXmlDoc(xmlDoc, dstDocument); return this.compileDocument(doc);
} }
,loadFromXmlDoc: function(xmlDoc, dstDocument, scope) {
if (!xmlDoc)
return false;
this._compileInit(dstDocument, scope); /**
* 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;
var docElement = xmlDoc.documentElement; this._preCompile(exprArgs);
var docElement = doc.documentElement;
if (docElement.tagName !== 'vn') { if (docElement.tagName !== 'vn') {
this._showError('Malformed XML'); this.showError('The toplevel tag should be named \'vn\'');
this._contexts = null; this._contexts = null;
return false; return false;
} }
var childs = docElement.childNodes; var childs = docElement.childNodes;
if (childs) if (childs)
for (var i = 0; i < childs.length; i++) for (var i = 0; i < childs.length; i++)
this._compileNode(childs[i]); this._compile(childs[i]);
this._compileEnd(); this._postCompile();
return true; return true;
} }
@ -102,87 +64,171 @@ module.exports = new Class({
* Compiles a single DOM node. * Compiles a single DOM node.
* *
* @path Node The DOM node * @path Node The DOM node
* @dstDocument Document The document used to create the nodes
* @return %true on success, %false othersise * @return %true on success, %false othersise
*/ */
,loadXmlFromNode: function(node, dstDocument, scope) { ,compileNode: function(node, exprArgs) {
this._compileInit(dstDocument, scope); this._preCompile(exprArgs);
this._mainContext = this._compileNode(node).id; this._mainContext = this._compile(node).id;
this._compileEnd(); this._postCompile();
return true; return true;
} }
/**
* 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(',');
}
,load: function() { /**
* 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) if (this._contexts === null)
return null; return null;
var contexts = this._contexts; const contexts = this._contexts;
var len = contexts.length; const len = contexts.length;
var objects = new Array(len); const objects = new Array(len);
const doc = dstDocument ? dstDocument : document;
for (var i = 0; i < len; i++) { for (var i = 0; i < len; i++) {
var context = contexts[i]; var context = contexts[i];
if (context.tagName) if (context.tagName)
objects[i] = this.elementInstantiate(context); objects[i] = this.elementInstantiate(doc, context);
else if (context.klass) else if (context.klass)
objects[i] = this.objectInstantiate(context); objects[i] = this.objectInstantiate(doc, context);
else 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) { ,link: function(scope, exprScope) {
var objects = result.objects; 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];
if (addedObject) { // Pre-link
if (l.prop)
objects[l.context.id][l.prop] = addedObject; for (var i = links.length - 1; i >= 0; i--) {
else const link = links[i];
objects[l.context.id].appendChild(addedObject); const object = objects[link.context.id];
} else const objectRef = scope._$[link.objectId];
this._showError('Referenced unexistent object with id \'%s\'',
l.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++) { for (var i = 0; i < contexts.length; i++) {
var context = contexts[i]; const context = contexts[i];
var object = objects[i]; const object = objects[i];
if (context.tagName) if (context.tagName)
this.elementLink(context, object, objects, result); this.elementLink(context, object, objects, scope, baseExprScope);
else if (context.klass) else if (context.klass)
this.objectLink(context, object, objects, result); this.objectLink(context, object, objects, scope, baseExprScope);
} }
} }
,fnExpr(expr) { ,linkExpr(scope, baseScope, exprScope) {
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) {
const contexts = this._contexts; const contexts = this._contexts;
const objects = result.objects; const objects = scope.objects;
let args = [_]
if (scope) args = args.concat(scope); exprScope = baseScope.concat(exprScope);
for (let i = 0; i < contexts.length; i++) { for (let i = 0; i < contexts.length; i++) {
const context = contexts[i]; const context = contexts[i];
@ -193,7 +239,7 @@ module.exports = new Class({
for (expr of context.exprs) { for (expr of context.exprs) {
let value = undefined; let value = undefined;
try { try {
value = expr.apply(self, args); value = expr.apply(scope.thisArg, exprScope);
} catch (e) { } catch (e) {
console.warn('Expression error:', e.message); console.warn('Expression error:', e.message);
continue; continue;
@ -212,7 +258,7 @@ module.exports = new Class({
for (const prop in dynProps) { for (const prop in dynProps) {
let value = undefined; let value = undefined;
try { try {
value = dynProps[prop].apply(self, args); value = dynProps[prop].apply(scope.thisArg, exprScope);
} catch (e) { } catch (e) {
console.warn('Expression error:', e.message); console.warn('Expression error:', e.message);
continue; continue;
@ -227,82 +273,80 @@ module.exports = new Class({
} }
} }
,_compileInit: function(dstDocument, scope) { ,showError: function(error) {
this._path = null; var path = this._path ? this._path : 'Node';
this._tags = {}; var logArgs = ['Vn.Builder: %s: '+ error, path];
this._contexts = [];
this._contextMap = {}; for (var i = 1; i < arguments.length; i++)
this._links = []; logArgs.push(arguments[i]);
this._mainContext = null;
this._doc = dstDocument ? dstDocument : document; console.warn.apply(null, logArgs);
this._scope = ['_'];
if (scope)
this._scope = this._scope.concat(scope);
this._scopeArgs = this._scope.join(',');
} }
,_compileEnd: function() { ,_addLink: function(context, prop, objectId) {
for (var i = this._links.length - 1; i >= 0; i--) { this._links.push({
var l = this._links[i]; context
var contextId = this._contextMap[l.objectId]; ,prop
,objectId: kebabToCamel(objectId)
});
}
,fnExpr(expr) {
return new Function(this._exprArgs,
'"use strict"; return ' + expr + ';'
);
}
,matchExpr(value) {
const match = /^{{(.*)}}$/.exec(value);
if (!match) return null;
return this.fnExpr(match[1]);
}
,_translateValue: function(value) {
var chr = value.charAt(0);
if (chr === '_')
return _(value.substr(1));
else if (chr === '\\' && value.charAt(1) === '_')
return value.substr(1);
if (contextId != undefined) { return value;
if (l.prop) }
l.context.objectProps[l.prop] = contextId;
else ,_getMethod: function(value) {
l.context.childs.push(contextId); let method;
this._links.splice(i, 1); if (this.isIdentifier(value)) {
} else { // XXX: Compatibility with old events
var object = this._addedMap[l.objectId]; method = value;
} else {
if (!object && this._parentResult) try {
object = this._parentResult.getById(l.objectId); method = new Function(this._eventArgs,
'"use strict"; return ' + value + ';'
if (object) { );
l.context.props[l.prop] = object; } catch (err) {
this._links.splice(i, 1); 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) ,_isEvent: function(attribute) {
this._contextMap[nodeId] = context.id; return /^on-\w+/.test(attribute);
var tags = this._tags[tagName];
if (!tags)
this._tags[tagName] = tags = [];
tags.push(context.id);
}
this._contexts.push(context);
return context;
} }
,isIdentifier: function(value) {
return /^[a-zA-Z_$][\w$]*$/.test(value);
}
,_replaceFunc: function(token) {
return token.charAt(1).toUpperCase();
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ TextNode
/** /**
* Creates a text node context. * Creates a text node context.
*/ */
@ -328,9 +372,11 @@ module.exports = new Class({
return null; return null;
} }
,textInstantiate: function(context) { ,textInstantiate: function(doc, context) {
return this._doc.createTextNode(context.exprs ? '' : context.text); return doc.createTextNode(context.exprs ? '' : context.text);
} }
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Vn.Object
/** /**
* Creates a object context. * Creates a object context.
@ -342,7 +388,6 @@ module.exports = new Class({
return null; return null;
var props = {}; var props = {};
var dynProps = {};
var objectProps = {}; var objectProps = {};
var childs = []; var childs = [];
var events = {}; var events = {};
@ -350,7 +395,8 @@ module.exports = new Class({
var context = { var context = {
klass: klass, klass: klass,
props: props, props: props,
dynProps: dynProps, dynProps: {},
funcProps: {},
objectProps: objectProps, objectProps: objectProps,
childs: childs, childs: childs,
events: events, events: events,
@ -369,7 +415,7 @@ module.exports = new Class({
if (handler) if (handler)
events[attribute.substr(3)] = handler; events[attribute.substr(3)] = handler;
} else if (!/^(id|property)$/.test(attribute)) { } else if (!/^(id|property)$/.test(attribute)) {
this.propCompile(context, klass, props, dynProps, this.propCompile(context, klass, props,
node, attribute, value); node, attribute, value);
} }
} }
@ -387,7 +433,7 @@ module.exports = new Class({
this._addLink(context, null, child.getAttribute('object')); this._addLink(context, null, child.getAttribute('object'));
} else if (childTagName === 'custom') { } else if (childTagName === 'custom') {
context.custom = child; context.custom = child;
} else if (childContext = this._compileNode(child)) { } else if (childContext = this._compile(child)) {
var prop = isElement ? child.getAttribute('property') : null; var prop = isElement ? child.getAttribute('property') : null;
if (prop) { if (prop) {
@ -401,19 +447,20 @@ module.exports = new Class({
return context; return context;
} }
,propCompile: function(context, klass, props, dynProps, node, attribute, value) { ,propCompile: function(context, klass, props, node, attribute, value) {
var isLink = false; let isLink = false;
var newValue = null; let propError = false;
var propName = attribute.replace(/-./g, this._replaceFunc); let newValue = null;
var propInfo = klass.Properties[propName]; const propName = attribute.replace(/-./g, this._replaceFunc);
const propInfo = klass.Properties[propName];
if (!propInfo) { if (!propInfo) {
this._showError('Attribute \'%s\' not valid for tag \'%s\'', this.showError('Attribute \'%s\' not valid for tag \'%s\'',
attribute, node.tagName); attribute, node.tagName);
return; return;
} }
if (!value) { if (!value) {
this._showError('Attribute \'%s\' empty on tag \'%s\'', this.showError('Attribute \'%s\' empty on tag \'%s\'',
attribute, node.tagName); attribute, node.tagName);
return; return;
} }
@ -421,7 +468,7 @@ module.exports = new Class({
const expr = this.matchExpr(value); const expr = this.matchExpr(value);
if (expr) { if (expr) {
dynProps[propName] = expr; context.dynProps[propName] = expr;
} else { } else {
switch (propInfo.type) { switch (propInfo.type) {
case Boolean: case Boolean:
@ -434,48 +481,88 @@ module.exports = new Class({
newValue = this._translateValue(value); newValue = this._translateValue(value);
break; break;
case Function: case Function:
var method = this._getMethod(value); context.funcProps[propName] = this._getMethod(value);
newValue = method ? method.bind(this.signalData) : null;
break; break;
default: default:
if (propInfo.enumType) if (propInfo.enumType)
newValue = propInfo.enumType[value]; newValue = propInfo.enumType[value];
else if (propInfo.type instanceof Function) else if (propInfo.type instanceof Function)
isLink = true; isLink = true;
else
propError = true;
} }
if (isLink) if (isLink)
this._addLink(context, propName, value); this._addLink(context, propName, value);
else if (newValue !== null && newValue !== undefined) else if (newValue !== null && newValue !== undefined)
props[propName] = newValue; props[propName] = newValue;
else else if (propError)
this._showError('Attribute \'%s\' invalid for tag \'%s\'', this.showError('Attribute \'%s\' invalid for tag \'%s\'',
attribute, node.tagName); attribute, node.tagName);
} }
} }
,objectInstantiate: function(context) { ,objectInstantiate: function(doc, context) {
return new context.klass(); return new context.klass();
} }
,objectLink: function(context, object, objects, res) { ,objectLink: function(context, object, objects, scope, exprScope) {
object.setProperties(context.props); object.setProperties(context.props);
var objectProps = context.objectProps; const objectProps = context.objectProps;
for (var prop in objectProps) for (const prop in objectProps)
object[prop] = objects[objectProps[prop]]; object[prop] = objects[objectProps[prop]];
var childs = context.childs; const childs = context.childs;
for (var i = 0; i < childs.length; i++) for (let i = 0; i < childs.length; i++)
object.appendChild(objects[childs[i]]); object.appendChild(objects[childs[i]]);
var events = context.events; const funcProps = context.funcProps;
for (var event in events) for (const prop in funcProps) {
object.on(event, events[event], this.signalData); 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) if (context.custom)
object.loadXml(res, context.custom); object.loadXml(scope, context.custom);
} }
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Element
/** /**
* Creates a HTML node context. * Creates a HTML node context.
@ -492,17 +579,17 @@ module.exports = new Class({
for (var i = 0; i < a.length; i++) { for (var i = 0; i < a.length; i++) {
var attribute = a[i].nodeName; var attribute = a[i].nodeName;
var value = a[i].nodeValue; var value = a[i].nodeValue;
const expr = this.matchExpr(value);
if (expr) { if (this._isEvent(attribute)) {
dynProps[attribute] = expr;
} else if (this._isEvent(attribute)) {
var handler = this._getMethod(value); var handler = this._getMethod(value);
if (handler) events[attribute.substr(3)] = handler;
if (handler) } else if (attribute !== 'id') {
events[attribute.substr(3)] = handler; const expr = this.matchExpr(value);
} else if (attribute !== 'id') if (expr)
attributes[attribute] = this._translateValue(value); dynProps[attribute] = expr;
else
attributes[attribute] = this._translateValue(value);
}
} }
var childContext; var childContext;
@ -510,7 +597,7 @@ module.exports = new Class({
if (childNodes) if (childNodes)
for (var i = 0; i < childNodes.length; i++) for (var i = 0; i < childNodes.length; i++)
if (childContext = this._compileNode(childNodes[i])) if (childContext = this._compile(childNodes[i]))
childs.push(childContext.id); childs.push(childContext.id);
return { return {
@ -522,18 +609,18 @@ module.exports = new Class({
}; };
} }
,elementInstantiate: function(context) { ,elementInstantiate: function(doc, context) {
return this._doc.createElement(context.tagName); return doc.createElement(context.tagName);
} }
,elementLink: function(context, object, objects) { ,elementLink: function(context, object, objects, scope, exprScope) {
var attributes = context.attributes; const attributes = context.attributes;
for (var attribute in attributes) for (const attribute in attributes)
object.setAttribute(attribute, attributes[attribute]); object.setAttribute(attribute, attributes[attribute]);
var childs = context.childs; const childs = context.childs;
for (var i = 0; i < childs.length; i++) { for (var i = 0; i < childs.length; i++) {
var child = objects[childs[i]]; let child = objects[childs[i]];
if (child instanceof Htk.Widget) if (child instanceof Htk.Widget)
child = child.node; child = child.node;
@ -541,98 +628,24 @@ module.exports = new Class({
object.appendChild(child); object.appendChild(child);
} }
var events = context.events; const events = context.events;
for (var event in events) for (const event in events) {
object.addEventListener(event, let listener;
events[event].bind(this.signalData)); const handler = events[event];
} if (typeof handler === 'string') {
// XXX: Compatibility with old expressions
,_showError: function(error) { listener = scope.thisArg[handler];
var path = this._path ? this._path : 'Node'; if (!listener)
var logArgs = ['Vn.Builder: %s: '+ error, path]; this.showError(`Function '${handler}' not found`);
listener = listener.bind(scope.thisArg);
} else {
listener = function(e) {
handler.apply(scope.thisArg, exprScope.concat(e));
};
}
for (var i = 1; i < arguments.length; i++) if (listener)
logArgs.push(arguments[i]); object.addEventListener(event, listener);
}
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();
} }
}); });
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);
}