├── .gitignore
├── LICENSE
├── README.md
├── example.png
├── extension-icon.png
├── extension-screenshot.png
├── icon-install_2x.png
├── jsonview.safariextension
├── Info.plist
├── default.css
├── icon.png
└── jsonview.js
├── jsonview.safariextz
└── update.plist
/.gitignore:
--------------------------------------------------------------------------------
1 | *.certSigningRequest
2 | *.cer
3 | .DS_Store
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Adrian Rangel
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Advanced JSON Viewer
2 |
3 | Better improved version:
4 | https://apps.apple.com/app/advanced-json-viewer/id6739271287
5 |
6 | # No longer available
7 | The safari extensions framework change a lot. This code is outdated
8 |
9 | jsonview-safari
10 | ===============
11 |
12 | Formats & syntax highlights JSON viewed inside of the web browser!
13 |
14 | [Install Now ![download-icon]][download-link]
15 |
16 | [View on Apple Safari Extensions Gallery](https://extensions.apple.com/details/?id=com.acrogenesis.jsonview-56Q494QF3L)
17 |
18 | This plugin was ported from [jsonview](https://github.com/bhollis/jsonview) and [jsonview-chrome](https://github.com/jamiew/jsonview-chrome)
19 |
20 | __If you like JSONView check out [JSONAce](https://github.com/acrogenesis/JSONAce) it's like JSONView but uses the ACE editor.__
21 |
22 | ![example]
23 |
24 | Contributing
25 | ---
26 |
27 | 1. Fork it.
28 | 2. Create a branch `git checkout -b my_markup`
29 | 3. Commit your changes `git commit -am "Cool new feature"`
30 | 4. Push to the branch `git push origin my_markup`
31 | 5. Open a [Pull Request][1]
32 | 6. Enjoy a refreshing `Insert Favorite Beverage` and wait
33 |
34 | [1]: https://github.com/acrogenesis/jsonview-safari/pulls
35 | [download-link]: https://github.com/acrogenesis/jsonview-safari/raw/v1.7/jsonview.safariextz
36 | [download-icon]: https://github.com/acrogenesis/jsonview-safari/blob/master/icon-install_2x.png
37 | [example]: https://github.com/acrogenesis/jsonview-safari/blob/master/example.png
38 |
--------------------------------------------------------------------------------
/example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acrogenesis/jsonview-safari/72421642adc65c987a637caf3df87bb5faef1140/example.png
--------------------------------------------------------------------------------
/extension-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acrogenesis/jsonview-safari/72421642adc65c987a637caf3df87bb5faef1140/extension-icon.png
--------------------------------------------------------------------------------
/extension-screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acrogenesis/jsonview-safari/72421642adc65c987a637caf3df87bb5faef1140/extension-screenshot.png
--------------------------------------------------------------------------------
/icon-install_2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acrogenesis/jsonview-safari/72421642adc65c987a637caf3df87bb5faef1140/icon-install_2x.png
--------------------------------------------------------------------------------
/jsonview.safariextension/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Author
6 | Adrian Rangel
7 | Builder Version
8 | 10600.7.5
9 | CFBundleDisplayName
10 | JsonView
11 | CFBundleIdentifier
12 | com.acrogenesis.jsonview
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleShortVersionString
16 | 1.7
17 | CFBundleVersion
18 | 1.7
19 | Chrome
20 |
21 | Global Page
22 | global.html
23 |
24 | Content
25 |
26 | Scripts
27 |
28 | End
29 |
30 | jsonview.js
31 |
32 |
33 | Stylesheets
34 |
35 | jsonview.css
36 |
37 |
38 | Description
39 | An extension that helps you view JSON documents in the browser.
40 | DeveloperIdentifier
41 | 56Q494QF3L
42 | ExtensionInfoDictionaryVersion
43 | 1.0
44 | Permissions
45 |
46 | Website Access
47 |
48 | Include Secure Pages
49 |
50 | Level
51 | All
52 |
53 |
54 | Update Manifest URL
55 | https://raw.githubusercontent.com/acrogenesis/jsonview-safari/master/update.plist
56 | Website
57 | https://github.com/acrogenesis/jsonview-safari
58 |
59 |
60 |
--------------------------------------------------------------------------------
/jsonview.safariextension/default.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: sans-serif;
3 | margin: 0;
4 | padding: 0;
5 | }
6 |
7 | .prop {
8 | font-weight: bold;
9 | }
10 |
11 | .null {
12 | color: red;
13 | }
14 |
15 | .bool {
16 | color: blue;
17 | }
18 |
19 | .num {
20 | color: blue;
21 | }
22 |
23 | .string {
24 | color: green;
25 | white-space: pre-wrap;
26 | }
27 |
28 | .collapser {
29 | position: absolute;
30 | left: -1em;
31 | top: -.2em;
32 | cursor: pointer;
33 | user-select: none;
34 | -webkit-backface-visibility: hidden;
35 | backface-visibility: hidden;
36 | -webkit-perspective: 1000;
37 | perspective: 1000;
38 | -webkit-transform: rotate(90deg);
39 | transform: rotate(90deg);
40 | -webkit-transition: -webkit-transform .2s;
41 | transition: transform .2s;
42 | }
43 |
44 | .collapser:before {
45 | content: "\25B8";
46 | }
47 |
48 | .collapsible {
49 | -webkit-backface-visibility: hidden;
50 | backface-visibility: hidden;
51 | -webkit-perspective: 1000;
52 | perspective: 1000;
53 | -webkit-transition: height 1.2s;
54 | transition: height 1.2s;
55 | -webkit-transition: width 1.2s;
56 | transition: width 1.2s;
57 | }
58 |
59 | .collapsible.collapsed {
60 | height: .8em;
61 | width: 1em;
62 | display: inline-block;
63 | overflow: hidden;
64 | margin: 0;
65 | }
66 | .collapsible.collapsed:before {
67 | content: "…";
68 | width: 1em;
69 | margin-left: .2em;
70 | }
71 |
72 | .collapser.collapsed {
73 | -webkit-backface-visibility: hidden;
74 | backface-visibility: hidden;
75 | -webkit-perspective: 1000;
76 | perspective: 1000;
77 | -webkit-transform: rotate(0deg);
78 | transform: rotate(0deg);
79 | }
80 |
81 | .q {
82 | display: inline-block;
83 | width: 0;
84 | color: transparent;
85 | }
86 |
87 | .quoted .q {
88 | display: inline;
89 | width: auto;
90 | color: inherit;
91 | font-weight: normal;
92 | }
93 |
94 | li {
95 | position: relative;
96 | }
97 |
98 | #error {
99 | border-bottom: 1px solid rgb(212, 209, 209);
100 | background-color: rgb(239, 239, 239);
101 | margin-bottom: 1.5em;
102 | padding: 1em .5em;
103 | }
104 |
105 | .errormessage {
106 | font-family: monospace;
107 | margin-top: .5em;
108 | color: rgb(167, 5, 5);
109 | }
110 |
111 | .errorcolumn {
112 | background-color: rgb(167, 5, 5);
113 | color: white;
114 | }
115 |
116 | .errorline {
117 | background-color: rgb(255, 226, 226);
118 | }
119 |
120 | #json {
121 | font-family: monospace;
122 | font-size: 1.1em;
123 | white-space: pre-wrap;
124 | margin: .5em;
125 | }
126 |
127 | ul {
128 | list-style: none;
129 | margin: 0 0 0 2em;
130 | padding: 0;
131 | }
132 |
133 | h1 {
134 | font-size: 1.2em;
135 | }
136 |
137 | /* Indent JSON when there's a callback. */
138 | .callback + #json {
139 | padding-left: 1em;
140 | }
141 |
142 | .callback {
143 | font-family: monospace;
144 | color: #A52A2A;
145 | }
146 |
147 | .btn {
148 | z-index: 10;
149 | position: absolute;
150 | right: 10px;
151 | top: 10px;
152 | }
153 | /*!
154 | * Bootstrap v3.3.4 (http://getbootstrap.com)
155 | * Copyright 2011-2015 Twitter, Inc.
156 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
157 | */
158 |
159 | /*!
160 | * Generated using the Bootstrap Customizer (http://getbootstrap.com/customize/?id=81c419f0ed2a9be873de)
161 | * Config saved to config.json and https://gist.github.com/81c419f0ed2a9be873de
162 | *//*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:hover,a:focus{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role="button"]{cursor:pointer}.btn{display:inline-block;margin-bottom:0;font-weight:normal;text-align:center;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;line-height:1.42857143;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn:focus,.btn:active:focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn.active.focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus,.btn.focus{color:#333;text-decoration:none}.btn:active,.btn.active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;pointer-events:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default.focus,.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled.focus,.btn-default[disabled].focus,fieldset[disabled] .btn-default.focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary:hover,.btn-primary:focus,.btn-primary.focus,.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled.focus,.btn-primary[disabled].focus,fieldset[disabled] .btn-primary.focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success.focus,.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled.focus,.btn-success[disabled].focus,fieldset[disabled] .btn-success.focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info.focus,.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled.focus,.btn-info[disabled].focus,fieldset[disabled] .btn-info.focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning.focus,.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled.focus,.btn-warning[disabled].focus,fieldset[disabled] .btn-warning.focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger.focus,.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled.focus,.btn-danger[disabled].focus,fieldset[disabled] .btn-danger.focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{color:#337ab7;font-weight:normal;border-radius:0}.btn-link,.btn-link:active,.btn-link.active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#777;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.clearfix:before,.clearfix:after{content:" ";display:table}.clearfix:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right !important}.pull-left{float:left !important}.hide{display:none !important}.show{display:block !important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none !important}.affix{position:fixed}
163 |
--------------------------------------------------------------------------------
/jsonview.safariextension/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acrogenesis/jsonview-safari/72421642adc65c987a637caf3df87bb5faef1140/jsonview.safariextension/icon.png
--------------------------------------------------------------------------------
/jsonview.safariextension/jsonview.js:
--------------------------------------------------------------------------------
1 | this.data = document.body.innerHTML;
2 | this.uri = document.location.href;
3 |
4 | if(document.getElementsByTagName("pre")[0] && document.body.getElementsByTagName('*').length == 1 && document.getElementsByTagName("pre").length == 1){
5 | // console.log("JSONView: data is wrapped in
...
, stripping HTML...");
6 | this.data = document.getElementsByTagName("pre")[0].innerHTML;
7 | }
8 |
9 | function IsJsonString(str) {
10 | try {
11 | JSON.parse(str);
12 | } catch (e) {
13 | return false;
14 | }
15 | return true;
16 | }
17 |
18 | var is_json = IsJsonString(this.data);
19 |
20 | if(is_json){
21 | if (!(window.location.hash === "#raw-json")){
22 | /*
23 | * The JSONFormatter helper object. This contains two major functions, jsonToHTML and errorPage,
24 | * each of which returns an HTML document.
25 | */
26 | function JSONFormatter() { }
27 |
28 | JSONFormatter.prototype = {
29 | /**
30 | * Completely escape a json string
31 | */
32 | jsString: function(s) {
33 | // Slice off the surrounding quotes
34 | s = JSON.stringify(s).slice(1, -1);
35 | return s;
36 | },
37 |
38 | /**
39 | * Is this a valid "bare" property name?
40 | */
41 | isBareProp: function(prop) {
42 | return /^[A-Za-z_$][A-Za-z0-9_\-$]*$/.test(prop);
43 | },
44 |
45 | /**
46 | * Surround value with a span, including the given className
47 | */
48 | decorateWithSpan: function(value, className) {
49 | return '' + value + '';
50 | },
51 |
52 | // Convert a basic JSON datatype (number, string, boolean, null, object, array) into an HTML fragment.
53 | valueToHTML: function(value, path) {
54 | var valueType = typeof value;
55 |
56 | if (value === null) {
57 | return this.decorateWithSpan('null', 'null');
58 | }
59 | else if (Array.isArray(value)) {
60 | return this.arrayToHTML(value, path);
61 | }
62 | else if (valueType == 'object') {
63 | return this.objectToHTML(value, path);
64 | }
65 | else if (valueType == 'number') {
66 | return this.decorateWithSpan(value, 'num');
67 | }
68 | else if (valueType == 'string') {
69 | if (/^(http|https|file):\/\/[^\s]+$/i.test(value)) {
70 | return '"' + this.jsString(value) + '"';
71 | } else {
72 | return '"' + this.jsString(value) + '"';
73 | }
74 | }
75 | else if (valueType == 'boolean') {
76 | return this.decorateWithSpan(value, 'bool');
77 | }
78 |
79 | return '';
80 | },
81 |
82 | // Convert an array into an HTML fragment
83 | arrayToHTML: function(json, path) {
84 | if (json.length === 0) {
85 | return '[ ]';
86 | }
87 |
88 | var output = '';
89 | for (var i = 0; i < json.length; i++) {
90 | var subPath = path + '[' + i + ']';
91 | output += '' + this.valueToHTML(json[i], subPath);
92 | if (i < json.length - 1) {
93 | output += ',';
94 | }
95 | output += '';
96 | }
97 | return '[]';
98 | },
99 |
100 | // Convert a JSON object to an HTML fragment
101 | objectToHTML: function(json, path) {
102 | var numProps = Object.keys(json).length;
103 | if (numProps === 0) {
104 | return '{ }';
105 | }
106 |
107 | var output = '';
108 | for (var prop in json) {
109 | var subPath = '';
110 | var escapedProp = JSON.stringify(prop).slice(1, -1);
111 | var bare = this.isBareProp(prop);
112 | if (bare) {
113 | subPath = path + '.' + escapedProp;
114 | } else {
115 | escapedProp = '"' + escapedProp + '"';
116 | }
117 | output += '"' + this.jsString(prop) +
119 | '": ' + this.valueToHTML(json[prop], subPath);
120 | if (numProps > 1) {
121 | output += ',';
122 | }
123 | output += '';
124 | numProps--;
125 | }
126 |
127 | return '{}';
128 | },
129 |
130 | // Convert a whole JSON value / JSONP response into a formatted HTML document
131 | jsonToHTML: function(json, callback, uri) {
132 | var output = '' + this.valueToHTML(json, '') + '
';
133 | if (callback) {
134 | output = '' + callback + '(
' + output + ')
';
135 | }
136 | return this.toHTML(output, uri);
137 | },
138 |
139 | // Clean up a JSON parsing error message
140 | massageError: function(error) {
141 | var message = error.message.replace(/^JSON.parse: /, '').replace(/of the JSON data/, '');
142 | var parts = /line (\d+) column (\d+)/.exec(message);
143 |
144 | return {
145 | message: message,
146 | line: +parts[1],
147 | column: +parts[2]
148 | };
149 | },
150 |
151 | highlightError: function(data, lineNum, columnNum) {
152 | if (!lineNum || !columnNum) {
153 | return data;
154 | }
155 |
156 | var lines = data.match(/^.*((\r\n|\n|\r)|$)/gm);
157 |
158 | var output = '';
159 | for (var i = 0; i < lines.length; i++) {
160 | var line = lines[i];
161 |
162 | if (i == lineNum - 1) {
163 | output += '';
164 | output += line.substring(0, columnNum - 1) + '' + line[columnNum - 1] + '' + line.substring(columnNum);
165 | output += '';
166 | } else {
167 | output += line;
168 | }
169 | }
170 |
171 | return output;
172 | },
173 |
174 | // Produce an error document for when parsing fails.
175 | errorPage: function(error, data, uri) {
176 | // Escape unicode nulls
177 | data = data.replace("\u0000","\uFFFD");
178 |
179 | var errorInfo = this.massageError(error);
180 |
181 | var output = '' + _('errorParsing');
182 | if (errorInfo.message) {
183 | output += '
' + errorInfo.message + '
';
184 | }
185 | output += '
' + this.highlightError(data, errorInfo.line, errorInfo.column) + '
';
186 | return this.toHTML(output, uri + ' - Error');
187 | },
188 |
189 | // Wrap the HTML fragment in a full document. Used by jsonToHTML and errorPage.
190 | toHTML: function(content, title) {
191 | return '\n' +
192 | '' + title + '' +
193 | '' +
194 | '' +
195 | content +
196 | '';
197 | }
198 | };
199 |
200 | // Sanitize & output -- all magic from JSONView Firefox
201 | this.jsonFormatter = new JSONFormatter();
202 |
203 | // This regex attempts to match a JSONP structure:
204 | // * Any amount of whitespace (including unicode nonbreaking spaces) between the start of the file and the callback name
205 | // * Callback name (any valid JavaScript function name according to ECMA-262 Edition 3 spec)
206 | // * Any amount of whitespace (including unicode nonbreaking spaces)
207 | // * Open parentheses
208 | // * Any amount of whitespace (including unicode nonbreaking spaces)
209 | // * Either { or [, the only two valid characters to start a JSON string.
210 | // * Any character, any number of times
211 | // * Either } or ], the only two valid closing characters of a JSON string.
212 | // * Any amount of whitespace (including unicode nonbreaking spaces)
213 | // * A closing parenthesis, an optional semicolon, and any amount of whitespace (including unicode nonbreaking spaces) until the end of the file.
214 | // This will miss anything that has comments, or more than one callback, or requires modification before use.
215 | var outputDoc = '';
216 | // text = text.match(jsonp_regex)[1];
217 | var cleanData = '',
218 | callback = '';
219 |
220 | var callback_results = IsJsonString(this.data);
221 | if( callback_results && callback_results.length == 3 ){
222 | // console.log("THIS IS JSONp");
223 | callback = callback_results[1];
224 | cleanData = callback_results[2];
225 | } else {
226 | // console.log("Vanilla JSON");
227 | cleanData = this.data;
228 | }
229 | // console.log(cleanData);
230 |
231 | // Covert, and catch exceptions on failure
232 | try {
233 | // var jsonObj = this.nativeJSON.decode(cleanData);
234 | var jsonObj = JSON.parse(cleanData);
235 | if ( jsonObj ) {
236 | outputDoc = this.jsonFormatter.jsonToHTML(jsonObj, callback, this.uri);
237 | } else {
238 | throw "There was no object!";
239 | }
240 | } catch(e) {
241 | // console.log(e);
242 | outputDoc = this.jsonFormatter.errorPage(e, this.data, this.uri);
243 | }
244 | // document.body.innerHTML = outputDoc;
245 | document.documentElement.innerHTML = 'RAW' + outputDoc;
246 |
247 | //////////////////////////////////
248 | ////////BEGINS DEFAULT.JS/////////
249 | //////////////////////////////////
250 |
251 | // Click handler for collapsing and expanding objects and arrays
252 | function collapse(evt) {
253 | var collapser = evt.target;
254 |
255 | while (collapser && (!collapser.classList || !collapser.classList.contains('collapser'))) {
256 | collapser = collapser.nextSibling;
257 | }
258 | if (!collapser || !collapser.classList || !collapser.classList.contains('collapser')) {
259 | return;
260 | }
261 |
262 | evt.stopPropagation();
263 |
264 | collapser.classList.toggle('collapsed');
265 |
266 | var collapsible = collapser;
267 | while (collapsible && (!collapsible.classList || !collapsible.classList.contains('collapsible'))) {
268 | collapsible = collapsible.nextSibling;
269 | }
270 | collapsible.classList.toggle('collapsed');
271 | }
272 |
273 | /*
274 | * Collapses the whole json using keyboard
275 | * TODO: Add a navigator support for each of the elements
276 | */
277 | function collapseAll(evt) {
278 | var inputList;
279 |
280 | // Ignore anything paired with a modifier key. See https://github.com/bhollis/jsonview/issues/69
281 | if (evt.ctrlKey || evt.shiftKey || evt.altKey || evt.metaKey) {
282 | return;
283 | }
284 |
285 | if (evt.keyCode === 37) { // Collapses the json on left arrow key up
286 | inputList = document.querySelectorAll('.collapsible, .collapser');
287 | for (var i = 0; i < inputList.length; i++) {
288 | if (inputList[i].parentNode.id != 'json') {
289 | inputList[i].classList.add('collapsed');
290 | }
291 | }
292 | evt.preventDefault();
293 | } else if (evt.keyCode === 39) { // Expands the json on right arrow key up
294 | inputList = document.querySelectorAll('.collapsed');
295 | for (var i = 0; i < inputList.length; i++) {
296 | inputList[i].classList.remove('collapsed');
297 | }
298 | evt.preventDefault();
299 | }
300 | }
301 |
302 | // collapse with event delegation
303 | document.addEventListener('click', collapse, false);
304 | document.addEventListener('keyup', collapseAll, false);
305 |
306 | //////////////////////////////////
307 | /////////ENDS DEFAULT.JS//////////
308 | //////////////////////////////////
309 |
310 | /**
311 | * Converts the markup to DOM nodes
312 | *
313 | * @private
314 | * @param {string|Markup} value The node
315 | * @return {Node}
316 | */
317 | function toDOM(value) {
318 | var wrapper = createElement('div');
319 | wrapper.innerHTML = ''+value;
320 |
321 | // trim extraneous whitespace
322 | trimWhitespace(wrapper);
323 |
324 | // eliminate wrapper for single nodes
325 | if (wrapper.childNodes.length === 1) {
326 | return wrapper.firstChild;
327 | }
328 |
329 | // create a document fragment to hold elements
330 | var frag = createElement('');
331 | while (wrapper.firstChild) {
332 | frag.appendChild(wrapper.firstChild);
333 | }
334 | return frag;
335 | }
336 | var rawButton = document.getElementById('raw');
337 | rawButton.href = location.protocol+'//'+location.host+location.pathname+'?&jsonace='+Math.floor(Math.random()*1000)+'#raw-json';
338 | } else {
339 | var outputDoc = 'BEAUTIFY' + this.data;
340 | var impcss = document.createElement('link');
341 | impcss.rel = "stylesheet";
342 | impcss.href = safari.extension.baseURI + 'default.css';
343 | document.head.appendChild(impcss);
344 | document.body.innerHTML = outputDoc;
345 | }
346 | }else {
347 | // console.log("JSONView: this is not json, not formatting.");
348 | }
349 |
--------------------------------------------------------------------------------
/jsonview.safariextz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/acrogenesis/jsonview-safari/72421642adc65c987a637caf3df87bb5faef1140/jsonview.safariextz
--------------------------------------------------------------------------------
/update.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Extension Updates
6 |
7 |
8 | CFBundleIdentifier
9 | com.acrogenesis.jsonview
10 | Developer Identifier
11 | 56Q494QF3L
12 | CFBundleVersion
13 | 1.7
14 | CFBundleShortVersionString
15 | 1.7
16 | URL
17 | https://github.com/acrogenesis/jsonview-safari/raw/v1.7/jsonview.safariextz
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------