UNPKG

10.1 kBtext/coffeescriptView Raw
1window.dashable_keys = []
2dashable = (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
9parse_key = (key) ->
10 word = "([^/]+)"
11 # Matching things like: "/new/name/number"
12 # or: "/name/number"
13 # or: "/name"
14 # or: "name/number"
15 # or: "name"
16 # ... and you can optionally include a final slash.
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
26dom.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 # The key tree looks like:
44 #
45 # {server: {thing: [obj1, obj2], shing: [obj1, obj2], ...}
46 # client: {dong: [obj1, ...]}}
47 #
48 # And objects without a number, like '/shong' will go on:
49 # key_tree.server.shong[null]
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 # Render the object
137 # PRE className: 'right', ref: 'json_preview',
138 # JSON.stringify(arest.cache[best_guess], undefined, 3)
139 DIV className: 'right',
140 # Next: go through the list, cluster those that fit the same
141 # schema, and display a table for each.
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 # Print each table
147 DIV null,
148 # Print the table header
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 # Print the table body
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 # INPUT
193 # type: 'submit'
194 # onClick: (event) =>
195 # try
196 # val = JSON.parse(@refs.dash_input.getDOMNode().value)
197 # cache[@local.editing.key_][@local.editing.field] = val
198 # bus.save(cache[@local.editing.key_])
199 # c = bus.fetch('component/1')
200 # delete c.editing
201 # bus.save(c)
202 # event.stopPropagation()
203 # catch e
204 # @local.editing.error = true
205 # bus.save(@local)
206 # style:
207 # position: 'absolute'
208 # marginTop: 30
209
210 JSON.stringify(row[field])
211
212 # Render the top (name) menu
213 DIV className: 'left', #onMouseLeave: reset_selection,
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
232recent_keys = [0,0,0,0,0]
233
234dash_initialized = false
235window.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 # console.log('recent keys:', recent_keys)
242 if key==4 or "#{recent_keys}" == "#{[105, 100, 109, 97, 112]}" \ # idmap
243 or "#{recent_keys}" == "#{[105, 100, 107, 102, 97]}" # idkfa
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 # setTimeout =>
251 # console.log @refs
252 # @refs.search.getDOMNode().focus()
253)
254
255get_search_results = ->
256 # Returns two filtered views of the cache:
257 #
258 # { key_matches: {...a cache filtered to matching keys... }
259 # data_matches: {...a cache filtered to matching data...} }
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# componentDidUpdate: () ->
280# el = @refs.json_preview.getDOMNode()
281# el.innerHTML = rainbows(el.innerHTML)
282
283reset_selection = () ->
284 dash = bus.fetch('state_dash')
285 dash.selected = {owner: null, name: null, number: null}
286 bus.save(dash)
287
288rainbows = (json) ->
289 json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
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