Skip to content

Commit 2b2fba9

Browse files
Abadi Kurniawanbdukes
authored andcommitted
Add knockout-postbox library
1 parent dc6d55f commit 2b2fba9

File tree

4 files changed

+263
-0
lines changed

4 files changed

+263
-0
lines changed

knockout-postbox_0.5.2/CHANGES.htm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<p>See the <a href="https://github.com/rniemeyer/knockout-postbox/releases/">knockout-postbox changelog</a></p>

knockout-postbox_0.5.2/LICENSE.htm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<p>knockout-postbox is licensed under the <a href="https://raw.githubusercontent.com/rniemeyer/knockout-postbox/master/LICENSE">MIT License</a>.</p>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<dotnetnuke type="Package" version="5.0">
2+
<packages>
3+
<package name="knockout-postbox" type="JavaScript_Library" version="0.5.2">
4+
<friendlyName>Knockout Validation</friendlyName>
5+
<description>A small library that uses Knockout's native pub/sub capabilities to facilitate decoupled communication between separate view models or components.</description>
6+
<owner>
7+
<name>Engage Software</name>
8+
<organization>Engage Software</organization>
9+
<url>http://www.engagesoftware.com</url>
10+
<email>support@engagesoftware.com</email>
11+
</owner>
12+
<license src="LICENSE.htm" />
13+
<releaseNotes src="CHANGES.htm" />
14+
<azureCompatible>true</azureCompatible>
15+
<dependencies>
16+
<dependency type="managedPackage" version="2.0.0">Knockout</dependency>
17+
</dependencies>
18+
<components>
19+
<component type="JavaScript_Library">
20+
<javaScriptLibrary>
21+
<libraryName>knockout-postbox</libraryName>
22+
<fileName>knockout-postbox.js</fileName>
23+
<objectName>ko.postbox</objectName>
24+
<cdnUrl>https://cdnjs.cloudflare.com/ajax/libs/knockout-postbox/0.5.2/knockout-postbox.js</cdnUrl>
25+
<preferredScriptLocation>BodyBottom</preferredScriptLocation>
26+
</javaScriptLibrary>
27+
</component>
28+
<component type="JavaScriptFile">
29+
<jsfiles>
30+
<libraryFolderName>knockout-postbox</libraryFolderName>
31+
<jsfile>
32+
<name>knockout-postbox.js</name>
33+
</jsfile>
34+
</jsfiles>
35+
</component>
36+
</components>
37+
</package>
38+
</packages>
39+
</dotnetnuke>
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
// knockout-postbox 0.5.2 | (c) 2015 Ryan Niemeyer | http://www.opensource.org/licenses/mit-license
2+
;(function(factory) {
3+
//CommonJS
4+
if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
5+
factory(require("knockout"), exports);
6+
//AMD
7+
} else if (typeof define === "function" && define.amd) {
8+
define(["knockout", "exports"], factory);
9+
//normal script tag
10+
} else {
11+
factory(ko, ko.postbox = {});
12+
}
13+
}(function(ko, exports, undefined) {
14+
var disposeTopicSubscription, existingSubscribe,
15+
subscriptions = {},
16+
subId = 1;
17+
18+
exports.subscriptions = subscriptions;
19+
20+
//create a global postbox that supports subscribing/publishing
21+
ko.subscribable.call(exports);
22+
23+
//keep a cache of the latest value and subscribers
24+
exports.topicCache = {};
25+
26+
//allow customization of the function used to serialize values for the topic cache
27+
exports.serializer = ko.toJSON;
28+
29+
//wrap notifySubscribers passing topic first and caching latest value
30+
exports.publish = function(topic, value) {
31+
if (topic) {
32+
//keep the value and a serialized version for comparison
33+
exports.topicCache[topic] = {
34+
value: value,
35+
serialized: exports.serializer(value)
36+
};
37+
exports.notifySubscribers(value, topic);
38+
}
39+
};
40+
41+
//provide a subscribe API for the postbox that takes in the topic as first arg
42+
existingSubscribe = exports.subscribe;
43+
exports.subscribe = function(topic, action, target, initializeWithLatestValue) {
44+
var subscription, current, existingDispose;
45+
46+
if (topic) {
47+
if (typeof target === "boolean") {
48+
initializeWithLatestValue = target;
49+
target = undefined;
50+
}
51+
52+
subscription = existingSubscribe.call(exports, action, target, topic);
53+
subscription.subId = ++subId;
54+
subscriptions[ subId ] = subscription;
55+
56+
if (initializeWithLatestValue) {
57+
current = exports.topicCache[topic];
58+
59+
if (current !== undefined) {
60+
action.call(target, current.value);
61+
}
62+
}
63+
64+
existingDispose = subscription.dispose;
65+
subscription.dispose = function() {
66+
delete subscriptions[subscription.subId];
67+
existingDispose.call(subscription);
68+
};
69+
70+
return subscription;
71+
}
72+
};
73+
74+
//clean up all subscriptions and references
75+
exports.reset = function() {
76+
var subscription;
77+
78+
for (var id in subscriptions) {
79+
if (subscriptions.hasOwnProperty(id)) {
80+
subscription = subscriptions[id];
81+
82+
if (subscription && typeof subscription.dispose === "function") {
83+
subscription.dispose();
84+
}
85+
}
86+
}
87+
88+
exports.topicCache = {};
89+
};
90+
91+
//by default publish when the previous cached value does not equal the new value
92+
exports.defaultComparer = function(newValue, cacheItem) {
93+
return cacheItem && exports.serializer(newValue) === cacheItem.serialized;
94+
};
95+
96+
//augment observables/computeds with the ability to automatically publish updates on a topic
97+
ko.subscribable.fn.publishOn = function(topic, skipInitialOrEqualityComparer, equalityComparer) {
98+
var skipInitialPublish, subscription, existingDispose;
99+
100+
if (topic) {
101+
//allow passing the equalityComparer as the second argument
102+
if (typeof skipInitialOrEqualityComparer === "function") {
103+
equalityComparer = skipInitialOrEqualityComparer;
104+
} else {
105+
skipInitialPublish = skipInitialOrEqualityComparer;
106+
}
107+
108+
equalityComparer = equalityComparer || exports.defaultComparer;
109+
110+
//remove any existing subs
111+
disposeTopicSubscription.call(this, topic, "publishOn");
112+
113+
//keep a reference to the subscription, so we can stop publishing
114+
subscription = this.subscribe(function(newValue) {
115+
if (!equalityComparer.call(this, newValue, exports.topicCache[topic])) {
116+
exports.publish(topic, newValue);
117+
}
118+
}, this);
119+
120+
//track the subscription in case of a reset
121+
subscription.id = ++subId;
122+
subscriptions[subId] = subscription;
123+
124+
//ensure that we cleanup pointers to subscription on dispose
125+
existingDispose = subscription.dispose;
126+
subscription.dispose = function() {
127+
delete this.postboxSubs[topic].publishOn;
128+
delete subscriptions[subscription.id];
129+
130+
existingDispose.call(subscription);
131+
}.bind(this);
132+
133+
this.postboxSubs[topic].publishOn = subscription;
134+
135+
//do an initial publish
136+
if (!skipInitialPublish) {
137+
exports.publish(topic, this());
138+
}
139+
}
140+
141+
return this;
142+
};
143+
144+
//handle disposing a subscription used to publish or subscribe to a topic
145+
disposeTopicSubscription = function(topic, type) {
146+
var subs = this.postboxSubs = this.postboxSubs || {};
147+
subs[topic] = subs[topic] || {};
148+
149+
if (subs[topic][type]) {
150+
subs[topic][type].dispose();
151+
}
152+
};
153+
154+
//discontinue automatically publishing on a topic
155+
ko.subscribable.fn.stopPublishingOn = function(topic) {
156+
disposeTopicSubscription.call(this, topic, "publishOn");
157+
158+
return this;
159+
};
160+
161+
//augment observables/computeds to automatically be updated by notifications on a topic
162+
ko.subscribable.fn.subscribeTo = function(topic, initializeWithLatestValueOrTransform, transform) {
163+
var initializeWithLatestValue, current, callback, subscription, existingDispose,
164+
self = this;
165+
166+
//allow passing the filter as the second argument
167+
if (typeof initializeWithLatestValueOrTransform === "function") {
168+
transform = initializeWithLatestValueOrTransform;
169+
} else {
170+
initializeWithLatestValue = initializeWithLatestValueOrTransform;
171+
}
172+
173+
if (topic && ko.isWriteableObservable(this)) {
174+
//remove any existing subs
175+
disposeTopicSubscription.call(this, topic, "subscribeTo");
176+
177+
//if specified, apply a filter function in the subscription
178+
callback = function(newValue) {
179+
self(transform ? transform.call(self, newValue) : newValue);
180+
};
181+
182+
////keep a reference to the subscription, so we can unsubscribe, if necessary
183+
subscription = exports.subscribe(topic, callback);
184+
this.postboxSubs[topic].subscribeTo = subscription;
185+
186+
//ensure that we cleanup pointers to subscription on dispose
187+
existingDispose = subscription.dispose;
188+
subscription.dispose = function() {
189+
delete this.postboxSubs[topic].subscribeTo;
190+
existingDispose.call(subscription);
191+
}.bind(this);
192+
193+
if (initializeWithLatestValue) {
194+
current = exports.topicCache[topic];
195+
196+
if (current !== undefined) {
197+
callback(current.value);
198+
}
199+
}
200+
}
201+
202+
return this;
203+
};
204+
205+
//discontinue receiving updates on a topic
206+
ko.subscribable.fn.unsubscribeFrom = function(topic) {
207+
disposeTopicSubscription.call(this, topic, "subscribeTo");
208+
209+
return this;
210+
};
211+
212+
// both subscribe and publish on the same topic
213+
// -allows the ability to sync an observable/writeable computed/observableArray between view models
214+
// -subscribeTo should really not use a filter function, as it would likely cause infinite recursion
215+
ko.subscribable.fn.syncWith = function(topic, initializeWithLatestValue, skipInitialOrEqualityComparer, equalityComparer) {
216+
this.subscribeTo(topic, initializeWithLatestValue).publishOn(topic, skipInitialOrEqualityComparer, equalityComparer);
217+
218+
return this;
219+
};
220+
221+
ko.postbox = exports;
222+
}));

0 commit comments

Comments
 (0)