index.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. 'use strict';
  2. var clear = require('es5-ext/array/#/clear')
  3. , assign = require('es5-ext/object/assign')
  4. , callable = require('es5-ext/object/valid-callable')
  5. , value = require('es5-ext/object/valid-value')
  6. , d = require('d')
  7. , autoBind = require('d/auto-bind')
  8. , Symbol = require('es6-symbol')
  9. , defineProperty = Object.defineProperty
  10. , defineProperties = Object.defineProperties
  11. , Iterator;
  12. module.exports = Iterator = function (list, context) {
  13. if (!(this instanceof Iterator)) return new Iterator(list, context);
  14. defineProperties(this, {
  15. __list__: d('w', value(list)),
  16. __context__: d('w', context),
  17. __nextIndex__: d('w', 0)
  18. });
  19. if (!context) return;
  20. callable(context.on);
  21. context.on('_add', this._onAdd);
  22. context.on('_delete', this._onDelete);
  23. context.on('_clear', this._onClear);
  24. };
  25. defineProperties(Iterator.prototype, assign({
  26. constructor: d(Iterator),
  27. _next: d(function () {
  28. var i;
  29. if (!this.__list__) return;
  30. if (this.__redo__) {
  31. i = this.__redo__.shift();
  32. if (i !== undefined) return i;
  33. }
  34. if (this.__nextIndex__ < this.__list__.length) return this.__nextIndex__++;
  35. this._unBind();
  36. }),
  37. next: d(function () { return this._createResult(this._next()); }),
  38. _createResult: d(function (i) {
  39. if (i === undefined) return { done: true, value: undefined };
  40. return { done: false, value: this._resolve(i) };
  41. }),
  42. _resolve: d(function (i) { return this.__list__[i]; }),
  43. _unBind: d(function () {
  44. this.__list__ = null;
  45. delete this.__redo__;
  46. if (!this.__context__) return;
  47. this.__context__.off('_add', this._onAdd);
  48. this.__context__.off('_delete', this._onDelete);
  49. this.__context__.off('_clear', this._onClear);
  50. this.__context__ = null;
  51. }),
  52. toString: d(function () { return '[object Iterator]'; })
  53. }, autoBind({
  54. _onAdd: d(function (index) {
  55. if (index >= this.__nextIndex__) return;
  56. ++this.__nextIndex__;
  57. if (!this.__redo__) {
  58. defineProperty(this, '__redo__', d('c', [index]));
  59. return;
  60. }
  61. this.__redo__.forEach(function (redo, i) {
  62. if (redo >= index) this.__redo__[i] = ++redo;
  63. }, this);
  64. this.__redo__.push(index);
  65. }),
  66. _onDelete: d(function (index) {
  67. var i;
  68. if (index >= this.__nextIndex__) return;
  69. --this.__nextIndex__;
  70. if (!this.__redo__) return;
  71. i = this.__redo__.indexOf(index);
  72. if (i !== -1) this.__redo__.splice(i, 1);
  73. this.__redo__.forEach(function (redo, i) {
  74. if (redo > index) this.__redo__[i] = --redo;
  75. }, this);
  76. }),
  77. _onClear: d(function () {
  78. if (this.__redo__) clear.call(this.__redo__);
  79. this.__nextIndex__ = 0;
  80. })
  81. })));
  82. defineProperty(Iterator.prototype, Symbol.iterator, d(function () {
  83. return this;
  84. }));
  85. defineProperty(Iterator.prototype, Symbol.toStringTag, d('', 'Iterator'));