-
Notifications
You must be signed in to change notification settings - Fork 0
/
yManager.js
154 lines (123 loc) · 5.17 KB
/
yManager.js
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
yManager = function () {
var objIndex = 0,
manager = this,
privateKey = (new Date()).valueOf(),
methods = [],
map = {},
undefined;
function validatePath(str) {
if (!str || typeof (str) !== "string")
throw new TypeError("Invalid path for the data item.");
return true;
}
// Finds an object inside the manager.
this.find = function (name, key, withMap) {
if (!name)
return withMap && key === privateKey ? { currentPath: manager, currentMapPath: map} : manager;
validatePath(name);
var pathMembers = name.split("."),
currentPath = manager,
currentMapPath = map;
for (var i = 0; i < pathMembers.length; i++) {
currentPath = currentPath[pathMembers[i]];
currentMapPath = currentMapPath[pathMembers[i]];
if (typeof (currentPath) === "undefined")
return;
}
return withMap && key === privateKey ? { currentPath: currentPath, currentMapPath: currentMapPath} : currentPath;
};
this.each = function(name, callback, deep, key, root) {
if (!callback)
return;
root = root !== undefined && key !== undefined && key === privateKey ? root : this.find(name, privateKey, true);
for (pName in root.currentMapPath) {
if (pName !== "__value") {
var path = (name !== undefined ? name + "." : "") + pName;
if (root.currentMapPath[pName].__value) {
if (root.currentPath[pName] === undefined) {
delete root.currentMapPath[pName]; // Remove entries in map if no corresponding entry exists in manager (if the property's been deleted externally)
}
else {
var context = {
path: path,
name: pName,
value: root.currentPath[pName],
parent: root.currentPath
};
if (deep)
manager.each(path, callback, true, privateKey, { currentMapPath: root.currentMapPath[pName], currentPath: root.currentPath[pName] });
callback.call(context, context.value);
}
}
else if (deep)
manager.each(path, callback, true, privateKey, { currentMapPath: root.currentMapPath[pName], currentPath: root.currentPath[pName] });
}
}
return this;
};
function getNamespaceByName(name, allowExists) {
validatePath(name);
var pathMembers = name.split("."),
currentPathMember = 0;
// Returns the namespace specified in the path. If the ns doesn't exists, creates it.
// If an object exists with the same name, but it isn't an object, an error is thrown.
function getNamespace(parent) {
var root = manager;
if (pathMembers.length === 1) {
if (!allowExists && root[name])
throw new Error("Specified name already exists: " + name);
return { ns: root, map: map, endpoint: name };
}
var nsName = pathMembers[currentPathMember],
returnNs,
existingNs;
parent = parent || { ns: root, map: map };
existingNs = parent.ns[nsName];
if (!existingNs) {
returnNs = { ns: parent.ns[nsName] = {}, map: parent.map[nsName] = {} };
}
else if (typeof existingNs === "object")
returnNs = { ns: existingNs, map: parent.map[nsName] };
else
throw new Error("Specified namespace exists and is not an object: " + name);
if (++currentPathMember < pathMembers.length - 1) {
returnNs = getNamespace(returnNs);
}
returnNs.endpoint = pathMembers[pathMembers.length - 1];
return returnNs;
}
return getNamespace();
}
// Adds a value to the manager.
this.register = function (name, o) {
if (typeof (o) === "object") {
o.ID = ++objIndex;
}
var nameSpace = getNamespaceByName(name);
nameSpace.ns[nameSpace.endpoint] = o;
nameSpace.map[nameSpace.endpoint] = { "__value": true };
if (o.subscribes) {
for (eventName in o.subscribes) {
this.subscribe(o, eventName, o.subscribes[eventName]);
}
}
return this;
};
this.unregister = function (name) {
var nameSpace = getNamespaceByName(name, true),
o;
if (!nameSpace || typeof (nameSpace.ns[nameSpace.endpoint]) === undefined)
throw new Error("Item to unregister not found.");
o = nameSpace.ns[nameSpace.endpoint];
if (o && o.ID)
delete o.ID;
delete nameSpace.ns[nameSpace.endpoint];
delete nameSpace.map[nameSpace.endpoint];
return this;
};
for (methodName in this) {
if (this.hasOwnProperty(methodName)) {
methods.push(methodName);
}
}
};