require('./style.scss'); var Component = require('vn/component'); module.exports = new Class({ Extends: Component ,Tag: 'htk-repeater' ,Child: 'model' ,Properties: { /** * The source data model. */ model: { type: Db.Model ,set(x) { this.link({_model: x}, { 'status-changed': this._onModelChange ,'row-deleted': this._onRowDelete ,'row-updated': this._onRowUpdate ,'row-inserted': this._onRowInsert }); this._onModelChange(); } ,get() { this._model; } } /** * The identifier for internal iterator. */ ,formId: { type: String ,set(x) { this._formId = x; } ,get() { this._formId; } } /** * {Function (Vn.BuilderResult, Db.Form)} Function to call after every * box rendering. */ ,renderer: { type: Function ,set(x) { this._renderer = x; } ,get() { this._renderer; } } /** * Wether to show the model status. */ ,showStatus: { type: Boolean ,set(x) { this._showStatus = x; this._onModelChange(); } ,get() { this._showStatus; } } /** * Message that should be displayed when source model is not ready. */ ,emptyMessage: { type: String ,value: null } } ,_builder: null ,_formId: 'form' ,_showStatus: true ,render() { var div = this.createRoot('div'); this._container = this.createElement('div'); this._container.className = 'htk-repeater'; div.appendChild(this._container); } ,loadXml(scope, node) { Component.prototype.loadXml.call(this, scope, node); this._parentScope = scope; var builder = this._builder = new Vn.Builder(); builder.compileNode(node.firstElementChild, [this._formId]); this._onModelChange(); } ,getChild(index) { return this._container.childNodes[index]; } ,getBuilder(index) { return this._childsData[index].scope; } ,getForm(index) { return this._childsData[index].set; } ,_buildBox(index) { var set = new Db.SimpleIterator({ model: this._model, row: index }); var scope = this._builder.load(this.doc, null, this._parentScope); scope.link({ $iter: set, [this._formId]: set.getObject() }); this._childsData.push({scope, set}); if (this._renderer) this._renderer(scope, set); return scope.getMain(); } ,_onModelChange() { if (!this._model || !this._builder) return; this.node.removeChild(this._container); Vn.Node.removeChilds(this._container); this._freeChildsData(); this._childsData = []; switch (this._model.status) { case Db.Model.Status.READY: { for (var i = 0; i < this._model.numRows; i++) this._container.appendChild(this._buildBox(i)); this._showNoRecordsFound(); break; } case Db.Model.Status.LOADING: this._showMessage(_('Loading'), null); break; case Db.Model.Status.CLEAN: { var emptyMessage = this.emptyMessage ? this.emptyMessage : _('NoData'); this._showMessage(emptyMessage, 'refresh'); break; } case Db.Model.Status.ERROR: this._showMessage(_('ErrorLoadingData'), 'error'); break; } this.node.appendChild(this._container); this.emit('change'); } ,_showNoRecordsFound() { if (this._model.numRows === 0) this._showMessage(_('EmptyList'), 'block'); } ,_showMessage(message, src) { if (!this._showStatus) return; var div = this.createElement('div'); div.className = 'message'; this._container.appendChild(div); if (src) { const icon = new Htk.Icon({ name: src }); div.appendChild(icon.node); } else { var spinner = new Htk.Spinner(); spinner.start(); div.appendChild(spinner.node); } div.appendChild(this.createTextNode(message)); } ,_onRowDelete(model, row) { Vn.Node.remove(this._container.childNodes[row]); this._unrefChildData(row); this._childsData.splice(row, 1); for (var i = row; i < this._model.numRows; i++) this._childsData[i].set.row = i; this._showNoRecordsFound(); } ,_onRowUpdate(model, row) { this._childsData[row].set.iterChanged(); } ,_onRowInsert(model, row) { var box = this._buildBox(row); this._container.appendChild(box); } ,_freeChildsData() { if (this._childsData) for (var i = 0; i < this._childsData.length; i++) this._unrefChildData(i); } ,_unrefChildData(index) { var childData = this._childsData[index]; childData.set._destroy(); childData.scope._destroy(); } ,_destroy() { this._freeChildsData(); Component.prototype._destroy.call(this); } });