omniscientjs / immstruct

Immutable data structures with history for top-to-bottom properties in component based libraries like React. Based on Immutable.js
374 stars 21 forks source link

Refactor Structure to be cursor type agnostic #44

Closed dashed closed 9 years ago

dashed commented 9 years ago

While sketching out API for some new cursor types that extend Immutable cursors, one type uses Structure of a different cursor type in a meta manner. I needed something akin to immstruct Structures.

So I figured that it could be configured to use a different cursor type.

This is needed for some cursor types I'm sketching out to solve the following issues in a more fundamental way:

/cc @Gozala


By default, Structure would use some extended cursor type.

This is how I would envision the refactor of Structure:

// this is cursor type agnostic

function Structure(options) {
    this.state = options.state || Immutable.Map();
    this.cursorType = options.cursorType || Carbon;
    this.onChange = options.onChange || null;
    this.updateCurrent = options.updateCurrent; // required
    this.captureEvent = options.captureEvent || analyze;
    this.__onCommit = function() {
        self.onCommit.apply(self, arguments)
    };

    EventEmitter.call(this, arguments);
}

inherits(Structure, EventEmitter);

Structure.prototype.onCommit = function() {

    const oldState = this.state;
    const self = this;

    this.state = this.updateCurrent.apply(this._onChange, arguments);

    const event = this.captureEvent.apply(this.captureEvent, arguments);

    setTimeout(function() {
        self.onChange && self.onChange();
        self.emit.call(self, 'swap', state, oldState);
        self.emit.apply(self, [event.name].concat(event.arguments));
    }, 0);

    if(!this.history) return;

    // update history
    this.history = this.history
      .take(++this._currentRevision)
      .push(this.current);
}

Structure.prototype.cursor = function(path) {
    path = path || [];
    return this.cursorType.from(this.state, path, this.__onCommit);
}

// this was forceHasSwapped(...)
// I think this is a better name; inspired by 
// http://facebook.github.io/react/docs/component-api.html#replacestate
Structure.prototype.replaceState = function(newState) {
    this.state = newState;

    const self = this;
    setTimeout(function() {
        self.emit.call(self, 'swap', state, oldState);
    }, 0);
}

// all of these are the same API. but by semantics, they should call swap.
// user has access to this.history anyways
Structure.prototype.undo = // same ...
Structure.prototype.redo = // same ...
Structure.prototype.undoUntil = // same ...
mikaelbr commented 9 years ago

While a cool idea, I don't think this is feasible. It's an extension to Immutable Cursors, and I don't think it makes sense for immstruct to support other libraries.