-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathflag.js
More file actions
356 lines (317 loc) · 11.2 KB
/
flag.js
File metadata and controls
356 lines (317 loc) · 11.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
/**
* @class Flags
* @constructor
* @param {Array} newFlags Optional array of flag keys to define when the flags module is instantiated
*/
/*global module,define*/
var Flags = function( newFlags ){
this.flags = 0;
this.flagHash = {};
this.keys = 0;
if(newFlags){
this.newFlags(newFlags);
}
};
Flags.prototype = (function(){
/*jshint curly:false */
/**
* An object representing the public attributes and methods of the flags object
*
* @type {Object}
*/
var _public = {};
/**
* A function for registering a single flag
*
* @param {String} name The name of the flag to be created
*/
var createFlag = function( name ){
if(this.flagHash[name]) return this.flagHash[name];
if(this.keys === 32) throw 'a single instance of the flag module can only hold 32 flags. Try instantiating a second copy of the flag object';
this.flagHash[name] = Math.pow(2, this.keys);
this.keys += 1;
};
/**
* Adds a single flag to the user object
*
* @param {String} name The name of the flag to add to the user
*/
var addFlag = function( name ){
if( !this.flagHash[name] ) throw name + "is not a valid flag. Make sure you created it with the newFlag function";
if(this.flags & this.flagHash[name]) return;
this.flags += this.flagHash[name];
};
/**
* Removes a single flag from the user
*
* @param {String} name The name of the flag to be removed
*/
var removeFlag = function( name ){
if( !this.flagHash[name] ) throw name + "is not a valid flag. Make sure you created it with the newFlag function";
if(!(this.flags & this.flagHash[name])) return;
this.flags -= this.flagHash[name];
};
/**
* Creates a mask based on an array of keys
*
* @param {Array} flags An array of flag keys to be converted to a mask
* @return {Number} A number mask representing the specified flags
*/
var createMask = function( flags ){
var mask = 0;
for(var f in flags){
if (flags.hasOwnProperty(f)){
if( !this.flagHash[flags[f]] ) throw flags[f] + " is not a valid flag. Make sure you created it with the newFlag function";
mask += this.flagHash[flags[f]];
}
}
return mask;
};
/**
* Tests whether the user's flags match the input criteria
*
* @param {Number} mask A filter representing the keys to check the user's flags against
* @param {Boolean} all Whether or not this function is checking against 'all' or 'any' of the keys
* @param {Boolean} inverse Whether to check if the user has the properties or does not have the properties
* @return {Boolean} Whether the user's flags match the input criteria
*/
var flagTest = function( mask, all, inverse ){
var flagMask = (typeof mask === "number") ? mask : (typeof mask === "string") ? this.flagHash[mask] : createMask.call(this, mask);
var ret = false;
if(all){
ret = ((this.flags & flagMask) === flagMask) ? true : false;
} else {
ret = (this.flags & flagMask) ? true : false;
}
if (inverse){
ret = !ret;
}
return ret;
};
/**
* Creates new possible flags
*
* @method newFlags
* @param {[String]} flags A string representing a possible flag
* @param {[Array]} flags An array of strings representing possible flags
* @return {Flags} Returns self for chaining
*/
_public.newFlags = function( flags ){
if(typeof flags === 'string'){
createFlag.call(this, flags);
} else {
for(var flag in flags){
if (flags.hasOwnProperty(flag)){
createFlag.call(this, flags[flag]);
}
}
}
return this;
};
/**
* Returns a mask with a given array of flags. Used primarily for debugging
*
* @example
* Util.Flag.newFlags(['cat', 'dog', 'bat']);
* Util.Flag._createMask(['cat, dog']); // 3
*
* @method _createMask
* @param {Array} flags An array of flag key strings
* @return {Number} An integer representing the mask created my those options
*/
_public._createMask = function( flags ){
return createMask.call(this, flags);
};
/**
* Checks to see if the user has any of the described flags
*
* @method hasAny
* @param {[String]} mask A string representing a flag to check
* @param {[Number]} mask A number mask
* @param {[Array]} mask An array of flag key strings to be checked
* @return {Boolean} A boolean representing whether the user has any of the specified flags
*/
_public.hasAny = function( mask ){
return flagTest.call(this, mask, false, false);
};
/**
* Checks to see if the user has all of the specified flags
*
* @method hasAllOf
* @param {[String]} mask A string representing a flag to check
* @param {[Number]} mask A number mask
* @param {[Array]} mask An array of flag key strings to be checked
* @return {Boolean} A boolean representing whether the user has any of the specified flags
*/
_public.hasAllOf = function( mask ){
return flagTest.call(this, mask, true, false);
};
/**
* Checks to see if the user has all of the flags that have been defined
*
* @method all
* @return {Boolean} A boolean representing whether the user has all the defined flags
*/
_public.all = function(){
var flagTotal = Math.pow(2, this.keys) - 1;
if(this.flags === flagTotal){
return true;
}
return false;
};
/**
* Checks to see if the user does not have any of the specified flags
* This method will return `true` if the user *does not* have **any** of the specified flags
*
* @method notAny
* @param {[String]} mask A string representing a flag to check
* @param {[Number]} mask A number mask
* @param {[Array]} mask An array of flag key strings to be checked
* @return {Boolean} A boolean representing whether the user has any of the specified flags
*/
_public.notAny = function( mask ){
return flagTest.call(this, mask, false, true);
};
/**
* Checks to see if the user does not have all of a set of specified flags
* This method will only return `true` if the user *does not* have **all** of the specified flags
*
* @method notAllOf
* @param {[String]} mask A string representing a flag to check
* @param {[Number]} mask A number mask
* @param {[Array]} mask An array of flag key strings to be checked
* @return {Boolean} A boolean representing whether the user has any of the specified flags
*/
_public.notAllOf = function( mask ){
return flagTest.call(this, mask, true, true);
};
/**
* Checks to see if the user has *any* flags defined
* This method will return true only if the user has **no** flags set
*
* @method none
* @return {Boolean} A boolean representing whether the user has no set flags
*/
_public.none = function(){
if(this.flags === 0){
return true;
}
return false;
};
/**
* Converts the user's flags back into their keys. Returns an array of flags that
* have been set on the user
*
* @method parseFlags
* @return {Array} An array of flags set on the user
*/
_public.parseFlags = function(){
var aFromFlags = [];
for(var key in this.flagHash){
if (this.flagHash.hasOwnProperty(key)){
if(this.flags & this.flagHash[key]){
aFromFlags.push(key);
}
}
}
return aFromFlags;
};
/**
* Converts the current state of the flag object into a javascript object with the
* flag keys as the keys and true or false as the value. This method also allows the
* flag object to interact correctly with JSON methods
*
* @example
* JSON.stringify(flag);
* flag.toJSON();
*
* @method toJSON
* @return {Object} An object representing the current state of the flags object
*/
_public.toJSON = function(){
var oFromFlags = {};
for(var key in this.flagHash){
if (this.flagHash.hasOwnProperty(key)){
oFromFlags[key] = (this.flags & this.flagHash[key]) ? true : false;
}
}
return oFromFlags;
};
/**
* Sets a flag as true on the user
*
* @todo merge this and the remove method for a mor DRY implementation
* @method add
* @param {[String]} flags A flag key string to be set on the user
* @param {[Array]} flags An array of flag key strings to be set on the user
* @return {Flags} Self reference for chaining
*/
_public.add = function(flags) {
if (typeof flags === 'string') {
addFlag.call(this, flags);
} else {
for (var flag in flags) {
if (flags.hasOwnProperty(flag)) {
addFlag.call(this, flags[flag]);
}
}
}
return this;
};
/**
* Sets a flag as false on the user
*
* @method remove
* @param {[String]} flags A flag key string to be set on the user
* @param {[Array]} flags An array of flag key strings to be set on the user
* @return {Flags} Self reference for chaining
*/
_public.remove = function(flags) {
if (typeof flags === 'string') {
removeFlag.call(this, flags);
} else {
for (var flag in flags) {
if (flags.hasOwnProperty(flag)) {
removeFlag.call(this, flags[flag]);
}
}
}
return this;
};
/**
* Resets the flags currently set to the specified mask
*
* @method reset
* @param {Number} flags A mask representing the flags to reset the state to
* @param {String} flags Resets the currently set flags, delegates to the add function
* @param {Array} flags Resets the currently set flags, delegates to the add function
* @return {Flags} Returns self for chaning;
*/
_public.reset = function(flags){
var flagTotal = Math.pow(2, this.keys) - 1;
if(typeof flags !== 'number'){
this.flags = 0;
return this.add(flags);
}
if(flags <= flagTotal){
this.flags = flags;
} else {
throw flags + ' is not a valid flag mask. Please make sure all your flags are defined';
}
return this;
};
_public.unregister = function(){
this.keys = 0;
this.flagHash = {};
this.flags = 0;
};
return _public;
}());
// Expose module to AMD and Node systems
if(typeof define === 'function' && define.amd){
define('flags', [], function(){
return Flags;
});
} else if (typeof exports !== 'undefined'){
module.exports = Flags;
}