Security update for permissions_by_term
[yaffs-website] / node_modules / hooker / dist / ba-hooker.js
1 /*! JavaScript Hooker - v0.2.3 - 1/29/2012
2 * http://github.com/cowboy/javascript-hooker
3 * Copyright (c) 2012 "Cowboy" Ben Alman; Licensed MIT */
4
5 (function(exports) {
6   // Get an array from an array-like object with slice.call(arrayLikeObject).
7   var slice = [].slice;
8   // Get an "[object [[Class]]]" string with toString.call(value).
9   var toString = {}.toString;
10
11   // I can't think of a better way to ensure a value is a specific type other
12   // than to create instances and use the `instanceof` operator.
13   function HookerOverride(v) { this.value = v; }
14   function HookerPreempt(v) { this.value = v; }
15   function HookerFilter(c, a) { this.context = c; this.args = a; }
16
17   // When a pre- or post-hook returns the result of this function, the value
18   // passed will be used in place of the original function's return value. Any
19   // post-hook override value will take precedence over a pre-hook override
20   // value.
21   exports.override = function(value) {
22     return new HookerOverride(value);
23   };
24
25   // When a pre-hook returns the result of this function, the value passed will
26   // be used in place of the original function's return value, and the original
27   // function will NOT be executed.
28   exports.preempt = function(value) {
29     return new HookerPreempt(value);
30   };
31
32   // When a pre-hook returns the result of this function, the context and
33   // arguments passed will be applied into the original function.
34   exports.filter = function(context, args) {
35     return new HookerFilter(context, args);
36   };
37
38   // Execute callback(s) for properties of the specified object.
39   function forMethods(obj, props, callback) {
40     var prop;
41     if (typeof props === "string") {
42       // A single prop string was passed. Create an array.
43       props = [props];
44     } else if (props == null) {
45       // No props were passed, so iterate over all properties, building an
46       // array. Unfortunately, Object.keys(obj) doesn't work everywhere yet, so
47       // this has to be done manually.
48       props = [];
49       for (prop in obj) {
50         if (obj.hasOwnProperty(prop)) {
51           props.push(prop);
52         }
53       }
54     }
55     // Execute callback for every method in the props array.
56     var i = props.length;
57     while (i--) {
58       // If the property isn't a function...
59       if (toString.call(obj[props[i]]) !== "[object Function]" ||
60         // ...or the callback returns false...
61         callback(obj, props[i]) === false) {
62         // ...remove it from the props array to be returned.
63         props.splice(i, 1);
64       }
65     }
66     // Return an array of method names for which the callback didn't fail.
67     return props;
68   }
69
70   // Monkey-patch (hook) a method of an object.
71   exports.hook = function(obj, props, options) {
72     // If the props argument was omitted, shuffle the arguments.
73     if (options == null) {
74       options = props;
75       props = null;
76     }
77     // If just a function is passed instead of an options hash, use that as a
78     // pre-hook function.
79     if (typeof options === "function") {
80       options = {pre: options};
81     }
82
83     // Hook the specified method of the object.
84     return forMethods(obj, props, function(obj, prop) {
85       // The original (current) method.
86       var orig = obj[prop];
87       // The new hooked function.
88       function hooked() {
89         var result, origResult, tmp;
90
91         // Get an array of arguments.
92         var args = slice.call(arguments);
93
94         // If passName option is specified, prepend prop to the args array,
95         // passing it as the first argument to any specified hook functions.
96         if (options.passName) {
97           args.unshift(prop);
98         }
99
100         // If a pre-hook function was specified, invoke it in the current
101         // context with the passed-in arguments, and store its result.
102         if (options.pre) {
103           result = options.pre.apply(this, args);
104         }
105
106         if (result instanceof HookerFilter) {
107           // If the pre-hook returned hooker.filter(context, args), invoke the
108           // original function with that context and arguments, and store its
109           // result.
110           origResult = result = orig.apply(result.context, result.args);
111         } else if (result instanceof HookerPreempt) {
112           // If the pre-hook returned hooker.preempt(value) just use the passed
113           // value and don't execute the original function.
114           origResult = result = result.value;
115         } else {
116           // Invoke the original function in the current context with the
117           // passed-in arguments, and store its result.
118           origResult = orig.apply(this, arguments);
119           // If the pre-hook returned hooker.override(value), use the passed
120           // value, otherwise use the original function's result.
121           result = result instanceof HookerOverride ? result.value : origResult;
122         }
123
124         if (options.post) {
125           // If a post-hook function was specified, invoke it in the current
126           // context, passing in the result of the original function as the
127           // first argument, followed by any passed-in arguments.
128           tmp = options.post.apply(this, [origResult].concat(args));
129           if (tmp instanceof HookerOverride) {
130             // If the post-hook returned hooker.override(value), use the passed
131             // value, otherwise use the previously computed result.
132             result = tmp.value;
133           }
134         }
135
136         // Unhook if the "once" option was specified.
137         if (options.once) {
138           exports.unhook(obj, prop);
139         }
140
141         // Return the result!
142         return result;
143       }
144       // Re-define the method.
145       obj[prop] = hooked;
146       // Fail if the function couldn't be hooked.
147       if (obj[prop] !== hooked) { return false; }
148       // Store a reference to the original method as a property on the new one.
149       obj[prop]._orig = orig;
150     });
151   };
152
153   // Get a reference to the original method from a hooked function.
154   exports.orig = function(obj, prop) {
155     return obj[prop]._orig;
156   };
157
158   // Un-monkey-patch (unhook) a method of an object.
159   exports.unhook = function(obj, props) {
160     return forMethods(obj, props, function(obj, prop) {
161       // Get a reference to the original method, if it exists.
162       var orig = exports.orig(obj, prop);
163       // If there's no original method, it can't be unhooked, so fail.
164       if (!orig) { return false; }
165       // Unhook the method.
166       obj[prop] = orig;
167     });
168   };
169 }(typeof exports === "object" && exports || this));