-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSubscriber.js
More file actions
129 lines (104 loc) · 6.7 KB
/
Subscriber.js
File metadata and controls
129 lines (104 loc) · 6.7 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
// This is a very crude way of adding subscribers to JavaScript///
// You can add and remove functions by using the math operators ( += -= ) on properties
// user can then invoke all the functions within a subscriber property
// the relay is an object but the subscriber itself is an array of functions (so you can order them)//
// Issues:
// Whenever a function is evaluated it will attach it's self to the subscriberRelay and won't be deleted until set to the subscriber//
// A global variable that caches the functions before they're passed on.
const subscriberRelay = {};
//// We store the toString function somewhere else before overriding it's behaviour
Function.prototype._toString = Function.prototype.toString;
//// We then override the toString method so that if it is asked to display its body it will instead return a numerical id while attaching a copy of this function the relay
// By using a copy we retain it's scope, i've used evaluation options before but wasn't happy with it//
Function.prototype.toString = function()
{
if(!this.id)this.id = (function(str=""){ // generate a 16 digit number, with each digit randomised, as ID//
for(i=0;i<4;i++)for(a=0; a<4;a++)str += Math.round(Math.random()*9);
return Number(str);
})();
subscriberRelay[this.id] = this; // attach the function to the Relay
return this.id; // then return the id;
}
// The function createSubscriber allows a user to create a subscriber, the subscriber itself is a property so we need to define a new property on the object//
Object.prototype.createSubscriber = function(propertyNameorMap)
{
// the user can give a string name or a property map//
// if a string is given then it's assumed to be a single property being constructed
// the succeeding arguments must be functions to add to the subscriber upon creation //
// example
// myObject.createSubscriber("Tasks", function(a){return a;}, function(b){return b;});
// if an object is given : it's assumed to be a property map//
// if so then each field must contain either a function or an array of functions or an empty array or null//
// example
// myObject.createSubscriber({
// "Tasks":[ function(a){return a;}, function(b){return b;} ],
// "TasksForLater":[]
// });
/// Convert the arguments into map if one wasn't already defined//
var map =
typeof(propertyNameorMap) == "string" ?
(function(){
var obj={};
obj[propertyNameorMap] = Array.prototype.slice.call(arguments,1);
return obj;
}).apply(this,arguments):
typeof(propertyNameorMap) == "object" && !Array.isArray(propertyNameorMap)?
propertyNameorMap: {};
// One object can have many subscribers, this is an object that will contain all the references to those subscribers//
if(!Reflect.has(this,"_subscriber"))Object.defineProperty(this,"_subscriber",{value:{},enumerable:false,configurable:false,writable:false});
// This function is used to invoke all the given functions in the subscriber//
// A reduce function is used so that returned values can be passed on in sequence in case the user wants to transform the arguments into something else along the chain//
// if an array is returned from a function then it is passed on as arguments to the next function//
// if a single item is returned then it is passed as a single argument//
// if undefinded (so no return) it will use the arguments supplied from before//
if(!Reflect.has(this,"Invoke"))this["Invoke"] = function(name){
return Reflect.has(this,name)?function(args){
var that = this;
return this.reduce(function(a,c){
var value = Array.isArray(a) ? c.apply(that,a) : c.call(that,a);
return(value === undefined)? a : value;
},args);
}.call(this[name],Array.prototype.slice.call(arguments,1)): // Get an Array of the arguments//
null;
}.bind(this["_subscriber"]);
// Iterate through the map
Object.getOwnPropertyNames(map).forEach(function(name){
// If the property in the map isn't an array, turn it into one then filter out anything that isn't a function //
var prefunctions = (Array.isArray(map[name])?map[name]:[map[name]]).filter(function(x){return typeof(x) === "function"});
// Overwrite the functions in the Subscriber if it's already defined
if(Reflect.has(this["_subscriber"],name))this["_subscriber"][name] = prefunctions;
else{
// Define the property //
// Put the functions into property//
Object.defineProperty(this["_subscriber"],name,{value:prefunctions,enumerable:false,configurable:true});
// So, null when evaluated against another number or string returns 0
//so our getter for the subscriber property will always return null//
// When the += operator is used//
// The numerical id of the function is passed through the setter
// it's then checked against the subscriberRelay to see if it exists and also whether it's a function//
// then it's checked to see if the id in question already exists and, if it passes all checks,
// is then added onto the array
// the function is then deleted from the relay
// When the -= operator is used//
// The numerical id is shown as negative when sent through the setter
// The id is evaluated against all the id's in the array and, if found, proceeds to remove the function//
Object.defineProperty(this,name,{
get:function(){return null;},
set:function(v){
if( v > 0 ){
if(Reflect.has(subscriberRelay,v) && typeof(subscriberRelay[v]) === "function" &&
this.findIndex(function(x){return x === subscriberRelay[v];}) < 0){
this.push(subscriberRelay[v]);
Reflect.deleteProperty(subscriberRelay,v);
}
}
if( v < 0 ){
var item = this.findIndex(function(x){return x.toString() === (v.toString()*-1);});
if(item > -1)Reflect.deleteProperty(this,item);
if(Reflect.has(subscriberRelay,v))Reflect.deleteProperty(subscriberRelay,v);
}
}.bind(this["_subscriber"][name]),enumerable:true,configurable:true
});
}
},this);
}