1 | window.dashable_keys = []
|
2 | dashable = (k) ->
|
3 | return true
|
4 | for k2 of dashable_keys
|
5 | if k == k2 or (k2.match(/\*$/) and k2.substr(k2.length-1) == k.substr(k2.length-1))
|
6 | return true
|
7 | return false
|
8 |
|
9 | parse_key = (key) ->
|
10 | word = "([^/]+)"
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | regexp = new RegExp("(/)?(new/)?#{word}(/#{word})?(/)?")
|
18 | m = key.match(regexp)
|
19 | if not m
|
20 | return null
|
21 |
|
22 | [has_match, server_owned, is_new, name, tmp1, number, tmp2] = m
|
23 | owner = if server_owned then 'server' else 'client'
|
24 | return has_match and {owner, 'new': is_new, name, number}
|
25 |
|
26 | dom.STATE_DASH = ->
|
27 | dash = bus.fetch('state_dash')
|
28 |
|
29 | if !dash.on?
|
30 | dash.on = false
|
31 | dash.selected = {owner: null, name: null, number: null}
|
32 | dash.filter = null
|
33 |
|
34 | if dash.filter?.match(/idkfa/) or dash.filter?.match(/idmap/)
|
35 | dash.on = false
|
36 | dash.filter = ''
|
37 | bus.save(dash)
|
38 |
|
39 | if not dash.on
|
40 | return DIV null, ''
|
41 |
|
42 | url_tree = (cache) ->
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 | tree = {server: {}, client: {}}
|
51 |
|
52 | add_key = (key) ->
|
53 | p = parse_key(key)
|
54 | if not p
|
55 | console.log('The state dash can\'t deal with key', key); return null
|
56 |
|
57 | if not p.name in dashable_keys then return null
|
58 |
|
59 | tree[p.owner][p.name] ||= []
|
60 | tree[p.owner][p.name][p.number or null] = bus.fetch(key)
|
61 |
|
62 | for key of cache
|
63 | add_key(key)
|
64 | return tree
|
65 |
|
66 | search_results = get_search_results()
|
67 | cache = search_results.matches
|
68 | tree = url_tree(cache)
|
69 |
|
70 | first_key = (cache) ->
|
71 | for key of cache
|
72 | reject_name = dash.selected.name and parse_key(key).name != dash.selected.name
|
73 | reject_numb = dash.selected.number and parse_key(key).number != dash.selected.number
|
74 | if !reject_name and !reject_numb
|
75 | return key
|
76 | return null
|
77 |
|
78 | best_guess = first_key(search_results.key_matches) or \
|
79 | first_key(search_results.data_matches)
|
80 |
|
81 | cluster_rows = (keys) ->
|
82 | clusters = {}
|
83 | for key in keys
|
84 | fields = JSON.stringify(Object.keys(cache[key]))
|
85 | clusters[fields] = clusters[fields] or []
|
86 | clusters[fields].push(key)
|
87 | return clusters
|
88 |
|
89 | filter_to = (e) ->
|
90 | dash.filter = e.target.value
|
91 | if dash.filter.length == 0
|
92 | dash.filter = null
|
93 | bus.save(dash)
|
94 | true
|
95 |
|
96 |
|
97 | DIV className: 'state_dash', style: this.props.style,
|
98 | React.DOM.style({dangerouslySetInnerHTML: {__html:
|
99 | """
|
100 | .state_dash {
|
101 | position: fixed;
|
102 | margin: 20px;
|
103 | z-index: 10000;
|
104 | top: 0;
|
105 | left: 0;
|
106 | }
|
107 | .state_dash .left, .state_dash .right, .state_dash .top {
|
108 | background-color: #eee;
|
109 | overflow-wrap: break-word;
|
110 | padding: 10px;
|
111 | vertical-align: top;
|
112 | }
|
113 | .state_dash .left { min-width: 40px; max-width: 140px; }
|
114 | .state_dash .right { left: 180px; position: absolute; white-space: nowrap; }
|
115 | .state_dash .top { max-width: 100%; margin: 20px 0; }
|
116 |
|
117 | .string { color: green; }
|
118 | .number { color: darkorange; }
|
119 | .boolean { color: blue; }
|
120 | .null { color: magenta; }
|
121 | .key { color: red; }
|
122 |
|
123 | .cell {
|
124 | width: 150px;
|
125 | height: 26px;
|
126 | border: 1px solid grey;
|
127 | padding: 2px;
|
128 | display: inline-block;
|
129 | white-space: nowrap;
|
130 | overflow: hidden;
|
131 | text-overflow: clip;
|
132 | margin: 0;
|
133 | }
|
134 | """}})
|
135 |
|
136 |
|
137 |
|
138 |
|
139 | DIV className: 'right',
|
140 |
|
141 |
|
142 | if dash.selected.name
|
143 | selected_keys = (key for key of cache when parse_key(key).name == dash.selected.name)
|
144 | clusters = cluster_rows(selected_keys)
|
145 | for fieldset of clusters
|
146 |
|
147 | DIV null,
|
148 |
|
149 | for field in JSON.parse(fieldset)
|
150 | DIV
|
151 | key: field
|
152 | style: {fontWeight: 'bold', borderColor: '#eee'}
|
153 | className: 'cell'
|
154 | field
|
155 |
|
156 |
|
157 | for key in clusters[fieldset]
|
158 | row = cache[key]
|
159 | DIV key: key,
|
160 | for field of row
|
161 | DIV
|
162 | className: 'cell'
|
163 | key: field
|
164 | onClick: do (key, field) => (evt) =>
|
165 | @local.editing = {key_:key, field:field}
|
166 | bus.save(@local)
|
167 | setTimeout(=> @refs.dash_input.getDOMNode().focus())
|
168 | if (@local.editing \
|
169 | and @local.editing.key_ == key \
|
170 | and @local.editing.field == field)
|
171 | SPAN null,
|
172 | TEXTAREA
|
173 | key: field
|
174 | type: 'text'
|
175 | ref: 'dash_input'
|
176 | defaultValue: JSON.stringify(row[field])
|
177 | onChange: (event) =>
|
178 | try
|
179 | val = JSON.parse(@refs.dash_input.getDOMNode().value)
|
180 | cache[@local.editing.key_][@local.editing.field] = val
|
181 | bus.save(cache[@local.editing.key_])
|
182 | event.stopPropagation()
|
183 |
|
184 | delete @local.editing.error; bus.save(@local)
|
185 | catch e
|
186 | @local.editing.error = true; bus.save(@local)
|
187 | onBlur: (event) =>
|
188 | delete @local.editing; bus.save(@local)
|
189 | style:
|
190 | position: 'absolute'
|
191 | backgroundColor: '#faa' if @local.editing.error
|
192 |
|
193 |
|
194 |
|
195 |
|
196 |
|
197 |
|
198 |
|
199 |
|
200 |
|
201 |
|
202 |
|
203 |
|
204 |
|
205 |
|
206 |
|
207 |
|
208 |
|
209 |
|
210 | JSON.stringify(row[field])
|
211 |
|
212 |
|
213 | DIV className: 'left',
|
214 | INPUT
|
215 | ref: 'search'
|
216 | className: 'search'
|
217 | onChange: filter_to
|
218 | onMouseEnter: reset_selection
|
219 |
|
220 | for owner in ['client', 'server']
|
221 | prefix = (owner == 'server') and '/' or ''
|
222 | names = (n for n of tree[owner])
|
223 | DIV {key: owner},
|
224 | for name in names.sort()
|
225 | do (owner, name) ->
|
226 | f = -> dash.selected={owner, name, number:null}; bus.save(dash)
|
227 | style = (name == dash.selected.name) and {'background-color':'#aaf'} or {}
|
228 | DIV onMouseEnter: f, key: name, style: style,
|
229 | prefix + name
|
230 |
|
231 |
|
232 | recent_keys = [0,0,0,0,0]
|
233 |
|
234 | dash_initialized = false
|
235 | window.addEventListener('DOMContentLoaded', ->
|
236 | document.addEventListener "keypress", (e) =>
|
237 | key = (e and e.keyCode) or e.keyCode
|
238 | recent_keys.push(key)
|
239 | recent_keys = recent_keys.slice(1)
|
240 |
|
241 |
|
242 | if key==4 or "#{recent_keys}" == "#{[105, 100, 109, 97, 112]}" \
|
243 | or "#{recent_keys}" == "#{[105, 100, 107, 102, 97]}"
|
244 | dash = bus.fetch('state_dash')
|
245 | if dash.on
|
246 | dash.on = false
|
247 | else
|
248 | dash.on = true
|
249 | bus.save(dash)
|
250 |
|
251 |
|
252 |
|
253 | )
|
254 |
|
255 | get_search_results = ->
|
256 |
|
257 |
|
258 |
|
259 |
|
260 |
|
261 | dash = bus.fetch('state_dash')
|
262 | matches = {}
|
263 | key_matches = {}
|
264 | data_matches = {}
|
265 | if dash.filter
|
266 | for key of bus.cache
|
267 | if key.match(dash.filter)
|
268 | matches[key] = bus.cache[key]
|
269 | key_matches[key] = bus.cache[key]
|
270 | if JSON.stringify(bus.cache[key]).match(dash.filter)
|
271 | matches[key] = bus.cache[key]
|
272 | data_matches[key] = bus.cache[key]
|
273 | else
|
274 | matches = key_matches = data_matches = bus.cache
|
275 |
|
276 | return {matches, key_matches, data_matches}
|
277 |
|
278 |
|
279 |
|
280 |
|
281 |
|
282 |
|
283 | reset_selection = () ->
|
284 | dash = bus.fetch('state_dash')
|
285 | dash.selected = {owner: null, name: null, number: null}
|
286 | bus.save(dash)
|
287 |
|
288 | rainbows = (json) ->
|
289 | json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
290 | return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, (match) ->
|
291 | cls = 'number'
|
292 | if (/^"/.test(match))
|
293 | if (/:$/.test(match))
|
294 | cls = 'key'
|
295 | else
|
296 | cls = 'string';
|
297 | else if (/true|false/.test(match))
|
298 | cls = 'boolean'
|
299 | else if (/null/.test(match))
|
300 | cls = 'null';
|
301 |
|
302 | return "<span class=\"#{cls}\">#{match}</span>") |
\ | No newline at end of file |