silk.data = xb.core.object.extend( { ctor: function( set, ident ) { var set = ( set instanceof Array ) ? set : []; var ident = ( typeof( ident ) === "string" ) ? ident : "id"; this.set = set; this.ident = ident; this.$id = 0; this.index = {}; this.reindex(); }, getArray: function() { return this.set; }, __index: function( set, ident, $id ) { var set = ( set instanceof Array ) ? set : this.set; var ident = ( typeof( ident ) !== "undefined" ) ? ident : this.ident; var $id = ( typeof( $id ) !== "undefined" ) ? $id : 0; var index = {}; var n_set = []; for ( var i = 0, il = set.length; i < il; i++ ) { if ( typeof( set[ i ] ) === "object" && set[ i ] !== null ) { if ( ( new Number( set[ i ][ ident ] ) ) > ( new Number( $id ) ) ) { $id = set[ i ][ ident ]; } n_set.push( set[ i ] ); } } for ( var i = 0, il = n_set.length; i < il; i++ ) { if ( ! n_set[ i ][ ident ] ) { n_set[ i ][ ident ] = "" + ( ++$id ); } index[ "" + n_set[ i ][ ident ] ] = set[ i ]; } return ( { "$id": $id, "ident": ident, "set": n_set, "index": index } ); }, reindex: function() { var res = this.__index(); this.$id = res.$id; this.set = res.set; this.index = res.index; return this; }, get: function( $id, index ) { var index = ( typeof( index ) === "object" && index !== null ) ? index : this.index; var result = index[ $id ]; if ( typeof( result ) === "undefined" ) { return null; } return result; }, add: function( list, set, ident, index ) { var set = ( set instanceof Array ) ? set : this.set; var ident = ( typeof( ident ) !== "undefined" ) ? ident : this.ident; var index = ( typeof( index ) === "object" && index !== null ) ? index : this.index; for ( var i = 0, il = list.length; i < il; i++ ) { var object = list[ i ].object; this.insertAfter( object, "" + list[ i ].after, list[ i ].node, set, ident, index ); } return ( { "set": set, "index": index } ); }, insertAfter: function( object, after, node, set, ident, index ) { var set = ( set instanceof Array ) ? set : this.set; var ident = ( typeof( ident ) !== "undefined" ) ? ident : this.ident; var index = ( typeof( index ) === "object" && index !== null ) ? index : this.index; if ( typeof( object[ ident ] ) === "undefined" || ! ( object[ ident ] ) ) { $id = "" + ( ++this.$id ); if ( typeof( node ) === "object" ) { var id = node.get( ident ); id.setValue( $id ); node.domNode.setAttribute( "data-silk-new", $id ); } object[ ident ] = $id; } else { $id = "" + object[ ident ]; } var offset = -1; if ( typeof( after ) !== "undefined" ) { offset = this.indexOf( after, set, ident ); } set.splice( offset + 1, 0, object ); index[ $id ] = object; console.log( "silk.data.insertAfter", $id, "after", after, "@", offset + 1 ); return ( { "set": set, "offset": offset + 1 } ); }, indexOf: function( id, set, ident ) { var set = ( set instanceof Array ) ? set : this.set; var ident = ( typeof( ident ) !== "undefined" ) ? ident : this.ident; for ( var i = 0, il = set.length; i < il; i++ ) { if ( id === set[ i ][ ident ] ) { return i; } } return -1; }, delete: function( indexedListOfIDs, set, ident, index ) { var set = ( set instanceof Array ) ? set : this.set; var ident = ( typeof( ident ) !== "undefined" ) ? ident : this.ident; var index = ( typeof( index ) === "object" && index !== null ) ? index : this.index; for ( var i = set.length - 1; i >= 0; i-- ) { var $id = "" + set[ i ][ ident ]; if ( typeof( indexedListOfIDs[ $id ] ) !== "undefined" ) { console.warn( "silk.data.delete", $id, "@" + i + ":", index[ $id ] ); set.splice( i, 1 ); delete index[ $id ]; } } return ( { "set": set, "index": index } ); }, update: function( list, index, ident ) { var index = ( typeof( index ) === "object" && index !== null ) ? index : this.index; var ident = ( typeof( ident ) !== "undefined" ) ? ident : this.ident; for ( var i = 0, il = list.length; i < il; i++ ) { var $id = "" + list[ i ][ ident ]; this.updateObject( $id, list[ i ], index ); } return ( { "index": index } ); }, updateObject: function( $id, changes, index ) { var index = ( typeof( index ) === "object" && index !== null ) ? index : this.index; var indexed = index[ $id ]; if ( typeof( changes ) === "object" && typeof( indexed ) === "object" ) { for ( var n in changes ) { indexed[ n ] = changes[ n ]; } } return indexed; }, reorder: function( orderIDs, orderIDsBefore, set, ident ) { var set = ( ( set instanceof Array ) ? set : this.set ); var ident = ( typeof( ident ) !== "undefined" ) ? ident : this.ident; var orderIDsBefore = orderIDsBefore.slice(); // wordt aangepast, dus kopie maken if ( orderIDs.length < 2 || orderIDs.length !== orderIDsBefore.length ) { console.warn( "no ordering @ length < 2 or order lengths are not the same" ); return ( { "set": set } ); } var reordered = {}; for ( var i = 0, il = orderIDs.length; i < il; i++ ) { if ( orderIDs[ i ] != orderIDsBefore[ i ] ) { if ( typeof( reordered[ orderIDs[ i ] ] ) !== "undefined" ) { //console.log( "reorderd", i ); continue; } var offsetFrom = this.indexOf( orderIDs[ i ], set, ident ); var object = set[ offsetFrom ]; set.splice( offsetFrom, 1 ); var offsetTo = 0; if ( i < 1 ) { offsetTo = this.indexOf( orderIDsBefore[ i ], set, ident ); set.splice( offsetTo, 1, object, set[ offsetTo ] ); console.log( "insertBefore(" + i + ")", offsetFrom, "=>", offsetTo ); } else { offsetTo = this.indexOf( orderIDs[ i - 1 ], set, ident ) + 1; set.splice( offsetTo, 0, object ); console.log( "insertAfter(" + i + ")", offsetFrom, "=>", offsetTo ); } orderIDsBefore.splice( orderIDsBefore.indexOf( orderIDs[ i ], set, ident ), 1 ); orderIDsBefore.splice( i, 0, orderIDs[ i ] ); //console.log( "work-order-list", orderBefore ); reordered[ orderIDs[ i ] ] = i; } } return ( { "set": set } ); }, handleDOMChanges: function( handler, before, ident ) { var ident = ( typeof( ident ) !== "undefined" ) ? ident : this.ident; var self = this; var $prevID = 0; var seen = {}; var added = []; var removed = {}; var order = []; var orderBefore = []; var mutations = handler.getValue(); handler.each( function() { var id = this.get( ident ); if ( id !== null ) { var $id = id.getValue( true ); if ( !$id ) { var object = this.getValue(); added.push( { "node": this, "object": object, "after": $prevID } ); console.log( "silk.data.handleDOMChanges: Added new object", added[ added.length - 1 ] ); } else { order.push( $id ); } seen[ $id ] = $id; $prevID = $id; } } ); before.each( function() { var id = this.get( ident ); if ( id !== null ) { $id = id.getValue( true ); if ( $id ) { if ( typeof( seen[ $id ] ) === "undefined" ) { console.log( "silk.data.handleDOMChanges: removed object", $id ); removed[ $id ] = $id; } else { orderBefore.push( $id ); } } } } ); return ( { "removed": removed, "mutations": mutations, "added": added, "reorder": [ order, orderBefore ] } ); }, onDOMChange: function( handler, before ) { var changes = this.handleDOMChanges( handler, before ); this.delete( changes.removed ); this.update( changes.mutations ); this.add( changes.added ); this.reorder( changes.reorder[ 0 ], changes.reorder[ 1 ] ); return this; } } ); silk.data.ptr = xb.core.object.extend( silk.data, { ctor: function( db, set, ident ) { var set = ( set instanceof Array ) ? set : []; silk.data.prototype.ctor.call( this, set, ident ); this.db = db; }, getArray: function() { var result = []; for ( var i = 0, il = this.set.length; i < il; i++ ) { var object = this.db.index[ this.set[ i ][ this.ident ] ]; if ( typeof( object ) === "object" ) { result.push( object ); } } return result; }, get: function( $id, index ) { return this.db.get( $id, index ); }, update: function( list, index, ident ) { return this.db.update( list, index, ident ); }, insertRef: function( id, after ) { var ptr = {}; ptr[ this.ident ] = id; return silk.data.prototype.insertAfter.call( this, ptr, after ); }, insertAfter: function( object, after, node, set, ident, index ) { this.db.insertAfter( object, -1, node ); var ptr = {}; ptr[ ident ] = object[ ident ]; return silk.data.prototype.insertAfter.call( this, ptr, after, node ); } } );