@jinntec/fore 3.3.1 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -70
- package/dist/fore-dev.js +5593 -6832
- package/dist/fore.js +5602 -4887
- package/index.js +5 -10
- package/package.json +7 -7
- package/resources/fore.css +33 -0
- package/src/DependencyNotifyingDomFacade.js +90 -21
- package/src/DependentXPathQueries.js +15 -2
- package/src/ForeElementMixin.js +110 -16
- package/src/UndoManager.js +267 -0
- package/src/actions/abstract-action.js +71 -30
- package/src/actions/fx-action.js +5 -0
- package/src/actions/fx-append.js +3 -3
- package/src/actions/fx-commit-history.js +26 -0
- package/src/actions/fx-hide.js +1 -1
- package/src/actions/fx-insert.js +25 -22
- package/src/actions/fx-load.js +5 -5
- package/src/actions/fx-redo.js +58 -0
- package/src/actions/fx-refresh.js +2 -2
- package/src/actions/fx-reload.js +1 -1
- package/src/actions/fx-replace.js +1 -1
- package/src/actions/fx-send.js +27 -5
- package/src/actions/fx-setattribute.js +11 -7
- package/src/actions/fx-undo.js +58 -0
- package/src/createNodes.js +314 -0
- package/src/fore.js +53 -18
- package/src/functions/fx-functionlib.js +10 -10
- package/src/fx-bind.js +30 -18
- package/src/fx-fore.js +222 -200
- package/src/fx-instance.js +18 -1
- package/src/fx-model.js +236 -69
- package/src/fx-submission.js +37 -29
- package/src/fx-var.js +49 -13
- package/src/getInScopeContext.js +1 -1
- package/src/json/JSONDomFacade.js +1 -1
- package/src/json/JSONLens.js +2 -2
- package/src/ui/UIElement.js +18 -8
- package/src/ui/abstract-control.js +45 -3
- package/src/ui/fx-alert.js +4 -0
- package/src/ui/fx-case.js +1 -1
- package/src/ui/fx-container.js +3 -0
- package/src/ui/fx-control-menu.js +79 -11
- package/src/ui/fx-control.js +130 -41
- package/src/ui/fx-dialog.js +5 -0
- package/src/ui/fx-items.js +6 -6
- package/src/ui/fx-output.js +37 -1
- package/src/ui/fx-repeat.js +1065 -103
- package/src/ui/fx-repeatitem.js +4 -1
- package/src/ui/fx-switch.js +116 -3
- package/src/ui/fx-trigger.js +9 -4
- package/src/ui/fx-upload.js +10 -4
- package/src/ui/repeat-base.js +20 -12
- package/src/withDraggability.js +10 -1
- package/src/xpath-evaluation.js +30 -18
- package/src/xpath-path.js +122 -0
- package/src/xpath-util.js +11 -126
- package/src/actions/StringTpl.js +0 -17
- package/src/extract-predicate-deps.js +0 -57
- package/src/extractPredicateDependencies.js +0 -36
- package/src/json/lensFromNode.js +0 -5
- package/src/json-util.js +0 -27
- package/src/tools/adi.js +0 -1111
- package/src/tools/deprecation.md +0 -1
- package/src/tools/fx-action-log.js +0 -745
- package/src/tools/fx-devtools.js +0 -444
- package/src/tools/fx-dom-inspector.js +0 -610
- package/src/tools/fx-json-instance.js +0 -444
- package/src/tools/fx-log-item.js +0 -128
- package/src/tools/fx-log-settings.js +0 -533
- package/src/tools/fx-minimap.js +0 -203
- package/src/tools/helpers.js +0 -132
- package/src/ui/TemplateExpression.js +0 -12
- package/src/ui/fx-dom-inspector.js +0 -1255
|
@@ -1,1255 +0,0 @@
|
|
|
1
|
-
import AbstractControl from './abstract-control.js';
|
|
2
|
-
|
|
3
|
-
export class FxDomInspector extends HTMLElement {
|
|
4
|
-
constructor() {
|
|
5
|
-
super();
|
|
6
|
-
this.attachShadow({ mode: 'open' });
|
|
7
|
-
this.delegatedEvents = [];
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
connectedCallback() {
|
|
11
|
-
this.render();
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
render(){
|
|
15
|
-
const style = `
|
|
16
|
-
:host {
|
|
17
|
-
display:block;
|
|
18
|
-
}
|
|
19
|
-
`;
|
|
20
|
-
|
|
21
|
-
const html = `
|
|
22
|
-
<slot></slot>
|
|
23
|
-
`;
|
|
24
|
-
|
|
25
|
-
this.shadowRoot.innerHTML = `
|
|
26
|
-
<style>
|
|
27
|
-
${style}
|
|
28
|
-
</style>
|
|
29
|
-
${html}
|
|
30
|
-
`;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Node types shim -- creates Node type constants if necessary
|
|
34
|
-
nodeTypesShim() {
|
|
35
|
-
if (!window.Node) {
|
|
36
|
-
return {
|
|
37
|
-
ELEMENT_NODE : 1,
|
|
38
|
-
ATTRIBUTE_NODE : 2,
|
|
39
|
-
TEXT_NODE : 3,
|
|
40
|
-
CDATA_SECTION_NODE : 4,
|
|
41
|
-
ENTITY_REFERENCE_NODE : 5,
|
|
42
|
-
ENTITY_NODE : 6,
|
|
43
|
-
PROCESSING_INSTRUCTION_NODE : 7,
|
|
44
|
-
COMMENT_NODE : 8,
|
|
45
|
-
DOCUMENT_NODE : 9,
|
|
46
|
-
DOCUMENT_TYPE_NODE : 10,
|
|
47
|
-
DOCUMENT_FRAGMENT_NODE : 11,
|
|
48
|
-
NOTATION_NODE : 12
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
addEvent(elem, evt, fn, capture) {
|
|
54
|
-
if (typeof elem !== 'object') {
|
|
55
|
-
throw "addEvent: Expected argument elem of type object, " + typeof elem + " given.";
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (window.addEventListener) {
|
|
59
|
-
if (!capture) {
|
|
60
|
-
capture = false;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
elem.addEventListener(evt, fn, capture);
|
|
64
|
-
} else {
|
|
65
|
-
elem.attachEvent('on' + evt, fn);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Simple cross-browser event handler that enables simple event delegation.
|
|
70
|
-
// Note that the selector must be a string and no nesting is supported.
|
|
71
|
-
// Selector is expected to be in one of formats listed below and works for all children
|
|
72
|
-
// in the particular element.
|
|
73
|
-
// Store parameter enables storing the reference to custom event handler.
|
|
74
|
-
// Exclude parameter will exclude the particular element and all of its children, this works
|
|
75
|
-
// only for id selectors.
|
|
76
|
-
// Selector formats: tag name ("div"), class name (".my-class"), id ("#my-id") and any ("*").
|
|
77
|
-
|
|
78
|
-
addEventDelegate(elem, evt, fn, capture, selector, store, exclude) {
|
|
79
|
-
// custom event handler is registered
|
|
80
|
-
var handler = function(e) {
|
|
81
|
-
// check if target corresponds to the selector
|
|
82
|
-
var target = e ? e.target : window.event.srcElement,
|
|
83
|
-
sel = selector.substr(1),
|
|
84
|
-
delegate = false;
|
|
85
|
-
|
|
86
|
-
if (exclude) {
|
|
87
|
-
var node = target;
|
|
88
|
-
|
|
89
|
-
while (node !== document) {
|
|
90
|
-
if (node.id === exclude) {
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
node = node.parentNode;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// should the event be delegated?
|
|
99
|
-
if (selector.indexOf('#') === 0) { // ID
|
|
100
|
-
delegate = target.id === sel;
|
|
101
|
-
} else if (selector.indexOf('.') === 0) { // class
|
|
102
|
-
delegate = target.className.indexOf(sel) !== -1;
|
|
103
|
-
} else if (selector === '*') { // any
|
|
104
|
-
delegate = true;
|
|
105
|
-
} else { // tag name
|
|
106
|
-
delegate = target.nodeName.toLowerCase() === selector;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// delegate the event handling
|
|
110
|
-
if (delegate) {
|
|
111
|
-
fn.call(this, e);
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
// save the reference
|
|
115
|
-
if (store) {
|
|
116
|
-
delegatedEvents.push({
|
|
117
|
-
'handle' : handler,
|
|
118
|
-
'elem' : elem,
|
|
119
|
-
'fn' : fn,
|
|
120
|
-
'evt': evt
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// add custom event
|
|
125
|
-
addEvent(elem, evt, handler, capture);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Simple cross-browser event removing
|
|
129
|
-
removeEvent(elem, evt, fn, wasDelegated) {
|
|
130
|
-
if (typeof elem !== 'object') {
|
|
131
|
-
throw "addEvent: Expected argument elem of type object, " + typeof elem + " given.";
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// try to find stored delegated event
|
|
135
|
-
var stored = null;
|
|
136
|
-
if (wasDelegated) {
|
|
137
|
-
for (var i = 0, len = delegatedEvents.length; i < len; ++i) {
|
|
138
|
-
stored = delegatedEvents[i];
|
|
139
|
-
if (stored.elem === elem && stored.evt === evt && stored.fn === fn) {
|
|
140
|
-
fn = stored.handle;
|
|
141
|
-
delegatedEvents.splice(i, 1);
|
|
142
|
-
break;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (window.addEventListener) {
|
|
148
|
-
elem.removeEventListener(evt, fn, false);
|
|
149
|
-
} else {
|
|
150
|
-
elem.dettachEvent('on' + evt, fn);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
// Stops event propagation and also prevents the default behavior.
|
|
154
|
-
pauseEvent(e){
|
|
155
|
-
if(e.stopPropagation) {
|
|
156
|
-
e.stopPropagation();
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if(e.preventDefault) {
|
|
160
|
-
e.preventDefault();
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
e.cancelBubble = true;
|
|
164
|
-
e.returnValue = false;
|
|
165
|
-
|
|
166
|
-
return false;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Create element wrapper -- allows to set attributes using the config object.
|
|
170
|
-
newElement(elem, attrs) {
|
|
171
|
-
var el = document.createElement(elem);
|
|
172
|
-
|
|
173
|
-
attrs = attrs || {};
|
|
174
|
-
for (var attr in attrs) {
|
|
175
|
-
// work only with direct (non-inherited) properties
|
|
176
|
-
if (attrs.hasOwnProperty(attr)) {
|
|
177
|
-
el.setAttribute(attr, attrs[attr]);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
return el;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Function adds a class to the element, only if the class does not already exist.
|
|
185
|
-
// Cls parameter may be either a string or an array listing multiple classes.
|
|
186
|
-
// Implementation uses modern element.classList API if available, dummy shim provided for older
|
|
187
|
-
// browsers.
|
|
188
|
-
addClass(elem, cls) {
|
|
189
|
-
if (typeof elem !== 'object') {
|
|
190
|
-
throw "addClass: Expected argument elem of type object, " + typeof elem + " given.";
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// normalize to array
|
|
194
|
-
if (typeof cls === 'string') {
|
|
195
|
-
cls = [cls];
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// iterate over classes and add new if necessary
|
|
199
|
-
for (var i = 0, len = cls.length; i < len; ++i) {
|
|
200
|
-
if (supported('classList')) {
|
|
201
|
-
elem.classList.add(cls[i]);
|
|
202
|
-
} else {
|
|
203
|
-
// prevents the match when new class is only a substring of another class name
|
|
204
|
-
if (!new RegExp('(?:^|\\s)' + cls[i] + '(?:\\s|$)').test(elem.className)) {
|
|
205
|
-
elem.className += ' ' + cls[i];
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Function removes a class from the element, only if the class exists.
|
|
212
|
-
// Cls parameter may be either a string or an array listing multiple classes.
|
|
213
|
-
// Implementation uses modern element.classList API if available, dummy shim provided for older
|
|
214
|
-
// browsers.
|
|
215
|
-
removeClass(elem, cls) {
|
|
216
|
-
if (typeof elem !== 'object') {
|
|
217
|
-
throw "removeClass: Expected argument elem of type object, " + typeof elem + " given.";
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// normalize to array
|
|
221
|
-
if (typeof cls === 'string') {
|
|
222
|
-
cls = [cls];
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// iterate over classes and remove if necessary
|
|
226
|
-
for (var i = 0, len = cls.length; i < len; ++i) {
|
|
227
|
-
if (supported('classList')) {
|
|
228
|
-
elem.classList.remove(cls[i]);
|
|
229
|
-
} else {
|
|
230
|
-
// removes the class if it exists
|
|
231
|
-
var newClassName = elem.className.replace(new RegExp('(?:^|\\s)' + cls[i] + '(?:\\s|$)', 'g'), ' ');
|
|
232
|
-
elem.className = newClassName.replace(/^\s+|\s+$/g, '');
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// Functions checks whether the feature is supported.
|
|
238
|
-
supported(key) {
|
|
239
|
-
switch (key) {
|
|
240
|
-
case 'localStorage':
|
|
241
|
-
try {
|
|
242
|
-
return 'localStorage' in window && !!window.localStorage;
|
|
243
|
-
} catch (e) {
|
|
244
|
-
return false;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
break;
|
|
248
|
-
case 'classList':
|
|
249
|
-
return 'classList' in document.createElement('a');
|
|
250
|
-
|
|
251
|
-
default:
|
|
252
|
-
throw "supported: Unknown or unsupported key.";
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// AcID DOM Inspector definition (using module pattern).
|
|
257
|
-
var ADI = (function() {
|
|
258
|
-
// private methods and variables
|
|
259
|
-
var Node = window.Node || nodeTypesShim(),
|
|
260
|
-
uiView = null,
|
|
261
|
-
menuView = null,
|
|
262
|
-
domView = null,
|
|
263
|
-
attrView = null,
|
|
264
|
-
pathView = null,
|
|
265
|
-
optsView = null,
|
|
266
|
-
activeElement = null,
|
|
267
|
-
vertResizing = false,
|
|
268
|
-
horizResizing = false,
|
|
269
|
-
pathScrolling = null,
|
|
270
|
-
elemLookup = false,
|
|
271
|
-
styleBackup = '',
|
|
272
|
-
xPos = 0,
|
|
273
|
-
options = {
|
|
274
|
-
align: 'right', // NOTE: left is not supported in this version
|
|
275
|
-
width: 500,
|
|
276
|
-
minWidth: 260,
|
|
277
|
-
split: 50,
|
|
278
|
-
minSplit: 30,
|
|
279
|
-
visible: true,
|
|
280
|
-
saving: false,
|
|
281
|
-
transparent: true,
|
|
282
|
-
omitEmptyText: true,
|
|
283
|
-
makeVisible: true,
|
|
284
|
-
foldText: true,
|
|
285
|
-
nodeTypes: [1, 3, 8, 9]
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
// Returns selected element or null
|
|
289
|
-
function getSelected() {
|
|
290
|
-
if (!activeElement) {
|
|
291
|
-
return null;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
var elem = document,
|
|
295
|
-
path = JSON.parse(activeElement.getAttribute('data-js-path'));
|
|
296
|
-
|
|
297
|
-
if (path[0] !== "") {
|
|
298
|
-
for (var i = 0, len = path.length; i < len; ++i) {
|
|
299
|
-
elem = elem.childNodes[path[i]];
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
return elem;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Loads user defined options stored in HTML5 storage (if available)
|
|
307
|
-
function loadOptions() {
|
|
308
|
-
var userOptions = {};
|
|
309
|
-
|
|
310
|
-
if (supported('localStorage')) {
|
|
311
|
-
userOptions = JSON.parse(localStorage.getItem('ADI.options')) || {};
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// merge with defaults
|
|
315
|
-
for (var opt in userOptions) {
|
|
316
|
-
options[opt] = userOptions[opt];
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
// Saves user defined options into the HTML5 storage (if available)
|
|
321
|
-
function saveOptions() {
|
|
322
|
-
if (supported('localStorage') && options.saving) {
|
|
323
|
-
localStorage.setItem('ADI.options', JSON.stringify(options));
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// Resets user defined options and removes them from the HTML5 storage
|
|
328
|
-
function resetOptions() {
|
|
329
|
-
if (supported('localStorage')) {
|
|
330
|
-
localStorage.removeItem('ADI.options');
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
// Returns CSS and JS paths to the element
|
|
335
|
-
// Result is an object with two variables (cssPath, jsPath) where cssPath is a string
|
|
336
|
-
// which holds the css path starting from the HTML element, and jsPath is an array which
|
|
337
|
-
// contains indexes for childNodes arrays (starting at document object).
|
|
338
|
-
//
|
|
339
|
-
// Inspired by the selector function from Rochester Oliveira's jQuery plugin
|
|
340
|
-
// http://rockingcode.com/tutorial/element-dom-tree-jquery-plugin-firebug-like-functionality/
|
|
341
|
-
function getElemPaths(elem) {
|
|
342
|
-
if (typeof elem !== 'object') {
|
|
343
|
-
throw "getElemPaths: Expected argument elem of type object, " + typeof elem + " given.";
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
var css = "",
|
|
347
|
-
js = "",
|
|
348
|
-
parent = "",
|
|
349
|
-
i, len;
|
|
350
|
-
|
|
351
|
-
while (elem !== document) {
|
|
352
|
-
parent = elem.parentNode;
|
|
353
|
-
|
|
354
|
-
// javascript selector
|
|
355
|
-
for (i = 0, len = parent.childNodes.length; i < len; ++i) {
|
|
356
|
-
if (parent.childNodes[i] === elem) {
|
|
357
|
-
js = i + "," + js;
|
|
358
|
-
break;
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// CSS selector
|
|
363
|
-
var cssTmp = elem.nodeName;
|
|
364
|
-
|
|
365
|
-
if (elem.id) {
|
|
366
|
-
cssTmp += '#' + elem.id;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
if (elem.className) {
|
|
370
|
-
// use classList if available
|
|
371
|
-
var classList = elem.classList || elem.className.split(' ');
|
|
372
|
-
|
|
373
|
-
for (i = 0, len = classList.length; i < len; ++i) {
|
|
374
|
-
cssTmp += '.' + classList[i];
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
css = cssTmp + ' ' + css;
|
|
379
|
-
elem = elem.parentNode;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
js = js.slice(0, -1).split(',');
|
|
383
|
-
|
|
384
|
-
return {
|
|
385
|
-
cssPath: css.toLowerCase(),
|
|
386
|
-
jsPath: js
|
|
387
|
-
};
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
// Checks if a node has some child nodes and if at least on of them is of a supported type
|
|
391
|
-
function hasRequiredNodes(node) {
|
|
392
|
-
if (typeof node !== 'object') {
|
|
393
|
-
throw "hasRequiredNodes: Expected argument node of type object, " + typeof node + " given.";
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
if (node.hasChildNodes()) {
|
|
397
|
-
for (var i = 0, len = node.childNodes.length; i < len; i++) {
|
|
398
|
-
if (options.nodeTypes.indexOf(node.childNodes[i].nodeType) !== -1) {
|
|
399
|
-
return true;
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
return false;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
// Checks whether the text node is not empty or contains only the EOL
|
|
408
|
-
function isEmptyTextNode(node) {
|
|
409
|
-
if (typeof node !== 'object') {
|
|
410
|
-
throw "isEmptyTextNode: Expected argument node of type object, " + typeof node + " given.";
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
return (/^\s*$/).test(node.textContent);
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
// Checks whether the node or its children contains only text information
|
|
417
|
-
function containsOnlyText(node, checkChildren) {
|
|
418
|
-
if (typeof node !== 'object') {
|
|
419
|
-
throw "containsOnlyText: Expected argument node of type object, " + typeof node + " given.";
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
checkChildren = checkChildren || false;
|
|
423
|
-
|
|
424
|
-
var result = false,
|
|
425
|
-
nodeTmp = null;
|
|
426
|
-
|
|
427
|
-
// does the node contain only text nodes?
|
|
428
|
-
if (checkChildren) {
|
|
429
|
-
for (var i = 0, len = node.childNodes.length; i < len; ++i) {
|
|
430
|
-
nodeTmp = node.childNodes[i];
|
|
431
|
-
result = nodeTmp.nodeType === Node.TEXT_NODE
|
|
432
|
-
|| nodeTmp.nodeType === Node.COMMENT_NODE
|
|
433
|
-
|| nodeTmp.nodeType === Node.CDATA_SECTION_NODE;
|
|
434
|
-
|
|
435
|
-
if (!result) {
|
|
436
|
-
break;
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
} else {
|
|
440
|
-
// check the node type if it doesn't have any children
|
|
441
|
-
result = node.nodeType === Node.TEXT_NODE
|
|
442
|
-
|| node.nodeType === Node.COMMENT_NODE
|
|
443
|
-
|| node.nodeType === Node.CDATA_SECTION_NODE;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
return result;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
// Creates a starting markup for a new DOM tree view node
|
|
450
|
-
function newTreeNode(node) {
|
|
451
|
-
if (typeof node !== 'object') {
|
|
452
|
-
throw "newTreeNode: Expected argument node of type object, " + typeof node + " given.";
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
var withChildren = hasRequiredNodes(node),
|
|
456
|
-
omit = false,
|
|
457
|
-
elem = newElement('li', {
|
|
458
|
-
class: (withChildren ? 'adi-node' : '')
|
|
459
|
-
});
|
|
460
|
-
|
|
461
|
-
// do not show ADI DOM nodes in the DOM view
|
|
462
|
-
if (node === uiView) {
|
|
463
|
-
return null;
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
// generate UI for elements with children
|
|
467
|
-
if (withChildren) {
|
|
468
|
-
elem.appendChild(newElement('span', { class: 'adi-trigger' }));
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
// we can omit empty text nodes if allowed in options
|
|
472
|
-
if (options.omitEmptyText && node.nodeType === Node.TEXT_NODE) {
|
|
473
|
-
omit = isEmptyTextNode(node);
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
if (!omit) {
|
|
477
|
-
var path = getElemPaths(node),
|
|
478
|
-
tagStart = newElement('span', {
|
|
479
|
-
'data-css-path' : path.cssPath,
|
|
480
|
-
'data-js-path' : JSON.stringify(path.jsPath)
|
|
481
|
-
}),
|
|
482
|
-
tagEnd = null;
|
|
483
|
-
|
|
484
|
-
if (containsOnlyText(node)) {
|
|
485
|
-
|
|
486
|
-
if (node.nodeType === Node.COMMENT_NODE) {
|
|
487
|
-
addClass(tagStart, 'adi-comment-node');
|
|
488
|
-
if (typeof tagStart.innerText === 'string') {
|
|
489
|
-
tagStart.innerText = '<!-- ' + node.textContent + ' -->';
|
|
490
|
-
} else {
|
|
491
|
-
tagStart.textContent = '<!-- ' + node.textContent + ' -->';
|
|
492
|
-
}
|
|
493
|
-
} else {
|
|
494
|
-
addClass(tagStart, 'adi-text-node');
|
|
495
|
-
tagStart.textContent = node.textContent;
|
|
496
|
-
}
|
|
497
|
-
} else {
|
|
498
|
-
addClass(tagStart, 'adi-normal-node');
|
|
499
|
-
if (node.nodeType !== Node.DOCUMENT_NODE) {
|
|
500
|
-
// tagStart.textContent = '<' + node.nodeName.toLowerCase() + '>';
|
|
501
|
-
|
|
502
|
-
if(node.nodeName === 'FX-BIND'){
|
|
503
|
-
tagStart.textContent = `<${node.nodeName.toLowerCase()} ref="${node.getAttribute('ref')}">`;
|
|
504
|
-
}else if(node.nodeName === 'FX-INSTANCE'){
|
|
505
|
-
tagStart.textContent = `<${node.nodeName.toLowerCase()} id="${node.id}">`;
|
|
506
|
-
}else if(node.nodeName === 'FX-CONTROL'){
|
|
507
|
-
tagStart.textContent = `<${node.nodeName.toLowerCase()} ref="${node.getAttribute('ref')}">`;
|
|
508
|
-
}else if(node.nodeName === 'FX-SEND'){
|
|
509
|
-
tagStart.textContent = `<${node.nodeName.toLowerCase()} submission="${node.getAttribute('submission')}">`;
|
|
510
|
-
}else{
|
|
511
|
-
tagStart.textContent = `<${node.nodeName.toLowerCase()}>`;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
if (withChildren) {
|
|
515
|
-
tagEnd = newElement('span');
|
|
516
|
-
addClass(tagEnd, 'adi-end-node');
|
|
517
|
-
tagEnd.textContent = '</' + node.nodeName.toLowerCase() + '>';
|
|
518
|
-
}
|
|
519
|
-
} else {
|
|
520
|
-
tagStart.textContent = node.nodeName.toLowerCase();
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
elem.appendChild(tagStart);
|
|
525
|
-
/*
|
|
526
|
-
const icon = document.createElement('span');
|
|
527
|
-
icon.textContent = 'x';
|
|
528
|
-
icon.classList.add(('icon'))
|
|
529
|
-
const icon2 = document.createElement('span');
|
|
530
|
-
icon2.textContent = '<-';
|
|
531
|
-
icon2.classList.add(('icon'))
|
|
532
|
-
elem.appendChild(icon);
|
|
533
|
-
elem.appendChild(icon2);
|
|
534
|
-
*/
|
|
535
|
-
if(node.nodeName.startsWith('FX-')){
|
|
536
|
-
tagStart.classList.add('fore-node');
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
if (tagEnd) {
|
|
540
|
-
elem.appendChild(tagEnd);
|
|
541
|
-
|
|
542
|
-
if(node.nodeName.startsWith('FX-')){
|
|
543
|
-
tagEnd.classList.add('fore-node');
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
return elem;
|
|
548
|
-
} else {
|
|
549
|
-
return null;
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
// Renders the DOM Tree view
|
|
554
|
-
function drawDOM(root, elem, isRoot) {
|
|
555
|
-
if (typeof root !== 'object') {
|
|
556
|
-
throw "drawDOM: Expected argument root of type object, " + typeof root + " given.";
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
var newNode = null,
|
|
560
|
-
isOpen = true;
|
|
561
|
-
|
|
562
|
-
if (isRoot && options.nodeTypes.indexOf(root.nodeType) !== -1) {
|
|
563
|
-
elem.innerHTML = '';
|
|
564
|
-
newNode = newTreeNode(root);
|
|
565
|
-
|
|
566
|
-
if (hasRequiredNodes(root)) {
|
|
567
|
-
newNode.appendChild(newElement('ul', { 'data-open' : true }));
|
|
568
|
-
addClass(newNode.querySelector('.adi-trigger'), 'opened');
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
elem.appendChild(newNode);
|
|
572
|
-
elem = elem.querySelector('ul');
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
// recursive DOM traversal
|
|
576
|
-
for (var i = 0, len = root.childNodes.length; i < len; ++i) {
|
|
577
|
-
var node = root.childNodes[i],
|
|
578
|
-
withChildren = hasRequiredNodes(node);
|
|
579
|
-
|
|
580
|
-
if (options.nodeTypes.indexOf(node.nodeType) !== -1) {
|
|
581
|
-
newNode = newTreeNode(node);
|
|
582
|
-
|
|
583
|
-
if (newNode) {
|
|
584
|
-
if (withChildren) {
|
|
585
|
-
if (options.foldText) {
|
|
586
|
-
isOpen = containsOnlyText(node, true) ? false : true;
|
|
587
|
-
} else {
|
|
588
|
-
isOpen = true;
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
if (node.nodeType === Node.DOCUMENT_NODE) {
|
|
592
|
-
newNode.appendChild(newElement('ul', { 'data-open' : isOpen }));
|
|
593
|
-
} else {
|
|
594
|
-
newNode.insertBefore(newElement('ul', { 'data-open' : isOpen }), newNode.lastChild);
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
addClass(newNode.querySelector('.adi-trigger'), isOpen ? 'opened' : 'closed');
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
elem.appendChild(newNode);
|
|
601
|
-
|
|
602
|
-
if (withChildren) {
|
|
603
|
-
drawDOM(node, newNode.querySelector('ul'), false);
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
// Show/hide the options view
|
|
611
|
-
function toggleOptions() {
|
|
612
|
-
if (optsView.className.indexOf('adi-hidden') !== -1) {
|
|
613
|
-
removeClass(optsView, 'adi-hidden');
|
|
614
|
-
} else {
|
|
615
|
-
addClass(optsView, 'adi-hidden');
|
|
616
|
-
pathView.textContent = '';
|
|
617
|
-
attrView.querySelector('.adi-content').innerHTML = '';
|
|
618
|
-
refreshUI();
|
|
619
|
-
drawDOM(document, domView.querySelector('.adi-tree-view'), true);
|
|
620
|
-
if (options.saving) {
|
|
621
|
-
saveOptions();
|
|
622
|
-
} else {
|
|
623
|
-
resetOptions();
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
// Helper function for options view
|
|
629
|
-
function drawOptionRow(optionCode, optionText) {
|
|
630
|
-
var row = newElement('span', { class: 'adi-opt' });
|
|
631
|
-
row.innerHTML = '<label><input type="checkbox" data-opt="' + optionCode + '">' + optionText + '</label>';
|
|
632
|
-
|
|
633
|
-
return row;
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
// Renders the options panel
|
|
637
|
-
function drawOptions() {
|
|
638
|
-
var ui = newElement('div', { id: 'adi-opts-view', class: 'adi-hidden' }),
|
|
639
|
-
head1 = newElement('span', { class: 'adi-opt-heading' }),
|
|
640
|
-
head2 = newElement('span', { class: 'adi-opt-heading' }),
|
|
641
|
-
close = newElement('span', { class: 'adi-opt-close' });
|
|
642
|
-
|
|
643
|
-
head1.textContent = 'General options';
|
|
644
|
-
head2.textContent = 'Observed nodes';
|
|
645
|
-
|
|
646
|
-
ui.appendChild(head1);
|
|
647
|
-
ui.appendChild(drawOptionRow('saving', 'Enable saving of settings'));
|
|
648
|
-
ui.appendChild(drawOptionRow('makeVisible', 'Scroll to the active element in DOM View'));
|
|
649
|
-
ui.appendChild(drawOptionRow('omitEmptyText', 'Hide empty text nodes'));
|
|
650
|
-
ui.appendChild(drawOptionRow('foldText', 'Fold the text nodes'));
|
|
651
|
-
ui.appendChild(drawOptionRow('transparent', 'Enable transparent background'));
|
|
652
|
-
ui.appendChild(head2);
|
|
653
|
-
ui.appendChild(drawOptionRow('nodeTypes-3', 'Text node'));
|
|
654
|
-
ui.appendChild(drawOptionRow('nodeTypes-8', 'Comment node'));
|
|
655
|
-
// ui.appendChild(drawOptionRow('nodeTypes-1', 'Element node'));
|
|
656
|
-
// ui.appendChild(drawOptionRow('nodeTypes-9', 'Document node'));
|
|
657
|
-
ui.appendChild(close);
|
|
658
|
-
|
|
659
|
-
return ui;
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
// Renders the UI
|
|
663
|
-
function drawUI() {
|
|
664
|
-
var wrapper = newElement('div', {
|
|
665
|
-
id: 'adi-wrapper',
|
|
666
|
-
class: options.transparent ? 'transparent' : ''
|
|
667
|
-
}),
|
|
668
|
-
domViewWrap = newElement('div', { id: 'adi-dom-view' }),
|
|
669
|
-
domViewContent = newElement('div', { class: 'adi-content' }),
|
|
670
|
-
attrViewWrap = newElement('div', { id: 'adi-attr-view' }),
|
|
671
|
-
attrViewContent = newElement('div', { class: 'adi-content' }),
|
|
672
|
-
horizSplit = newElement('div', { id: 'adi-horiz-split' }),
|
|
673
|
-
vertSplit = newElement('div', { id: 'adi-vert-split' }),
|
|
674
|
-
domTree = newElement('ul', { class: 'adi-tree-view' }),
|
|
675
|
-
domPathWrap = newElement('div', { class: 'adi-path-wrap' }),
|
|
676
|
-
domPath = newElement('div', { class: 'adi-path' }),
|
|
677
|
-
domPathScrollLeft = newElement('span', { class: 'adi-path-left' }),
|
|
678
|
-
domPathScrollRight = newElement('span', { class: 'adi-path-right' }),
|
|
679
|
-
naviWrap = newElement('div', { id: 'adi-panel' }),
|
|
680
|
-
naviButtons = newElement('div', { class: 'adi-menu-wrap' }),
|
|
681
|
-
naviConfig = newElement('a', { class: 'adi-menu-config', title: 'Settings' }),
|
|
682
|
-
naviLookup = newElement('a', { class: 'adi-menu-lookup', title: 'Lookup tool' }),
|
|
683
|
-
optionsView = drawOptions();
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
// put UI together
|
|
687
|
-
domViewContent.appendChild(domTree);
|
|
688
|
-
domViewWrap.appendChild(domViewContent);
|
|
689
|
-
attrViewWrap.appendChild(attrViewContent);
|
|
690
|
-
domPathWrap.appendChild(domPath);
|
|
691
|
-
domPathWrap.appendChild(domPathScrollLeft);
|
|
692
|
-
domPathWrap.appendChild(domPathScrollRight);
|
|
693
|
-
naviButtons.appendChild(naviLookup);
|
|
694
|
-
naviButtons.appendChild(naviConfig);
|
|
695
|
-
naviWrap.appendChild(domPathWrap);
|
|
696
|
-
naviWrap.appendChild(naviButtons);
|
|
697
|
-
wrapper.appendChild(naviWrap);
|
|
698
|
-
wrapper.appendChild(optionsView);
|
|
699
|
-
wrapper.appendChild(domViewWrap);
|
|
700
|
-
wrapper.appendChild(horizSplit);
|
|
701
|
-
wrapper.appendChild(attrViewWrap);
|
|
702
|
-
// wrapper.appendChild(naviWrap);
|
|
703
|
-
wrapper.appendChild(vertSplit);
|
|
704
|
-
|
|
705
|
-
// cache UI object and append to the DOM
|
|
706
|
-
|
|
707
|
-
// #### here it attaches to the body
|
|
708
|
-
document.getElementsByTagName('body')[0].appendChild(wrapper);
|
|
709
|
-
// document.querySelector('#inspector').appendChild(wrapper);
|
|
710
|
-
|
|
711
|
-
uiView = wrapper;
|
|
712
|
-
menuView = naviWrap;
|
|
713
|
-
domView = uiView.querySelector('#adi-dom-view');
|
|
714
|
-
attrView = uiView.querySelector('#adi-attr-view');
|
|
715
|
-
|
|
716
|
-
const adiPanel = attrView.querySelector('.adi-content');
|
|
717
|
-
adiPanel.setAttribute('id','detailsView');
|
|
718
|
-
|
|
719
|
-
pathView = domPath;
|
|
720
|
-
optsView = optionsView;
|
|
721
|
-
refreshUI(true);
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
// Refreshes the global UI
|
|
725
|
-
function refreshUI(refreshOpts) {
|
|
726
|
-
if (uiView === null) {
|
|
727
|
-
return false;
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
// load options if requested (e.g. before the first UI refresh)
|
|
731
|
-
if (refreshOpts) {
|
|
732
|
-
loadOptions();
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
// Options view refresh
|
|
736
|
-
if (refreshOpts) {
|
|
737
|
-
optsView.querySelector('[data-opt="transparent"]').checked = options.transparent;
|
|
738
|
-
optsView.querySelector('[data-opt="saving"]').checked = options.saving;
|
|
739
|
-
optsView.querySelector('[data-opt="omitEmptyText"]').checked = options.omitEmptyText;
|
|
740
|
-
optsView.querySelector('[data-opt="makeVisible"]').checked = options.makeVisible;
|
|
741
|
-
optsView.querySelector('[data-opt="foldText"]').checked = options.foldText;
|
|
742
|
-
optsView.querySelector('[data-opt="nodeTypes-3"]').checked = options.nodeTypes.indexOf(3) !== -1;
|
|
743
|
-
optsView.querySelector('[data-opt="nodeTypes-8"]').checked = options.nodeTypes.indexOf(8) !== -1;
|
|
744
|
-
// optsView.querySelector('[data-opt="nodeTypes-1"]').checked = options.nodeTypes.indexOf(1) !== -1;
|
|
745
|
-
// optsView.querySelector('[data-opt="nodeTypes-9"]').checked = options.nodeTypes.indexOf(9) !== -1;
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
// UI appearance refresh
|
|
749
|
-
uiView.className = options.transparent ? 'transparent' : '';
|
|
750
|
-
uiView.style.display = options.visible ? 'block' : 'none';
|
|
751
|
-
uiView.style.width = options.width + 'px';
|
|
752
|
-
menuView.style.width = options.width + 'px';
|
|
753
|
-
domView.style.height = options.split + '%';
|
|
754
|
-
attrView.style.height = (100 - options.split) + '%';
|
|
755
|
-
domView.querySelector('.adi-content').style.height = domView.clientHeight + 'px';
|
|
756
|
-
attrView.querySelector('.adi-content').style.height = (attrView.clientHeight - menuView.clientHeight) + 'px';
|
|
757
|
-
addClass(uiView, options.align);
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
// UI visibility toggle handler
|
|
761
|
-
function toggleVisibilityUI() {
|
|
762
|
-
if (uiView === null) {
|
|
763
|
-
return false;
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
uiView.style.display = options.visible ? 'none' : 'block';
|
|
767
|
-
options.visible = !options.visible;
|
|
768
|
-
saveOptions();
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
// Helper function for attributes view
|
|
772
|
-
function drawAttrRow(attrName, attrValue) {
|
|
773
|
-
var row = newElement('span', { class: 'adi-attr' });
|
|
774
|
-
switch (attrName.toLowerCase()) {
|
|
775
|
-
case 'defaultaction':
|
|
776
|
-
row.innerHTML = '<label>' + attrName + ': <select data-attr="' + attrName + '" value="' + attrValue + '"><option>perform</option><option>cancel</option></label>';
|
|
777
|
-
break;
|
|
778
|
-
case 'delay':
|
|
779
|
-
row.innerHTML = '<label>' + attrName + ': <input type="number" data-attr="' + attrName + '" value="' + attrValue + '"></label>';
|
|
780
|
-
break;
|
|
781
|
-
default:
|
|
782
|
-
row.innerHTML = '<label>' + attrName + ': <input type="text" data-attr="' + attrName + '" value="' + attrValue + '"></label>';
|
|
783
|
-
}
|
|
784
|
-
return row;
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
// Renders the attribute view
|
|
788
|
-
function drawAttrs(elem) {
|
|
789
|
-
|
|
790
|
-
//todo: hook element-def.json in here
|
|
791
|
-
if(elem.nodeName.startsWith('FX-')){
|
|
792
|
-
console.log('got a fore element')
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
if (typeof elem !== 'object') {
|
|
796
|
-
throw "drawAttrs: Expected argument elem of type object, " + typeof elem + " given.";
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
var content = attrView.querySelector('.adi-content'),
|
|
800
|
-
attrsMain = {
|
|
801
|
-
'id': '',
|
|
802
|
-
'class': '',
|
|
803
|
-
'style': ''
|
|
804
|
-
},
|
|
805
|
-
attrsOther = {},
|
|
806
|
-
keys = [],
|
|
807
|
-
attr, i, len;
|
|
808
|
-
|
|
809
|
-
// prepare attributes
|
|
810
|
-
content.innerHTML = '';
|
|
811
|
-
for (i = 0, len = elem.attributes.length; i < len; ++i) {
|
|
812
|
-
attr = elem.attributes[i];
|
|
813
|
-
|
|
814
|
-
switch (attr.nodeName.toLowerCase()) {
|
|
815
|
-
case 'id':
|
|
816
|
-
attrsMain['id'] = attr.nodeValue;
|
|
817
|
-
break;
|
|
818
|
-
case 'class':
|
|
819
|
-
attrsMain['class'] = attr.nodeValue;
|
|
820
|
-
break;
|
|
821
|
-
case 'style':
|
|
822
|
-
attrsMain['style'] = styleBackup;
|
|
823
|
-
break;
|
|
824
|
-
default:
|
|
825
|
-
attrsOther[attr.nodeName.toLowerCase()] = attr.nodeValue;
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
if(elem.nodeName.startsWith('FX-')){
|
|
830
|
-
switch (elem.nodeName) {
|
|
831
|
-
case 'FX-BIND':
|
|
832
|
-
attrsOther['calculate'] = attrsOther['calculate'] || '';
|
|
833
|
-
attrsOther['constraint'] = attrsOther['constraint'] || '';
|
|
834
|
-
attrsOther['readonly'] = attrsOther['readonly'] || '';
|
|
835
|
-
attrsOther['relevant'] = attrsOther['relevant'] || '';
|
|
836
|
-
attrsOther['required'] = attrsOther['required'] || '';
|
|
837
|
-
break;
|
|
838
|
-
case 'FX-MESSAGE':
|
|
839
|
-
case 'FX-SEND':
|
|
840
|
-
case 'FX-ACTION':
|
|
841
|
-
attrsOther['defaultaction'] = attrsOther['defaultaction'] || '';
|
|
842
|
-
attrsOther['delay'] = attrsOther['delay'] || '';
|
|
843
|
-
attrsOther['event'] = attrsOther['event'] || '';
|
|
844
|
-
attrsOther['handler'] = attrsOther['handler'] || '';
|
|
845
|
-
attrsOther['if'] = attrsOther['if'] || '';
|
|
846
|
-
attrsOther['phase'] = attrsOther['phase'] || '';
|
|
847
|
-
attrsOther['propagate'] = attrsOther['propagate'] || '';
|
|
848
|
-
attrsOther['target'] = attrsOther['target'] || '';
|
|
849
|
-
attrsOther['while'] = attrsOther['while'] || '';
|
|
850
|
-
break;
|
|
851
|
-
default:
|
|
852
|
-
attrsOther[attr.nodeName.toLowerCase()] = attr.nodeValue;
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
// sort attributes
|
|
857
|
-
for (var key in attrsOther) {
|
|
858
|
-
keys.push(key);
|
|
859
|
-
}
|
|
860
|
-
keys.sort();
|
|
861
|
-
|
|
862
|
-
// render the content
|
|
863
|
-
content.appendChild(drawAttrRow('id', attrsMain['id']));
|
|
864
|
-
content.appendChild(drawAttrRow('class', attrsMain['class']));
|
|
865
|
-
content.appendChild(drawAttrRow('style', attrsMain['style']));
|
|
866
|
-
content.appendChild(newElement('hr'));
|
|
867
|
-
|
|
868
|
-
for (i = 0, len = keys.length; i < len; ++i) {
|
|
869
|
-
content.appendChild(drawAttrRow(keys[i], attrsOther[keys[i]]));
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
// Handles attribute changes
|
|
874
|
-
function changeAttribute(e) {
|
|
875
|
-
var target = e ? e.target : window.event.srcElement,
|
|
876
|
-
attr = target.getAttribute('data-attr'),
|
|
877
|
-
val = target.value,
|
|
878
|
-
elem = getSelected();
|
|
879
|
-
|
|
880
|
-
// remove attribute if the new value is empty
|
|
881
|
-
if (val === '') {
|
|
882
|
-
elem.removeAttribute(attr);
|
|
883
|
-
} else {
|
|
884
|
-
elem.setAttribute(attr, val);
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
// Handles option changes
|
|
889
|
-
function changeOption(e) {
|
|
890
|
-
var target = e ? e.target : window.event.srcElement,
|
|
891
|
-
data = target.getAttribute('data-opt'),
|
|
892
|
-
val = target.checked;
|
|
893
|
-
|
|
894
|
-
if (data.indexOf('nodeTypes') !== -1) {
|
|
895
|
-
var type = parseInt(data.match(/\d+/)[0]);
|
|
896
|
-
|
|
897
|
-
if (val) {
|
|
898
|
-
options.nodeTypes.push(type);
|
|
899
|
-
} else {
|
|
900
|
-
options.nodeTypes.splice(options.nodeTypes.indexOf(type), 1);
|
|
901
|
-
}
|
|
902
|
-
} else {
|
|
903
|
-
options[data] = val;
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
// Key events processing
|
|
908
|
-
function processKey(e) {
|
|
909
|
-
e = e || window.event;
|
|
910
|
-
var code = e.keyCode || e.which;
|
|
911
|
-
|
|
912
|
-
switch (code) {
|
|
913
|
-
case 272: // ctrl + alt + d
|
|
914
|
-
toggleVisibilityUI();
|
|
915
|
-
break;
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
// Vertical splitter resize handler
|
|
920
|
-
function verticalResize(e) {
|
|
921
|
-
if (!vertResizing) {
|
|
922
|
-
return;
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
e = e || window.event;
|
|
926
|
-
document.documentElement.style.cursor = 'e-resize';
|
|
927
|
-
var nWidth = options.width + xPos - e.clientX;
|
|
928
|
-
|
|
929
|
-
if (nWidth >= options.minWidth) {
|
|
930
|
-
options.width = nWidth;
|
|
931
|
-
xPos = e.clientX;
|
|
932
|
-
refreshUI();
|
|
933
|
-
saveOptions();
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
checkPathOverflow();
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
// Horizontal splitter resize handler
|
|
940
|
-
function horizontalResize(e) {
|
|
941
|
-
if (!horizResizing) {
|
|
942
|
-
return;
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
e = e || window.event;
|
|
946
|
-
document.documentElement.style.cursor = 'n-resize';
|
|
947
|
-
var nSplit = Math.floor(e.clientY / uiView.clientHeight * 100);
|
|
948
|
-
|
|
949
|
-
if (nSplit >= options.minSplit && nSplit <= 100 - options.minSplit) {
|
|
950
|
-
options.split = nSplit;
|
|
951
|
-
refreshUI();
|
|
952
|
-
saveOptions();
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
// Dom view folding handler
|
|
957
|
-
function handleFolding(e) {
|
|
958
|
-
var target = e ? e.target : window.event.srcElement,
|
|
959
|
-
ul = target.parentNode.querySelector('ul');
|
|
960
|
-
|
|
961
|
-
if (ul.getAttribute('data-open') === "true") {
|
|
962
|
-
removeClass(target, 'opened');
|
|
963
|
-
addClass(target, 'closed');
|
|
964
|
-
ul.setAttribute('data-open', "false");
|
|
965
|
-
} else {
|
|
966
|
-
removeClass(target, 'closed');
|
|
967
|
-
addClass(target, 'opened');
|
|
968
|
-
ul.setAttribute('data-open', "true");
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
// Handles active element selection
|
|
973
|
-
function handleActive(e) {
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
var target = e ? e.target : window.event.srcElement,
|
|
977
|
-
active = domView.querySelector('.adi-active-node');
|
|
978
|
-
|
|
979
|
-
if (active) {
|
|
980
|
-
removeClass(active, 'adi-active-node');
|
|
981
|
-
}
|
|
982
|
-
|
|
983
|
-
// clicked on normal-node or end-node?
|
|
984
|
-
if (target.className === 'adi-end-node') {
|
|
985
|
-
target = target.parentNode.querySelector('.adi-normal-node');
|
|
986
|
-
}
|
|
987
|
-
|
|
988
|
-
activeElement = target;
|
|
989
|
-
addClass(target, 'adi-active-node');
|
|
990
|
-
pathView.textContent = target.getAttribute('data-css-path');
|
|
991
|
-
|
|
992
|
-
this.dispatchEvent(
|
|
993
|
-
new CustomEvent('handle-active', {
|
|
994
|
-
composed: true,
|
|
995
|
-
bubbles: true,
|
|
996
|
-
detail: { active: activeElement, selected: getSelected()},
|
|
997
|
-
}),
|
|
998
|
-
);
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
// make it visible (scroll)
|
|
1002
|
-
if (options.makeVisible) {
|
|
1003
|
-
var wrap = domView.querySelector('.adi-content');
|
|
1004
|
-
if (target.offsetTop >= wrap.clientHeight || target.offsetTop <= wrap.scrollTop) {
|
|
1005
|
-
wrap.scrollTop = target.offsetTop - (Math.floor(wrap.clientHeight / 2));
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
|
|
1009
|
-
checkPathOverflow();
|
|
1010
|
-
drawAttrs(getSelected());
|
|
1011
|
-
const fore = document.createElement('fx-fore');
|
|
1012
|
-
fore.setAttribute('src','inspector/inspector.html');
|
|
1013
|
-
// const detailsView = document.getElementById('detailsView');
|
|
1014
|
-
// detailsView.appendChild(fore);
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
// Checks if pathView is overflowing or not
|
|
1018
|
-
function checkPathOverflow() {
|
|
1019
|
-
if (pathView.scrollWidth > pathView.clientWidth) {
|
|
1020
|
-
addClass(pathView.parentNode, 'adi-overflowing');
|
|
1021
|
-
} else {
|
|
1022
|
-
removeClass(pathView.parentNode, 'adi-overflowing');
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
// Handles scroll behavior for overflowing pathView
|
|
1027
|
-
function scrollPathView(e) {
|
|
1028
|
-
var target = e ? e.target : window.event.srcElement,
|
|
1029
|
-
maxScroll = pathView.scrollWidth - pathView.clientWidth,
|
|
1030
|
-
scroll = pathView.scrollLeft,
|
|
1031
|
-
change = 5;
|
|
1032
|
-
|
|
1033
|
-
if (target.className === "adi-path-right") {
|
|
1034
|
-
pathView.scrollLeft = (scroll <= maxScroll - change) ? scroll + change : maxScroll;
|
|
1035
|
-
} else {
|
|
1036
|
-
pathView.scrollLeft = (scroll - change >= 0) ? scroll - change : 0;
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
if (!pathScrolling) {
|
|
1040
|
-
pathScrolling = setInterval(scrollPathView, 20, e);
|
|
1041
|
-
}
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
|
-
// Highlights an element on page
|
|
1045
|
-
function highlightElement(e) {
|
|
1046
|
-
var target = e ? e.target : window.event.srcElement,
|
|
1047
|
-
node = document,
|
|
1048
|
-
path;
|
|
1049
|
-
|
|
1050
|
-
if (target.className === 'adi-end-node') {
|
|
1051
|
-
target = target.parentNode.querySelector('.adi-normal-node');
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
|
-
path = JSON.parse(target.getAttribute('data-js-path'));
|
|
1055
|
-
|
|
1056
|
-
// find the element
|
|
1057
|
-
for (var i = 0, len = path.length; i < len; ++i) {
|
|
1058
|
-
node = node.childNodes[path[i]];
|
|
1059
|
-
}
|
|
1060
|
-
|
|
1061
|
-
if (node) {
|
|
1062
|
-
if (e.type === 'mouseover') {
|
|
1063
|
-
styleBackup = node.getAttribute('style') || '';
|
|
1064
|
-
node.setAttribute('style', 'outline: 1px dashed red; ' + styleBackup);
|
|
1065
|
-
} else {
|
|
1066
|
-
if (styleBackup === '') {
|
|
1067
|
-
node.removeAttribute('style');
|
|
1068
|
-
} else {
|
|
1069
|
-
node.setAttribute('style', styleBackup);
|
|
1070
|
-
}
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1073
|
-
}
|
|
1074
|
-
|
|
1075
|
-
// Handles element lookup on page
|
|
1076
|
-
function handleLookup(e) {
|
|
1077
|
-
var target = e ? e.target : window.event.srcElement;
|
|
1078
|
-
|
|
1079
|
-
if (target.className.indexOf('adi-menu-lookup') !== -1) {
|
|
1080
|
-
// enable/disable interactive lookup
|
|
1081
|
-
if (elemLookup) {
|
|
1082
|
-
removeClass(target, 'adi-active');
|
|
1083
|
-
elemLookup = false;
|
|
1084
|
-
removeEvent(document.body, 'mouseover', handleLookup, true);
|
|
1085
|
-
removeEvent(document.body, 'mouseout', handleLookup, true);
|
|
1086
|
-
removeEvent(document.body, 'click', handleLookup, true);
|
|
1087
|
-
} else {
|
|
1088
|
-
addClass(target, 'adi-active');
|
|
1089
|
-
elemLookup = true;
|
|
1090
|
-
addEventDelegate(document.body, 'mouseover', handleLookup, false, '*', true, 'adi-wrapper');
|
|
1091
|
-
addEventDelegate(document.body, 'mouseout', handleLookup, false, '*', true, 'adi-wrapper');
|
|
1092
|
-
addEventDelegate(document.body, 'click', handleLookup, false, '*', true, 'adi-wrapper');
|
|
1093
|
-
}
|
|
1094
|
-
} else {
|
|
1095
|
-
// handle lookup events
|
|
1096
|
-
if (e.type === 'mouseover') {
|
|
1097
|
-
styleBackup = target.getAttribute('style') || '';
|
|
1098
|
-
target.setAttribute('style', 'outline: 1px dashed red; ' + styleBackup);
|
|
1099
|
-
} else if (e.type === 'mouseout') {
|
|
1100
|
-
target.setAttribute('style', styleBackup);
|
|
1101
|
-
} else {
|
|
1102
|
-
elemLookup = false;
|
|
1103
|
-
removeClass(menuView.querySelector('.adi-menu-lookup'), 'adi-active');
|
|
1104
|
-
target.setAttribute('style', styleBackup);
|
|
1105
|
-
removeEvent(document.body, 'mouseover', handleLookup, true);
|
|
1106
|
-
removeEvent(document.body, 'mouseout', handleLookup, true);
|
|
1107
|
-
removeEvent(document.body, 'click', handleLookup, true);
|
|
1108
|
-
pauseEvent(e);
|
|
1109
|
-
|
|
1110
|
-
// find corresponding node in the DOM view
|
|
1111
|
-
var path = getElemPaths(target),
|
|
1112
|
-
active = domView.querySelector('[data-js-path=\'' + JSON.stringify(path.jsPath) + '\']');
|
|
1113
|
-
|
|
1114
|
-
// activate it
|
|
1115
|
-
if (active) {
|
|
1116
|
-
active.click();
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
|
-
// open the whole path in DOM view
|
|
1120
|
-
var node = active.parentNode,
|
|
1121
|
-
tmp;
|
|
1122
|
-
|
|
1123
|
-
if (node.querySelector('ul')) {
|
|
1124
|
-
node.querySelector('ul').setAttribute('data-open', 'true');
|
|
1125
|
-
}
|
|
1126
|
-
while(node !== domView.querySelector('.adi-content')) {
|
|
1127
|
-
if (node.className.indexOf('adi-node') !== -1) {
|
|
1128
|
-
tmp = node.querySelector('.adi-trigger');
|
|
1129
|
-
removeClass(tmp, 'closed');
|
|
1130
|
-
addClass(tmp, 'opened');
|
|
1131
|
-
|
|
1132
|
-
node = node.parentNode; // ul node
|
|
1133
|
-
node.setAttribute('data-open', 'true');
|
|
1134
|
-
}
|
|
1135
|
-
|
|
1136
|
-
node = node.parentNode;
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
|
-
// make it visible (scroll)
|
|
1140
|
-
if (options.makeVisible) {
|
|
1141
|
-
var wrap = domView.querySelector('.adi-content');
|
|
1142
|
-
if (active.offsetTop >= wrap.clientHeight || active.offsetTop <= wrap.scrollTop) {
|
|
1143
|
-
wrap.scrollTop = active.offsetTop - (Math.floor(wrap.clientHeight / 2));
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
}
|
|
1147
|
-
}
|
|
1148
|
-
}
|
|
1149
|
-
|
|
1150
|
-
// Event registration
|
|
1151
|
-
function registerEvents() {
|
|
1152
|
-
var vertSplit = document.getElementById('adi-vert-split'),
|
|
1153
|
-
horizSplit = document.getElementById('adi-horiz-split');
|
|
1154
|
-
|
|
1155
|
-
// events for splitters
|
|
1156
|
-
addEvent(vertSplit, 'mousedown', function(e) {
|
|
1157
|
-
e = e || window.event;
|
|
1158
|
-
pauseEvent(e);
|
|
1159
|
-
vertResizing = true;
|
|
1160
|
-
xPos = e.clientX;
|
|
1161
|
-
}, false);
|
|
1162
|
-
|
|
1163
|
-
addEvent(horizSplit, 'mousedown', function(e) {
|
|
1164
|
-
e = e || window.event;
|
|
1165
|
-
pauseEvent(e);
|
|
1166
|
-
horizResizing = true;
|
|
1167
|
-
}, false);
|
|
1168
|
-
|
|
1169
|
-
addEvent(document, 'mouseup', function() {
|
|
1170
|
-
document.documentElement.style.cursor = 'default';
|
|
1171
|
-
vertResizing = false;
|
|
1172
|
-
horizResizing = false;
|
|
1173
|
-
}, false);
|
|
1174
|
-
|
|
1175
|
-
addEvent(document, 'mousemove', verticalResize, false);
|
|
1176
|
-
addEvent(document, 'mousemove', horizontalResize, false);
|
|
1177
|
-
|
|
1178
|
-
// window resize
|
|
1179
|
-
addEvent(window, 'resize', refreshUI, false);
|
|
1180
|
-
|
|
1181
|
-
// keypress events
|
|
1182
|
-
addEvent(document, 'keypress', processKey, false);
|
|
1183
|
-
|
|
1184
|
-
// dom tree view folding
|
|
1185
|
-
addEventDelegate(domView, 'click', handleFolding, false, '.adi-trigger');
|
|
1186
|
-
|
|
1187
|
-
// active element
|
|
1188
|
-
addEventDelegate(domView, 'click', handleActive, false, '.adi-normal-node');
|
|
1189
|
-
addEventDelegate(domView, 'click', handleActive, false, '.adi-end-node');
|
|
1190
|
-
|
|
1191
|
-
// path view scrolling
|
|
1192
|
-
addEventDelegate(pathView.parentNode, 'mousedown', scrollPathView, false, '.adi-path-left');
|
|
1193
|
-
addEventDelegate(pathView.parentNode, 'mousedown', scrollPathView, false, '.adi-path-right');
|
|
1194
|
-
addEventDelegate(pathView.parentNode, 'mouseup', function() {
|
|
1195
|
-
clearInterval(pathScrolling);
|
|
1196
|
-
pathScrolling = false;
|
|
1197
|
-
}, false, '.adi-path-left');
|
|
1198
|
-
addEventDelegate(pathView.parentNode, 'mouseup', function() {
|
|
1199
|
-
clearInterval(pathScrolling);
|
|
1200
|
-
pathScrolling = false;
|
|
1201
|
-
}, false, '.adi-path-right');
|
|
1202
|
-
|
|
1203
|
-
// matching tag highlighting
|
|
1204
|
-
addEventDelegate(domView, 'mouseover', function(e) {
|
|
1205
|
-
var target = e ? e.target : window.event.srcElement;
|
|
1206
|
-
addClass(target.parentNode.querySelector('.adi-normal-node'), 'hover');
|
|
1207
|
-
}, false, '.adi-end-node');
|
|
1208
|
-
addEventDelegate(domView, 'mouseout', function(e) {
|
|
1209
|
-
var target = e ? e.target : window.event.srcElement;
|
|
1210
|
-
removeClass(target.parentNode.querySelector('.adi-normal-node'), 'hover');
|
|
1211
|
-
}, false, '.adi-end-node');
|
|
1212
|
-
|
|
1213
|
-
// page element highlighting
|
|
1214
|
-
addEventDelegate(domView, 'mouseover', highlightElement, false, '.adi-end-node');
|
|
1215
|
-
addEventDelegate(domView, 'mouseover', highlightElement, false, '.adi-normal-node');
|
|
1216
|
-
addEventDelegate(domView, 'mouseout', highlightElement, false, '.adi-end-node');
|
|
1217
|
-
addEventDelegate(domView, 'mouseout', highlightElement, false, '.adi-normal-node');
|
|
1218
|
-
|
|
1219
|
-
// element lookup
|
|
1220
|
-
addEvent(menuView.querySelector('.adi-menu-lookup'), 'click', handleLookup, false);
|
|
1221
|
-
|
|
1222
|
-
// options events
|
|
1223
|
-
addEventDelegate(optsView, 'change', changeOption, false, 'input');
|
|
1224
|
-
addEventDelegate(optsView, 'click', toggleOptions, false, '.adi-opt-close');
|
|
1225
|
-
addEvent(menuView.querySelector('.adi-menu-config'), 'click', toggleOptions, false);
|
|
1226
|
-
|
|
1227
|
-
// attributes events
|
|
1228
|
-
addEventDelegate(attrView, 'change', changeAttribute, false, 'input');
|
|
1229
|
-
}
|
|
1230
|
-
|
|
1231
|
-
drawUI();
|
|
1232
|
-
registerEvents();
|
|
1233
|
-
drawDOM(document, domView.querySelector('.adi-tree-view'), true);
|
|
1234
|
-
|
|
1235
|
-
return {
|
|
1236
|
-
// TODO: public methods and variables (this will be visible to the global scope)
|
|
1237
|
-
getSelectedElement: getSelected,
|
|
1238
|
-
toggle: toggleVisibilityUI
|
|
1239
|
-
};
|
|
1240
|
-
})();
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
appInit() {
|
|
1244
|
-
// make public API visible to the global scope
|
|
1245
|
-
window.ADI = ADI;
|
|
1246
|
-
|
|
1247
|
-
}
|
|
1248
|
-
|
|
1249
|
-
// Launch the app when the DOM is ready and all assets are loaded
|
|
1250
|
-
addEvent(window, 'load', appInit, false);
|
|
1251
|
-
|
|
1252
|
-
}
|
|
1253
|
-
if (!customElements.get('fx-dom-inspector')) {
|
|
1254
|
-
customElements.define('fx-dom-inspector', FxDomInspector);
|
|
1255
|
-
}
|