Add content selection before removing content
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / js / WoltLabSuite / Core / Dictionary.js
CommitLineData
4bbf6ff1 1/**
c89533c4 2 * Dictionary implementation relying on an object or if supported on a Map to hold key => value data.
4bbf6ff1 3 *
58d7e8f8 4 * If you're looking for a dictionary with object keys, please see `WoltLabSuite/Core/ObjectMap`.
f5b26fab 5 *
10f1c560 6 * @author Tim Duesterhus, Alexander Ebert
c839bd49 7 * @copyright 2001-2018 WoltLab GmbH
4bbf6ff1 8 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
58d7e8f8 9 * @module WoltLabSuite/Core/Dictionary
4bbf6ff1 10 */
59ab4d0f 11define(['Core'], function(Core) {
565853e8
TD
12 "use strict";
13
d0023381 14 var _hasMap = objOwns(window, 'Map') && typeof window.Map === 'function';
4bbf6ff1
AE
15
16 /**
17 * @constructor
18 */
a0c09b4b 19 function Dictionary() {
4bbf6ff1 20 this._dictionary = (_hasMap) ? new Map() : {};
f0115fd9 21 }
4bbf6ff1
AE
22 Dictionary.prototype = {
23 /**
24 * Sets a new key with given value, will overwrite an existing key.
25 *
f64defda
AE
26 * @param {(number|string)} key key
27 * @param {?} value value
4bbf6ff1
AE
28 */
29 set: function(key, value) {
ab8ebbc4
AE
30 if (typeof key === 'number') key = key.toString();
31
4bbf6ff1 32 if (typeof key !== "string") {
ab8ebbc4 33 throw new TypeError("Only strings can be used as keys, rejected '" + key + "' (" + typeof key + ").");
4bbf6ff1
AE
34 }
35
36 if (_hasMap) this._dictionary.set(key, value);
37 else this._dictionary[key] = value;
38 },
39
40 /**
41 * Removes a key from the dictionary.
42 *
f64defda 43 * @param {(number|string)} key key
4bbf6ff1 44 */
f5b26fab 45 'delete': function(key) {
ab8ebbc4
AE
46 if (typeof key === 'number') key = key.toString();
47
f5b26fab 48 if (_hasMap) this._dictionary['delete'](key);
4bbf6ff1
AE
49 else this._dictionary[key] = undefined;
50 },
51
52 /**
53 * Returns true if dictionary contains a value for given key and is not undefined.
54 *
f64defda 55 * @param {(number|string)} key key
4bbf6ff1
AE
56 * @return {boolean} true if key exists and value is not undefined
57 */
58 has: function(key) {
ab8ebbc4
AE
59 if (typeof key === 'number') key = key.toString();
60
4bbf6ff1
AE
61 if (_hasMap) return this._dictionary.has(key);
62 else {
f5336f4f 63 return (objOwns(this._dictionary, key) && typeof this._dictionary[key] !== "undefined");
4bbf6ff1
AE
64 }
65 },
66
67 /**
ab8ebbc4 68 * Retrieves a value by key, returns undefined if there is no match.
4bbf6ff1 69 *
f64defda 70 * @param {(number|string)} key key
4bbf6ff1
AE
71 * @return {*}
72 */
73 get: function(key) {
ab8ebbc4
AE
74 if (typeof key === 'number') key = key.toString();
75
4bbf6ff1
AE
76 if (this.has(key)) {
77 if (_hasMap) return this._dictionary.get(key);
78 else return this._dictionary[key];
79 }
80
ab8ebbc4 81 return undefined;
4bbf6ff1
AE
82 },
83
84 /**
85 * Iterates over the dictionary keys and values, callback function should expect the
86 * value as first parameter and the key name second.
87 *
88 * @param {function<*, string>} callback callback for each iteration
89 */
90 forEach: function(callback) {
91 if (typeof callback !== "function") {
92 throw new TypeError("forEach() expects a callback as first parameter.");
93 }
94
95 if (_hasMap) {
96 this._dictionary.forEach(callback);
97 }
98 else {
99 var keys = Object.keys(this._dictionary);
100 for (var i = 0, length = keys.length; i < length; i++) {
5f335673 101 callback(this._dictionary[keys[i]], keys[i]);
4bbf6ff1
AE
102 }
103 }
5f335673
AE
104 },
105
106 /**
107 * Merges one or more Dictionary instances into this one.
108 *
109 * @param {...Dictionary} var_args one or more Dictionary instances
110 */
111 merge: function() {
112 for (var i = 0, length = arguments.length; i < length; i++) {
113 var dictionary = arguments[i];
114 if (!(dictionary instanceof Dictionary)) {
115 throw new TypeError("Expected an object of type Dictionary, but argument " + i + " is not.");
116 }
117
118 dictionary.forEach((function(value, key) {
119 this.set(key, value);
120 }).bind(this));
121 }
59ab4d0f
MS
122 },
123
124 /**
125 * Returns the object representation of the dictionary.
126 *
127 * @return {object} dictionary's object representation
128 */
129 toObject: function() {
130 if (!_hasMap) return Core.clone(this._dictionary);
131
132 var object = { };
133 this._dictionary.forEach(function(value, key) {
134 object[key] = value;
135 });
136
137 return object;
4bbf6ff1
AE
138 }
139 };
140
10f1c560
TD
141 /**
142 * Creates a new Dictionary based on the given object.
143 * All properties that are owned by the object will be added
144 * as keys to the resulting Dictionary.
145 *
146 * @param {object} object
147 * @return {Dictionary}
148 */
149 Dictionary.fromObject = function(object) {
150 var result = new Dictionary();
151
152 for (var key in object) {
f5336f4f 153 if (objOwns(object, key)) {
10f1c560
TD
154 result.set(key, object[key]);
155 }
156 }
157
158 return result;
159 };
160
4bbf6ff1
AE
161 Object.defineProperty(Dictionary.prototype, 'size', {
162 enumerable: false,
163 configurable: true,
164 get: function() {
165 if (_hasMap) {
166 return this._dictionary.size;
167 }
168 else {
169 return Object.keys(this._dictionary).length;
170 }
171 }
172 });
173
174 return Dictionary;
565853e8 175});