Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Index refactor - RFC #1474

Merged
merged 7 commits into from
Nov 28, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/parse/converters/mustache/content.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import handlebarsBlockCodes from 'parse/converters/mustache/handlebarsBlockCodes
import 'legacy';

var indexRefPattern = /^\s*:\s*([a-zA-Z_$][a-zA-Z_$0-9]*)/,
keyIndexRefPattern = /^\s*,\s*([a-zA-Z_$][a-zA-Z_$0-9]*)/,
arrayMemberPattern = /^[0-9][1-9]*$/,
handlebarsBlockPattern = new RegExp( '^(' + Object.keys( handlebarsBlockCodes ).join( '|' ) + ')\\b' ),
legalReference;
Expand Down Expand Up @@ -181,9 +182,15 @@ export default function ( parser, delimiterType ) {
];
}

// optional index reference
// optional index and key references
if ( i = parser.matchPattern( indexRefPattern ) ) {
mustache.i = i;
let extra;

if ( extra = parser.matchPattern( keyIndexRefPattern ) ) {
mustache.i = i + ',' + extra;
} else {
mustache.i = i;
}
}

return mustache;
Expand Down
11 changes: 8 additions & 3 deletions src/shared/keypaths/decode.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import isNumeric from 'utils/isNumeric';

export default function decodeKeypath ( keypath ) {
var value = keypath.slice( 1 );
return isNumeric( value ) ? +value : value;
}
var value = keypath.slice( 2 );

if ( keypath[1] === 'i' ) {
return isNumeric( value ) ? +value : value;
} else {
return value;
}
}
4 changes: 2 additions & 2 deletions src/shared/parameters/ComplexParameter.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ ComplexParameter.prototype = {
this.dirty = false;
},

rebind: function ( indexRef, newIndex, oldKeypath, newKeypath ) {
this.fragment.rebind( indexRef, newIndex, oldKeypath, newKeypath );
rebind: function ( oldKeypath, newKeypath ) {
this.fragment.rebind( oldKeypath, newKeypath );
},

unbind: function () {
Expand Down
10 changes: 0 additions & 10 deletions src/shared/resolveRef.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import resolveAncestorRef from 'shared/resolveAncestorRef';
export default function resolveRef ( ractive, ref, fragment, isParentLookup ) {
var context,
key,
index,
keypath,
parentValue,
hasContextChain,
Expand Down Expand Up @@ -61,15 +60,6 @@ export default function resolveRef ( ractive, ref, fragment, isParentLookup ) {
hasContextChain = true;
fragment = ractive.component.parentFragment;

// Special case - index refs
if ( fragment.indexRefs && ( index = fragment.indexRefs[ ref ] ) !== undefined ) {
// Create an index ref binding, so that it can be rebound letter if necessary.
// It doesn't have an alias since it's an implicit binding, hence `...[ ref ] = ref`
ractive.component.indexRefBindings[ ref ] = ref;
ractive.viewmodel.set( ref, index, { silent: true } );
return;
}

keypath = resolveRef( ractive.parent, ref, fragment, true );

if ( keypath ) {
Expand Down
10 changes: 10 additions & 0 deletions src/virtualdom/Fragment.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,19 @@ Fragment.prototype = {
getValue: getValue,
init: init,
rebind: rebind,
registerIndexRef: function( idx ) {
var idxs = this.registeredIndexRefs;
if ( idxs.indexOf( idx ) === -1 ) {
idxs.push( idx );
}
},
render: render,
toString: toString,
unbind: unbind,
unregisterIndexRef: function( idx ) {
var idxs = this.registeredIndexRefs;
idxs.splice( idxs.indexOf( idx ), 1 );
},
unrender: unrender
};

Expand Down
18 changes: 3 additions & 15 deletions src/virtualdom/Fragment/prototype/init.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import types from 'config/types';
import create from 'utils/create';
import createItem from 'virtualdom/Fragment/prototype/init/createItem';

export default function Fragment$init ( options ) {
Expand All @@ -14,19 +12,9 @@ export default function Fragment$init ( options ) {
this.root = options.root;
this.pElement = options.pElement;
this.context = options.context;

// If parent item is a section, this may not be the only fragment
// that belongs to it - we need to make a note of the index
if ( this.owner.type === types.SECTION ) {
this.index = options.index;
}

// index references (the 'i' in {{#section:i}}...{{/section}}) need to cascade
// down the tree
this.indexRefs = create( parentFragment ? parentFragment.indexRefs : null );
if ( options.indexRef ) {
this.indexRefs[ options.indexRef ] = options.index;
}
this.index = options.index;
this.key = options.key;
this.registeredIndexRefs = [];

// Time to create this fragment's child items

Expand Down
12 changes: 2 additions & 10 deletions src/virtualdom/Fragment/prototype/rebind.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
import assignNewKeypath from 'shared/keypaths/assignNew';

export default function Fragment$rebind ( indexRef, newIndex, oldKeypath, newKeypath ) {

if ( newIndex !== undefined ) {
this.index = newIndex;
}
export default function Fragment$rebind ( oldKeypath, newKeypath ) {

// assign new context keypath if needed
assignNewKeypath( this, 'context', oldKeypath, newKeypath );

if ( this.indexRefs && this.indexRefs[ indexRef ] !== undefined ) {
this.indexRefs[ indexRef ] = newIndex;
}

this.items.forEach( item => {
if ( item.rebind ) {
item.rebind( indexRef, newIndex, oldKeypath, newKeypath );
item.rebind( oldKeypath, newKeypath );
}
});
}
15 changes: 3 additions & 12 deletions src/virtualdom/items/Component/prototype/rebind.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import runloop from 'global/runloop';

export default function Component$rebind ( indexRef, newIndex, oldKeypath, newKeypath ) {
var childInstance = this.instance,
indexRefAlias,
query;
export default function Component$rebind ( oldKeypath, newKeypath ) {
var query;

this.resolvers.forEach( rebind );

Expand All @@ -13,16 +9,11 @@ export default function Component$rebind ( indexRef, newIndex, oldKeypath, newKe
}
}

if ( indexRefAlias = this.indexRefBindings[ indexRef ] ) {
runloop.addViewmodel( childInstance.viewmodel );
childInstance.viewmodel.set( indexRefAlias, newIndex );
}

if ( query = this.root._liveComponentQueries[ '_' + this.name ] ) {
query._makeDirty();
}

function rebind ( x ) {
x.rebind( indexRef, newIndex, oldKeypath, newKeypath );
x.rebind( oldKeypath, newKeypath );
}
}
4 changes: 2 additions & 2 deletions src/virtualdom/items/Element/Attribute/prototype/rebind.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export default function Attribute$rebind ( indexRef, newIndex, oldKeypath, newKeypath ) {
export default function Attribute$rebind ( oldKeypath, newKeypath ) {
if ( this.fragment ) {
this.fragment.rebind( indexRef, newIndex, oldKeypath, newKeypath );
this.fragment.rebind( oldKeypath, newKeypath );
}
}
4 changes: 2 additions & 2 deletions src/virtualdom/items/Element/Binding/RadioNameBinding.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ var RadioNameBinding = Binding.extend({
}
},

rebound: function ( indexRef, newIndex, oldKeypath, newKeypath ) {
rebound: function ( oldKeypath, newKeypath ) {
var node;

Binding.prototype.rebound.call( this, indexRef, newIndex, oldKeypath, newKeypath );
Binding.prototype.rebound.call( this, oldKeypath, newKeypath );

if ( node = this.element.node ) {
node.name = '{{' + this.keypath + '}}';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ ConditionalAttribute.prototype = {
this.element.bubble();
},

rebind: function ( indexRef, newIndex, oldKeypath, newKeypath ) {
this.fragment.rebind( indexRef, newIndex, oldKeypath, newKeypath );
rebind: function ( oldKeypath, newKeypath ) {
this.fragment.rebind( oldKeypath, newKeypath );
},

render: function ( node ) {
Expand Down
4 changes: 2 additions & 2 deletions src/virtualdom/items/Element/Decorator/_Decorator.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,9 @@ Decorator.prototype = {
}
},

rebind: function ( indexRef, newIndex, oldKeypath, newKeypath ) {
rebind: function ( oldKeypath, newKeypath ) {
if ( this.fragment ) {
this.fragment.rebind( indexRef, newIndex, oldKeypath, newKeypath );
this.fragment.rebind( oldKeypath, newKeypath );
}
},

Expand Down
4 changes: 2 additions & 2 deletions src/virtualdom/items/Element/EventHandler/prototype/rebind.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export default function EventHandler$rebind ( indexRef, newIndex, oldKeypath, newKeypath ) {
export default function EventHandler$rebind ( oldKeypath, newKeypath ) {
var fragment;
if ( this.method ) {
fragment = this.element.parentFragment;
Expand All @@ -16,6 +16,6 @@ export default function EventHandler$rebind ( indexRef, newIndex, oldKeypath, ne
}

function rebind ( thing ) {
thing && thing.rebind( indexRef, newIndex, oldKeypath, newKeypath );
thing && thing.rebind( oldKeypath, newKeypath );
}
}
14 changes: 12 additions & 2 deletions src/virtualdom/items/Element/EventHandler/shared/genericHandler.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
import findIndexRefs from 'virtualdom/items/shared/Resolvers/findIndexRefs';

export default function genericHandler ( event ) {
var storage, handler;
var storage, handler, indices, index = {};

storage = this._ractive;
handler = storage.events[ event.type ];

if ( indices = findIndexRefs( handler.element.parentFragment ) ) {
let k, ref;
for ( k in indices.refs ) {
ref = indices.refs[k];
index[ ref.ref.n ] = ref.ref.t === 'k' ? ref.fragment.key : ref.fragment.index;
}
}

handler.fire({
node: this,
original: event,
index: storage.index,
index: index,
keypath: storage.keypath,
context: storage.root.get( storage.keypath )
});
Expand Down
1 change: 1 addition & 0 deletions src/virtualdom/items/Element/prototype/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export default function Element$init ( options ) {

this.root = ractive = parentFragment.root;
this.index = options.index;
this.key = options.key;

this.name = enforceCase( template.e );

Expand Down
8 changes: 2 additions & 6 deletions src/virtualdom/items/Element/prototype/rebind.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import assignNewKeypath from 'shared/keypaths/assignNew';

export default function Element$rebind ( indexRef, newIndex, oldKeypath, newKeypath ) {
export default function Element$rebind ( oldKeypath, newKeypath ) {
var i, storage, liveQueries, ractive;

if ( this.attributes ) {
Expand Down Expand Up @@ -38,13 +38,9 @@ export default function Element$rebind ( indexRef, newIndex, oldKeypath, newKeyp

// adjust keypath if needed
assignNewKeypath( storage, 'keypath', oldKeypath, newKeypath );

if ( indexRef != undefined ) {
storage.index[ indexRef ] = newIndex;
}
}

function rebind ( thing ) {
thing.rebind( indexRef, newIndex, oldKeypath, newKeypath );
thing.rebind( oldKeypath, newKeypath );
}
}
1 change: 0 additions & 1 deletion src/virtualdom/items/Element/prototype/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ export default function Element$render () {
value: {
proxy: this,
keypath: getInnerContext( this.parentFragment ),
index: create( this.parentFragment.indexRefs ),
events: create( null ),
root: root
}
Expand Down
8 changes: 4 additions & 4 deletions src/virtualdom/items/Partial/_Partial.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,13 @@ Partial.prototype = {
return this.fragment.getValue();
},

rebind: function ( indexRef, newIndex, oldKeypath, newKeypath ) {
rebind: function ( oldKeypath, newKeypath ) {
// named partials aren't bound, so don't rebind
if ( !this.isNamed ) {
rebind.call( this, indexRef, newIndex, oldKeypath, newKeypath );
rebind.call( this, oldKeypath, newKeypath );
}

this.fragment.rebind( indexRef, newIndex, oldKeypath, newKeypath );
this.fragment.rebind( oldKeypath, newKeypath );
},

render: function () {
Expand Down
17 changes: 16 additions & 1 deletion src/virtualdom/items/Section/_Section.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import update from 'virtualdom/items/Section/prototype/update';

var Section = function ( options ) {
this.type = types.SECTION;
this.subtype = options.template.n;
this.subtype = this.currentSubtype = options.template.n;
this.inverted = this.subtype === types.SECTION_UNLESS;


Expand All @@ -31,6 +31,12 @@ var Section = function ( options ) {
this.fragmentsToRender = [];
this.fragmentsToUnrender = [];

if ( options.template.i ) {
this.indexRefs = options.template.i.split(',').map( ( k, i ) => {
return { n: k, t: i === 0 ? 'k' : 'i' };
});
}

this.renderedFragments = [];

this.length = 0; // number of times this section is rendered
Expand All @@ -47,6 +53,15 @@ Section.prototype = {
findComponent: findComponent,
findNextNode: findNextNode,
firstNode: firstNode,
getIndexRef: function( name ) {
if ( this.indexRefs ) {
for ( let ref of this.indexRefs ) {
if ( ref.n === name ) {
return ref;
}
}
}
},
getValue: Mustache.getValue,
shuffle: shuffle,
rebind: rebind,
Expand Down
13 changes: 2 additions & 11 deletions src/virtualdom/items/Section/prototype/rebind.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
import Mustache from 'virtualdom/items/shared/Mustache/_Mustache';
import types from 'config/types';

export default function( indexRef, newIndex, oldKeypath, newKeypath ) {
var ref, idx;

if ( indexRef !== undefined || this.currentSubtype !== types.SECTION_EACH ) {
ref = indexRef;
idx = newIndex;
}

// If the new index belonged to us, we'd be shuffling instead
Mustache.rebind.call( this, ref, idx, oldKeypath, newKeypath );
export default function( oldKeypath, newKeypath ) {
Mustache.rebind.call( this, oldKeypath, newKeypath );
}
Loading