-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHypeSymbolCache.js
More file actions
174 lines (153 loc) · 7.2 KB
/
HypeSymbolCache.js
File metadata and controls
174 lines (153 loc) · 7.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
/*!
Hype SymbolCache 1.1
copyright (c) 2020 Max Ziebell, (https://maxziebell.de). MIT-license
*/
/**
* A module that allows Tumult Hype symbols to be extended in a persistent way
* @module HypeSymbolCache
*/
/*
* Version-History
* 1.0 Initial release under MIT-license
* 1.1 Bugfixes, additional API and immediate refresh
*/
if("HypeSymbolCache" in window === false) window['HypeSymbolCache'] = (function () {
var _cache = {};
function documentLoad (hypeDocument, element, event){
// init document cache
_cache[hypeDocument.documentId()] = {}
/**
* This function is an copy of the function found in the Hype Runtime. As that is an IIFE it isn't available and hence we need to redifine it for custom event handling following the official Hype Event schema.
*
* @param {Object} event This object contains at least the event type (name of event) and in some cases some additional information (key, value) or nested structures
* @param {HTMLElement} element This is the element the current tagert of the event or null if the event doesn't require or was called without an target
* @return Returns the result of the event. Mostly this is an Boolean in case of Hype as it uses the events in an Observer pattern.
*/
hypeDocument.notifyEvent = function(event, element) {
var eventListeners = window['HYPE_eventListeners'];
if (eventListeners == null) {
return;
}
var result;
for (var i = 0; i < eventListeners.length; i++) {
if (eventListeners[i]['type'] == event['type'] && eventListeners[i]['callback'] != null) {
result = eventListeners[i]['callback'](this, element, event);
if (result === false) {
return false;
}
}
}
return result;
};
/**
* This helper does a backwards treewalk from the element it is started on and returns the symbolInstance if one is found. This function was originally written by Stephen Decker from Tumult Inc. but has been tweaked to use the Hype Symbol Cache. The cache is also used to return save the search result for child elements of symbols. Hence, a repeated symbol won't be a treewalk but rather a simple lookup.
*
* @param {HTMLElement} element The element to start the treewalk on
* @return {Object} Returns the first found symbolInstance while tree walking or null if no symbolInstance is found
*/
hypeDocument.getSymbolInstanceForElement = function(element){
if (_cache[this.documentId()][element.id]) return _cache[this.documentId()][element.id];
var symbolInstance = null;
var currentElm = element;
var docElm = document.getElementById(hypeDocument.documentId());
while (symbolInstance == null && currentElm != null && currentElm != docElm) {
symbolInstance = _cache[this.documentId()][currentElm.id];
if (symbolInstance != null) {
if (element != currentElm) _cache[this.documentId()][element.id] = symbolInstance;
} else {
currentElm = currentElm.parentNode;
}
}
return symbolInstance;
}
/**
* This function reset the entire symbol cache and purging the entire symbol cache. This resets the return values for getSymbolInstanceById an getSymbolInstancesByName for all symbol instances.
*
* @param {Boolean} refreshImmediately If this is set to true it will fire HypeSymbolInit rather then only deleting the symbol cache.
*/
hypeDocument.purgeSymbolCache = function(refreshImmediately){
if (refreshImmediately) {
for (var id in _cache[this.documentId()]){
hypeDocument.refreshSymbolCacheForId(id);
}
} else {
_cache[this.documentId()] = {}
}
}
/**
* This function reset the symbol cache of an single symbol by purging its symbol instance from the symbol cache. This resets the return values for getSymbolInstanceById an getSymbolInstancesByName for the symbol instance with the given id.
*
* @param {String} id This is the id of the symbol cache that should be reseted
* @param {Boolean} refreshImmediately If this is set to true it will fire HypeSymbolInit rather then only deleting the symbol cache.
*/
hypeDocument.purgeSymbolCacheForId = function(id, refreshImmediately){
if (refreshImmediately) {
hypeDocument.refreshSymbolCacheForId(id);
} else {
delete _cache[this.documentId()][id];
}
}
// Alias original command
hypeDocument._getSymbolInstanceById = hypeDocument.getSymbolInstanceById;
hypeDocument._getSymbolInstancesByName = hypeDocument.getSymbolInstancesByName;
/**
* This function overrides the original Hype document API and returns the symbol instance from the cache lookup instead. The original function is still available and aliased as hypeDocument._getSymbolInstanceById.
*
* @param {String} id The id your trying to get the symbolinstace from
*/
hypeDocument.getSymbolInstanceById = function(id){
return _cache[this.documentId()][id];
}
/**
* This function overrides the original Hype document API and returns the symbol instances requested by name from the cache lookup instead. The original function is still available and aliased as hypeDocument._getSymbolInstancesByName.
*
* @param {String} id The id your trying to get the symbol instance from
*/
hypeDocument.getSymbolInstancesByName = function(name){
var instances = hypeDocument._getSymbolInstancesByName(name);
var cacheList = [];
for (var i=0; i<instances.length; i++){
cacheList.push(_cache[this.documentId()][instances[i].element().id]);
}
return cacheList;
}
/**
* This function refreshes the symbol cache by requesting a fresh copy of the symbol instance APi from the Hype Runtime and firing the custom event HypeSymbolInit afterwards
*
* @param {String} id The id your trying to refresh the symbol instance for
*/
hypeDocument.refreshSymbolCacheForId = function(id){
_cache[hypeDocument.documentId()][id] = hypeDocument._getSymbolInstanceById(id);
//todo in 1.2 only fire if cache is set for an symbol and is not null to secure against user passing in a non symbol id
hypeDocument.notifyEvent({type: "HypeSymbolInit"}, document.getElementById(id));
}
/**
* This function refreshes the symbol cache by requesting a fresh copy of the symbol instance API from the Hype Runtime and firing the custom event HypeSymbolInit afterwards but only if the system cache isn't already set for the id
*
* @param {String} id The id your trying to refresh the symbol instance for
*/
hypeDocument.refreshSymbolCacheForIdIfNecessary = function(id){
if (!_cache[hypeDocument.documentId()][id]) {
this.refreshSymbolCacheForId(id);
}
}
}
function symbolLoad (hypeDocument, element, event){
hypeDocument.refreshSymbolCacheForIdIfNecessary(element.id);
}
if("HYPE_eventListeners" in window === false) window.HYPE_eventListeners = Array();
window.HYPE_eventListeners.push({"type":"HypeDocumentLoad", "callback":documentLoad});
window.HYPE_eventListeners.push({"type":"HypeSymbolLoad", "callback":symbolLoad});
/**
* @typedef {Object} HypeHandlebars
* @property {String} version Version of the extension
*/
var HypeSymbolCache = {
version: '1.1',
};
/**
* Reveal Public interface to window['HypeSymbolCache']
* return {HypeSymbolCache}
*/
return HypeSymbolCache;
})();