Ext.define('PVE.panel.LogView', { extend: 'Ext.panel.Panel', alias: ['widget.pveLogView'], pageSize: 500, lineHeight: 16, viewInfo: undefined, scrollToEnd: true, getMaxDown: function(scrollToEnd) { var me = this; var target = me.getTargetEl(); var dom = target.dom; if (scrollToEnd) { dom.scrollTop = dom.scrollHeight - dom.clientHeight; } var maxDown = dom.scrollHeight - dom.clientHeight - dom.scrollTop; return maxDown; }, updateView: function(start, end, total, text) { var me = this; var el = me.dataCmp.el; if (me.viewInfo && me.viewInfo.start === start && me.viewInfo.end === end && me.viewInfo.total === total && me.viewInfo.textLength === text.length) { return; // same content } var maxDown = me.getMaxDown(); var scrollToEnd = (maxDown <= 0) && me.scrollToEnd; el.setStyle('padding-top', start*me.lineHeight); el.update(text); me.dataCmp.setHeight(total*me.lineHeight); if (scrollToEnd) { me.getMaxDown(true); } me.viewInfo = { start: start, end: end, total: total, textLength: text.length }; }, doAttemptLoad: function(start) { var me = this; PVE.Utils.API2Request({ url: me.url, params: { start: start, limit: me.pageSize }, method: 'GET', success: function(response) { PVE.Utils.setErrorMask(me, false); var list = response.result.data; var total = response.result.total; var first = 0, last = 0; var text = ''; Ext.Array.each(list, function(item) { if (!first|| item.n < first) { first = item.n; } if (!last || item.n > last) { last = item.n; } text = text + Ext.htmlEncode(item.t) + "<br>"; }); if (first && last && total) { me.updateView(first -1 , last -1, total, text); } else { me.updateView(0, 0, 0, ''); } }, failure: function(response) { var msg = response.htmlStatus; PVE.Utils.setErrorMask(me, msg); } }); }, attemptLoad: function(start) { var me = this; if (!me.loadTask) { me.loadTask = Ext.create('Ext.util.DelayedTask', me.doAttemptLoad, me, []); } me.loadTask.delay(200, me.doAttemptLoad, me, [start]); }, requestUpdate: function(top, force) { var me = this; if (top === undefined) { var target = me.getTargetEl(); top = target.dom.scrollTop; } var viewStart = parseInt((top / me.lineHeight) - 1, 10); if (viewStart < 0) { viewStart = 0; } var viewEnd = parseInt(((top + me.getHeight())/ me.lineHeight) + 1, 10); var info = me.viewInfo; if (info && !force) { if (viewStart >= info.start && viewEnd <= info.end) { return; } } var line = parseInt((top / me.lineHeight) - (me.pageSize / 2) + 10, 10); if (line < 0) { line = 0; } me.attemptLoad(line); }, afterRender: function() { var me = this; me.callParent(arguments); Ext.Function.defer(function() { var target = me.getTargetEl(); target.on('scroll', function(e) { me.requestUpdate(); }); me.requestUpdate(0); }, 20); }, initComponent : function() { /*jslint confusion: true */ var me = this; if (!me.url) { throw "no url specified"; } me.dataCmp = Ext.create('Ext.Component', { style: 'font:normal 11px tahoma, arial, verdana, sans-serif;' + 'line-height: ' + me.lineHeight.toString() + 'px; white-space: pre;' }); me.task = Ext.TaskManager.start({ run: function() { if (!me.isVisible() || !me.scrollToEnd || !me.viewInfo) { return; } var maxDown = me.getMaxDown(); if (maxDown > 0) { return; } me.requestUpdate(undefined, true); }, interval: 1000 }); Ext.apply(me, { autoScroll: true, layout: 'auto', items: me.dataCmp, bodyStyle: 'padding: 5px;', listeners: { show: function() { var target = me.getTargetEl(); if (target && target.dom) { target.dom.scrollTop = me.savedScrollTop; } }, beforehide: function() { // Hack: chrome reset scrollTop to 0, so we save/restore var target = me.getTargetEl(); if (target && target.dom) { me.savedScrollTop = target.dom.scrollTop; } }, destroy: function() { Ext.TaskManager.stop(me.task); } } }); me.callParent(); } });