Tags, errores solucionados

This commit is contained in:
Juan Ferrer Toribio 2017-11-16 15:53:20 +01:00
parent f9c002f08a
commit 7658a5680d
29 changed files with 375 additions and 497 deletions

View File

@ -5,6 +5,20 @@ var View = {
GRID: 1 GRID: 1
}; };
var orderBy = [
{way: 'DESC', id: 'relevancy', name: 'Relevancy'},
{way: 'ASC', id: 'name', name: 'Name'},
{way: 'ASC', id: 'price', name: 'Lower price'},
{way: 'DESC', id: 'price', name: 'Higher price'},
{way: 'ASC', id: 'available', name: 'Available'},
{way: 'ASC', id: 'size', name: 'Lower size'},
{way: 'DESC', id: 'size', name: 'Higher size'},
{way: 'ASC', id: 'color', name: 'Color'},
{way: 'ASC', id: 'producer', name: 'Producer'},
{way: 'ASC', id: 'origin', name: 'Origin'},
{way: 'ASC', id: 'category', name: 'Category'}
];
Hedera.Catalog = new Class Hedera.Catalog = new Class
({ ({
Extends: Hedera.Form Extends: Hedera.Form
@ -36,7 +50,7 @@ Hedera.Catalog = new Class
,activate: function () ,activate: function ()
{ {
this.$.items.setInfo ('a', 'Articles', 'vn2008', ['item_id']); this.$.items.setInfo ('i', 'item', 'vn', ['id']);
document.body.appendChild (this.$.rightPanel); document.body.appendChild (this.$.rightPanel);
if (localStorage.getItem ('hederaView')) if (localStorage.getItem ('hederaView'))
@ -44,7 +58,11 @@ Hedera.Catalog = new Class
else else
this.setView (View.GRID); this.setView (View.GRID);
this.onRealmChange (); this.$.orderBy.model = new Vn.Model ({
data: orderBy
});
this.onCategoryChange ();
this.refreshTitle (); this.refreshTitle ();
this.onParamsChange (); this.onParamsChange ();
} }
@ -96,11 +114,10 @@ Hedera.Catalog = new Class
Vn.Node.setText (this.$.method, _('Warehouse')); Vn.Node.setText (this.$.method, _('Warehouse'));
} }
,onOrderChange: function (e) ,onOrderChange: function (combo)
{ {
var value = e.target.value; var sortField = combo.$.id;
var sortField = value.substr (2); var sortWay = combo.$.way === 'ASC' ?
var sortWay = value.charAt (0) === 'A' ?
Db.Model.SortWay.ASC : Db.Model.SortWay.DESC; Db.Model.SortWay.ASC : Db.Model.SortWay.DESC;
if (sortField) if (sortField)
@ -113,34 +130,37 @@ Hedera.Catalog = new Class
{ {
var params = this.params.$; var params = this.params.$;
var shouldRefresh = params.search || var shouldRefresh = params.search ||
params.realm && params.type; params.category && params.type;
Vn.Node.removeChilds (this.$.tagFilters);
if (shouldRefresh) if (shouldRefresh)
{ {
var filterSql = this.$.filter.render (params); this.$.items.query = this.buildQuery ('CALL catalogGetItems ()');
var modelParams = { this.$.items.refresh ();
filter: new Sql.String ({query: filterSql})
}; var tagsQuery = this.buildQuery ('CALL catalogGetTags ()');
this.$.items.refresh (modelParams); this.conn.execQuery (tagsQuery, this.onTagsReady.bind (this));
this.hideMenu (); this.hideMenu ();
} }
else else
this.$.items.clean (); this.$.items.clean ();
this.showFilters (params.search || params.realm); this.showFilters (params.search || params.category);
} }
,showFilters: function (show) ,showFilters: function (show)
{ {
this.$.filters.style.display = show ? 'block' : 'none'; this.$.filters.style.display = show ? 'block' : 'none';
this.$.realmMsg.style.display = show ? 'none' : 'block'; this.$.categoryMsg.style.display = show ? 'none' : 'block';
this.$.order.style.display = show ? 'block' : 'none'; this.$.order.style.display = show ? 'block' : 'none';
} }
,onRemoveFiltersClick: function () ,onRemoveFiltersClick: function ()
{ {
this.params.$ = {}; this.params.$ = {};
this.tagFilter = {};
} }
,tagFilter: {} ,tagFilter: {}
@ -150,12 +170,35 @@ Hedera.Catalog = new Class
tagFilter[tag.id] = tag.value; tagFilter[tag.id] = tag.value;
} }
,buildQuery: function (query, params)
{
var query = new Sql.MultiStmt ({
stmts: [
this.$.preQuery,
new Sql.String ({query: query}),
this.$.postQuery
]
});
var qParams = {
joins: this.buildTagFilter (),
filter: this.buildMainFilter ()
};
Object.assign (qParams, params);
return this.conn.renderStmt (query, qParams)
}
,buildMainFilter: function ()
{
var filterSql = this.$.filter.render (this.params.$);
return new Sql.String ({query: filterSql});
}
,buildTagFilter: function (excludeTag) ,buildTagFilter: function (excludeTag)
{ {
var Type = Sql.Operation.Type; var Type = Sql.Operation.Type;
var join = new Sql.Join ({ var join = new Sql.Join ({
target: Sql.Table ({ target: new Sql.Table ({
schema: 'vn', schema: 'vn',
name: 'item', name: 'item',
alias: 'i' alias: 'i'
@ -165,19 +208,19 @@ Hedera.Catalog = new Class
join.push (new Sql.JoinItem ({ join.push (new Sql.JoinItem ({
target: new Sql.Table ({ target: new Sql.Table ({
schema: 'vn', schema: 'vn',
name: 'family', name: 'itemType',
alias: 'f' alias: 't'
}), }),
condition: new Sql.Operation ({ condition: new Sql.Operation ({
type: Type.EQUAL, type: Type.EQUAL,
exprs: [ exprs: [
new Sql.Field ({ new Sql.Field ({
target: 'f', target: 't',
name: 'id' name: 'id'
}), }),
new Sql.Field ({ new Sql.Field ({
target: 'i', target: 'i',
name: 'familyFk' name: 'typeFk'
}) })
] ]
}) })
@ -247,46 +290,60 @@ Hedera.Catalog = new Class
}) })
]; ];
} }
return join;
} }
,onTagsReady: function (resultSet) ,onTagsReady: function (resultSet)
{ {
var tags = resultSet.fetchArray (); var filters = this.$.tagFilters;
var tags = resultSet.results[2].data;
tags.forEach (function (tag) { tags.forEach (function (tag) {
var model = new Db.Model ({ var query = this.buildQuery (
autoLoad: false, 'CALL catalogGetTagValues (#tag)', {tag: tag.id});
query: query
});
var combo = new Vn.Combo ({ var label = this.createElement ('label');
name: tag.name, label.appendChild (this.createTextNode (tag.name));
lot: lot, filters.appendChild (label);
placeholder: tag.description,
model: model
});
div.appendChild (combo); var combo = new Htk.Combo ({
valueField: 'value',
showField: 'value',
model: new Db.Model ({
autoLoad: true,
resultIndex: 2,
query: query,
conn: this.conn
})
}); });
combo.on ('changed', this.onComboChange, this);
filters.appendChild (combo.node);
}, this);
} }
,onRealmChange: function () ,onComboChange: function (combo)
{
console.log (combo.value);
}
,onCategoryChange: function ()
{ {
this.refreshTitleColor (); this.refreshTitleColor ();
} }
,refreshTitleColor: function () ,refreshTitleColor: function ()
{ {
var realms = this.$.realms; var categories = this.$.categories;
var realm = this.params.$.realm; var category = this.params.$.category;
var color = null; var color = null;
if (realm) if (category)
{ {
var row = realms.search ('id', realm); var row = categories.search ('id', category);
if (row != -1) if (row != -1)
color = '#'+ realms.get (row, 'color'); color = '#'+ categories.get (row, 'color');
} }
this.gui.$.navbar.style.backgroundColor = color; this.gui.$.navbar.style.backgroundColor = color;
@ -294,18 +351,8 @@ Hedera.Catalog = new Class
,refreshTitle: function () ,refreshTitle: function ()
{ {
var types = this.$.types; var type = this.$.type.$.name;
var type = this.params.$.type; var title = type ? type : _('Catalog');
var title = _('Catalog');
if (type)
{
var row = types.search ('tipo_id', type);
if (row != -1)
title = types.get (row, 'name');
}
Vn.Node.setText (this.$.title, title); Vn.Node.setText (this.$.title, title);
} }
@ -370,7 +417,7 @@ Hedera.Catalog = new Class
this.onEraseClick (); this.onEraseClick ();
var lot = button.lot; var lot = button.lot;
this.$.card.row = lot.row; this.$.card.row = lot.row;
this.$.cardLot.assign ({item: lot.$.item_id}); this.$.cardLot.assign ({item: lot.$.id});
this.$.cardPopup.show (); this.$.cardPopup.show ();
} }
@ -441,221 +488,4 @@ Hedera.Catalog = new Class
} }
}); });
Vn.Filter = new Class
({
Extends: Htk.Field
,Tag: 'vn-filter'
,Properties:
{
model:
{
type: Db.Model
,set: function (x)
{
this._model = x;
this._select.model = x;
this._refreshModelLot ();
}
,get: function ()
{
return this._model;
}
},
placeholder:
{
type: String
,set: function (x)
{
this._select.placeholder = x;
this._placeholder = x;
}
,get: function ()
{
return this._placeholder;
}
},
filter:
{
type: Sql.Filter
,set: function (x)
{
this._filter = x;
this._modelLot.assign ({filter: x});
this._refreshModelLot ();
}
,get: function ()
{
return this._filter;
}
},
lot:
{
type: Vn.LotIface
,set: function (x)
{
this._modelLot.source = x;
this._setLot (x);
}
,get: function ()
{
return this._lot;
}
},
name:
{
type: String
,set: function (x)
{
this._modelLot.fields = [x];
this._setName (x);
}
,get: function ()
{
return this._name;
}
}
}
,_valueColumnIndex: 0
,_showColumnIndex: 1
,initialize: function (props)
{
var node = this.createRoot ('div');
node.className = 'vn-filter';
this._select = new Htk.Combo ();
this._select.on ('mousedown', this._onMouseDown, this);
this._select.on ('changed', this._onChange, this);
this._select.on ('ready', this._onReady, this);
this.node.appendChild (this._select.node);
this._ul = this.createElement ('ul');
this.node.appendChild (this._ul);
this._modelLot = new Vn.LotQuery ();
this.parent (props);
}
,_refreshModelLot: function ()
{
if (this._model && this._filter)
this._model.lot = this._modelLot;
}
,_onMouseDown: function ()
{
if (this._model && this._model.status === Db.Model.Status.CLEAN)
{
var params = {
filter: this._filter
};
this._model.refresh ();
}
}
,_onUnselectClick: function ()
{
this._removeSelectionNode ();
this.valueChanged (undefined);
}
,_removeSelectionNode: function ()
{
if (this._lastLi)
{
Vn.Node.remove (this._lastLi);
this._lastLi = null;
this._label = null;
}
}
,_onChange: function ()
{
if (this._select.value === null
|| this._select.value === undefined)
return;
var value = this._select.value;
this._selectValue (value);
this.valueChanged (value);
}
,_onReady: function ()
{
if (this._emptyLabel)
this._refreshLabel ();
}
,_onTimeout: function ()
{
this._select.value = null;
}
,putValue: function (value)
{
this._selectValue (value);
}
,_selectValue: function (value)
{
this._removeSelectionNode ();
if (value === null || value === undefined)
return;
var li = this._lastLi = this.createElement ('li');
this._ul.appendChild (li);
var button = this.createElement ('button');
button.addEventListener ('click',
this._onUnselectClick.bind (this, li));
li.appendChild (button);
var icon = new Htk.Icon ({
icon: 'close',
alt: _('Close')
});
button.appendChild (icon.node);
var text = this._label = this.createTextNode ('');
li.appendChild (text);
setTimeout (this._onTimeout.bind (this));
this._refreshLabel ();
}
,_refreshLabel: function ()
{
if (!this._label)
return;
var row = -1;
if (this._model && this._model.ready)
row = this._model.searchByIndex (this._valueColumnIndex, this._value);
if (row != -1)
{
var label = this._model.getByIndex (row, this._showColumnIndex);
this._label.nodeValue = label;
this._emptyLabel = false;
}
else
{
this._emptyLabel = true;
this._label.nodeValue = _('Loading...');
}
}
,_destroy: function ()
{
this._select.unref ();
this._modelLot.unref ();
this.parent ();
}
});
})(); })();

View File

@ -57,11 +57,11 @@
{ {
display: none; display: none;
} }
.right-panel .realm-msg .right-panel .category-msg
{ {
margin-top: 1em; margin-top: 1em;
} }
.right-panel .realm-msg > h1 .right-panel .category-msg > h1
{ {
font-weight: normal; font-weight: normal;
text-align: center; text-align: center;
@ -75,19 +75,19 @@
color: #777; color: #777;
font-size: 1.1em; font-size: 1.1em;
} }
.right-panel .realms .right-panel .categories
{ {
width: 95%; width: 95%;
margin: .2em auto; margin: .2em auto;
} }
.right-panel .realms a .right-panel .categories a
{ {
display: block; display: block;
float: left; float: left;
width: 33.33%; width: 33.33%;
border-radius: .1em; border-radius: .1em;
} }
.right-panel .realms a > img .right-panel .categories a > img
{ {
display: block; display: block;
padding: 0; padding: 0;

View File

@ -3,12 +3,12 @@
<vn-lot-query id="params" on-change="onParamsChange"> <vn-lot-query id="params" on-change="onParamsChange">
<vn-spec name="search" type="String"/> <vn-spec name="search" type="String"/>
<vn-spec name="itemId" type="Number"/> <vn-spec name="itemId" type="Number"/>
<vn-spec name="realm" type="Number"/> <vn-spec name="category" type="Number"/>
<vn-spec name="type" type="Number"/> <vn-spec name="type" type="Number"/>
</vn-lot-query> </vn-lot-query>
<sql-filter type="AND" id="filter"> <sql-filter type="AND" id="filter">
<sql-filter-item type="EQUAL" <sql-filter-item type="EQUAL"
target="i" field="familyFk" target="i" field="typeFk"
param="type"/> param="type"/>
<sql-filter type="OR"> <sql-filter type="OR">
<sql-filter-item type="LIKE" <sql-filter-item type="LIKE"
@ -22,41 +22,22 @@
param="itemId"/> param="itemId"/>
</sql-filter> </sql-filter>
</sql-filter> </sql-filter>
<vn-string id="pre-query"> <sql-string id="pre-query">
DROP TEMPORARY TABLE IF EXISTS tItems; DROP TEMPORARY TABLE IF EXISTS tItems;
CREATE TEMPORARY TABLE tItems CREATE TEMPORARY TABLE tItems
(INDEX (id)) (INDEX (id))
ENGINE = MEMORY ENGINE = MEMORY
SELECT i.id SELECT i.id
FROM #joins FROM #joins
WHERE #filter; WHERE #filter
</vn-string> </sql-string>
<vn-string id="post-query"> <sql-string id="post-query">
DROP TEMPORARY TABLE tItems; DROP TEMPORARY TABLE tItems
</vn-string> </sql-string>
<db-model <db-model
id="items" id="items"
result-index="2" result-index="2"
auto-load="false"> auto-load="false">
CREATE TEMPORARY TABLE tmp.bionic_calc
(INDEX (item_id))
ENGINE = MEMORY
SELECT i.id item_id
FROM vn.item i
JOIN vn.family f ON f.id = i.familyFk
WHERE #filter;
CALL bionic_calc ();
SELECT a.Id_Article item_id, a.description, b.available, b.price,
b.producer, a.Foto, a.Article, a.Categoria, a.Medida,
IF(a.Tallos > 1, a.Tallos, NULL) Tallos, c.str color
FROM tmp.bionic_item b
JOIN vn2008.Articles a ON a.Id_Article = b.item_id
LEFT JOIN vn2008.producer p ON p.producer_id = a.producer_id
LEFT JOIN vn_locale.color_view c ON c.color_id = a.Color
LEFT JOIN vn_locale.origin_view o ON o.origin_id = a.id_origen
WHERE b.available > 0
ORDER BY a.relevancy DESC, a.Article, a.Medida
LIMIT 40;
</db-model> </db-model>
<db-form id="basket" on-ready="onBasketReady"> <db-form id="basket" on-ready="onBasketReady">
<db-model property="model"> <db-model property="model">
@ -102,8 +83,7 @@
ORDER BY warehouse_id, grouping; ORDER BY warehouse_id, grouping;
</db-model> </db-model>
<vn-lot id="card-lot"/> <vn-lot id="card-lot"/>
<vn-param lot="params" name="realm" on-changed="onRealmChange"/> <vn-param lot="params" name="category" on-changed="onCategoryChange"/>
<vn-param lot="params" name="type" on-changed="refreshTitle"/>
</vn-group> </vn-group>
<h1 id="title"> <h1 id="title">
_Catalog _Catalog
@ -136,36 +116,34 @@
directory="catalog" directory="catalog"
subdir="200x200" subdir="200x200"
lot="item" lot="item"
name="Foto" name="image"
full-dir="900x900"/> full-dir="900x900"/>
<div class="item-info"> <div class="item-info">
<htk-button <htk-button
lot="item" lot="item"
value="{{item.item_id}}" value="{{item.id}}"
tip="_AddToBasket" tip="_AddToBasket"
icon="add" icon="add"
on-click="onAddItemClick" on-click="onAddItemClick"
class="add-button"/> class="add-button"/>
<h2>{{item.Article}}</h2> <h2>{{item.name}}</h2>
<p class="producer"> <p class="producer">
{{item.producer}} {{item.producer}}
</p> </p>
<p> <p>
@{{item.item_id}} @{{item.id}}
</p> </p>
<p> <p>
<span>_Size</span> {{item.Medida}} <span>_Size</span> {{item.size}}
<span>_Category</span> {{item.Categoria}} <span>_Category</span> {{item.category}}
</p> </p>
<p class="color"> <p class="color">
<span>_Color</span> {{item.color}} <span>_Color</span> {{item.inkFk}}
<htk-text lot="item" name="Tallos" format="_, %.0d Units"/> <htk-text lot="item" name="stems" format="_, %.0d Units"/>
</p> </p>
<div class="aval-price"> <div class="aval-price">
{{item.available}} {{item.available}}
<span class="from"> <span class="from">_from</span>
_from
</span>
<span class="price"> <span class="price">
<htk-text lot="item" name="price" format="%.2d€"/> <htk-text lot="item" name="price" format="%.2d€"/>
</span> </span>
@ -190,21 +168,21 @@
</div> </div>
<div class="filter"> <div class="filter">
<div class="categories"> <div class="categories">
<div class="realms"> <div class="categories">
<htk-repeater <htk-repeater
class="realms-box"> class="categories-box">
<db-model <db-model
id="realms" id="categories"
property="model" property="model"
on-status-changed="refreshTitleColor"> on-status-changed="refreshTitleColor">
SELECT r.id, l.str name, r.color SELECT c.id, l.name, c.color
FROM vn2008.reinos r FROM vn.itemCategory c
LEFT JOIN vn_locale.realm_view l ON l.realm_id = r.id JOIN vn.itemCategoryL10n l ON l.id = c.id
WHERE r.display != FALSE WHERE c.display > 0
ORDER BY name ORDER BY l.name
</db-model> </db-model>
<custom> <custom>
<a class="clickable" href="#!form={{hash.form}}&amp;realm={{id}}"> <a class="clickable" href="#!form={{hash.form}}&amp;category={{id}}">
<img <img
src="image/family/light/{{id}}.svg" src="image/family/light/{{id}}.svg"
title="{{name}}" title="{{name}}"
@ -215,73 +193,46 @@
<div class="clear"/> <div class="clear"/>
</div> </div>
</div> </div>
<div id="realm-msg" class="realm-msg"> <div id="order" class="order">
<h1>_Choose a realm</h1> <h2>_Order by</h2>
<htk-combo
id="order-by"
on-change="onOrderChange"
value="relevancy"
not-null="true"/>
</div>
<div id="category-msg" class="category-msg">
<h1>_Choose a category</h1>
</div> </div>
<div id="filters" class="filters"> <div id="filters" class="filters">
<h2>_Filter by</h2> <h2>_Filter by</h2>
<label>_Family</label> <label>_Family</label>
<htk-combo <htk-combo
id="type"
name="type" name="type"
on-change="refreshTitle"
lot="params"> lot="params">
<db-model <db-model
id="types" id="types"
property="model" property="model"
lot="params" lot="params"
result-index="1" result-index="1">
on-status-changed="refreshTitle">
CALL item_available (); CALL item_available ();
SELECT DISTINCT t.tipo_id, l.str name SELECT DISTINCT t.id, l.name
FROM vn2008.Tipos t FROM vn.itemType t
JOIN vn2008.Articles a ON a.tipo_id = t.tipo_id JOIN vn.item i ON i.typeFk = t.id
LEFT JOIN vn_locale.family_view l ON l.family_id = t.tipo_id JOIN tmp.item_available a ON a.item_id = i.id
JOIN tmp.item_available i ON i.item_id = a.Id_Article JOIN vn.itemTypeL10n l ON l.id = t.id
WHERE t.reino_id = #realm WHERE t.categoryFk = #category
ORDER BY name ORDER BY name
</db-model> </db-model>
</htk-combo> </htk-combo>
<button on-click="onRemoveFiltersClick"> <div id="tag-filters">
</div>
<button on-click="onRemoveFiltersClick" class="thin">
_Remove filters _Remove filters
</button> </button>
</div> </div>
<div id="order" class="order">
<h2>_Order by</h2>
<select on-change="onOrderChange">
<option value="D|relevancy" selected="true">
_Relevancy
</option>
<option value="A|Article">
_Name
</option>
<option value="A|price">
_Lower price
</option>
<option value="D|price">
_Higher price
</option>
<option value="A|available">
_Available
</option>
<option value="A|Medida">
_Lower size
</option>
<option value="D|Medida">
_Higher size
</option>
<option value="A|color">
_Color
</option>
<option value="A|producer">
_Producer
</option>
<option value="A|Abreviatura">
_Origin
</option>
<option value="A|Categoria">
_Category
</option>
</select>
</div>
</div> </div>
</div> </div>
<htk-popup id="desc-popup"> <htk-popup id="desc-popup">
@ -301,23 +252,23 @@
directory="catalog" directory="catalog"
subdir="200x200" subdir="200x200"
lot="card" lot="card"
name="Foto" name="image"
full-dir="900x900" full-dir="900x900"
conn="conn" conn="conn"
editable="true"/> editable="true"/>
<div class="item-info"> <div class="item-info">
<h2> <h2>
{{card.Article}} {{card.name}}
</h2> </h2>
<p class="producer"> <p class="producer">
{{card.producer}} {{card.producer}}
</p> </p>
<p> <p>
<span>_Size</span> {{card.Medida}}, <span>_Size</span> {{card.size}},
<span>_Category</span> {{card.categoria}} <span>_Category</span> {{card.category}}
</p> </p>
<p class="color"> <p class="color">
<span>_Color</span> {{card.color}} <span>_Color</span> {{card.inkFk}}
<htk-text lot="card" name="Tallos" format="_, %.0d Units"/> <htk-text lot="card" name="Tallos" format="_, %.0d Units"/>
</p> </p>
<p> <p>
@ -356,22 +307,4 @@
</div> </div>
</div> </div>
</htk-popup> </htk-popup>
<!--
<htk-combo on-change="onOrderChange">
<vn-json-model property="model">
<array>
<object way="A" field="Article" desc="_Name"/>
<object way="A" field="price" desc="_Lower price"/>
<object way="D" field="price" desc="_Higher price"/>
<object way="A" field="available" desc="_Available"/>
<object way="A" field="Medida" desc="_Lower size"/>
<object way="D" field="Medida" desc="_Higher size"/>
<object way="A" field="color" desc="_Color"/>
<object way="A" field="producer" desc="_Producer"/>
<object way="A" field="Abreviatura" desc="_Origin"/>
<object way="A" field="Categoria" desc="_Category"/>
</array>
</vn-json-model>
</htk-combo>
-->
</vn> </vn>

View File

@ -109,6 +109,7 @@
id="agency" id="agency"
lot="lot" lot="lot"
name="agency" name="agency"
show-field="description"
on-changed="onFieldChange" on-changed="onFieldChange"
model="agencies"/> model="agencies"/>
</div> </div>
@ -120,6 +121,7 @@
id="warehouse" id="warehouse"
lot="lot" lot="lot"
name="agency" name="agency"
show-field="description"
on-changed="onFieldChange" on-changed="onFieldChange"
model="agencies"/> model="agencies"/>
</div> </div>

View File

@ -104,10 +104,13 @@ module.exports = new Class
} }
,_editable: true ,_editable: true
,_lockEntry: false
,_setValue: function (newValue) ,_setValue: function (newValue)
{ {
Vn.ParamIface.prototype._setValue.call (this, newValue); Vn.ParamIface.prototype._setValue.call (this, newValue);
if (!this._lockEntry)
this.putValue (newValue); this.putValue (newValue);
if (this.conditionalFunc) if (this.conditionalFunc)
@ -122,7 +125,9 @@ module.exports = new Class
*/ */
,valueChanged: function (value) ,valueChanged: function (value)
{ {
this._lockEntry = true;
this._setValue (value); this._setValue (value);
this._lockEntry = false;
} }
/** /**

View File

@ -125,24 +125,48 @@ module.exports = new Class
return this._params; return this._params;
} }
} }
,valueField:
{
type: String,
value: 'id'
}
,showField:
{
type: String,
value: 'name'
}
} }
,_row: -1 ,_row: -1
,_model: null ,_model: null
,valueColumnIndex: 0 ,_notNull: false
,valueColumnName: null
,showColumnIndex: 1
,showColumnName: null
,_notNull: true
,_webkitRefresh: false
,render: function () ,render: function ()
{ {
var button = this.createRoot ('button'); var node = this.createRoot ('div');
node.className = 'htk-combo';
var clearButton = this.createElement ('htk-icon');
clearButton.className = 'clear';
clearButton.icon = 'close';
clearButton.on ('click', this._onClearClick, this);
node.appendChild (clearButton.node);
var button = this.createElement ('button');
button.type = 'button'; button.type = 'button';
button.className = 'htk-select input'; button.className = 'htk-combo input';
button.addEventListener ('mousedown', button.addEventListener ('mousedown',
this._onButtonMouseDown.bind (this)); this._onButtonMouseDown.bind (this));
node.appendChild (button);
this.button = button;
this.clearButton = clearButton;
this._refreshShowText ();
}
,_onClearClick: function ()
{
this.value = null;
} }
,_setRow: function (row) ,_setRow: function (row)
@ -150,7 +174,6 @@ module.exports = new Class
this._row = row; this._row = row;
this._refreshShowText (); this._refreshShowText ();
this.rowChanged (); this.rowChanged ();
this.changed ();
} }
,_onButtonMouseDown: function (e) ,_onButtonMouseDown: function (e)
@ -164,7 +187,7 @@ module.exports = new Class
var model = this._model; var model = this._model;
var menu = this.createElement ('div'); var menu = this.createElement ('div');
menu.className = 'htk-select-menu'; menu.className = 'htk-combo-menu';
var grid = new Htk.Grid ({showHeader: false}); var grid = new Htk.Grid ({showHeader: false});
menu.appendChild (grid.node); menu.appendChild (grid.node);
@ -173,7 +196,7 @@ module.exports = new Class
gridNode.addEventListener ('click', gridNode.addEventListener ('click',
this._onGridClicked.bind (this, grid)); this._onGridClicked.bind (this, grid));
var column = new ColumnText ({columnIndex: this.showColumnIndex}); var column = new ColumnText ({column: this.showField});
grid.appendColumn (column); grid.appendColumn (column);
grid.model = model; grid.model = model;
@ -199,7 +222,7 @@ module.exports = new Class
var row = target.rowIndex - 1; var row = target.rowIndex - 1;
if (row >= 0) if (row >= 0)
value = this._model.getByIndex (row, this.valueColumnIndex); value = this._model.get (row, this.valueField);
else else
value = null; value = null;
@ -221,7 +244,7 @@ module.exports = new Class
var model = this._model; var model = this._model;
if (this._row !== -1) if (this._row !== -1)
var showText = model.getByIndex (this._row, this.showColumnIndex); var showText = model.get (this._row, this.showField);
else if (model && model.status === Db.Model.Status.LOADING) else if (model && model.status === Db.Model.Status.LOADING)
var showText = _('Loading...'); var showText = _('Loading...');
else if (this._placeholder) else if (this._placeholder)
@ -229,7 +252,18 @@ module.exports = new Class
else else
var showText = ''; var showText = '';
Vn.Node.setText (this.node, showText); if (this.node)
{
var visibility;
if (this._value && !this._notNull)
visibility = 'visible';
else
visibility = 'hidden';
this.clearButton.node.style.visibility = visibility;
Vn.Node.setText (this.button, showText);
}
} }
,_onModelChange: function () ,_onModelChange: function ()
@ -259,7 +293,7 @@ module.exports = new Class
var row; var row;
if (this._model && this._model.ready) if (this._model && this._model.ready)
row = this._model.searchByIndex (this.valueColumnIndex, this._value); row = this._model.search (this.valueField, this._value);
else else
row = -1; row = -1;

View File

@ -134,35 +134,60 @@ td.cell-image .htk-image
/* Select */ /* Select */
.htk-select .htk-combo
{
position: relative;
}
.htk-combo > button
{ {
max-width: 100%; max-width: 100%;
height: 2em; height: 2em;
text-align: left; text-align: left;
z-index: 1;
} }
.htk-select-menu .htk-combo > .clear
{
position: absolute;
right: 0;
margin: .2em;
padding: .3em;
cursor: pointer;
z-index: 2;
border-radius: .1em;
visibility: hidden;
}
.htk-combo:hover > .clear
{
visibility: visible;
}
.htk-combo > .clear:hover
{
background-color: rgba(0, 0, 0, 0.1)
}
.htk-combo-menu
{ {
max-width: 100%; max-width: 100%;
} }
.modal > .htk-select-menu .modal > .htk-combo-menu
{ {
min-width: 14em; min-width: 14em;
} }
.htk-select-menu tbody > tr .htk-combo-menu tbody > tr
{ {
border-top: none; border-top: none;
height: 2.5em; height: 2.5em;
} }
.htk-select-menu td.message .htk-combo-menu td.message
{ {
padding: 1em; padding: 1em;
} }
.htk-select-menu tr:hover .htk-combo-menu tr:hover
{ {
background-color: rgba(1, 1, 1, 0.1); background-color: rgba(1, 1, 1, 0.1);
cursor: pointer; cursor: pointer;
} }
.htk-select-menu td .htk-combo-menu td
{ {
max-width: 0; max-width: 0;
overflow: hidden; overflow: hidden;

View File

@ -11,13 +11,9 @@ module.exports = new Class
,render: function (params) ,render: function (params)
{ {
var sql = 'DELETE FROM ' return 'DELETE FROM'
+ this.renderTarget (params); + this.renderTarget (params)
+ this.renderIfSet (this.where, 'WHERE', params)
if (this.where) + this.renderLimit (params);
sql += ' WHERE ' + this.where.render (params);
sql += this.renderLimit(params);
return sql;
} }
}); });

View File

@ -15,14 +15,14 @@ module.exports = new Class
,addSet: function (fieldName, value) ,addSet: function (fieldName, value)
{ {
this.expr.push (new Value ({value: value}));
this.field.push (new Field ({name: fieldName})); this.field.push (new Field ({name: fieldName}));
this.expr.push (new Value ({value: value}));
} }
,addExpr: function (fieldName, expr) ,addExpr: function (fieldName, expr)
{ {
this.expr.push (expr);
this.field.push (new Field ({name: fieldName})); this.field.push (new Field ({name: fieldName}));
this.expr.push (expr);
} }
,delSet: function () ,delSet: function ()

View File

@ -32,12 +32,7 @@ module.exports = new Class
,render: function () ,render: function ()
{ {
var sql = ''; return this.renderPreIdent (this.target)
+ this.renderIdent (this.name);
if (this.target)
sql += this.renderIdentifier (this.target) +'.';
sql += this.renderIdentifier (this.name);
return sql;
} }
}); });

View File

@ -36,7 +36,7 @@ module.exports = new Class
this.exprs.forEach (function (expr) { this.exprs.forEach (function (expr) {
if (expr.isReady (params)) if (expr.isReady (params))
newExprs.push (exprs[i]); newExprs.push (expr);
}) })
if (newExprs.length > 0) if (newExprs.length > 0)

View File

@ -47,15 +47,10 @@ module.exports = new Class
,render: function (params) ,render: function (params)
{ {
var sql = ''; return this.renderPreIdent (this.schema)
+ this.renderIdent (this.name)
if (this.schema)
sql += this.renderIdentifier (this.schema) +'.';
sql += this.renderIdentifier (this.name)
+ '(' + '('
+ this.renderListWs (this.list, params, ', ') + this.renderListWs (this.list, params, ', ')
+ ')'; + ')';
return sql;
} }
}); });

View File

@ -3,7 +3,12 @@ var Target = require ('./target');
var Expr = require ('./expr'); var Expr = require ('./expr');
var SqlObject = require ('./object'); var SqlObject = require ('./object');
var Type = require ('./join').Type; var Type = require ('./join').Type;
var TypeSql = require ('./join').TypeSql;
var TypeSql = [
'INNER',
'LEFT',
'RIGHT'
];
/** /**
* The equivalent of a SQL join. * The equivalent of a SQL join.

View File

@ -14,16 +14,9 @@ var Type = {
RIGHT : 2 RIGHT : 2
}; };
var TypeSql = [
'INNER',
'LEFT',
'RIGHT'
];
Klass.extend Klass.extend
({ ({
Type: Type, Type: Type
TypeSql: TypeSql
}); });
Klass.implement Klass.implement
@ -52,7 +45,9 @@ Klass.implement
,render: function (params) ,render: function (params)
{ {
return '('+ this.target.render (params) +' ' return '('
+ this.target.render (params)
+ ' '
+ this.renderList (this.list, params) + this.renderList (this.list, params)
+ ')'; + ')';
} }

View File

@ -5,6 +5,7 @@ module.exports = new Class
({ ({
Properties: Properties:
{ {
/*
list: list:
{ {
type: Array type: Array
@ -17,13 +18,14 @@ module.exports = new Class
return this._list; return this._list;
} }
} }
*/
} }
,_list: [] ,list: []
,appendChild: function (child) ,appendChild: function (child)
{ {
this._list.push (child); this.list.push (child);
} }
/** /**
@ -33,7 +35,7 @@ module.exports = new Class
*/ */
,push: function (element) ,push: function (element)
{ {
this._list.push (element); this.list.push (element);
} }
/** /**
@ -43,7 +45,7 @@ module.exports = new Class
*/ */
,splice: function (i) ,splice: function (i)
{ {
this._list.splice (i); this.list.splice (i);
} }
/** /**
@ -53,6 +55,6 @@ module.exports = new Class
*/ */
,get: function (i) ,get: function (i)
{ {
return this._list[i]; return this.list[i];
} }
}); });

View File

@ -31,12 +31,6 @@ module.exports = new Class
,render: function (params) ,render: function (params)
{ {
var sql = ''; return this.renderListWs (this.list, params, ";\n");
this._list.forEach (function (stmt) {
sql += stmt.render (params) +";\n";
});
return sql;
} }
}); });

View File

@ -76,11 +76,25 @@ module.exports = new Class
* @param {String} identifier The identifier * @param {String} identifier The identifier
* @return {string} The quoted identifier * @return {string} The quoted identifier
*/ */
,renderIdentifier: function (identifier) ,renderIdent: function (identifier)
{ {
return '`'+ identifier +'`'; return '`'+ identifier +'`';
} }
/**
* Renders a quoted SQL identifier.
*
* @param {String} identifier The identifier
* @return {string} The quoted identifier
*/
,renderPreIdent: function (identifier)
{
if (identifier)
return this.renderIdent (identifier) +'.';
else
return '';
}
/** /**
* Renders the object if it's defined. * Renders the object if it's defined.
* *

View File

@ -18,6 +18,16 @@ var Type =
,AND : 2 ,AND : 2
,OR : 3 ,OR : 3
,REGEXP : 4 ,REGEXP : 4
,LOWER : 5
,UPPER : 6
,LE : 7
,UE : 8
,PLUS : 9
,MINUS : 10
,MULT : 11
,DIV : 12
,NE : 13
,MOD : 14
}; };
var Operators = var Operators =
@ -27,6 +37,16 @@ var Operators =
,'AND' ,'AND'
,'OR' ,'OR'
,'REGEXP' ,'REGEXP'
,'<'
,'>'
,'<='
,'>='
,'+'
,'-'
,'*'
,'/'
,'<>'
,'MOD'
]; ];
Klass.extend Klass.extend
@ -47,6 +67,11 @@ Klass.implement
enumType: Type enumType: Type
,value: -1 ,value: -1
}, },
target:
{
type: String
,value: null
},
exprs: exprs:
{ {
type: Array type: Array

View File

@ -18,15 +18,11 @@ module.exports = new Class
,render: function (params) ,render: function (params)
{ {
var sql = 'SELECT ' return 'SELECT '
+ this.renderListWs (this.expr, params, ', ') + this.renderListWs (this.expr, params, ', ')
+ ' FROM' + ' FROM'
+ this.renderTarget (params); + this.renderTarget (params)
+ this.renderIfSet (this.where, 'WHERE', params)
if (this.where) + this.renderLimit (params);
sql += ' WHERE ' + this.where.render (params);
sql += this.renderLimit (params);
return sql;
} }
}); });

View File

@ -32,7 +32,7 @@ module.exports = new Class
,renderTarget: function (params) ,renderTarget: function (params)
{ {
if (this.target.length > 0) if (this.target.length > 0)
return this.renderListWs (this.target, params, ', '); return ' '+ this.renderListWs (this.target, params, ', ');
else else
return ' DUAL'; return ' DUAL';
} }

View File

@ -8,6 +8,7 @@ var Holder = require ('./holder');
module.exports = new Class module.exports = new Class
({ ({
Extends: Stmt Extends: Stmt
,Tag: 'sql-string'
,Properties: ,Properties:
{ {
query: query:
@ -19,6 +20,12 @@ module.exports = new Class
,regexp: /#\w+/g ,regexp: /#\w+/g
,appendChild: function (child)
{
if (child.nodeType === Node.TEXT_NODE)
this.query = child.textContent;
}
,render: function (params) ,render: function (params)
{ {
if (!this.query) if (!this.query)

View File

@ -28,15 +28,11 @@ module.exports = new Class
,render: function () ,render: function ()
{ {
var sql = ''; var sql = this.renderPreIdent (this.schema)
+ this.renderIdent (this.name);
if (this.schema)
sql += this.renderIndentifier (this.schema) +'.';
sql += this.renderIndentifier (this.name);
if (this.alias) if (this.alias)
sql += ' AS '+ this.renderIndentifier (this.alias); sql += ' AS '+ this.renderIdent (this.alias);
return sql; return sql;
} }

View File

@ -17,10 +17,11 @@ module.exports = new Class
this.field.forEach (function (field, i) { this.field.forEach (function (field, i) {
if (i > 0) if (i > 0)
sql += ', '; sql += ', ';
sql += field.render (params) sql += field.render (params)
+ ' = ' + ' = '
+ this.expr[i].render(params); + this.expr[i].render(params);
}); }, this);
sql += this.renderIfSet (this.where, 'WHERE', params) sql += this.renderIfSet (this.where, 'WHERE', params)
+ this.renderLimit(params); + this.renderLimit(params);

View File

@ -6,9 +6,11 @@ var kebabToCamel = require ('./string-util').kebabToCamel;
var CompilerObject = require ('./compiler-object'); var CompilerObject = require ('./compiler-object');
var CompilerElement = require ('./compiler-element'); var CompilerElement = require ('./compiler-element');
var CompilerText = require ('./compiler-text'); var CompilerText = require ('./compiler-text');
var CompilerString = require ('./compiler-string');
var CompilerInterpolable = require ('./compiler-interpolable'); var CompilerInterpolable = require ('./compiler-interpolable');
var regCompilers = [ var regCompilers = [
CompilerString,
CompilerObject, CompilerObject,
CompilerElement, CompilerElement,
CompilerText CompilerText

23
js/vn/compiler-string.js Normal file
View File

@ -0,0 +1,23 @@
var Compiler = require ('./compiler');
/**
* Compiles a string from text node.
*/
module.exports = new Class
({
Extends: Compiler
,compile: function (builder, node, tagName)
{
if (tagName !== 'string')
return null;
return {string: node.firstChild.textContent};
}
,instantiate: function (doc, context)
{
return context.string;
}
});

View File

@ -78,15 +78,13 @@ module.exports = new Class
,rowChanged: function () ,rowChanged: function ()
{ {
this._rowLock = true;
var row; var row;
if (this._model) if (this._model)
row = this._model.getObject (this._row); row = this._model.getObject (this._row);
this._rowLock = true;
this.params = row != null ? row : {}; this.params = row != null ? row : {};
this._rowLock = false; this._rowLock = false;
} }
}); });

View File

@ -218,13 +218,17 @@ Klass.implement
,_sort: function (columnName, way) ,_sort: function (columnName, way)
{ {
var status = this._status;
this._setStatus (Status.LOADING); this._setStatus (Status.LOADING);
this._realSort (columnName, way); this._realSort (columnName, way);
this._setStatus (Status.READY); this._setStatus (status);
} }
,_realSort: function (columnName, way) ,_realSort: function (columnName, way)
{ {
if (!this._data)
return;
if (columnName !== this._sortColumn) if (columnName !== this._sortColumn)
{ {
if (way === SortWay.DESC) if (way === SortWay.DESC)

View File

@ -21,6 +21,7 @@ Vn = module.exports = {
,ParamIface : require ('./param-iface') ,ParamIface : require ('./param-iface')
,Param : require ('./param') ,Param : require ('./param')
,Spec : require ('./spec') ,Spec : require ('./spec')
,Model : require ('./model')
,ModelIface : require ('./model-iface') ,ModelIface : require ('./model-iface')
,ModelProxy : require ('./model-proxy') ,ModelProxy : require ('./model-proxy')
,IteratorIface : require ('./iterator-iface') ,IteratorIface : require ('./iterator-iface')