Completed
Push — master ( 8fc280...7b9442 )
by Dongxin
01:15
created

mjsonviewer.js (14 issues)

1
//////////////////////////////////////////////////////////////////////////////////////
2
// Copyright © 2017 TangDongxin
3
//
4
// Permission is hereby granted, free of charge, to any person obtaining
5
// a copy of this software and associated documentation files (the "Software"),
6
// to deal in the Software without restriction, including without limitation
7
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
// and/or sell copies of the Software, and to permit persons to whom the
9
// Software is furnished to do so, subject to the following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
20
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
//////////////////////////////////////////////////////////////////////////////////////
22
23
!function() {
24
    var str, jsonpMatch, hovered, tag,
25
        chrome = this.chrome || this.browser,
26
        jsonRe = /^\s*(?:\[\s*(?=-?\d|true|false|null|["[{])[^]*\]|\{\s*"[^]+\})\s*$/,
27
        div    = document.createElement("div"),
28
        body   = document.body,
29
        first  = body && body.firstChild,
30
        mod    = /Mac|iPod|iPhone|iPad|Pike/.test(navigator.platform) ? "metaKey" : "ctrlKey",
0 ignored issues
show
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
31
        rand   = Math.random().toString(36).slice(2),
32
        HOV    = "H" + rand,
33
        DIV    = "D" + rand,
34
        KEY    = "K" + rand,
35
        STR    = "S" + rand,
36
        BOOL   = "B" + rand,
37
        ERR    = "E" + rand,
38
        COLL   = "C" + rand;
39
40
    function reconvert(str){
41
        str = str.replace(/(\\u)(\w{1,4})/gi, function($0) {
42
            return (String.fromCharCode(parseInt((escape($0).replace(/(%5Cu)(\w{1,4})/g, "$2")), 16)));
43
        });
44
        str = str.replace(/(&#x)(\w{1,4});/gi, function($0) {
45
            return String.fromCharCode(parseInt(escape($0).replace(/(%26%23x)(\w{1,4})(%3B)/g, "$2"),16));
46
        });
47
        str = str.replace(/(&#)(\d{1,6});/gi, function($0) {
48
            return String.fromCharCode(parseInt(escape($0).replace(/(%26%23)(\d{1,6})(%3B)/g, "$2")));
49
        });
50
51
        return str;
52
    }
53
54
    function units(size) {
55
        return size > 1048576 ? (0|(size / 1048576)) + "MB" :
56
            size > 1024 ? (0|(size / 1024)) + "KB" :
57
            size + "B";
58
    }
59
60
    function fragment(a, b) {
61
        var frag = document.createDocumentFragment();
62
        frag.appendChild(document.createTextNode(a));
63
        if (b) {
64
            frag.appendChild(div.cloneNode());
65
            frag.appendChild(document.createTextNode(b));
66
        } else {
67
            frag.appendChild(document.createElement("br"));
68
        }
69
        return frag;
70
    }
71
72
    function change(node, query, name, set) {
73
        var list = node.querySelectorAll(query), i = list.length;
74
        for (; i--; ) list[i].classList[set ? "add" : "remove"](name);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
75
    }
76
77
    function changeSiblings(node, name, set) {
78
        var tmp, i = 0, query = [];
79
80
        for (; node && node.tagName === "I"; ) {
81
            tmp = node.previousElementSibling;
82
            if (tmp && tmp.className == KEY) {
83
                query.unshift(".D" + rand + ">i.I" + rand + "[data-key='" + node.dataset.key + "']");
84
            } else if (query[0]) {
85
                query.unshift(".D" + rand + ">i.I" + rand);
86
            } else {
87
                for (; tmp; tmp = tmp.previousElementSibling) if (tmp.tagName === "BR") i++;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
88
                query.unshift(".D" + rand + ">" + (i ? "br:nth-of-type(" + i + ")+i.I" + rand : "i.I" + rand + ":first-child"));
89
            }
90
            node = node.parentNode && node.parentNode.previousElementSibling;
91
        }
92
        if (!query[1]) return;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
93
        query[0] = ".R" + rand + ">i.I" + rand;
94
        change(document, query.join("+"), name, set);
95
    }
96
97
    function keydown(e) {
98
        if (hovered) {
99
            e.preventDefault();
100
            if (e.altKey) {
101
                changeSiblings(hovered, HOV, 1);
102
            } else if (e[mod]) {
103
                change(hovered.nextSibling, "i.I" + rand, HOV, 1);
104
            }
105
        }
106
    }
107
108
    function init() {
109
        tag = document.createElement("style");
110
        tag.textContent = [
111
            '.R', ',.D', '{font:16px consolas, Menlo, monospace}' +
112
            '.D', '{margin-left:6px; padding-left:1em; margin-top: 1px; border-left:1px dashed; border-color: #93A1A1;}' +
113
            '.X', '{border:1px solid #ccc; padding:1em}' +
114
            'a.L', '{text-decoration:none}' +
115
            'a.L', ':hover,a.L', ':focus{text-decoration:underline}' +
116
            'i.I', '{cursor:pointer;color:#ccc}' +
117
            'i.H', ',i.I', ':hover{text-shadow: 1px 1px 3px #999; color:#333}'+
118
            'i.I', ':before{content:" ▼ "}' +
119
            'i.C', ':before{content:" ▶ "}' +
120
            'i.I', ':after{content:attr(data-content)}' +
121
            'i.C', '+.D', '{width:1px; height:1px; margin:0; padding:0; border:0; display:inline-block; overflow:hidden}' +
122
            '.S', '{color:#2AA198}' + // string
123
            '.K', '{color:#B58900}' + // key
124
            '.E', '{color:#BCADAD}' + // error
125
            '.B', '{color:#657A81}' + // number and bool
126
            '.E', ',.B', '{font-style: italic}' + // number bold
127
            'h3.E', '{margin:0 0 1em}'
128
        ].join(rand);
129
130
        tag.textContent = tag.textContent + 'body {background: #FDF6E3; color:#586E75;}';
131
132
        div.classList.add(DIV);
133
        document.head.appendChild(tag);
134
        document.addEventListener("keydown", keydown);
135
        document.addEventListener("keyup", function(e) {
0 ignored issues
show
The parameter e is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
136
            if (hovered) change(document, "." + HOV, HOV);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
137
        })
138
        document.addEventListener("mouseover", function(e) {
139
            if (e.target.tagName === "I") {
140
                hovered = e.target;
141
                keydown(e);
142
            }
143
        })
144
        document.addEventListener("mouseout", function(e) {
0 ignored issues
show
The parameter e is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
145
            if (hovered) {
146
                change(document, "." + HOV, HOV);
147
                hovered = null;
148
            }
149
        })
150
    }
151
152
    function draw(str, to, first, box) {
153
        tag || init();
154
155
        var re = /("(?:((?:https?|file):\/\/(?:\\?\S)+?)|(?:\\?.)*?)")\s*(:?)|-?\d+\.?\d*(?:e[+-]?\d+)?|true|false|null|[[\]{},]|(\S[^-[\]{},"\d]*)/gi
156
            , node = div.cloneNode()
157
            , link = document.createElement("a")
158
            , span = document.createElement("span")
159
            , info = document.createElement("i")
160
            , colon = document.createTextNode(": ")
161
            , comma = fragment(",")
162
            , path = []
163
            , cache = {
164
                "{": fragment("{", "}"),
165
                "[": fragment("[", "]")
166
            };
167
168
        node.className = "R" + rand + (box ? " " + box : "");
169
170
        link.classList.add("L" + rand);
171
        info.classList.add("I" + rand);
172
173
        to.addEventListener("click", function(e) {
174
            var target = e.target, open = target.classList.contains(COLL);
175
            if (target.tagName == "I") {
176
                if (e.altKey) {
177
                    changeSiblings(target, COLL, !open);
178
                } else if (e[mod]) {
179
                    open = target.nextSibling.querySelector("i");
180
                    if (open) change(target.nextSibling, "i", COLL, !open.classList.contains(COLL));
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
181
                } else {
182
                    target.classList[open ? "remove" : "add"](COLL);
183
                }
184
            }
185
        }, true);
186
187
        to.replaceChild(box = node, first);
188
        loop(str, re);
189
190
        function loop(str, re) {
191
            str = reconvert(str);
192
            var match, val, tmp, i = 0, len = str.length;
193
            try {
194
                for (; match = re.exec(str); ) {
195
                    val = match[0];
196
                    if (val == "{" || val == "[") {
197
                        path.push(node);
0 ignored issues
show
The variable node is changed as part of the for loop for example by node.lastChild.previousSibling on line 199. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
198
                        node.appendChild(cache[val].cloneNode(true));
199
                        node = node.lastChild.previousSibling;
200
                        node.len = 1;
201
                        node.start = re.lastIndex;
202
                    } else if ((val == "}" || val == "]") && node.len) {
203
                        if (node.childNodes.length) {
204
                            tmp = info.cloneNode();
205
                            tmp.dataset.content = node.len + (
206
                                node.len == 1 ?
207
                                (val == "]" ? " item, " : " property, ") :
208
                                (val == "]" ? " items, " : " properties, ")
209
                            ) + units(re.lastIndex - node.start + 1);
210
211
                            if ((val = node.previousElementSibling) && val.className == KEY) {
212
                                tmp.dataset.key = reconvert(val.textContent.slice(1, -1).replace(/'/, "\\'"));
213
                            }
214
                            node.parentNode.insertBefore(tmp, node);
215
                        } else {
216
                            node.parentNode.removeChild(node);
217
                        }
218
                        node = path.pop();
219
                    } else if (val == ",") {
220
                        node.len += 1;
221
                        node.appendChild(comma.cloneNode(true));
222
                    } else {
223
                        if (match[2]) {
224
                            tmp = link.cloneNode();
225
                            tmp.href = match[2].replace(/\\"/g, '"');
226
                        } else {
227
                            tmp = span.cloneNode();
228
                        }
229
                        tmp.textContent = match[1] || val;
230
                        tmp.classList.add(match[3] ? KEY : match[1] ? STR : match[4] ? ERR : BOOL);
231
                        node.appendChild(tmp);
232
                        if (match[3]) {
233
                            node.appendChild(colon.cloneNode());
234
                        }
235
                    }
236
                    if (++i > 1000) {
237
                        document.title = (0|(100*re.lastIndex/len)) + "% of " + units(len);
238
                        return setTimeout(function() { loop(str, re) });
239
                    }
240
                }
241
                document.title = ""
242
                JSON.parse(str)
0 ignored issues
show
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
243
            } catch(e) {
244
                tmp = document.createElement("h3");
245
                tmp.className = ERR;
246
                tmp.textContent = e;
247
                box.insertBefore(tmp, box.firstChild);
0 ignored issues
show
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
248
            }
249
        }
250
    }
251
252
    // check whether the content is json or like json
253
    if (first
254
        && (first.tagName == "PRE"
255
            && first == body.lastElementChild
256
            || first == body.lastChild
257
            && first.nodeType == 3)
258
        && (str = first.textContent)
259
        && (/[+\/]json$/i.test(document.contentType)
260
            || (jsonpMatch = /^\s*((?:\/\*\*\/\s*)?([$a-z_][$\w]*)\s*(?:&&\s*\2\s*)?\()([^]+)(\)[\s;]*)$/i.exec(str))
261
            && jsonRe.test(jsonpMatch[3]) || jsonRe.test(str)))
262
    {
263
        if (jsonpMatch) {
264
            str = jsonpMatch[3]
265
            body.replaceChild(fragment(jsonpMatch[1], jsonpMatch[4]), first)
266
            first = body.lastChild.previousSibling
267
        }
268
        draw(str, body, first)
269
    }
270
271
    chrome.runtime.onMessage.addListener(function(req, sender, sendResponse) {
0 ignored issues
show
The parameter sendResponse is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
The parameter sender is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
272
        var node,
273
            sel   = window.getSelection(),
274
            range = sel.rangeCount && sel.getRangeAt(0),
275
            str   = range && range.toString()
276
277
        if (!str) return
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
278
279
        if (req.op === "formatSelection") {
280
            node = document.createElement("div")
281
            range.deleteContents()
282
            range.insertNode(node)
283
            sel.removeAllRanges()
284
            draw(str, node.parentNode, node, "X" + rand)
285
        }
286
    })
287
}()
288
289