UNPKG

electron-devtools-vendor

Version:

<div align="center"> <h2>electron-devtools-vendor</h2> <img alt="MIT" src="https://img.shields.io/github/license/BlackHole1/electron-devtools-vendor?color=9cf&style=flat-square"> <img alt="GitHub repo size" src="https://img.shields.io/github/r

287 lines (239 loc) 10.6 kB
// Read a collection Modules.set('Reader', function() { // imports var Component = Modules.get('Component'); var u = Modules.get('utils'); var Reader = Component.extend({ // setted by the reader manager (the dedicated server) on registration index: undefined, // the collection to read collection: undefined, // if the collection must be read in reverse order, e.g. from end to start orderReverse: false, // the filter to use on the collection filter: undefined, initialize: function(collection, orderReverse) { this.collection = collection; if (typeof orderReverse !== 'undefined') { // otherwise keep default this.orderReverse = orderReverse; } this.readListeners = []; this.isReadMoreInProgress = false; this.readMoreLeft = 0; this.lastUnfilteredIndex = undefined; // inizialize position from which to read the collection (depends on the order type) this.position = undefined; this.begin(); this.readNewModels(); }, moveTo: function(position) { if (position >= 0 && position < this.collection.length) { this.position = position; return this.collection.at(position); } }, next: function() { return this.moveTo(this.orderReverse? this.position-1 : this.position+1); }, prev: function() { return this.moveTo(this.orderReverse? this.position+1 : this.position-1); }, first: function() { return this.moveTo(this.orderReverse? this.collection.length-1 : 0); }, last: function() { return this.moveTo(this.orderReverse? 0 : this.collection.length-1); }, current: function() { return this.collection.at(this.position); }, beginPosition: function() { return (this.orderReverse) ? this.collection.length : -1; }, begin: function() { this.position = this.beginPosition(); // reset everything, this is a new begin! this.lastUnfilteredIndex = undefined; this.unreadAll(); this.readMoreFinished(); this.send('begin'); }, setOrderReverse: function(orderReverse) { if (this.orderReverse != orderReverse) { this.orderReverse = orderReverse; this.begin(); } }, // pass falsy value for no filter. // Note: the reader takes ownership of the filter, // i.e. will remove it when not needed anymore. setFilter: function(filter) { // remove old filter if (this.filter) this.filter.remove(); if (!this.filter && filter) { // no filter -> filter // => calculate last visible index // (is the current since all the models are visible) var current = this.current(); this.lastUnfilteredIndex = current? current.index : undefined; } else if (this.filter && !filter) { // filter -> no filter // => restore previous models // (after a filter is setted, the user could have read many hidden models, // thus in order to avoid their massive showing when removing the filter, // we only reshow the models that were visible before having any filter) var current = this.current(); while (current && current.index !== this.lastUnfilteredIndex) { this.unread(); this.visibilityChange(current, false); // signal model as hidden (TODO: generalize this directly in unreadModel?) current = this.prev(); } if (!current) { // index not found, but reader now is actually at first position, // even though we have unread the first model, so subsequent read more would // never read it again, thus we manually move into the begin position this.position = this.beginPosition(); } // an eventual pending read more is not valid anymore this.readMoreFinished(); } // set new filter this.filter = filter; // check new visibility with new filter for (var i=0, l=this.readListeners.length; i<l; i++) { if (this.readListeners[i]) { // (the array might be sparse!) var model = this.collection.at(i); this.readModel(model); } } }, readNewModels: function() { // Note: assumes model is not added in middle position! this.listenTo(this.collection, 'add', function(model) { // an add is relevant if: // - in reverse mode: always (model is on top) // - in normal mode: when there are still models left to read var isRelevant = this.orderReverse || this.isReadMoreInProgress; if (isRelevant) { if (!this.orderReverse && this.isReadMoreInProgress && this.position === this.collection.length-2) { // we were at the end waiting for new models => // the model must be 'consumed' or subsequents // readMore will read it again this.next(); } else if (this.orderReverse && this.position === this.collection.length-1) { // we were at this.collection.length before the model was added, i.e. // we just begun => keep the position this.position = this.collection.length; } // process model var passes = this.readModel(model); // if a read more is in progress and the model was actually added // at the (relative) end, update the models left to read // (never in reverse mode since the adds are done at the collection end, // (i.e. at the relative start, that's intended.) if (passes && !this.orderReverse && this.isReadMoreInProgress) { this.readMoreLeft--; if (this.readMoreLeft == 0) { this.readMoreFinished(); } } } }); }, // read 'howMany' passing models readMore: function(howMany) { if (this.isReadMoreInProgress) return; this.readMoreStarted(); this.readMoreLeft = howMany; while (this.readMoreLeft != 0 && this.next()) { var passes = this.read(); if (passes) this.readMoreLeft--; } if (this.readMoreLeft == 0) { this.readMoreFinished(); } else { // read will finish after remaining models have been read via add events // (will never finish in reverse order since new models are actually // before the current position, that's intended to prevent infinite // client back and forth for new never-existing models) } }, readMoreStarted: function() { if (!this.isReadMoreInProgress) { this.isReadMoreInProgress = true; this.send('readMoreStarted'); } }, readMoreFinished: function() { if (this.isReadMoreInProgress) { this.readMoreLeft = 0; this.isReadMoreInProgress = false; this.send('readMoreFinished'); } }, read: function() { var model = this.current(); if (!model) return; return this.readModel(model); }, readModel: function(model) { var modelIndex = model.index; if (this.readListeners[modelIndex]) { // already readed, unread it first this.unreadModel(model); } // initial visibility var passes = !this.filter || this.filter.match(model); this.visibilityChange(model, passes); // monitor visibility changes var listener = [model, 'change', function() { if (this.filter) { var matchResult = this.filter.match(model); if (matchResult != passes) { passes = matchResult; this.visibilityChange(model, matchResult); } } else { // (needed if the filter has been removed) if (!passes) { passes = true; this.visibilityChange(model, true); } } }]; this.listenTo.apply(this, listener); this.readListeners[modelIndex] = listener; return passes; // initial visibility }, unread: function() { var model = this.current(); if (!model) return; return this.unreadModel(model); }, unreadModel: function(model) { var listener = this.readListeners[model.index]; if (listener) { this.stopListening.apply(this, listener); delete this.readListeners[model.index]; } }, unreadAll: function() { for (var i=0, l=this.readListeners.length; i<l; i++) { var listener = this.readListeners[i]; if (listener) { // (the array might be sparse!) this.stopListening.apply(this, listener); delete this.readListeners[i]; } } }, visibilityChange: function(model, isVisible) { this.send('visibilityChange', { modelIndex: model.index, isVisible: isVisible }); }, send: function(name, data) { this.trigger('send', name, data); } }); return Reader; });