11/**
2- * immstruct v1.3.1
2+ * immstruct v1.4.0
33* Authors: Mikael Brevik, @torgeir
44***************************************/
55! function ( e ) { if ( "object" == typeof exports && "undefined" != typeof module ) module . exports = e ( ) ; else if ( "function" == typeof define && define . amd ) define ( [ ] , e ) ; else { var f ; "undefined" != typeof window ?f = window :"undefined" != typeof global ?f = global :"undefined" != typeof self && ( f = self ) , f . immstruct = e ( ) } } ( function ( ) { var define , module , exports ; return ( function e ( t , n , r ) { function s ( o , u ) { if ( ! n [ o ] ) { if ( ! t [ o ] ) { var a = typeof require == "function" && require ; if ( ! u && a ) return a ( o , ! 0 ) ; if ( i ) return i ( o , ! 0 ) ; var f = new Error ( "Cannot find module '" + o + "'" ) ; throw f . code = "MODULE_NOT_FOUND" , f } var l = n [ o ] = { exports :{ } } ; t [ o ] [ 0 ] . call ( l . exports , function ( e ) { var n = t [ o ] [ 1 ] [ e ] ; return s ( n ?n :e ) } , l , l . exports , e , t , n , r ) } return n [ o ] . exports } var i = typeof require == "function" && require ; for ( var o = 0 ; o < r . length ; o ++ ) s ( r [ o ] ) ; return s } ) ( { 1 :[ function ( _dereq_ , module , exports ) {
66var Structure = _dereq_ ( './src/structure' ) ;
77
8- module . exports = function ( key , data ) {
9- return getInstance ( {
8+ function Immstruct ( ) {
9+ if ( ! ( this instanceof Immstruct ) ) {
10+ return new Immstruct ( ) ;
11+ }
12+
13+ this . instances = { } ;
14+ }
15+
16+ Immstruct . prototype . get = function ( key , data ) {
17+ return getInstance ( this , {
1018 key : key ,
1119 data : data
1220 } ) ;
1321} ;
1422
15- module . exports . instances = { } ;
23+ Immstruct . prototype . clear = function ( ) {
24+ this . instances = { } ;
25+ } ;
26+
27+ Immstruct . prototype . remove = function ( key ) {
28+ return delete this . instances [ key ] ;
29+ } ;
30+
31+ Immstruct . prototype . withHistory = function ( key , data ) {
32+ return getInstance ( this , {
33+ key : key ,
34+ data : data ,
35+ history : true
36+ } ) ;
37+ } ;
38+
39+ var inst = new Immstruct ( ) ;
40+
41+ module . exports = function ( key , data ) {
42+ return getInstance ( inst , {
43+ key : key ,
44+ data : data
45+ } ) ;
46+ } ;
1647
1748module . exports . withHistory = function ( key , data ) {
18- return getInstance ( {
49+ return getInstance ( inst , {
1950 key : key ,
2051 data : data ,
2152 history : true
2253 } ) ;
2354} ;
2455
2556module . exports . Structure = Structure ;
26-
27- function getInstance ( options ) {
57+ module . exports . Immstruct = Immstruct ;
58+ module . exports . clear = inst . clear . bind ( inst ) ;
59+ module . exports . remove = inst . remove . bind ( inst ) ;
60+ Object . defineProperty ( module . exports , 'instances' , {
61+ get : function ( ) { return inst . instances ; } ,
62+ enumerable : true ,
63+ configurable : true
64+ } ) ;
65+
66+ function getInstance ( obj , options ) {
2867 if ( typeof options . key === 'object' ) {
2968 options . data = options . key ;
3069 options . key = void 0 ;
3170 }
3271
33- if ( options . key && module . exports . instances [ options . key ] ) {
34- return module . exports . instances [ options . key ] ;
72+ if ( options . key && obj . instances [ options . key ] ) {
73+ return obj . instances [ options . key ] ;
3574 }
3675
3776 var newInstance = new Structure ( options ) ;
38- module . exports . instances [ newInstance . key ] = newInstance ;
77+ obj . instances [ newInstance . key ] = newInstance ;
3978 return newInstance ;
4079}
41-
42- module . exports . clear = function ( ) {
43- module . exports . instances = { } ;
44- } ;
45-
46- module . exports . remove = function ( key ) {
47- return delete module . exports . instances [ key ] ;
48- } ;
49-
5080} , { "./src/structure" :5 } ] , 2 :[ function ( _dereq_ , module , exports ) {
5181'use strict' ;
5282
@@ -596,13 +626,16 @@ var utils = _dereq_('./utils');
596626 * ## Public API.
597627 * Constructor({ history: bool, key: string, data: structure|object })
598628 * .cursor(path)
629+ * .reference(path)
599630 * .forceHasSwapped(newData, oldData, keyPath)
600631 * .undo(steps)
601632 * .redo(steps)
602633 * .undoUntil(structure)
603634 *
604635 ************************************/
605636function Structure ( options ) {
637+ var self = this ;
638+
606639 options = options || { } ;
607640 if ( ! ( this instanceof Structure ) ) {
608641 return new Structure ( options ) ;
@@ -620,6 +653,16 @@ function Structure (options) {
620653 this . _currentRevision = 0 ;
621654 }
622655
656+ this . _pathListeners = [ ] ;
657+ this . on ( 'swap' , function ( newData , oldData , keyPath ) {
658+ listListenerMatching ( self . _pathListeners , pathString ( keyPath ) ) . forEach ( function ( fns ) {
659+ fns . forEach ( function ( fn ) {
660+ if ( typeof fn !== 'function' ) return ;
661+ fn ( newData , oldData , keyPath ) ;
662+ } ) ;
663+ } ) ;
664+ } ) ;
665+
623666 EventEmitter . call ( this , arguments ) ;
624667}
625668inherits ( Structure , EventEmitter ) ;
@@ -634,7 +677,6 @@ Structure.prototype.cursor = function (path) {
634677 }
635678
636679 var changeListener = function ( newRoot , oldRoot , path ) {
637-
638680 if ( self . current === oldRoot ) {
639681 return self . current = newRoot ;
640682 }
@@ -655,6 +697,67 @@ Structure.prototype.cursor = function (path) {
655697 return Cursor . from ( self . current , path , changeListener ) ;
656698} ;
657699
700+ Structure . prototype . reference = function ( path ) {
701+ if ( isCursor ( path ) && path . _keyPath ) {
702+ path = path . _keyPath ;
703+ }
704+ var self = this , pathId = pathString ( path ) ;
705+ var listenerNs = self . _pathListeners [ pathId ] ;
706+ var cursor = this . cursor ( path ) ;
707+
708+ var changeListener = function ( newRoot , oldRoot , changedPath ) { cursor = self . cursor ( path ) ; } ;
709+ var referenceListeners = [ changeListener ] ;
710+ this . _pathListeners [ pathId ] = ! listenerNs ? referenceListeners : listenerNs . concat ( changeListener ) ;
711+
712+ return {
713+ observe : function ( eventName , newFn ) {
714+ if ( typeof eventName === 'function' ) {
715+ newFn = eventName ;
716+ eventName = void 0 ;
717+ }
718+ if ( this . _dead || typeof newFn !== 'function' ) return ;
719+ if ( eventName && eventName !== 'swap' ) {
720+ newFn = onlyOnEvent ( eventName , newFn ) ;
721+ }
722+
723+ self . _pathListeners [ pathId ] = self . _pathListeners [ pathId ] . concat ( newFn ) ;
724+ referenceListeners = referenceListeners . concat ( newFn ) ;
725+
726+ return function unobserve ( ) {
727+ var fnIndex = self . _pathListeners [ pathId ] . indexOf ( newFn ) ;
728+ var localListenerIndex = referenceListeners . indexOf ( newFn ) ;
729+
730+ if ( referenceListeners [ localListenerIndex ] === newFn ) {
731+ referenceListeners . splice ( localListenerIndex , 1 ) ;
732+ }
733+
734+ if ( ! self . _pathListeners [ pathId ] ) return ;
735+ if ( self . _pathListeners [ pathId ] [ fnIndex ] !== newFn ) return ;
736+ self . _pathListeners [ pathId ] . splice ( fnIndex , 1 ) ;
737+ } ;
738+ } ,
739+ cursor : function ( subPath ) {
740+ if ( subPath ) return cursor . cursor ( subPath ) ;
741+ return cursor ;
742+ } ,
743+ unobserveAll : function ( ) {
744+ removeAllListenersBut ( self , pathId , referenceListeners , changeListener ) ;
745+ referenceListeners = [ changeListener ] ;
746+ } ,
747+ destroy : function ( ) {
748+ removeAllListenersBut ( self , pathId , referenceListeners ) ;
749+ referenceListeners = void 0 ;
750+ cursor = void 0 ;
751+
752+ this . _dead = true ;
753+ this . observe = void 0 ;
754+ this . unobserveAll = void 0 ;
755+ this . cursor = void 0 ;
756+ this . destroy = void 0 ;
757+ }
758+ } ;
759+ } ;
760+
658761Structure . prototype . forceHasSwapped = function ( newData , oldData , keyPath ) {
659762 this . emit ( 'swap' , newData || this . current , oldData , keyPath ) ;
660763 possiblyEmitAnimationFrameEvent ( this , newData || this . current , oldData , keyPath )
@@ -742,19 +845,10 @@ function handlePersisting (emitter, fn) {
742845 return function ( newData , oldData , path ) {
743846 var newStructure = fn . apply ( fn , arguments ) ;
744847 if ( newData === oldData ) return newStructure ;
848+ var info = analyze ( newData , oldData , path ) ;
745849
746- var oldObject = oldData && oldData . getIn ( path ) ;
747- var newObject = newStructure && newStructure . getIn ( path ) ;
748-
749- var inOld = oldData && hasIn ( oldData , path ) ;
750- var inNew = newStructure && hasIn ( newStructure , path ) ;
751-
752- if ( inOld && ! inNew ) {
753- emitter . emit ( 'delete' , path , oldObject ) ;
754- } else if ( inOld && inNew ) {
755- emitter . emit ( 'change' , path , newObject , oldObject ) ;
756- } else if ( ! inOld && inNew ) {
757- emitter . emit ( 'add' , path , newObject ) ;
850+ if ( info . eventName ) {
851+ emitter . emit . apply ( emitter , [ info . eventName ] . concat ( info . arguments ) ) ;
758852 }
759853 return newStructure ;
760854 } ;
@@ -764,13 +858,78 @@ function handlePersisting (emitter, fn) {
764858 * Private helpers.
765859 ***********************************/
766860
861+ function removeAllListenersBut ( self , pathId , listeners , except ) {
862+ if ( ! listeners ) return ;
863+ listeners . forEach ( function ( fn ) {
864+ if ( except && fn === except ) return ;
865+ var index = self . _pathListeners [ pathId ] . indexOf ( fn ) ;
866+ self . _pathListeners [ pathId ] . splice ( index , 1 ) ;
867+ } ) ;
868+ }
869+
870+ function analyze ( newData , oldData , path ) {
871+ var oldObject = oldData && oldData . getIn ( path ) ;
872+ var newObject = newData && newData . getIn ( path ) ;
873+
874+ var inOld = oldData && hasIn ( oldData , path ) ;
875+ var inNew = newData && hasIn ( newData , path ) ;
876+
877+ var arguments , eventName ;
878+
879+ if ( inOld && ! inNew ) {
880+ eventName = 'delete' ;
881+ arguments = [ path , oldObject ] ;
882+ } else if ( inOld && inNew ) {
883+ eventName = 'change' ;
884+ arguments = [ path , newObject , oldObject ] ;
885+ } else if ( ! inOld && inNew ) {
886+ eventName = 'add' ;
887+ arguments = [ path , newObject ] ;
888+ }
889+
890+ return {
891+ eventName : eventName ,
892+ arguments : arguments
893+ } ;
894+ }
895+
896+
767897// Check if path exists.
768898var NOT_SET = { } ;
769899function hasIn ( cursor , path ) {
770900 if ( cursor . hasIn ) return cursor . hasIn ( path ) ;
771901 return cursor . getIn ( path , NOT_SET ) !== NOT_SET ;
772902}
773903
904+ function pathString ( path ) {
905+ var topLevel = 'global' ;
906+ if ( ! path || ! path . length ) return topLevel ;
907+ return [ topLevel ] . concat ( path ) . join ( '|' ) ;
908+ }
909+
910+ function listListenerMatching ( listeners , basePath ) {
911+ var newListeners = [ ] ;
912+ for ( var key in listeners ) {
913+ if ( ! listeners . hasOwnProperty ( key ) ) return ;
914+ if ( basePath . indexOf ( key ) !== 0 ) continue ;
915+ newListeners . push ( listeners [ key ] ) ;
916+ }
917+
918+ return newListeners ;
919+ }
920+
921+ function onlyOnEvent ( eventName , fn ) {
922+ return function ( newData , oldData , keyPath ) {
923+ var info = analyze ( newData , oldData , keyPath ) ;
924+ if ( info . eventName !== eventName ) return ;
925+ return fn ( newData , oldData , keyPath ) ;
926+ } ;
927+ }
928+
929+ function isCursor ( potential ) {
930+ return potential && typeof potential . deref === 'function' ;
931+ }
932+
774933// Check if passed structure is existing immutable structure.
775934// From https://github.com/facebook/immutable-js/wiki/Upgrading-to-Immutable-v3#additional-changes
776935function isImmutableStructure ( data ) {
0 commit comments