Skip to content

Commit 9da79b9

Browse files
committed
Commit 78 (v0.9.78 - Beta)
Breaking changes: - The $.observable(array).insert(index, items) method, with index > arrayLength now appends, rather than being a noop. - $.observable(array).move(...) is now optimized - and no longer refreshes the whole array. (Instead it removes then inserts). - $.observable(array).refresh(...) is now optimized - and executes a series of add or remove operations, rather than re-rendering the whole array. Improvements: - The merge(...) method for compiled View Models is now optimized - and can lead to major perf improvement (when specifying an id property or function for determining 'identity'). - Several improvments to event binding using {^{on ...}} or data-link'"{on ...}" documentation to follow. Small bug fixes: - If the value for a data-linked attribute on an element is set to null or undefined then the attribute is removed #338. - Modifying the 'key' property within a {{props}}...{{/props}} block now renames the corresponding data property on the data (and no longer leaves the previously named property with the value null. - Some additional small bug fixes... - Sereral additional unit tests. Documentation and samples: - The jsonview tag control has been improved, and has a css stylesheet for much improved rendering. New sample available at: http://www.jsviews.com/#samples/tag-controls/jsonview. - Many new or improved documenation topics including: http://www.jsviews.com/#removeprop and several new topics under: http://www.jsviews.com/#jsvtags.
1 parent bde012c commit 9da79b9

28 files changed

+2261
-1280
lines changed

jquery.observable.js

+79-36
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/*! JsObservable v0.9.77 (Beta): http://jsviews.com/#jsobservable */
1+
/*! JsObservable v0.9.78 (Beta): http://jsviews.com/#jsobservable */
22
/*
33
* Subcomponent of JsViews
44
* Data change events for data-linking
@@ -73,6 +73,7 @@ var versionNumber = "v0.9.74",
7373
$subSettings = $sub.settings,
7474
$subSettingsAdvanced = $subSettings.advanced,
7575
$isFunction = $.isFunction,
76+
$expando = $.expando,
7677
$isArray = $.isArray,
7778
OBJECT = "object";
7879

@@ -82,7 +83,6 @@ if (!$.observe) {
8283
slice = [].slice,
8384
splice = [].splice,
8485
concat = [].concat,
85-
$expando = $.expando,
8686
PARSEINT = parseInt,
8787
rNotWhite = /\S+/g,
8888
propertyChangeStr = $sub.propChng = $sub.propChng || "propertyChange",// These two settings can be overridden on settings after loading
@@ -254,10 +254,6 @@ if (!$.observe) {
254254
case "remove":
255255
observeArrayItems(eventArgs.items, true); // unobserveAll on removed items
256256
break;
257-
case "refresh":
258-
observeArrayItems(eventArgs.oldItems, true); // unobserveAll on old items
259-
observeArrayItems(ev.target); // observeAll on new items
260-
break;
261257
case "set":
262258
newAllPath = allPath + "." + eventArgs.path;
263259
filterAndObserveAll(eventArgs, "oldValue", true); // unobserve old value
@@ -864,7 +860,7 @@ if (!$.observe) {
864860
index = _data.length;
865861
}
866862
index = PARSEINT(index);
867-
if (index > -1 && index <= _data.length) {
863+
if (index > -1) {
868864
data = $isArray(data) ? data : [data];
869865
// data can be a single item (including a null/undefined value) or an array of items.
870866
// Note the provided items are inserted without being cloned, as direct references to the provided objects
@@ -879,6 +875,9 @@ if (!$.observe) {
879875
_insert: function(index, data) {
880876
var _data = this._data,
881877
oldLength = _data.length;
878+
if (index > oldLength) {
879+
index = oldLength;
880+
}
882881
splice.apply(_data, [index, 0].concat(data));
883882
this._trigger({change: "insert", index: index, items: data}, oldLength);
884883
},
@@ -893,10 +892,9 @@ if (!$.observe) {
893892

894893
index = PARSEINT(index);
895894
numToRemove = numToRemove ? PARSEINT(numToRemove) : numToRemove === 0 ? 0 : 1; // if null or undefined: remove 1
896-
if (numToRemove > -1 && index > -1) {
895+
if (numToRemove > 0 && index > -1) {
897896
items = _data.slice(index, index + numToRemove);
898-
numToRemove = items.length;
899-
if (numToRemove) {
897+
if (numToRemove = items.length) {
900898
this._remove(index, numToRemove, items);
901899
}
902900
}
@@ -917,46 +915,91 @@ if (!$.observe) {
917915
newIndex = PARSEINT(newIndex);
918916

919917
if (numToMove > 0 && oldIndex > -1 && newIndex > -1 && oldIndex !== newIndex) {
920-
var items = this._data.slice(oldIndex, oldIndex + numToMove);
921-
numToMove = items.length;
922-
if (numToMove) {
923-
this._move(oldIndex, newIndex, numToMove, items);
924-
}
918+
this._move(oldIndex, newIndex, numToMove);
925919
}
926920
return this;
927921
},
928922

929-
_move: function(oldIndex, newIndex, numToMove, items) {
930-
var _data = this._data,
931-
oldLength = _data.length;
932-
_data.splice(oldIndex, numToMove);
933-
splice.apply(_data, [newIndex, 0].concat(items));
934-
this._trigger({change: "move", oldIndex: oldIndex, index: newIndex, items: items}, oldLength);
935-
},
936-
937-
refresh: function(newItems) {
938-
var oldItems = this._data.slice();
939-
this._refresh(oldItems, newItems);
940-
return this;
923+
_move: function(oldIndex, newIndex, numToMove) {
924+
var items,
925+
_data = this._data,
926+
oldLength = _data.length,
927+
excess = oldIndex + numToMove - oldLength;
928+
if (excess > 0) {
929+
numToMove -= excess;
930+
}
931+
if (numToMove) {
932+
items = _data.splice(oldIndex, numToMove); // remove
933+
if (newIndex > _data.length) {
934+
newIndex = _data.length;
935+
}
936+
splice.apply(_data, [newIndex, 0].concat(items)); //re-insert
937+
this._trigger({change: "move", oldIndex: oldIndex, index: newIndex, items: items}, oldLength);
938+
}
941939
},
942940

943-
_refresh: function(oldItems, newItems) {
944-
var _data = this._data,
945-
oldLength = _data.length;
941+
refresh: function(newItems, sort) {
942+
function insertAdded() {
943+
if (k) {
944+
self.insert(j-k, addedItems); // Not found in original array - so insert
945+
dataLength += k;
946+
i += k;
947+
k = 0;
948+
addedItems = [];
949+
}
950+
}
946951

947-
splice.apply(_data, [0, _data.length].concat(newItems));
948-
this._trigger({change: "refresh", oldItems: oldItems}, oldLength);
952+
// For refresh operation we iteratively step through the target array and sort by move/add/remove operations on the source array until they match
953+
var i, j, k, newItem, num,
954+
self = this,
955+
addedItems = [],
956+
data = self._data,
957+
oldItems = data.slice(),
958+
oldLength = data.length,
959+
dataLength = oldLength,
960+
newLength = newItems.length;
961+
self._srt = true; // Flag for sorting during refresh
962+
for (j=k=0; j<newLength; j++) {
963+
if ((newItem = newItems[j]) === data[j-k]) {
964+
insertAdded();
965+
} else {
966+
for (i=j-k; i<dataLength; i++) {
967+
if (newItem === data[i]) {
968+
break;
969+
}
970+
}
971+
if (i<dataLength) {
972+
insertAdded();
973+
num = 0;
974+
while (num++ < newLength-i && newItems[j+num] === data[i+num]);
975+
self.move(i, j, num); // Found newItem in original array - so move it to new position
976+
j += num - 1;
977+
} else {
978+
k++;
979+
addedItems.push(newItem); // Not found in original array - so insert
980+
}
981+
}
982+
}
983+
insertAdded();
984+
if (dataLength > j) {
985+
self.remove(j, dataLength - j);
986+
}
987+
self._srt = undefined; // We have finished sort operations during refresh
988+
self._trigger({change: "refresh", oldItems: oldItems}, oldLength);
989+
return self;
949990
},
950991

951992
_trigger: function(eventArgs, oldLength) {
952-
var _data = this._data,
993+
var self = this,
994+
_data = self._data,
953995
length = _data.length,
954996
$_data = $([_data]);
955-
956-
if (length !== oldLength) {
997+
if (self._srt) {
998+
eventArgs.refresh = true; // We are sorting during refresh
999+
} else if (length !== oldLength) { // We have finished sort operations during refresh
9571000
$_data.triggerHandler(propertyChangeStr, {change: "set", path: "length", value: length, oldValue: oldLength});
9581001
}
959-
$_data.triggerHandler(arrayChangeStr + (this._ns ? "." + /^\S+/.exec(this._ns)[0] : ""), eventArgs); // If white-space separated namespaces, use first one only
1002+
$_data.triggerHandler(arrayChangeStr + (self._ns ? "." + /^\S+/.exec(self._ns)[0] : ""), eventArgs); // If white-space separated namespaces, use first one only
9601003
}
9611004
};
9621005

jquery.observable.min.js

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jquery.observable.min.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)