Completed
Push — master ( 6ad87d...e49cd7 )
by Dongxin
01:04
created

mjsonviewer.js (1 issue)

Severity
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
var bgColor, intColor, strColor, keyColor, defaultColor;
24
25
function onError(error) {
26
    console.log(`Error: ${error}`);
27
}
28
29
function onGot(result) {
30
    console.log((result[0]));
0 ignored issues
show
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
31
    bgColor      = result[0].bgColor      || "#FDF6E3";
32
    intColor     = result[0].intColor     || "#657A81";
33
    strColor     = result[0].strColor     || "#2AA198";
34
    keyColor     = result[0].keyColor     || "#B58900";
35
    defaultColor = result[0].defaultColor || "#586E75";
36
37
    var str, jsonpMatch, hovered, tag,
38
        chrome = this.chrome || this.browser,
39
        jsonRe = /^\s*(?:\[\s*(?=-?\d|true|false|null|["[{])[^]*\]|\{\s*"[^]+\})\s*$/,
40
        div    = document.createElement("div"),
41
        body   = document.body,
42
        first  = body && body.firstChild,
43
        mod    = /Mac|iPod|iPhone|iPad|Pike/.test(navigator.platform) ? "metaKey" : "ctrlKey",
44
        rand   = Math.random().toString(36).slice(2),
45
        HOV    = "H" + rand,
46
        DIV    = "D" + rand,
47
        KEY    = "K" + rand,
48
        STR    = "S" + rand,
49
        BOOL   = "B" + rand,
50
        ERR    = "E" + rand,
51
        COLL   = "C" + rand;
52
53
    function reconvert(str){
54
        str = str.replace(/(\\u)(\w{1,4})/gi, function($0) {
55
            return (String.fromCharCode(parseInt((escape($0).replace(/(%5Cu)(\w{1,4})/g, "$2")), 16)));
56
        });
57
        str = str.replace(/(&#x)(\w{1,4});/gi, function($0) {
58
            return String.fromCharCode(parseInt(escape($0).replace(/(%26%23x)(\w{1,4})(%3B)/g, "$2"),16));
59
        });
60
        str = str.replace(/(&#)(\d{1,6});/gi, function($0) {
61
            return String.fromCharCode(parseInt(escape($0).replace(/(%26%23)(\d{1,6})(%3B)/g, "$2")));
62
        });
63
64
        return str;
65
    }
66
67
    function units(size) {
68
        return size > 1048576 ? (0|(size / 1048576)) + "MB" :
69
            size > 1024 ? (0|(size / 1024)) + "KB" :
70
            size + "B";
71
    }
72
73
    function fragment(a, b) {
74
        var frag = document.createDocumentFragment();
75
        frag.appendChild(document.createTextNode(a));
76
        if (b) {
77
            frag.appendChild(div.cloneNode());
78
            frag.appendChild(document.createTextNode(b));
79
        } else {
80
            frag.appendChild(document.createElement("br"));
81
        }
82
        return frag;
83
    }
84
85
    function change(node, query, name, set) {
86
        var list = node.querySelectorAll(query), i = list.length;
87
        for (; i--; ) list[i].classList[set ? "add" : "remove"](name);
88
    }
89
90
    function changeSiblings(node, name, set) {
91
        var tmp, i = 0, query = [];
92
93
        for (; node && node.tagName === "I"; ) {
94
            tmp = node.previousElementSibling;
95
            if (tmp && tmp.className == KEY) {
96
                query.unshift(".D" + rand + ">i.I" + rand + "[data-key='" + node.dataset.key + "']");
97
            } else if (query[0]) {
98
                query.unshift(".D" + rand + ">i.I" + rand);
99
            } else {
100
                for (; tmp; tmp = tmp.previousElementSibling) if (tmp.tagName === "BR") i++;
101
                query.unshift(".D" + rand + ">" + (i ? "br:nth-of-type(" + i + ")+i.I" + rand : "i.I" + rand + ":first-child"));
102
            }
103
            node = node.parentNode && node.parentNode.previousElementSibling;
104
        }
105
        if (!query[1]) return;
106
        query[0] = ".R" + rand + ">i.I" + rand;
107
        change(document, query.join("+"), name, set);
108
    }
109
110
    function keydown(e) {
111
        if (hovered) {
112
            e.preventDefault();
113
            if (e.altKey) {
114
                changeSiblings(hovered, HOV, 1);
115
            } else if (e[mod]) {
116
                change(hovered.nextSibling, "i.I" + rand, HOV, 1);
117
            }
118
        }
119
    }
120
121
    function init() {
122
        tag = document.createElement("style");
123
        tag.textContent = [
124
            '.R', ',.D', '{font:16px consolas, Menlo, monospace}' +
125
            '.D', '{margin-left:6px; padding-left:1em; margin-top: 1px; border-left:1px dashed; border-color: #93A1A1;}' +
126
            '.X', '{border:1px solid #ccc; padding:1em}' +
127
            'a.L', '{text-decoration:none}' +
128
            'a.L', ':hover,a.L', ':focus{text-decoration:underline}' +
129
            'i.I', '{cursor:pointer;color:#ccc}' +
130
            'i.H', ',i.I', ':hover{text-shadow: 1px 1px 3px #999; color:#333}'+
131
            'i.I', ':before{content:" ▼ "}' +
132
            'i.C', ':before{content:" ▶ "}' +
133
            'i.I', ':after{content:attr(data-content)}' +
134
            'i.C', '+.D', '{width:1px; height:1px; margin:0; padding:0; border:0; display:inline-block; overflow:hidden}' +
135
            '.S', '{color:' + strColor + '}' + // string
136
            '.K', '{color:' + keyColor + '}' + // key
137
            '.E', '{color:#BCADAD}' + // error
138
            '.B', '{color:' + intColor + '}' + // number and bool
139
            '.E', ',.B', '{font-style: italic}' + // number bold
140
            'h3.E', '{margin:0 0 1em}'
141
        ].join(rand);
142
143
        tag.textContent = tag.textContent + 'body {background: ' + bgColor + '; color:' + defaultColor + ';}';
144
145
        div.classList.add(DIV);
146
        document.head.appendChild(tag);
147
        document.addEventListener("keydown", keydown);
148
        document.addEventListener("keyup", function(e) {
149
            if (hovered) change(document, "." + HOV, HOV);
150
        })
151
        document.addEventListener("mouseover", function(e) {
152
            if (e.target.tagName === "I") {
153
                hovered = e.target;
154
                keydown(e);
155
            }
156
        })
157
        document.addEventListener("mouseout", function(e) {
158
            if (hovered) {
159
                change(document, "." + HOV, HOV);
160
                hovered = null;
161
            }
162
        })
163
    }
164
165
    function draw(str, to, first, box) {
166
        tag || init();
167
168
        var re = /("(?:((?:https?|file):\/\/(?:\\?\S)+?)|(?:\\?.)*?)")\s*(:?)|-?\d+\.?\d*(?:e[+-]?\d+)?|true|false|null|[[\]{},]|(\S[^-[\]{},"\d]*)/gi
169
            , node = div.cloneNode()
170
            , link = document.createElement("a")
171
            , span = document.createElement("span")
172
            , info = document.createElement("i")
173
            , colon = document.createTextNode(": ")
174
            , comma = fragment(",")
175
            , path = []
176
            , cache = {
177
                "{": fragment("{", "}"),
178
                "[": fragment("[", "]")
179
            };
180
181
        node.className = "R" + rand + (box ? " " + box : "");
182
183
        link.classList.add("L" + rand);
184
        info.classList.add("I" + rand);
185
186
        to.addEventListener("click", function(e) {
187
            var target = e.target, open = target.classList.contains(COLL);
188
            if (target.tagName == "I") {
189
                if (e.altKey) {
190
                    changeSiblings(target, COLL, !open);
191
                } else if (e[mod]) {
192
                    open = target.nextSibling.querySelector("i");
193
                    if (open) change(target.nextSibling, "i", COLL, !open.classList.contains(COLL));
194
                } else {
195
                    target.classList[open ? "remove" : "add"](COLL);
196
                }
197
            }
198
        }, true);
199
200
        to.replaceChild(box = node, first);
201
        loop(str, re);
202
203
        function loop(str, re) {
204
            str = reconvert(str);
205
            var match, val, tmp, i = 0, len = str.length;
206
            try {
207
                for (; match = re.exec(str); ) {
208
                    val = match[0];
209
                    if (val == "{" || val == "[") {
210
                        path.push(node);
211
                        node.appendChild(cache[val].cloneNode(true));
212
                        node = node.lastChild.previousSibling;
213
                        node.len = 1;
214
                        node.start = re.lastIndex;
215
                    } else if ((val == "}" || val == "]") && node.len) {
216
                        if (node.childNodes.length) {
217
                            tmp = info.cloneNode();
218
                            tmp.dataset.content = node.len + (
219
                                node.len == 1 ?
220
                                (val == "]" ? " item, " : " property, ") :
221
                                (val == "]" ? " items, " : " properties, ")
222
                            ) + units(re.lastIndex - node.start + 1);
223
224
                            if ((val = node.previousElementSibling) && val.className == KEY) {
225
                                tmp.dataset.key = reconvert(val.textContent.slice(1, -1).replace(/'/, "\\'"));
226
                            }
227
                            node.parentNode.insertBefore(tmp, node);
228
                        } else {
229
                            node.parentNode.removeChild(node);
230
                        }
231
                        node = path.pop();
232
                    } else if (val == ",") {
233
                        node.len += 1;
234
                        node.appendChild(comma.cloneNode(true));
235
                    } else {
236
                        if (match[2]) {
237
                            tmp = link.cloneNode();
238
                            tmp.href = match[2].replace(/\\"/g, '"');
239
                        } else {
240
                            tmp = span.cloneNode();
241
                        }
242
                        tmp.textContent = match[1] || val;
243
                        tmp.classList.add(match[3] ? KEY : match[1] ? STR : match[4] ? ERR : BOOL);
244
                        node.appendChild(tmp);
245
                        if (match[3]) {
246
                            node.appendChild(colon.cloneNode());
247
                        }
248
                    }
249
                    if (++i > 1000) {
250
                        document.title = (0|(100*re.lastIndex/len)) + "% of " + units(len);
251
                        return setTimeout(function() { loop(str, re) });
252
                    }
253
                }
254
                document.title = ""
255
                JSON.parse(str)
256
            } catch(e) {
257
                tmp = document.createElement("h3");
258
                tmp.className = ERR;
259
                tmp.textContent = e;
260
                box.insertBefore(tmp, box.firstChild);
261
            }
262
        }
263
    }
264
265
    // check whether the content is json or like json
266
    if (first
267
        && (first.tagName == "PRE"
268
            && first == body.lastElementChild
269
            || first == body.lastChild
270
            && first.nodeType == 3)
271
        && (str = first.textContent)
272
        && (/[+\/]json$/i.test(document.contentType)
273
            || (jsonpMatch = /^\s*((?:\/\*\*\/\s*)?([$a-z_][$\w]*)\s*(?:&&\s*\2\s*)?\()([^]+)(\)[\s;]*)$/i.exec(str))
274
            && jsonRe.test(jsonpMatch[3]) || jsonRe.test(str)))
275
    {
276
        if (jsonpMatch) {
277
            str = jsonpMatch[3]
278
            body.replaceChild(fragment(jsonpMatch[1], jsonpMatch[4]), first)
279
            first = body.lastChild.previousSibling
280
        }
281
        draw(str, body, first)
282
    }
283
284
    chrome.runtime.onMessage.addListener(function(req, sender, sendResponse) {
285
        var node,
286
            sel   = window.getSelection(),
287
            range = sel.rangeCount && sel.getRangeAt(0),
288
            str   = range && range.toString()
289
290
        if (!str) return
291
292
        if (req.op === "formatSelection") {
293
            node = document.createElement("div")
294
            range.deleteContents()
295
            range.insertNode(node)
296
            sel.removeAllRanges()
297
            draw(str, node.parentNode, node, "X" + rand)
298
        }
299
    })
300
}
301
302
var getting = browser.storage.local.get();
303
getting.then(onGot, onError);
304
305