224 lines · 6.8 KB · JavaScript
RawDownload
// Knockout Observable Dictionary// (c) James Foster// License: MIT (http://www.opensource.org/licenses/mit-license.php) (function () {    function DictionaryItem(key, value, dictionary) {        var observableKey = new ko.observable(key);         this.value = new ko.observable(value);        this.key = new ko.computed({            read: observableKey,            write: function (newKey) {                var current = observableKey();                 if (current == newKey) return;                 // no two items are allowed to share the same key.                dictionary.remove(newKey);                 observableKey(newKey);            }        });    }     ko.observableDictionary = function (dictionary, keySelector, valueSelector) {        var result = {};         result.items = new ko.observableArray();         result._wrappers = {};        result._keySelector = keySelector || function (value, key) { return key; };        result._valueSelector = valueSelector || function (value) { return value; };         if (typeof keySelector == 'string') result._keySelector = function (value) { return value[keySelector]; };        if (typeof valueSelector == 'string') result._valueSelector = function (value) { return value[valueSelector]; };         ko.utils.extend(result, ko.observableDictionary['fn']);         result.pushAll(dictionary);         return result;    };     ko.observableDictionary['fn'] = {        remove: function (valueOrPredicate) {            var predicate = valueOrPredicate;             if (valueOrPredicate instanceof DictionaryItem) {                predicate = function (item) {                    return item.key() === valueOrPredicate.key();                };            }            else if (typeof valueOrPredicate != "function") {                predicate = function (item) {                    return item.key() === valueOrPredicate;                };            }             ko.observableArray['fn'].remove.call(this.items, predicate);        },         push: function (key, value) {            var item = null;             if (key instanceof DictionaryItem) {                // handle the case where only a DictionaryItem is passed in                item = key;                value = key.value();                key = key.key();            }             if (value === undefined) {                value = this._valueSelector(key);                key = this._keySelector(value);            }            else {                value = this._valueSelector(value);            }             var current = this.get(key, false);            if (current) {                // update existing value                current(value);                return current;            }             if (!item) {                item = new DictionaryItem(key, value, this);            }             ko.observableArray['fn'].push.call(this.items, item);             return value;        },         pushAll: function (dictionary) {            var self = this;            var items = self.items();             if (dictionary instanceof Array) {                $.each(dictionary, function (index, item) {                    var key = self._keySelector(item, index);                    var value = self._valueSelector(item);                    items.push(new DictionaryItem(key, value, self));                });            }            else {                for (var prop in dictionary) {                    if (dictionary.hasOwnProperty(prop)) {                        var item = dictionary[prop];                        var key = self._keySelector(item, prop);                        var value = self._valueSelector(item);                        items.push(new DictionaryItem(key, value, self));                    }                }            }             self.items.valueHasMutated();        },         sort: function (method) {            if (method === undefined) {                method = function (a, b) {                    return defaultComparison(a.key(), b.key());                };            }             return ko.observableArray['fn'].sort.call(this.items, method);        },         indexOf: function (key) {            if (key instanceof DictionaryItem) {                return ko.observableArray['fn'].indexOf.call(this.items, key);            }             var underlyingArray = this.items();            for (var index = 0; index < underlyingArray.length; index++) {                if (underlyingArray[index].key() == key)                    return index;            }            return -1;        },         get: function (key, wrap) {            if (wrap == false)                return getValue(key, this.items());             var wrapper = this._wrappers[key];             if (wrapper == null) {                wrapper = this._wrappers[key] = new ko.computed({                    read: function () {                        var value = getValue(key, this.items());                        return value ? value() : null;                    },                    write: function (newValue) {                        var value = getValue(key, this.items());                         if (value)                            value(newValue);                        else                            this.push(key, newValue);                    }                }, this);            }             return wrapper;        },         set: function (key, value) {            return this.push(key, value);        },         keys: function () {            return ko.utils.arrayMap(this.items(), function (item) { return item.key(); });        },         values: function () {            return ko.utils.arrayMap(this.items(), function (item) { return item.value(); });        },                removeAll: function () {            this.items.removeAll();        },         toJSON: function () {            var result = {};            var items = ko.utils.unwrapObservable(this.items);             ko.utils.arrayForEach(items, function (item) {                var key = ko.utils.unwrapObservable(item.key);                var value = ko.utils.unwrapObservable(item.value);                 result[key] = value;            });             return result;        }    };     function getValue(key, items) {        var found = ko.utils.arrayFirst(items, function (item) {            return item.key() == key;        });        return found ? found.value : null;    }})();  // Utility methods// ---------------------------------------------function isNumeric(n) {    return !isNaN(parseFloat(n)) && isFinite(n);} function defaultComparison(a, b) {    if (isNumeric(a) && isNumeric(b)) return a - b;     a = a.toString();    b = b.toString();     return a == b ? 0 : (a < b ? -1 : 1);}// ---------------------------------------------

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t