diff --git a/src/ns.box.js b/src/ns.box.js index 20c59330..ddee84ca 100644 --- a/src/ns.box.js +++ b/src/ns.box.js @@ -129,6 +129,8 @@ ns.Box.prototype._getRequestViews = function(updated, layout, params) { // сохраняем новый активный layout, в дальнейшем работает с ним this.active = layoutActive; + + this.__registerHideEvents(updated); }; /** @@ -164,37 +166,50 @@ ns.Box.prototype._getViewTree = function() { return tree; }; -ns.Box.prototype.beforeUpdateHTML = function(events) { - var activeLayout = this.active; - for (var viewId in activeLayout) { - var viewKey = activeLayout[viewId]; - // Достаем ранее созданный блок (в _getRequestViews). - /** @type {ns.View} */ - var view = this.views[viewKey]; - view.beforeUpdateHTML(events); - } +/** + * Скрываем все неактивные виды в боксе + * @param {ns.Update~updateViews} updatedViews Обновляемые виды. + * @private + */ +ns.Box.prototype.__registerHideEvents = function(updatedViews) { + // Пройдёмся по всем вложенным видам, чтобы кинуть hide, которым не попали в newLayout + for (var key in this.views) { + var view = this.views[key]; + // Если вид не входит в новый active + if (this.active[view.id] !== view.key) { - this._hideInactiveViews(events); + // Скроем виды, не попавшие в layout + var descs = view._getDescendantsAndSelf( [] ); + for (var i = 0, l = descs.length; i < l; i++) { + // тут могут быть боксы, а у них нет .trigger + if (descs[i].trigger) { + updatedViews.toHide.push(descs[i]); + } + } + } + } }; /** * Скрываем все неактивные виды в боксе - * @param {object} events * @private */ -ns.Box.prototype._hideInactiveViews = function(events) { - var hideEvents = events['ns-view-hide']; +ns.Box.prototype._hideInactiveViews = function() { // Пройдёмся по всем вложенным видам, чтобы кинуть hide, которым не попали в newLayout for (var key in this.views) { var view = this.views[key]; // Если вид не входит в новый active if (this.active[view.id] !== view.key) { - // Скроем виды, не попавшие в layout var descs = view._getDescendantsAndSelf( [] ); for (var i = 0, l = descs.length; i < l; i++) { - descs[i].hideAndUnbindEvents(hideEvents); + descs[i].hideAndUnbindEvents(); } + + // удаляем скрытые виды из DOM + //if (view.node) { + // ns.removeNode(view); + //} } } }; @@ -230,6 +245,8 @@ ns.Box.prototype._updateHTML = function(node, options, events) { var views = this.views; var boxLayout = this.active; + this._hideInactiveViews(); + // Строим новый active согласно layout'у. // Т.е. это тот набор блоков, которые должны быть видимы в боксе после окончания всего апдейта // (включая синхронную и все асинхронные подапдейты). diff --git a/src/ns.update.js b/src/ns.update.js index f95291fe..ec8e9c30 100644 --- a/src/ns.update.js +++ b/src/ns.update.js @@ -187,18 +187,24 @@ var timerName = 'collectModels.' + this._requestCount; this.startTimer(timerName); - var views = this.view._getRequestViews({ + var viewsToUpdate = { sync: [], async: [], + + toHide: [], + toHtmlDestroy: [], + // Флаг, что layout остался в неопределенном состоянии // Надо запросить модели и пройтись еще раз hasPatchLayout: false - }, this.layout, this.params); + }; + + this.view._getRequestViews(viewsToUpdate, this.layout, this.params); this.stopTimer(timerName); - this.log('collected incomplete views', views); + this.log('collected incomplete views', viewsToUpdate); - return views; + return viewsToUpdate; }; /** @@ -259,7 +265,9 @@ } else { requestPromise.fulfill({ - async: asyncPromises + async: asyncPromises, + toHide: views.toHide, + toHtmlDestroy: views.toHtmlDestroy }); } }, function(e) { @@ -324,22 +332,13 @@ return this._rejectWithStatus(this.STATUS.EXPIRED); } - this.startTimer('triggerHideEvents'); - var hideViewEvents = { - 'ns-view-hide': [], - 'ns-view-htmldestroy': [] - }; - this.view.beforeUpdateHTML(hideViewEvents); - this._triggerViewEvents(hideViewEvents); - + this.startTimer('insertNodes'); var viewEvents = { 'ns-view-async': [], 'ns-view-htmlinit': [], 'ns-view-show': [], 'ns-view-touch': [] }; - - this.switchTimer('triggerHideEvents', 'insertNodes'); this.view._updateHTML(node, {toplevel: true}, viewEvents); this.switchTimer('insertNodes', 'triggerEvents'); @@ -370,11 +369,21 @@ * потому что у видов будет уже другое состояние, если что-то поменяется между generateHTML и insertNodes * @private */ - ns.Update.prototype._updateDOM = function() { + ns.Update.prototype._updateDOM = function(result) { if (this._expired()) { return this._rejectWithStatus(this.STATUS.EXPIRED); } + this.startTimer('triggerHideEvents'); + if (result) { + //TODO: unbindEvents + this._triggerViewEvents({ + 'ns-view-hide': result.toHide, + 'ns-view-htmldestroy': result.toHtmlDestroy + }); + } + this.stopTimer('triggerHideEvents'); + var html = this._renderUpdateTree(); this.startTimer('html2node'); var node = ns.html2node(html || ''); @@ -443,7 +452,7 @@ // начинаем цепочку с промиса, чтобы ловить ошибки в том числе и из _requestAllModels Vow.invoke(this._requestAllModels.bind(this)) .then(function(result) { - this._updateDOM(); + this._updateDOM(result); this._fulfill(result); }, this._reject, this) // еще один reject, чтобы ловить ошибки из #_updateDOM @@ -708,6 +717,8 @@ * @typedef {object} ns.Update~updateViews * @property {ns.View[]} sync Массив видов, которые надо обновить синхронно. * @property {ns.View[]} async Массив видов, которые надо обновить асинхронно. + * @property {ns.View[]} toHide + * @property {ns.View[]} toHtmlDestroy * @property {boolean} hasPatchLayout Флаг, что в дереве есть неопределившиеся виды. */ diff --git a/src/ns.view.js b/src/ns.view.js index 8b38b7a1..cb833d57 100644 --- a/src/ns.view.js +++ b/src/ns.view.js @@ -245,12 +245,12 @@ * @returns {boolean} * @protected */ - ns.View.prototype.hideAndUnbindEvents = function(events) { + ns.View.prototype.hideAndUnbindEvents = function() { var eventsWasUnbinded = this.__onHide(); - if (eventsWasUnbinded && events) { - events.push(this); - } + //if (eventsWasUnbinded && events) { + // events.push(this); + //} // Скрывать и ставить флаг надо всегда. // Например, для асинхронных видов, которые отрендерили в состоянии async, @@ -732,6 +732,10 @@ * @private */ ns.View.prototype._getRequestViews = function(updated, pageLayout, updateParams) { + if (window.debug && this.id === 'content2-async') { + debugger; + } + var syncState = this.__evaluateState(); // Добавляем себя в обновляемые виды this.__registerInUpdate(syncState, updated); @@ -768,11 +772,13 @@ var layoutViews = pageLayout.views; this._saveLayout(layoutViews); + this.__registerHideEvents(updated); // Создаем детей и идем вниз только если находимся в синхронном состоянии // Иначе получится странная ситуация, // что дети асинхронного вида добавят себя как синхронные и для них будут запрошены модели. if (canGoFather) { + // Создаем подблоки for (var view_id in layoutViews) { this._addView(view_id, updateParams, layoutViews[view_id].type); @@ -782,8 +788,6 @@ view._getRequestViews(updated, layoutViews[id], updateParams); }); } - - return updated; }; /** @@ -896,6 +900,24 @@ } }; + /** + * + * @param {ns.Update~updateViews} updatedViews Обновляемые виды. + * @private + */ + ns.View.prototype.__registerHideEvents = function(updatedViews) { + var viewWasInvalid = !this.isValidSelf(); + if ( viewWasInvalid ) { + // если была видимая нода + if (this.node && !this.isLoading()) { + if (this.isVisible()) { + updatedViews.toHide.push(this); + } + updatedViews.toHtmlDestroy.push(this); + } + } + }; + /** * Строим дерево для шаблонизатора. * @description @@ -1183,6 +1205,7 @@ return viewNode; }; + /* ns.View.prototype._selfBeforeUpdateHTML = function(events) { var viewWasInvalid = !this.isValidSelf(); if ( viewWasInvalid ) { @@ -1196,6 +1219,7 @@ } }; + ns.View.prototype.beforeUpdateHTML = function(events) { this._selfBeforeUpdateHTML(events); @@ -1206,6 +1230,7 @@ }); } }; + */ /** * Обновляем (если нужно) ноду блока. diff --git a/src/ns.viewCollection.js b/src/ns.viewCollection.js index 21d7f552..8e6f2a7f 100644 --- a/src/ns.viewCollection.js +++ b/src/ns.viewCollection.js @@ -366,9 +366,7 @@ ns.ViewCollection.prototype._getRequestViews = function(updated, layout, updateP // Все элементы коллекции в контейнере, а коллекция может иметь собственную разметку, в т.ч. с другими видами this._saveLayout(pageLayout); - - // При необходимости добавим текущий вид в список "запрашиваемых" - return updated; + this.__registerHideEvents(updated); }; /** @@ -508,6 +506,7 @@ ns.ViewCollection.prototype._getDescViewTree = function() { return result; }; +/* ns.ViewCollection.prototype.beforeUpdateHTML = function(events) { this._selfBeforeUpdateHTML(events); @@ -518,6 +517,7 @@ ns.ViewCollection.prototype.beforeUpdateHTML = function(events) { }); } }; +*/ /** *