PHPView options
12 | 13 |
(*) safe method forces the browser to send an extra HTTP request to get the raw HTTP content.
30 |├── WebContent ├── error.gif ├── options.png ├── close_icon.gif ├── jsonview128.png ├── jsonview16.png ├── jsonview48.png ├── content_error.css ├── codemirror │ ├── default.css │ ├── LICENSE │ ├── codemirror.css │ └── css.js ├── jsonview.css ├── csseditor.html ├── manifest.json ├── options.html ├── options.css ├── options.js ├── jsonview-core.css ├── csseditor.js ├── csseditor.css ├── background.js ├── workerFormatter.js ├── content.js └── workerJSONLint.js ├── release ├── PHPView0.1.0.zip ├── PHPView0.1.1.zip ├── PHPView0.1.2.zip ├── PHPView0.1.3.zip ├── PHPView0.1.4.zip ├── PHPView0.1.5.zip └── PHPView0.2.0.zip ├── changelog.txt ├── README.md └── LICENSE.txt /WebContent/error.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theypsilon/PHPView-for-Chrome/HEAD/WebContent/error.gif -------------------------------------------------------------------------------- /WebContent/options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theypsilon/PHPView-for-Chrome/HEAD/WebContent/options.png -------------------------------------------------------------------------------- /release/PHPView0.1.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theypsilon/PHPView-for-Chrome/HEAD/release/PHPView0.1.0.zip -------------------------------------------------------------------------------- /release/PHPView0.1.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theypsilon/PHPView-for-Chrome/HEAD/release/PHPView0.1.1.zip -------------------------------------------------------------------------------- /release/PHPView0.1.2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theypsilon/PHPView-for-Chrome/HEAD/release/PHPView0.1.2.zip -------------------------------------------------------------------------------- /release/PHPView0.1.3.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theypsilon/PHPView-for-Chrome/HEAD/release/PHPView0.1.3.zip -------------------------------------------------------------------------------- /release/PHPView0.1.4.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theypsilon/PHPView-for-Chrome/HEAD/release/PHPView0.1.4.zip -------------------------------------------------------------------------------- /release/PHPView0.1.5.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theypsilon/PHPView-for-Chrome/HEAD/release/PHPView0.1.5.zip -------------------------------------------------------------------------------- /release/PHPView0.2.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theypsilon/PHPView-for-Chrome/HEAD/release/PHPView0.2.0.zip -------------------------------------------------------------------------------- /WebContent/close_icon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theypsilon/PHPView-for-Chrome/HEAD/WebContent/close_icon.gif -------------------------------------------------------------------------------- /WebContent/jsonview128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theypsilon/PHPView-for-Chrome/HEAD/WebContent/jsonview128.png -------------------------------------------------------------------------------- /WebContent/jsonview16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theypsilon/PHPView-for-Chrome/HEAD/WebContent/jsonview16.png -------------------------------------------------------------------------------- /WebContent/jsonview48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theypsilon/PHPView-for-Chrome/HEAD/WebContent/jsonview48.png -------------------------------------------------------------------------------- /changelog.txt: -------------------------------------------------------------------------------- 1 | 0.1.5 2 | ===== 3 | More restrictive when it comes to false positives. 4 | 5 | 0.1.4 6 | ===== 7 | Context Menu is disabled by default (change it in configurations page if you need it) 8 | Fixing false positives in recognition of webpages like this one: http://www.php.net/manual/es/function.array-filter.php 9 | 10 | 0.1.3 11 | ===== 12 | Bugfixing a problem which makes this work with any page 13 | 14 | 0.1.2 15 | ===== 16 | Now works also with Objects 17 | 18 | 0.1.1 19 | ===== 20 | It works even if there is no
before first Array
21 |
22 | 0.1.0
23 | =====
24 | Initial version
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | PHPView 0.2.0
2 | =============
3 |
4 | Chrome extension for pretty printing php print_r outputs.
5 |
6 | For example, by doing this in your PHP file:
7 | ```php
8 | $array = array('element' => 'value');
9 | echo '';
10 | print_r($array); die;
11 | ```
12 |
13 | Instead of displaying this:
14 | ```
15 | Array
16 | (
17 | [element] => value
18 | )
19 | ```
20 |
21 | We will see this in Chrome:
22 | ```js
23 | [{"element": "value"}]
24 | ```
25 |
26 |
27 | And it also allows you to collapse branches.
28 |
29 | Check it out int he Chrome Store: https://chrome.google.com/webstore/detail/phpview/nlkobfbkblfhlcobdomlhmpbbhmcbkfd
30 |
--------------------------------------------------------------------------------
/WebContent/content_error.css:
--------------------------------------------------------------------------------
1 | .error-position {
2 | display: inline-block;
3 | color: fireBrick;
4 | padding-left: 3px;
5 | padding-right: 3px;
6 | }
7 |
8 | .error-position img {
9 | padding-right: 3px;
10 | height: .8em;
11 | }
12 |
13 | .container {
14 | position: absolute;
15 | left: 0px;
16 | width: 100%;
17 | }
18 |
19 | .content {
20 | top: 3px;
21 | width: 30em;
22 | margin: 0 auto;
23 | background-color: #FEE;
24 | border: 2px solid #933;
25 | color: #933;
26 | padding: 20px;
27 | position: relative;
28 | -webkit-box-shadow: #888 3px 3px 5px;
29 | }
30 |
31 | .close-error {
32 | background-image: url("close_icon.gif");
33 | width: 16px;
34 | height: 16px;
35 | position: absolute;
36 | top: 3px;
37 | right: 3px;
38 | cursor: pointer;
39 | }
--------------------------------------------------------------------------------
/WebContent/codemirror/default.css:
--------------------------------------------------------------------------------
1 | .cm-s-default span.cm-keyword {color: #708;}
2 | .cm-s-default span.cm-atom {color: #219;}
3 | .cm-s-default span.cm-number {color: #164;}
4 | .cm-s-default span.cm-def {color: #00f;}
5 | .cm-s-default span.cm-variable {color: black;}
6 | .cm-s-default span.cm-variable-2 {color: #05a;}
7 | .cm-s-default span.cm-variable-3 {color: #085;}
8 | .cm-s-default span.cm-property {color: black;}
9 | .cm-s-default span.cm-operator {color: black;}
10 | .cm-s-default span.cm-comment {color: #a50;}
11 | .cm-s-default span.cm-string {color: #a11;}
12 | .cm-s-default span.cm-string-2 {color: #f50;}
13 | .cm-s-default span.cm-meta {color: #555;}
14 | .cm-s-default span.cm-error {color: #f00;}
15 | .cm-s-default span.cm-qualifier {color: #555;}
16 | .cm-s-default span.cm-builtin {color: #30a;}
17 | .cm-s-default span.cm-bracket {color: #cc7;}
18 | .cm-s-default span.cm-tag {color: #170;}
19 | .cm-s-default span.cm-attribute {color: #00c;}
20 |
--------------------------------------------------------------------------------
/WebContent/jsonview.css:
--------------------------------------------------------------------------------
1 | body {
2 | white-space: pre;
3 | font-family: monospace;
4 | }
5 |
6 | .property {
7 | font-weight: bold;
8 | }
9 |
10 | .type-null {
11 | color: gray;
12 | }
13 |
14 | .type-boolean {
15 | color: firebrick;
16 | }
17 |
18 | .type-number {
19 | color: blue;
20 | }
21 |
22 | .type-string {
23 | color: green;
24 | }
25 |
26 | .callback-function {
27 | color: gray;
28 | }
29 |
30 | .collapser:after {
31 | content: "-";
32 | }
33 |
34 | .collapsed > .collapser:after {
35 | content: "+";
36 | }
37 |
38 | .ellipsis:after {
39 | content: " … ";
40 | }
41 |
42 | .collapsible {
43 | margin-left: 2em;
44 | }
45 |
46 | .hoverable {
47 | padding-top: 1px;
48 | padding-bottom: 1px;
49 | padding-left: 2px;
50 | padding-right: 2px;
51 | border-radius: 2px;
52 | }
53 |
54 | .hovered {
55 | background-color: rgba(235, 238, 249, 1);
56 | }
57 |
58 | .collapser {
59 | padding-right: 6px;
60 | padding-left: 6px;
61 | }
--------------------------------------------------------------------------------
/WebContent/csseditor.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Style editor - PHPView
5 |
6 |
7 |
8 |
9 |
10 |
11 | Style editor
12 |
13 |
14 | CSS
15 |
16 |
17 |
18 | Preview
19 |
20 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/WebContent/codemirror/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2011 by Marijn Haverbeke
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/WebContent/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "PHPView",
3 | "icons": {
4 | "16": "jsonview16.png",
5 | "48": "jsonview48.png",
6 | "128": "jsonview128.png"},
7 | "version": "0.2.0",
8 | "description": "Validate and view PHP print_r outputs",
9 | "options_page": "options.html",
10 | "background" : {
11 | "service_worker": "background.js"
12 | },
13 | "content_scripts": [{
14 | "matches": ["http://*/*", "https://*/*", "ftp://*/*", "file:///*"],
15 | "js": ["content.js"],
16 | "run_at" : "document_end",
17 | "all_frames" : true
18 | }],
19 | "web_accessible_resources": [{
20 | "resources": [
21 | "jsonview.css",
22 | "jsonview-core.css",
23 | "content_error.css",
24 | "options.png",
25 | "close_icon.gif",
26 | "error.gif"
27 | ],
28 | "matches": [""]
29 | },{
30 | "resources": ["workerFormatter.js", "workerJSONLint.js"],
31 | "matches": ["http://*/*", "https://*/*", "file:///*", "ftp://*/*", "chrome-extension://*/*"]
32 | }],
33 | "permissions" : ["clipboardWrite", "contextMenus", "storage"],
34 | "host_permissions" : ["http://*/", "https://*/", "ftp://*/"],
35 | "manifest_version": 3
36 | }
37 |
--------------------------------------------------------------------------------
/WebContent/options.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | PHPView options
5 |
6 |
7 |
8 |
9 |
10 |
11 |
PHPView options
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | (*) safe method forces the browser to send an extra HTTP request to get the raw HTTP content.
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Based on work Copyright (c) 2009 Benjamin Hollis
4 | Based on work Copyright (c) 2012 Gildas Lormeau
5 | Modified work Copyright (c) 2014 José Manuel Barroso Galindo
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in
15 | all copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | THE SOFTWARE.
--------------------------------------------------------------------------------
/WebContent/options.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #EEE;
3 | font-size: 10pt;
4 | }
5 |
6 | body > div {
7 | position: relative;
8 | margin: 0px auto;
9 | width: 400px;
10 | font-family: sans-serif;
11 | background-color: white;
12 | border: 1px solid #D2DBED;
13 | font-family: Arial, sans-serif;
14 | font-size: 13px;
15 | -webkit-box-shadow: #888 2px 2px 2px;
16 | }
17 |
18 | body > div > div {
19 | padding-left: 10px;
20 | padding-right: 10px;
21 | }
22 |
23 | .optionBlock {
24 | overflow: hidden;
25 | height: 30px;
26 | position: relative;
27 | }
28 |
29 | h2 {
30 | font-size: 17px;
31 | font-weight: bold;
32 | margin-bottom: 20px;
33 | }
34 |
35 | label {
36 | position: absolute;
37 | top: 2px;
38 | display: inline-block;
39 | }
40 |
41 | input[type="checkbox"] {
42 | position: absolute;
43 | right: 0px;
44 | width: auto;
45 | margin-left: 15px;
46 | margin-bottom: 5px;
47 | margin-top: 5px;
48 | width: auto;
49 | }
50 |
51 | button {
52 | position: absolute;
53 | top: -4px;
54 | right: 0px;
55 | background-color: #F3F3F3;
56 | -webkit-border-radius: 3px;
57 | right: 0px;
58 | }
59 |
60 | #main {
61 | border-radius: 5px;
62 | }
63 |
64 | #icon {
65 | width: 25px;
66 | padding-right: 10px;
67 | vertical-align: bottom;
68 | }
69 |
70 | p {
71 | margin-top: 5px;
72 | font-style: italic;
73 | text-align: justify;
74 | color: gray;
75 | }
--------------------------------------------------------------------------------
/WebContent/options.js:
--------------------------------------------------------------------------------
1 | function initOptions() {
2 | storeGet(['options'], function (data) {
3 | const options = data.options ? data.options : {};
4 | const safeMethodInput = document.getElementById("safeMethodInput")
5 | const injectInFrameInput = document.getElementById("injectInFrameInput")
6 | const addContextMenuInput = document.getElementById("addContextMenuInput");
7 | safeMethodInput.checked = options.safeMethod;
8 | injectInFrameInput.checked = options.injectInFrame;
9 | addContextMenuInput.checked = options.addContextMenu;
10 | safeMethodInput.addEventListener("change", function() {
11 | options.safeMethod = safeMethodInput.checked;
12 | storeSet({options}, function() {})
13 | });
14 | injectInFrameInput.addEventListener("change", function() {
15 | options.injectInFrame = injectInFrameInput.checked;
16 | storeSet({options}, function() {})
17 | });
18 | addContextMenuInput.addEventListener("change", function() {
19 | options.addContextMenu = addContextMenuInput.checked;
20 | storeSet({options}, function() {
21 | chrome.runtime.sendMessage({phpViewRefreshMenuEntry: true}, function() {});
22 | })
23 | });
24 | document.getElementById("open-editor").addEventListener("click", function() {
25 | location.href = "csseditor.html";
26 | }, false);
27 | })
28 | }
29 |
30 | function storeGet(key, cb) {
31 | return chrome.storage.local.get(key, cb);
32 | }
33 |
34 | function storeSet(kv, cb) {
35 | return chrome.storage.local.set(kv, cb);
36 | }
37 |
38 | addEventListener("load", initOptions, false);
39 |
--------------------------------------------------------------------------------
/WebContent/jsonview-core.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin-bottom: 23px;
3 | white-space: normal !important;
4 | }
5 |
6 | ul {
7 | list-style-type: none;
8 | padding: 0px;
9 | margin: 0px 0px 0px 26px;
10 | }
11 |
12 | li {
13 | position: relative;
14 | }
15 |
16 | .hoverable {
17 | transition: background-color .2s ease-out 0s;
18 | -webkit-transition: background-color .2s ease-out 0s;
19 | display: inline-block;
20 | }
21 |
22 | .hovered {
23 | transition-delay: .2s;
24 | -webkit-transition-delay: .2s;
25 | }
26 |
27 | .selected {
28 | outline-style: solid;
29 | outline-width: 1px;
30 | outline-style: dotted;
31 | }
32 |
33 | .collapsed>.collapsible {
34 | display: none;
35 | }
36 |
37 | .ellipsis {
38 | display: none;
39 | }
40 |
41 | .collapsed>.ellipsis {
42 | display: inherit;
43 | }
44 |
45 | .collapser {
46 | position: absolute;
47 | top: 1px;
48 | left: -1.5em;
49 | cursor: default;
50 | user-select: none;
51 | -webkit-user-select: none;
52 | }
53 |
54 | .status {
55 | position: fixed;
56 | left: 0px;
57 | bottom: 0px;
58 | min-width: 628px;
59 | border-color: #c2c2c2;
60 | border-top-width: 1px;
61 | border-right-width: 1px;
62 | border-bottom-width: 0px;
63 | border-left-width: 0px;
64 | border-style: solid;
65 | border-top-right-radius: 4px;
66 | height: 16px;
67 | padding-top: 2px;
68 | padding-bottom: 2px;
69 | padding-right: 7px;
70 | padding-left: 4px;
71 | font-family: sans-serif;
72 | font-size: 12px;
73 | opacity: 0;
74 | background-color: #d2d2f6;
75 | color: #696969;
76 | transition: opacity .2s ease-out;
77 | -webkit-transition: opacity .2s ease-out;
78 | user-select: none;
79 | -webkit-user-select: none;
80 | }
81 |
82 | .status:not(:empty ) {
83 | opacity: 1;
84 | }
85 |
86 | .toolbox {
87 | font-family: sans-serif;
88 | font-size: 13px;
89 | opacity: .25;
90 | background-color: #d2d2f6;
91 | position: fixed;
92 | right: 0px;
93 | top: 0px;
94 | border-color: #c2c2c2;
95 | border-bottom-width: 1px;
96 | border-left-width: 1px;
97 | border-top-width: 0px;
98 | border-right-width: 0px;
99 | border-style: solid;
100 | border-bottom-left-radius: 4px;
101 | padding-bottom: 3px;
102 | transition: opacity .2s ease-out;
103 | -webkit-transition: opacity .2s ease-out;
104 | cursor: default;
105 | user-select: none;
106 | -webkit-user-select: none;
107 | padding-left: 2px;
108 | }
109 |
110 | .toolbox:hover {
111 | opacity: 1;
112 | }
113 |
114 | .toolbox>* {
115 | padding-left: 3px;
116 | padding-right: 3px;
117 | }
118 |
119 | .toolbox>a {
120 | padding-left: 5px;
121 | }
122 |
123 | .toolbox>img {
124 | height: 14px;
125 | vertical-align: bottom;
126 | cursor: pointer;
127 | }
--------------------------------------------------------------------------------
/WebContent/csseditor.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | var SAMPLE_PART1 = '{- hey: "guy",
- anumber: 243,
- anobject: {
- whoa: "nuts",
- anarray: [
- 1,
- 2,
- "thr<h1>ee"
], - more: "stuff"
}, - awesome: true,
- bogus: false,
- meaning: null,
- notLink: "http://jsonview.com is great"
}';
5 | var PASSIVE_KEYS = [ "Down", "Up", "Left", "Right", "End", "Home", "PageDown", "PageUp", "Control", "Alt", "Shift", "Insert" ];
6 |
7 | var bgPage = chrome.extension.getBackgroundPage(), editor = document.getElementById("editor"), resetButton = document.getElementById("reset-button"), saveButton = document
8 | .getElementById("save-button"), previewer = document.getElementById("previewer").contentWindow, codemirror;
9 |
10 | function updatePreview() {
11 | previewer.document.open();
12 | previewer.document.write(SAMPLE_PART1);
13 | previewer.document.write(codemirror.getValue());
14 | previewer.document.write(SAMPLE_PART2);
15 | previewer.document.close();
16 | }
17 |
18 | resetButton.addEventListener("click", function() {
19 | bgPage.getDefaultTheme(function(theme) {
20 | codemirror.setValue(theme);
21 | updatePreview();
22 | });
23 | }, false);
24 |
25 | saveButton.addEventListener("click", function() {
26 | localStorage.theme = codemirror.getValue();
27 | }, false);
28 |
29 | addEventListener("load", function() {
30 | var timeoutOnKey;
31 | codemirror = CodeMirror.fromTextArea(editor, {
32 | onKeyEvent : function(editor, event) {
33 | if (event.type == "keyup" && PASSIVE_KEYS.indexOf(event.keyIdentifier) == -1) {
34 | if (timeoutOnKey)
35 | clearTimeout(timeoutOnKey);
36 | timeoutOnKey = setTimeout(updatePreview, 500);
37 | }
38 | }
39 | });
40 | codemirror.setValue(localStorage.theme);
41 | updatePreview();
42 | }, false);
43 |
44 | })();
45 |
--------------------------------------------------------------------------------
/WebContent/csseditor.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #EEE;
3 | font-size: 10pt;
4 | }
5 |
6 | body>div {
7 | margin-left: auto;
8 | margin-right: auto;
9 | width: 950px;
10 | background-color: white;
11 | font-family: sans-serif;
12 | margin-bottom: 10px;
13 | border-width: 0px;
14 | border-style: solid;
15 | border-radius: 5px;
16 | padding-left: 10px;
17 | padding-right: 10px;
18 | padding-bottom: 5px;
19 | text-align: justify;
20 | -webkit-box-shadow: #888 2px 2px 2px;
21 | }
22 |
23 | h2 {
24 | padding-left: .1em;
25 | padding-top: 1em;
26 | padding-bottom: .1em;
27 | }
28 |
29 | #previewer {
30 | width: 420px;
31 | height: 315px;
32 | border-width: 1px;
33 | border-style: solid;
34 | border-color: #aaa;
35 | }
36 |
37 | #editor,.CodeMirror {
38 | width: 500px;
39 | height: 590px;
40 | border-width: 1px;
41 | border-style: solid;
42 | border-color: #aaa;
43 | }
44 |
45 | .CodeMirror .CodeMirror-scroll {
46 | height: 100%;
47 | }
48 |
49 | .panel {
50 | height: 620px;
51 | vertical-align: top;
52 | display: inline-block;
53 | margin: 5px;
54 | position: relative;
55 | }
56 |
57 | .panel-label {
58 | height: 20px;
59 | }
60 |
61 | .buttons {
62 | position: absolute;
63 | bottom: 0px;
64 | right: 0px;
65 | }
66 |
67 | .buttons button {
68 | background-color: #F3F3F3;
69 | -webkit-border-radius: 3px;
70 | }
71 |
72 |
73 | ::-webkit-scrollbar {
74 | height: 16px;
75 | overflow: visible;
76 | width: 16px
77 | }
78 |
79 | ::-webkit-scrollbar-button {
80 | height: 0;
81 | width: 0
82 | }
83 |
84 | ::-webkit-scrollbar-track {
85 | background-clip: padding-box;
86 | border: solid transparent;
87 | border-width: 0 0 0 7px
88 | }
89 |
90 | ::-webkit-scrollbar-track:horizontal {
91 | border-width: 7px 0 0
92 | }
93 |
94 | ::-webkit-scrollbar-track:hover {
95 | background-color: rgba(0, 0, 0, .05);
96 | box-shadow: inset 1px 0 0 rgba(0, 0, 0, .1)
97 | }
98 |
99 | ::-webkit-scrollbar-track:horizontal:hover {
100 | box-shadow: inset 0 1px 0 rgba(0, 0, 0, .1)
101 | }
102 |
103 | ::-webkit-scrollbar-track:active {
104 | background-color: rgba(0, 0, 0, .05);
105 | box-shadow: inset 1px 0 0 rgba(0, 0, 0, .14), inset -1px 0 0
106 | rgba(0, 0, 0, .07)
107 | }
108 |
109 | ::-webkit-scrollbar-track:horizontal:active {
110 | box-shadow: inset 0 1px 0 rgba(0, 0, 0, .14), inset 0 -1px 0
111 | rgba(0, 0, 0, .07)
112 | }
113 |
114 | ::-webkit-scrollbar-thumb {
115 | background-color: rgba(0, 0, 0, .2);
116 | background-clip: padding-box;
117 | border: solid transparent;
118 | border-width: 0 0 0 7px;
119 | min-height: 28px;
120 | padding: 100px 0 0;
121 | box-shadow: inset 1px 1px 0 rgba(0, 0, 0, .1), inset 0 -1px 0
122 | rgba(0, 0, 0, .07)
123 | }
124 |
125 | ::-webkit-scrollbar-thumb:horizontal {
126 | border-width: 7px 0 0;
127 | padding: 0 0 0 100px;
128 | box-shadow: inset 1px 1px 0 rgba(0, 0, 0, .1), inset -1px 0 0
129 | rgba(0, 0, 0, .07)
130 | }
131 |
132 | ::-webkit-scrollbar-thumb:hover {
133 | background-color: rgba(0, 0, 0, .4);
134 | box-shadow: inset 1px 1px 1px rgba(0, 0, 0, .25)
135 | }
136 |
137 | ::-webkit-scrollbar-thumb:active {
138 | background-color: rgba(0, 0, 0, 0.5);
139 | box-shadow: inset 1px 1px 3px rgba(0, 0, 0, 0.35)
140 | }
141 |
142 | ::-webkit-scrollbar-corner {
143 | background: transparent
144 | }
145 |
146 | body::-webkit-scrollbar-track-piece {
147 | background-clip: padding-box;
148 | background-color: #f5f5f5;
149 | border: solid #fff;
150 | border-width: 0 0 0 3px;
151 | box-shadow: inset 1px 0 0 rgba(0, 0, 0, .14), inset -1px 0 0
152 | rgba(0, 0, 0, .07)
153 | }
154 |
155 | body::-webkit-scrollbar-track-piece:horizontal {
156 | border-width: 3px 0 0;
157 | box-shadow: inset 0 1px 0 rgba(0, 0, 0, .14), inset 0 -1px 0
158 | rgba(0, 0, 0, .07)
159 | }
160 |
161 | body::-webkit-scrollbar-thumb {
162 | border-width: 1px 1px 1px 5px
163 | }
164 |
165 | body::-webkit-scrollbar-thumb:horizontal {
166 | border-width: 5px 1px 1px
167 | }
168 |
169 | body::-webkit-scrollbar-corner {
170 | background-clip: padding-box;
171 | background-color: #f5f5f5;
172 | border: solid #fff;
173 | border-width: 3px 0 0 3px;
174 | box-shadow: inset 1px 1px 0 rgba(0, 0, 0, .14)
175 | }
--------------------------------------------------------------------------------
/WebContent/background.js:
--------------------------------------------------------------------------------
1 | var path, value, copyPathMenuEntryId, copyValueMenuEntryId;
2 |
3 | function getDefaultTheme(callback) {
4 | fetch(chrome.runtime.getURL('jsonview.css'))
5 | .then(response => response.text())
6 | .then(function(responseText) {
7 | callback(responseText);
8 | })
9 | .catch(function(e) {
10 | console.error('PHPViewExtensions error fetching the custom theme.', e);
11 | callback("");
12 | })
13 | }
14 |
15 | function storeGet(key, cb) {
16 | return chrome.storage.local.get(key, cb);
17 | }
18 |
19 | function storeSet(kv, cb) {
20 | return chrome.storage.local.set(kv, cb);
21 | }
22 |
23 | function setCopy(tab, value) {
24 | chrome.tabs.sendMessage(tab.id, {
25 | writeToClipboard: value
26 | }, function(_response) {});
27 | }
28 |
29 | function refreshMenuEntry(port) {
30 | storeGet(['options'], function(data) {
31 | const options = data.options ? data.options : {};
32 | if (options.addContextMenu && !copyPathMenuEntryId) {
33 | copyPathMenuEntryId = chrome.contextMenus.create({
34 | title : "Copy path",
35 | id : "copy-path",
36 | contexts : [ "page", "link", "selection" ],
37 | });
38 | copyValueMenuEntryId = chrome.contextMenus.create({
39 | title : "Copy value",
40 | id : "copy-value",
41 | contexts : [ "page", "link", "selection" ],
42 | });
43 | chrome.contextMenus.onClicked.addListener((info, tab) => {
44 | if (!info.menuItemId) {
45 | return;
46 | }
47 | switch (info.menuItemId) {
48 | case 'copy-path': setCopy(tab, path); break;
49 | case 'copy-value': setCopy(tab, value); break;
50 | }
51 | })
52 | }
53 | if (!options.addContextMenu && copyPathMenuEntryId) {
54 | chrome.contextMenus.remove(copyPathMenuEntryId);
55 | chrome.contextMenus.remove(copyValueMenuEntryId);
56 | copyPathMenuEntryId = null;
57 | }
58 | });
59 | }
60 |
61 | function onWorkerJSONLintMessage(port, response) {
62 | if (response?.workerMessage?.error) {
63 | port.postMessage({
64 | ongetError : true,
65 | error : response.workerMessage.error,
66 | loc : response.workerMessage.loc,
67 | offset : msg.offset
68 | });
69 | }
70 | }
71 |
72 | function onWorkerFormatterMessage(port, response) {
73 | const message = response.workerMessage;
74 | if (message.html) {
75 | storeGet(['theme'], function(data) {
76 | port.postMessage({
77 | onjsonToHTML : true,
78 | html : message.html,
79 | theme : data.theme,
80 | jsonObject : message.jsonObject
81 | });
82 | })
83 | }
84 | if (message.error) {
85 | chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
86 | if (!tabs[0]) {
87 | return;
88 | }
89 | chrome.tabs.sendMessage(tabs[0].id, {
90 | action: 'workerJSONLintMessage',
91 | json: msg.json,
92 | }, function (response) {
93 | onWorkerJSONLintMessage(port, response)
94 | });
95 | });
96 | }
97 | }
98 |
99 | function init() {
100 | chrome.runtime.onConnect.addListener(function(port) {
101 | port.onMessage.addListener(function(msg) {
102 | if (msg.init) {
103 | storeGet(['options'], function(data) {
104 | port.postMessage({
105 | oninit : true,
106 | options : data.options ? data.options : {}
107 | });
108 | });
109 | }
110 | if (msg.copyPropertyPath) {
111 | path = msg.path;
112 | value = msg.value;
113 | }
114 | if (msg.jsonToHTML) {
115 | chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
116 | if (!tabs[0]) {
117 | return;
118 | }
119 | chrome.tabs.sendMessage(tabs[0].id, {
120 | action: 'workerFormatterMessage',
121 | json: msg.json,
122 | }, function (response) {
123 | onWorkerFormatterMessage(port, response)
124 | });
125 | });
126 | }
127 | });
128 | refreshMenuEntry(port);
129 | chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
130 | if (message.phpViewRefreshMenuEntry) {
131 | refreshMenuEntry(port)
132 | }
133 | sendResponse(true);
134 | });
135 | });
136 | }
137 |
138 | storeGet(['options', 'theme'], function(data) {
139 | const options = data.options ? data.options : {};
140 | let setOptions = false;
141 | if (typeof options.addContextMenu == "undefined") {
142 | options.addContextMenu = false;
143 | setOptions = true;
144 | }
145 | if (typeof data.theme !== 'string') {
146 | getDefaultTheme(function (defaultTheme) {
147 | storeSet({ options, theme: defaultTheme }, function () {
148 | init();
149 | });
150 | });
151 | } else if (setOptions) {
152 | storeSet({ options }, function () {
153 | init();
154 | });
155 | } else {
156 | init();
157 | }
158 | })
159 |
--------------------------------------------------------------------------------
/WebContent/codemirror/codemirror.css:
--------------------------------------------------------------------------------
1 | .CodeMirror {
2 | line-height: 1em;
3 | font-family: monospace;
4 |
5 | /* Necessary so the scrollbar can be absolutely positioned within the wrapper on Lion. */
6 | position: relative;
7 | /* This prevents unwanted scrollbars from showing up on the body and wrapper in IE. */
8 | overflow: hidden;
9 | }
10 |
11 | .CodeMirror-scroll {
12 | overflow: auto;
13 | height: 300px;
14 | /* This is needed to prevent an IE[67] bug where the scrolled content
15 | is visible outside of the scrolling box. */
16 | position: relative;
17 | outline: none;
18 | }
19 |
20 | /* Vertical scrollbar */
21 | .CodeMirror-scrollbar {
22 | position: absolute;
23 | right: 0; top: 0;
24 | overflow-x: hidden;
25 | overflow-y: scroll;
26 | z-index: 5;
27 | }
28 | .CodeMirror-scrollbar-inner {
29 | /* This needs to have a nonzero width in order for the scrollbar to appear
30 | in Firefox and IE9. */
31 | width: 1px;
32 | }
33 | .CodeMirror-scrollbar.cm-sb-overlap {
34 | /* Ensure that the scrollbar appears in Lion, and that it overlaps the content
35 | rather than sitting to the right of it. */
36 | position: absolute;
37 | z-index: 1;
38 | float: none;
39 | right: 0;
40 | min-width: 12px;
41 | }
42 | .CodeMirror-scrollbar.cm-sb-nonoverlap {
43 | min-width: 12px;
44 | }
45 | .CodeMirror-scrollbar.cm-sb-ie7 {
46 | min-width: 18px;
47 | }
48 |
49 | .CodeMirror-gutter {
50 | position: absolute; left: 0; top: 0;
51 | z-index: 10;
52 | background-color: #f7f7f7;
53 | border-right: 1px solid #eee;
54 | min-width: 2em;
55 | height: 100%;
56 | }
57 | .CodeMirror-gutter-text {
58 | color: #aaa;
59 | text-align: right;
60 | padding: .4em .2em .4em .4em;
61 | white-space: pre !important;
62 | cursor: default;
63 | }
64 | .CodeMirror-lines {
65 | padding: .4em;
66 | white-space: pre;
67 | cursor: text;
68 | }
69 |
70 | .CodeMirror pre {
71 | -moz-border-radius: 0;
72 | -webkit-border-radius: 0;
73 | -o-border-radius: 0;
74 | border-radius: 0;
75 | border-width: 0; margin: 0; padding: 0; background: transparent;
76 | font-family: inherit;
77 | font-size: inherit;
78 | padding: 0; margin: 0;
79 | white-space: pre;
80 | word-wrap: normal;
81 | line-height: inherit;
82 | color: inherit;
83 | overflow: visible;
84 | }
85 |
86 | .CodeMirror-wrap pre {
87 | word-wrap: break-word;
88 | white-space: pre-wrap;
89 | word-break: normal;
90 | }
91 | .CodeMirror-wrap .CodeMirror-scroll {
92 | overflow-x: hidden;
93 | }
94 |
95 | .CodeMirror textarea {
96 | outline: none !important;
97 | }
98 |
99 | .CodeMirror pre.CodeMirror-cursor {
100 | z-index: 10;
101 | position: absolute;
102 | visibility: hidden;
103 | border-left: 1px solid black;
104 | border-right: none;
105 | width: 0;
106 | }
107 | .cm-keymap-fat-cursor pre.CodeMirror-cursor {
108 | width: auto;
109 | border: 0;
110 | background: transparent;
111 | background: rgba(0, 200, 0, .4);
112 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800);
113 | }
114 | /* Kludge to turn off filter in ie9+, which also accepts rgba */
115 | .cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id) {
116 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
117 | }
118 | .CodeMirror pre.CodeMirror-cursor.CodeMirror-overwrite {}
119 | .CodeMirror-focused pre.CodeMirror-cursor {
120 | visibility: visible;
121 | }
122 |
123 | div.CodeMirror-selected { background: #d9d9d9; }
124 | .CodeMirror-focused div.CodeMirror-selected { background: #d7d4f0; }
125 |
126 | .CodeMirror-searching {
127 | background: #ffa;
128 | background: rgba(255, 255, 0, .4);
129 | }
130 |
131 | /* Default theme */
132 |
133 | .cm-s-default span.cm-keyword {color: #708;}
134 | .cm-s-default span.cm-atom {color: #219;}
135 | .cm-s-default span.cm-number {color: #164;}
136 | .cm-s-default span.cm-def {color: #00f;}
137 | .cm-s-default span.cm-variable {color: black;}
138 | .cm-s-default span.cm-variable-2 {color: #05a;}
139 | .cm-s-default span.cm-variable-3 {color: #085;}
140 | .cm-s-default span.cm-property {color: black;}
141 | .cm-s-default span.cm-operator {color: black;}
142 | .cm-s-default span.cm-comment {color: #a50;}
143 | .cm-s-default span.cm-string {color: #a11;}
144 | .cm-s-default span.cm-string-2 {color: #f50;}
145 | .cm-s-default span.cm-meta {color: #555;}
146 | .cm-s-default span.cm-error {color: #f00;}
147 | .cm-s-default span.cm-qualifier {color: #555;}
148 | .cm-s-default span.cm-builtin {color: #30a;}
149 | .cm-s-default span.cm-bracket {color: #997;}
150 | .cm-s-default span.cm-tag {color: #170;}
151 | .cm-s-default span.cm-attribute {color: #00c;}
152 | .cm-s-default span.cm-header {color: blue;}
153 | .cm-s-default span.cm-quote {color: #090;}
154 | .cm-s-default span.cm-hr {color: #999;}
155 | .cm-s-default span.cm-link {color: #00c;}
156 |
157 | span.cm-header, span.cm-strong {font-weight: bold;}
158 | span.cm-em {font-style: italic;}
159 | span.cm-emstrong {font-style: italic; font-weight: bold;}
160 | span.cm-link {text-decoration: underline;}
161 |
162 | span.cm-invalidchar {color: #f00;}
163 |
164 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
165 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
166 |
167 | @media print {
168 |
169 | /* Hide the cursor when printing */
170 | .CodeMirror pre.CodeMirror-cursor {
171 | visibility: hidden;
172 | }
173 |
174 | }
175 |
--------------------------------------------------------------------------------
/WebContent/workerFormatter.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Adapted the code in to order to run in a web worker.
3 | *
4 | * Original author: Benjamin Hollis
5 | * parse_PHP author: José Manuel Barroso Galindo
6 | */
7 |
8 | function htmlEncode(t) {
9 | return t != null ? t.toString().replace(/&/g, "&").replace(/"/g, """).replace(//g, ">") : '';
10 | }
11 |
12 | function decorateWithSpan(value, className) {
13 | return '' + htmlEncode(value) + '';
14 | }
15 |
16 | function valueToHTML(value) {
17 | var valueType = typeof value, output = "";
18 | if (value == null)
19 | output += decorateWithSpan("null", "type-null");
20 | else if (value && value.constructor == Array)
21 | output += arrayToHTML(value);
22 | else if (valueType == "object")
23 | output += objectToHTML(value);
24 | else if (valueType == "number")
25 | output += decorateWithSpan(value, "type-number");
26 | else if (valueType == "string")
27 | if (/^(http|https):\/\/[^\s]+$/.test(value))
28 | output += decorateWithSpan('"', "type-string") + '' + htmlEncode(value) + '' + decorateWithSpan('"', "type-string");
29 | else
30 | output += decorateWithSpan('"' + value + '"', "type-string");
31 | else if (valueType == "boolean")
32 | output += decorateWithSpan(value, "type-boolean");
33 |
34 | return output;
35 | }
36 |
37 | function arrayToHTML(json) {
38 | var i, length, output = '[', hasContents = false;
39 | for (i = 0, length = json.length; i < length; i++) {
40 | hasContents = true;
41 | output += '- ';
42 | output += valueToHTML(json[i]);
43 | if (i < length - 1)
44 | output += ',';
45 | output += '
';
46 | }
47 | output += '
]';
48 | if (!hasContents)
49 | output = "[ ]";
50 | return output;
51 | }
52 |
53 | function objectToHTML(json) {
54 | var i, key, length, keys = Object.keys(json), output = '{', hasContents = false;
55 | for (i = 0, length = keys.length; i < length; i++) {
56 | key = keys[i];
57 | hasContents = true;
58 | output += '- ';
59 | output += '' + htmlEncode(key) + ': ';
60 | output += valueToHTML(json[key]);
61 | if (i < length - 1)
62 | output += ',';
63 | output += '
';
64 | }
65 | output += '
}';
66 | if (!hasContents)
67 | output = "{ }";
68 | return output;
69 | }
70 |
71 | function jsonToHTML(json, fnName) {
72 | var output = '';
73 | if (fnName)
74 | output += '' + htmlEncode(fnName) + '(';
75 | output += '';
76 | output += valueToHTML(json);
77 | output += '';
78 | if (fnName)
79 | output += ')';
80 | return output;
81 | }
82 |
83 | function parse_PHP(input) {
84 | "use strict";
85 | var arrow1 = "=> ",
86 | arrow2 = "=> ";
87 | var trim = function(string) {
88 | return string.replace(/^\s+|\s+$/g, '');
89 | }
90 | var is_array = function(line) {
91 | return trim(line).indexOf("Array") !== -1 || trim(line).indexOf("Object") !== -1;
92 | }
93 | var is_beg_a = function(line) {
94 | return trim(line) == "(";
95 | }
96 | var is_end_a = function(line) {
97 | return trim(line) == ")";
98 | }
99 | var is_elmnt1 = function(line) {
100 | return line.match(/\[(.+?)\] =>/);
101 | }
102 | var is_elmnt2 = function(line) {
103 | return line.match(/\[(.+?)\] =>/);
104 | }
105 | var is_elmnt = function(line) {
106 | return is_elmnt1(line) || is_elmnt2(line);
107 | }
108 | var get_elmnt_key = function(line) {
109 | return line.match(/\[(.+?)\]/)[1];
110 | }
111 | var get_elmnt_value1 = function(line) {
112 | return line.slice(line.indexOf(arrow1) + arrow1.length);
113 | }
114 | var get_elmnt_value2 = function(line) {
115 | return line.slice(line.indexOf(arrow2) + arrow2.length);
116 | }
117 | var get_elmnt_value = function(line) {
118 | return is_elmnt1(line) ? get_elmnt_value1(line) : get_elmnt_value2(line);
119 | }
120 |
121 | var parse_array = function(lines) {
122 | var ret = {}
123 | while (lines.length > 0) {
124 | var line = lines.shift();
125 | if (is_elmnt(line)) {
126 | var key = get_elmnt_key(line);
127 | if (is_array(line) && is_beg_a(lines[0])) {
128 | var val = {__parent: ret};
129 | ret[key] = val;
130 | ret = val;
131 | } else {
132 | ret[key] = get_elmnt_value(line);
133 | }
134 |
135 | } else if (is_end_a(line)) {
136 | if (ret.__parent) {
137 | var temp = ret.__parent;
138 | delete ret.__parent;
139 | ret = temp;
140 | } else {
141 | break;
142 | }
143 | }
144 | }
145 | return ret;
146 | }
147 |
148 | var lines = trim(input).split("\n");
149 | var ret = [];
150 | while (lines.length > 0) {
151 | var line = lines.shift();
152 | ret.push(is_array(line) ? parse_array(lines) : line);
153 | }
154 | return ret;
155 | }
156 |
157 | addEventListener("message", function(event) {
158 | var object;
159 | try {
160 | object = parse_PHP(event.data.json);
161 | } catch (e) {
162 | postMessage({
163 | error : true
164 | });
165 | return;
166 | }
167 | postMessage({
168 | onjsonToHTML : true,
169 | html : jsonToHTML(object, event.data.fnName),
170 | jsonObject: object
171 | });
172 | }, false);
173 |
--------------------------------------------------------------------------------
/WebContent/content.js:
--------------------------------------------------------------------------------
1 | var port = chrome.runtime.connect(), collapsers, options, jsonSelector;
2 | let content
3 |
4 | function displayError(error, loc, offset) {
5 | const link = document.createElement("link");
6 | const pre = document.body.firstChild.firstChild;
7 | const text = pre.textContent.substring(offset);
8 | const start = 0;
9 | const ranges = [];
10 | const idx = 0;
11 | let end, range = document.createRange();
12 | const imgError = document.createElement("img");
13 | content = document.createElement("div");
14 | const errorPosition = document.createElement("span");
15 | const container = document.createElement("div");
16 | const closeButton = document.createElement("div");;
17 | link.rel = "stylesheet";
18 | link.type = "text/css";
19 | link.href = chrome.runtime.getURL("content_error.css");
20 | document.head.appendChild(link);
21 | while (idx != -1) {
22 | idx = text.indexOf("\n", start);
23 | ranges.push(start);
24 | start = idx + 1;
25 | }
26 | start = ranges[loc.first_line - 1] + loc.first_column + offset;
27 | end = ranges[loc.last_line - 1] + loc.last_column + offset;
28 | range.setStart(pre, start);
29 | if (start == end - 1)
30 | range.setEnd(pre, start);
31 | else
32 | range.setEnd(pre, end);
33 | errorPosition.className = "error-position";
34 | errorPosition.id = "error-position";
35 | range.surroundContents(errorPosition);
36 | imgError.src = chrome.runtime.getURL("error.gif");
37 | errorPosition.insertBefore(imgError, errorPosition.firstChild);
38 | content.className = "content";
39 | closeButton.className = "close-error";
40 | closeButton.onclick = function() {
41 | content.parentElement.removeChild(content);
42 | };
43 | content.textContent = error;
44 | content.appendChild(closeButton);
45 | container.className = "container";
46 | container.appendChild(content);
47 | errorPosition.parentNode.insertBefore(container, errorPosition.nextSibling);
48 | location.hash = "error-position";
49 | history.replaceState({}, "", "#");
50 | }
51 |
52 | function displayUI(theme, html, jsonObject) {
53 | var statusElement, toolboxElement, expandElement, reduceElement, viewSourceElement, optionsElement, userStyleElement, baseStyleElement;
54 | content += '';
55 | baseStyleElement = document.createElement("link");
56 | content += "";
57 | baseStyleElement.rel = "stylesheet";
58 | content += html;
59 | baseStyleElement.type = "text/css";
60 | document.body.innerHTML = content;
61 | baseStyleElement.href = chrome.runtime.getURL("jsonview-core.css");
62 | document.head.appendChild(baseStyleElement);
63 | userStyleElement = document.createElement("style");
64 | userStyleElement.appendChild(document.createTextNode(theme));
65 | document.head.appendChild(userStyleElement);
66 | document.body.innerHTML = html;
67 | collapsers = document.querySelectorAll("#json .collapsible .collapsible");
68 | statusElement = document.createElement("div");
69 | statusElement.className = "status";
70 | copyPathElement = document.createElement("div");
71 | copyPathElement.className = "copy-path";
72 | statusElement.appendChild(copyPathElement);
73 | document.body.appendChild(statusElement);
74 | toolboxElement = document.createElement("div");
75 | toolboxElement.className = "toolbox";
76 | expandElement = document.createElement("span");
77 | expandElement.title = "expand all";
78 | expandElement.innerText = "+";
79 | reduceElement = document.createElement("span");
80 | reduceElement.title = "reduce all";
81 | reduceElement.innerText = "-";
82 | viewSourceElement = document.createElement("a");
83 | viewSourceElement.innerText = "View source";
84 | viewSourceElement.target = "_blank";
85 | viewSourceElement.href = "view-source:" + location.href;
86 | optionsElement = document.createElement("img");
87 | optionsElement.title = "options";
88 | optionsElement.src = chrome.runtime.getURL("options.png");
89 | toolboxElement.appendChild(expandElement);
90 | toolboxElement.appendChild(reduceElement);
91 | toolboxElement.appendChild(viewSourceElement);
92 | toolboxElement.appendChild(optionsElement);
93 | document.body.appendChild(toolboxElement);
94 | document.body.addEventListener('click', ontoggle, false);
95 | document.body.addEventListener('mouseover', onmouseMove, false);
96 | document.body.addEventListener('click', onmouseClick, false);
97 | document.body.addEventListener('contextmenu', (event) => onContextMenu(event, jsonObject), false);
98 | expandElement.addEventListener('click', onexpand, false);
99 | reduceElement.addEventListener('click', onreduce, false);
100 | optionsElement.addEventListener("click", function() {
101 | window.open(chrome.runtime.getURL("options.html"));
102 | }, false);
103 | copyPathElement.addEventListener("click", function(event) {
104 | if (event.isTrusted === false)
105 | return;
106 |
107 | port.postMessage({
108 | copyPropertyPath : true,
109 | path : statusElement.innerText
110 | });
111 | }, false);
112 | }
113 |
114 | function extractData(rawText) {
115 | var tokens, text = rawText.trim();
116 |
117 | function test(text) {
118 | var pre = text.indexOf("");
119 | var arr = text.indexOf("Array\n(" );
120 | var obj = text.indexOf("Object\n(");
121 | return arr === 0 || obj === 0 || (pre < 10 && (arr !== -1 || obj !== -1));
122 | }
123 |
124 | if (test(text)) {
125 | var offset = text.indexOf("");
126 | return {
127 | text : rawText,
128 | offset : offset !== -1 ? offset : 0
129 | };
130 | }
131 | tokens = text.match(/^([^\s\(]*)\s*\(([\s\S]*)\)\s*;?$/);
132 | if (tokens && tokens[1] && tokens[2]) {
133 | if (test(tokens[2].trim()))
134 | return {
135 | fnName : tokens[1],
136 | text : tokens[2],
137 | offset : rawText.indexOf(tokens[2])
138 | };
139 | }
140 | }
141 |
142 | function processData(data) {
143 |
144 | var xhr, jsonText;
145 |
146 | function formatToHTML(fnName, offset) {
147 | if (!jsonText)
148 | return;
149 |
150 | port.postMessage({
151 | jsonToHTML : true,
152 | json : jsonText,
153 | fnName : fnName,
154 | offset : offset
155 | });
156 | }
157 |
158 | if (window == top || options.injectInFrame)
159 | if (options.safeMethod) {
160 | fetch(document.location.href)
161 | .then(response => response.text())
162 | .then(responseText => {
163 | const data = extractData(responseText);
164 | if (data) {
165 | jsonText = data.text;
166 | formatToHTML(data.fnName, data.offset);
167 | }
168 | })
169 | .catch(fetchError => {
170 | console.error('Unsafe request not working well on PHPView, please disable it.', fetchError)
171 | });
172 | } else if (data) {
173 | jsonText = data.text;
174 | formatToHTML(data.fnName, data.offset);
175 | }
176 | }
177 |
178 | function ontoggle(event) {
179 | var collapsed, target = event.target;
180 | if (event.target.className == 'collapser') {
181 | collapsed = target.parentNode.getElementsByClassName('collapsible')[0];
182 | if (collapsed.parentNode.classList.contains("collapsed"))
183 | collapsed.parentNode.classList.remove("collapsed");
184 | else
185 | collapsed.parentNode.classList.add("collapsed");
186 | }
187 | }
188 |
189 | function onexpand() {
190 | Array.prototype.forEach.call(collapsers, function(collapsed) {
191 | if (collapsed.parentNode.classList.contains("collapsed"))
192 | collapsed.parentNode.classList.remove("collapsed");
193 | });
194 | }
195 |
196 | function onreduce() {
197 | Array.prototype.forEach.call(collapsers, function(collapsed) {
198 | if (!collapsed.parentNode.classList.contains("collapsed"))
199 | collapsed.parentNode.classList.add("collapsed");
200 | });
201 | }
202 |
203 | function getParentLI(element) {
204 | if (element.tagName != "LI")
205 | while (element && element.tagName != "LI")
206 | element = element.parentNode;
207 | if (element && element.tagName == "LI")
208 | return element;
209 | }
210 |
211 | var onmouseMove = (function() {
212 | var hoveredLI;
213 |
214 | function onmouseOut() {
215 | var statusElement = document.querySelector(".status");
216 | if (hoveredLI) {
217 | hoveredLI.firstChild.classList.remove("hovered");
218 | hoveredLI = null;
219 | statusElement.innerText = "";
220 | jsonSelector = [];
221 | }
222 | }
223 |
224 | return function(event) {
225 | if (event.isTrusted === false)
226 | return;
227 | var str = "", statusElement = document.querySelector(".status");
228 | element = getParentLI(event.target);
229 | if (element) {
230 | jsonSelector = [];
231 | if (hoveredLI)
232 | hoveredLI.firstChild.classList.remove("hovered");
233 | hoveredLI = element;
234 | element.firstChild.classList.add("hovered");
235 | do {
236 | if (element.parentNode.classList.contains("array")) {
237 | var index = [].indexOf.call(element.parentNode.children, element);
238 | str = "[" + index + "]" + str;
239 | jsonSelector.unshift(index);
240 | }
241 | if (element.parentNode.classList.contains("obj")) {
242 | var key = element.firstChild.firstChild.innerText;
243 | str = "." + key + str;
244 | jsonSelector.unshift(key);
245 | }
246 | element = element.parentNode.parentNode.parentNode;
247 | } while (element.tagName == "LI");
248 | if (str.charAt(0) == '.')
249 | str = str.substring(1);
250 | statusElement.innerText = str;
251 | return;
252 | }
253 | onmouseOut();
254 | };
255 | })();
256 |
257 | var selectedLI;
258 |
259 | function onmouseClick() {
260 | if (selectedLI)
261 | selectedLI.firstChild.classList.remove("selected");
262 | selectedLI = getParentLI(event.target);
263 | if (selectedLI) {
264 | selectedLI.firstChild.classList.add("selected");
265 | }
266 | }
267 |
268 | function onContextMenu(event, jsonObject) {
269 | var currentLI, statusElement, selection = "", i, value;
270 | currentLI = getParentLI(event.target);
271 | statusElement = document.querySelector(".status");
272 | if (currentLI) {
273 |
274 | var value = jsonObject;
275 | jsonSelector.forEach(function(idx) {
276 | value = value[idx];
277 | });
278 |
279 | port.postMessage({
280 | copyPropertyPath : true,
281 | path : statusElement.innerText,
282 | value : typeof value == "object" ? JSON.stringify(value) : value
283 | });
284 | }
285 | }
286 |
287 | function init(data) {
288 | port.onMessage.addListener(function(msg) {
289 | if (msg.oninit) {
290 | options = msg.options;
291 | processData(data);
292 | }
293 | if (msg.onjsonToHTML)
294 | if (msg.html) {
295 | displayUI(msg.theme, msg.html, msg.jsonObject);
296 | } else if (msg.json)
297 | port.postMessage({
298 | getError : true,
299 | json : msg.json,
300 | fnName : data.fnName
301 | });
302 | if (msg.ongetError) {
303 | displayError(msg.error, msg.loc, msg.offset);
304 | }
305 | });
306 | port.postMessage({
307 | init : true
308 | });
309 | }
310 |
311 | function load() {
312 | var child, data;
313 | if (document.body.innerHTML.indexOf("Array\n(" ) !== -1 ||
314 | document.body.innerHTML.indexOf("Object\n(") !== -1
315 | ) {
316 | data = extractData(document.body.innerHTML);
317 | if (data) {
318 | init(data);
319 | }
320 | }
321 | }
322 |
323 | load();
324 |
325 | function startWorker(message, sendResponse, filename) {
326 | fetch(chrome.runtime.getURL(filename))
327 | .then(fetchResponse => fetchResponse.text())
328 | .then(function (scriptText) {
329 | const blob = new Blob([scriptText], { type: 'application/javascript' });
330 | return URL.createObjectURL(blob);
331 | })
332 | .then(workerUrl => {
333 | const worker = new Worker(workerUrl);
334 |
335 | worker.addEventListener('message', (event) => {
336 | sendResponse({ workerMessage: event.data });
337 | worker.terminate();
338 | });
339 |
340 | worker.postMessage({
341 | json: message.json,
342 | });
343 | })
344 | .catch(fetchError => {
345 | console.error('Error fetching worker script on PHPView:', fetchError)
346 | });
347 | }
348 |
349 | chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
350 | if (message.action === 'workerFormatterMessage') {
351 | startWorker(message, sendResponse, 'workerFormatter.js')
352 | } else if (message.action === 'workerJSONLintMessage') {
353 | startWorker(message, sendResponse, 'workerJSONLint.js')
354 | }
355 | return true;
356 | });
357 |
358 | chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
359 | if (message.writeToClipboard) {
360 | navigator.clipboard.writeText(message.writeToClipboard)
361 | .then(() => sendResponse())
362 | .catch(_e => {});
363 | }
364 | });
365 |
--------------------------------------------------------------------------------
/WebContent/workerJSONLint.js:
--------------------------------------------------------------------------------
1 | /* Jison generated parser */
2 | var jsonlint = (function(){
3 | var parser = {trace: function trace() { },
4 | yy: {},
5 | symbols_: {"error":2,"JSONString":3,"STRING":4,"JSONNumber":5,"NUMBER":6,"JSONNullLiteral":7,"NULL":8,"JSONBooleanLiteral":9,"TRUE":10,"FALSE":11,"JSONText":12,"JSONValue":13,"EOF":14,"JSONObject":15,"JSONArray":16,"{":17,"}":18,"JSONMemberList":19,"JSONMember":20,":":21,",":22,"[":23,"]":24,"JSONElementList":25,"$accept":0,"$end":1},
6 | terminals_: {2:"error",4:"STRING",6:"NUMBER",8:"NULL",10:"TRUE",11:"FALSE",14:"EOF",17:"{",18:"}",21:":",22:",",23:"[",24:"]"},
7 | productions_: [0,[3,1],[5,1],[7,1],[9,1],[9,1],[12,2],[13,1],[13,1],[13,1],[13,1],[13,1],[13,1],[15,2],[15,3],[20,3],[19,1],[19,3],[16,2],[16,3],[25,1],[25,3]],
8 | performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) {
9 |
10 | var $0 = $$.length - 1;
11 | switch (yystate) {
12 | case 1:this.$ = yytext;
13 | break;
14 | case 2:this.$ = Number(yytext);
15 | break;
16 | case 3:this.$ = null;
17 | break;
18 | case 4:this.$ = true;
19 | break;
20 | case 5:this.$ = false;
21 | break;
22 | case 6:return this.$ = $$[$0-1];
23 | break;
24 | case 13:this.$ = {};
25 | break;
26 | case 14:this.$ = $$[$0-1];
27 | break;
28 | case 15:this.$ = [$$[$0-2], $$[$0]];
29 | break;
30 | case 16:this.$ = {}; this.$[$$[$0][0]] = $$[$0][1];
31 | break;
32 | case 17:this.$ = $$[$0-2]; $$[$0-2][$$[$0][0]] = $$[$0][1];
33 | break;
34 | case 18:this.$ = [];
35 | break;
36 | case 19:this.$ = $$[$0-1];
37 | break;
38 | case 20:this.$ = [$$[$0]];
39 | break;
40 | case 21:this.$ = $$[$0-2]; $$[$0-2].push($$[$0]);
41 | break;
42 | }
43 | },
44 | table: [{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],12:1,13:2,15:7,16:8,17:[1,14],23:[1,15]},{1:[3]},{14:[1,16]},{14:[2,7],18:[2,7],22:[2,7],24:[2,7]},{14:[2,8],18:[2,8],22:[2,8],24:[2,8]},{14:[2,9],18:[2,9],22:[2,9],24:[2,9]},{14:[2,10],18:[2,10],22:[2,10],24:[2,10]},{14:[2,11],18:[2,11],22:[2,11],24:[2,11]},{14:[2,12],18:[2,12],22:[2,12],24:[2,12]},{14:[2,3],18:[2,3],22:[2,3],24:[2,3]},{14:[2,4],18:[2,4],22:[2,4],24:[2,4]},{14:[2,5],18:[2,5],22:[2,5],24:[2,5]},{14:[2,1],18:[2,1],21:[2,1],22:[2,1],24:[2,1]},{14:[2,2],18:[2,2],22:[2,2],24:[2,2]},{3:20,4:[1,12],18:[1,17],19:18,20:19},{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],13:23,15:7,16:8,17:[1,14],23:[1,15],24:[1,21],25:22},{1:[2,6]},{14:[2,13],18:[2,13],22:[2,13],24:[2,13]},{18:[1,24],22:[1,25]},{18:[2,16],22:[2,16]},{21:[1,26]},{14:[2,18],18:[2,18],22:[2,18],24:[2,18]},{22:[1,28],24:[1,27]},{22:[2,20],24:[2,20]},{14:[2,14],18:[2,14],22:[2,14],24:[2,14]},{3:20,4:[1,12],20:29},{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],13:30,15:7,16:8,17:[1,14],23:[1,15]},{14:[2,19],18:[2,19],22:[2,19],24:[2,19]},{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],13:31,15:7,16:8,17:[1,14],23:[1,15]},{18:[2,17],22:[2,17]},{18:[2,15],22:[2,15]},{22:[2,21],24:[2,21]}],
45 | defaultActions: {16:[2,6]},
46 | parseError: function parseError(str, hash) {
47 | throw new Error(str);
48 | },
49 | parse: function parse(input) {
50 | var self = this,
51 | stack = [0],
52 | vstack = [null], // semantic value stack
53 | lstack = [], // location stack
54 | table = this.table,
55 | yytext = '',
56 | yylineno = 0,
57 | yyleng = 0,
58 | recovering = 0,
59 | TERROR = 2,
60 | EOF = 1;
61 |
62 | // this.reductionCount = this.shiftCount = 0;
63 |
64 | this.lexer.setInput(input);
65 | this.lexer.yy = this.yy;
66 | this.yy.lexer = this.lexer;
67 | if (typeof this.lexer.yylloc == 'undefined')
68 | this.lexer.yylloc = {};
69 | var yyloc = this.lexer.yylloc;
70 | lstack.push(yyloc);
71 |
72 | if (typeof this.yy.parseError === 'function')
73 | this.parseError = this.yy.parseError;
74 |
75 | function popStack (n) {
76 | stack.length = stack.length - 2*n;
77 | vstack.length = vstack.length - n;
78 | lstack.length = lstack.length - n;
79 | }
80 |
81 | function lex() {
82 | var token;
83 | token = self.lexer.lex() || 1; // $end = 1
84 | // if token isn't its numeric value, convert
85 | if (typeof token !== 'number') {
86 | token = self.symbols_[token] || token;
87 | }
88 | return token;
89 | };
90 |
91 | var symbol, preErrorSymbol, state, action, a, r, yyval={},p,len,newState, expected;
92 | while (true) {
93 | // retreive state number from top of stack
94 | state = stack[stack.length-1];
95 |
96 | // use default actions if available
97 | if (this.defaultActions[state]) {
98 | action = this.defaultActions[state];
99 | } else {
100 | if (symbol == null)
101 | symbol = lex();
102 | // read action for current state and first input
103 | action = table[state] && table[state][symbol];
104 | }
105 |
106 | // handle parse error
107 | if (typeof action === 'undefined' || !action.length || !action[0]) {
108 |
109 | if (!recovering) {
110 | // Report error
111 | expected = [];
112 | for (p in table[state]) if (this.terminals_[p] && p > 2) {
113 | expected.push("'"+this.terminals_[p]+"'");
114 | }
115 | var errStr = '';
116 | if (this.lexer.showPosition) {
117 | errStr = 'Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+'\nExpecting '+expected.join(', ');
118 | } else {
119 | errStr = 'Parse error on line '+(yylineno+1)+": Unexpected " +
120 | (symbol == 1 /* EOF */ ? "end of input" :
121 | ("'"+(this.terminals_[symbol] || symbol)+"'"));
122 | }
123 | this.parseError(errStr,
124 | {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected});
125 | }
126 |
127 | // just recovered from another error
128 | if (recovering == 3) {
129 | if (symbol == EOF) {
130 | throw new Error(errStr || 'Parsing halted.');
131 | }
132 |
133 | // discard current lookahead and grab another
134 | yyleng = this.lexer.yyleng;
135 | yytext = this.lexer.yytext;
136 | yylineno = this.lexer.yylineno;
137 | yyloc = this.lexer.yylloc;
138 | symbol = lex();
139 | }
140 |
141 | // try to recover from error
142 | while (1) {
143 | // check for error recovery rule in this state
144 | if ((TERROR.toString()) in table[state]) {
145 | break;
146 | }
147 | if (state == 0) {
148 | throw new Error(errStr || 'Parsing halted.');
149 | }
150 | popStack(1);
151 | state = stack[stack.length-1];
152 | }
153 |
154 | preErrorSymbol = symbol; // save the lookahead token
155 | symbol = TERROR; // insert generic error symbol as new lookahead
156 | state = stack[stack.length-1];
157 | action = table[state] && table[state][TERROR];
158 | recovering = 3; // allow 3 real symbols to be shifted before reporting a new error
159 | }
160 |
161 | // this shouldn't happen, unless resolve defaults are off
162 | if (action[0] instanceof Array && action.length > 1) {
163 | throw new Error('Parse Error: multiple actions possible at state: '+state+', token: '+symbol);
164 | }
165 |
166 | switch (action[0]) {
167 |
168 | case 1: // shift
169 | // this.shiftCount++;
170 |
171 | stack.push(symbol);
172 | vstack.push(this.lexer.yytext);
173 | lstack.push(this.lexer.yylloc);
174 | stack.push(action[1]); // push state
175 | symbol = null;
176 | if (!preErrorSymbol) { // normal execution/no error
177 | yyleng = this.lexer.yyleng;
178 | yytext = this.lexer.yytext;
179 | yylineno = this.lexer.yylineno;
180 | yyloc = this.lexer.yylloc;
181 | if (recovering > 0)
182 | recovering--;
183 | } else { // error just occurred, resume old lookahead f/ before error
184 | symbol = preErrorSymbol;
185 | preErrorSymbol = null;
186 | }
187 | break;
188 |
189 | case 2: // reduce
190 | // this.reductionCount++;
191 |
192 | len = this.productions_[action[1]][1];
193 |
194 | // perform semantic action
195 | yyval.$ = vstack[vstack.length-len]; // default to $$ = $1
196 | // default location, uses first token for firsts, last for lasts
197 | yyval._$ = {
198 | first_line: lstack[lstack.length-(len||1)].first_line,
199 | last_line: lstack[lstack.length-1].last_line,
200 | first_column: lstack[lstack.length-(len||1)].first_column,
201 | last_column: lstack[lstack.length-1].last_column
202 | };
203 | r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);
204 |
205 | if (typeof r !== 'undefined') {
206 | return r;
207 | }
208 |
209 | // pop off stack
210 | if (len) {
211 | stack = stack.slice(0,-1*len*2);
212 | vstack = vstack.slice(0, -1*len);
213 | lstack = lstack.slice(0, -1*len);
214 | }
215 |
216 | stack.push(this.productions_[action[1]][0]); // push nonterminal (reduce)
217 | vstack.push(yyval.$);
218 | lstack.push(yyval._$);
219 | // goto new state = table[STATE][NONTERMINAL]
220 | newState = table[stack[stack.length-2]][stack[stack.length-1]];
221 | stack.push(newState);
222 | break;
223 |
224 | case 3: // accept
225 | return true;
226 | }
227 |
228 | }
229 |
230 | return true;
231 | }};/* Jison generated lexer */
232 | var lexer = (function(){var lexer = ({EOF:1,
233 | parseError:function parseError(str, hash) {
234 | if (this.yy.parseError) {
235 | this.yy.parseError(str, hash);
236 | } else {
237 | throw new Error(str);
238 | }
239 | },
240 | setInput:function (input) {
241 | this._input = input;
242 | this._more = this._less = this.done = false;
243 | this.yylineno = this.yyleng = 0;
244 | this.yytext = this.matched = this.match = '';
245 | this.conditionStack = ['INITIAL'];
246 | this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0};
247 | return this;
248 | },
249 | input:function () {
250 | var ch = this._input[0];
251 | this.yytext+=ch;
252 | this.yyleng++;
253 | this.match+=ch;
254 | this.matched+=ch;
255 | var lines = ch.match(/\n/);
256 | if (lines) this.yylineno++;
257 | this._input = this._input.slice(1);
258 | return ch;
259 | },
260 | unput:function (ch) {
261 | this._input = ch + this._input;
262 | return this;
263 | },
264 | more:function () {
265 | this._more = true;
266 | return this;
267 | },
268 | pastInput:function () {
269 | var past = this.matched.substr(0, this.matched.length - this.match.length);
270 | return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
271 | },
272 | upcomingInput:function () {
273 | var next = this.match;
274 | if (next.length < 20) {
275 | next += this._input.substr(0, 20-next.length);
276 | }
277 | return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, "");
278 | },
279 | showPosition:function () {
280 | var pre = this.pastInput();
281 | var c = new Array(pre.length + 1).join("-");
282 | return pre + this.upcomingInput() + "\n" + c+"^";
283 | },
284 | next:function () {
285 | if (this.done) {
286 | return this.EOF;
287 | }
288 | if (!this._input) this.done = true;
289 |
290 | var token,
291 | match,
292 | col,
293 | lines;
294 | if (!this._more) {
295 | this.yytext = '';
296 | this.match = '';
297 | }
298 | var rules = this._currentRules();
299 | for (var i=0;i < rules.length; i++) {
300 | match = this._input.match(this.rules[rules[i]]);
301 | if (match) {
302 | lines = match[0].match(/\n.*/g);
303 | if (lines) this.yylineno += lines.length;
304 | this.yylloc = {first_line: this.yylloc.last_line,
305 | last_line: this.yylineno+1,
306 | first_column: this.yylloc.last_column,
307 | last_column: lines ? lines[lines.length-1].length-1 : this.yylloc.last_column + match[0].length};
308 | this.yytext += match[0];
309 | this.match += match[0];
310 | this.matches = match;
311 | this.yyleng = this.yytext.length;
312 | this._more = false;
313 | this._input = this._input.slice(match[0].length);
314 | this.matched += match[0];
315 | token = this.performAction.call(this, this.yy, this, rules[i],this.conditionStack[this.conditionStack.length-1]);
316 | if (token) return token;
317 | else return;
318 | }
319 | }
320 | if (this._input === "") {
321 | return this.EOF;
322 | } else {
323 | this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(),
324 | {text: "", token: null, line: this.yylineno});
325 | }
326 | },
327 | lex:function lex() {
328 | var r = this.next();
329 | if (typeof r !== 'undefined') {
330 | return r;
331 | } else {
332 | return this.lex();
333 | }
334 | },
335 | begin:function begin(condition) {
336 | this.conditionStack.push(condition);
337 | },
338 | popState:function popState() {
339 | return this.conditionStack.pop();
340 | },
341 | _currentRules:function _currentRules() {
342 | return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules;
343 | }});
344 | lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
345 |
346 | var YYSTATE=YY_START;
347 | switch($avoiding_name_collisions) {
348 | case 0:/* skip whitespace */
349 | break;
350 | case 1:return 6;
351 | break;
352 | case 2:yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2); return 4;
353 | break;
354 | case 3: return 17;
355 | break;
356 | case 4: return 18;
357 | break;
358 | case 5:return 23;
359 | break;
360 | case 6:return 24;
361 | break;
362 | case 7:return 22;
363 | break;
364 | case 8:return 21;
365 | break;
366 | case 9:return 10;
367 | break;
368 | case 10:return 11;
369 | break;
370 | case 11:return 8;
371 | break;
372 | case 12:return 14;
373 | break;
374 | case 13:return 'INVALID';
375 | break;
376 | }
377 | };
378 | lexer.rules = [/^\s+/,/^-?([0-9]|[1-9][0-9]+)(\.[0-9]+)?([eE][-+]?[0-9]+)?\b/,/^"(\\["bfnrt/\\]|\\u[a-fA-F0-9]{4}|[^\0-\x09\x0a-\x1f"\\])*"/,/^\{/,/^\}/,/^\[/,/^\]/,/^,/,/^:/,/^true\b/,/^false\b/,/^null\b/,/^$/,/^./];
379 | lexer.conditions = {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13],"inclusive":true}};return lexer;})()
380 | parser.lexer = lexer;
381 | return parser;
382 | })();
383 | if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
384 | exports.parser = jsonlint;
385 | exports.parse = function () { return jsonlint.parse.apply(jsonlint, arguments); }
386 | exports.main = function commonjsMain(args) {
387 | if (!args[1])
388 | throw new Error('Usage: '+args[0]+' FILE');
389 | if (typeof process !== 'undefined') {
390 | var source = require('fs').readFileSync(require('path').join(process.cwd(), args[1]), "utf8");
391 | } else {
392 | var cwd = require("file").path(require("file").cwd());
393 | var source = cwd.join(args[1]).read({charset: "utf-8"});
394 | }
395 | return exports.parser.parse(source);
396 | }
397 | if (typeof module !== 'undefined' && require.main === module) {
398 | exports.main(typeof process !== 'undefined' ? process.argv.slice(1) : require("system").args);
399 | }
400 | }
401 |
402 | addEventListener("message", function(event) {
403 | var errorMessage;
404 | try {
405 | jsonlint.parse(event.data);
406 | } catch (errorMessage) {
407 | postMessage(JSON.stringify({error: errorMessage.toString(), loc: jsonlint.lexer.yylloc}));
408 | }
409 | }, false);
--------------------------------------------------------------------------------
/WebContent/codemirror/css.js:
--------------------------------------------------------------------------------
1 | CodeMirror.defineMode("css", function(config) {
2 | var indentUnit = config.indentUnit, type;
3 |
4 | var atMediaTypes = keySet([
5 | "all", "aural", "braille", "handheld", "print", "projection", "screen",
6 | "tty", "tv", "embossed"
7 | ]);
8 |
9 | var atMediaFeatures = keySet([
10 | "width", "min-width", "max-width", "height", "min-height", "max-height",
11 | "device-width", "min-device-width", "max-device-width", "device-height",
12 | "min-device-height", "max-device-height", "aspect-ratio",
13 | "min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio",
14 | "min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color",
15 | "max-color", "color-index", "min-color-index", "max-color-index",
16 | "monochrome", "min-monochrome", "max-monochrome", "resolution",
17 | "min-resolution", "max-resolution", "scan", "grid"
18 | ]);
19 |
20 | var propertyKeywords = keySet([
21 | "align-content", "align-items", "align-self", "alignment-adjust",
22 | "alignment-baseline", "anchor-point", "animation", "animation-delay",
23 | "animation-direction", "animation-duration", "animation-iteration-count",
24 | "animation-name", "animation-play-state", "animation-timing-function",
25 | "appearance", "azimuth", "backface-visibility", "background",
26 | "background-attachment", "background-clip", "background-color",
27 | "background-image", "background-origin", "background-position",
28 | "background-repeat", "background-size", "baseline-shift", "binding",
29 | "bleed", "bookmark-label", "bookmark-level", "bookmark-state",
30 | "bookmark-target", "border", "border-bottom", "border-bottom-color",
31 | "border-bottom-left-radius", "border-bottom-right-radius",
32 | "border-bottom-style", "border-bottom-width", "border-collapse",
33 | "border-color", "border-image", "border-image-outset",
34 | "border-image-repeat", "border-image-slice", "border-image-source",
35 | "border-image-width", "border-left", "border-left-color",
36 | "border-left-style", "border-left-width", "border-radius", "border-right",
37 | "border-right-color", "border-right-style", "border-right-width",
38 | "border-spacing", "border-style", "border-top", "border-top-color",
39 | "border-top-left-radius", "border-top-right-radius", "border-top-style",
40 | "border-top-width", "border-width", "bottom", "box-decoration-break",
41 | "box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
42 | "caption-side", "clear", "clip", "color", "color-profile", "column-count",
43 | "column-fill", "column-gap", "column-rule", "column-rule-color",
44 | "column-rule-style", "column-rule-width", "column-span", "column-width",
45 | "columns", "content", "counter-increment", "counter-reset", "crop", "cue",
46 | "cue-after", "cue-before", "cursor", "direction", "display",
47 | "dominant-baseline", "drop-initial-after-adjust",
48 | "drop-initial-after-align", "drop-initial-before-adjust",
49 | "drop-initial-before-align", "drop-initial-size", "drop-initial-value",
50 | "elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis",
51 | "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap",
52 | "float", "float-offset", "font", "font-feature-settings", "font-family",
53 | "font-kerning", "font-language-override", "font-size", "font-size-adjust",
54 | "font-stretch", "font-style", "font-synthesis", "font-variant",
55 | "font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
56 | "font-variant-ligatures", "font-variant-numeric", "font-variant-position",
57 | "font-weight", "grid-cell", "grid-column", "grid-column-align",
58 | "grid-column-sizing", "grid-column-span", "grid-columns", "grid-flow",
59 | "grid-row", "grid-row-align", "grid-row-sizing", "grid-row-span",
60 | "grid-rows", "grid-template", "hanging-punctuation", "height", "hyphens",
61 | "icon", "image-orientation", "image-rendering", "image-resolution",
62 | "inline-box-align", "justify-content", "left", "letter-spacing",
63 | "line-break", "line-height", "line-stacking", "line-stacking-ruby",
64 | "line-stacking-shift", "line-stacking-strategy", "list-style",
65 | "list-style-image", "list-style-position", "list-style-type", "margin",
66 | "margin-bottom", "margin-left", "margin-right", "margin-top",
67 | "marker-offset", "marks", "marquee-direction", "marquee-loop",
68 | "marquee-play-count", "marquee-speed", "marquee-style", "max-height",
69 | "max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index",
70 | "nav-left", "nav-right", "nav-up", "opacity", "order", "orphans", "outline",
71 | "outline-color", "outline-offset", "outline-style", "outline-width",
72 | "overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y",
73 | "padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
74 | "page", "page-break-after", "page-break-before", "page-break-inside",
75 | "page-policy", "pause", "pause-after", "pause-before", "perspective",
76 | "perspective-origin", "pitch", "pitch-range", "play-during", "position",
77 | "presentation-level", "punctuation-trim", "quotes", "rendering-intent",
78 | "resize", "rest", "rest-after", "rest-before", "richness", "right",
79 | "rotation", "rotation-point", "ruby-align", "ruby-overhang",
80 | "ruby-position", "ruby-span", "size", "speak", "speak-as", "speak-header",
81 | "speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set",
82 | "tab-size", "table-layout", "target", "target-name", "target-new",
83 | "target-position", "text-align", "text-align-last", "text-decoration",
84 | "text-decoration-color", "text-decoration-line", "text-decoration-skip",
85 | "text-decoration-style", "text-emphasis", "text-emphasis-color",
86 | "text-emphasis-position", "text-emphasis-style", "text-height",
87 | "text-indent", "text-justify", "text-outline", "text-shadow",
88 | "text-space-collapse", "text-transform", "text-underline-position",
89 | "text-wrap", "top", "transform", "transform-origin", "transform-style",
90 | "transition", "transition-delay", "transition-duration",
91 | "transition-property", "transition-timing-function", "unicode-bidi",
92 | "vertical-align", "visibility", "voice-balance", "voice-duration",
93 | "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
94 | "voice-volume", "volume", "white-space", "widows", "width", "word-break",
95 | "word-spacing", "word-wrap", "z-index"
96 | ]);
97 |
98 | var colorKeywords = keySet([
99 | "black", "silver", "gray", "white", "maroon", "red", "purple", "fuchsia",
100 | "green", "lime", "olive", "yellow", "navy", "blue", "teal", "aqua"
101 | ]);
102 |
103 | var valueKeywords = keySet([
104 | "above", "absolute", "activeborder", "activecaption", "afar",
105 | "after-white-space", "ahead", "alias", "all", "all-scroll", "alternate",
106 | "always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
107 | "arabic-indic", "armenian", "asterisks", "auto", "avoid", "background",
108 | "backwards", "baseline", "below", "bidi-override", "binary", "bengali",
109 | "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
110 | "both", "bottom", "break-all", "break-word", "button", "button-bevel",
111 | "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "cambodian",
112 | "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret",
113 | "cell", "center", "checkbox", "circle", "cjk-earthly-branch",
114 | "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
115 | "col-resize", "collapse", "compact", "condensed", "contain", "content",
116 | "content-box", "context-menu", "continuous", "copy", "cover", "crop",
117 | "cross", "crosshair", "currentcolor", "cursive", "dashed", "decimal",
118 | "decimal-leading-zero", "default", "default-button", "destination-atop",
119 | "destination-in", "destination-out", "destination-over", "devanagari",
120 | "disc", "discard", "document", "dot-dash", "dot-dot-dash", "dotted",
121 | "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out",
122 | "element", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede",
123 | "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er",
124 | "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er",
125 | "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et",
126 | "ethiopic-halehame-gez", "ethiopic-halehame-om-et",
127 | "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
128 | "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et",
129 | "ethiopic-halehame-tig", "ew-resize", "expanded", "extra-condensed",
130 | "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "footnotes",
131 | "forwards", "from", "geometricPrecision", "georgian", "graytext", "groove",
132 | "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hebrew",
133 | "help", "hidden", "hide", "higher", "highlight", "highlighttext",
134 | "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "icon", "ignore",
135 | "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
136 | "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
137 | "inline-block", "inline-table", "inset", "inside", "intrinsic", "invert",
138 | "italic", "justify", "kannada", "katakana", "katakana-iroha", "khmer",
139 | "landscape", "lao", "large", "larger", "left", "level", "lighter",
140 | "line-through", "linear", "lines", "list-item", "listbox", "listitem",
141 | "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
142 | "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
143 | "lower-roman", "lowercase", "ltr", "malayalam", "match",
144 | "media-controls-background", "media-current-time-display",
145 | "media-fullscreen-button", "media-mute-button", "media-play-button",
146 | "media-return-to-realtime-button", "media-rewind-button",
147 | "media-seek-back-button", "media-seek-forward-button", "media-slider",
148 | "media-sliderthumb", "media-time-remaining-display", "media-volume-slider",
149 | "media-volume-slider-container", "media-volume-sliderthumb", "medium",
150 | "menu", "menulist", "menulist-button", "menulist-text",
151 | "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
152 | "mix", "mongolian", "monospace", "move", "multiple", "myanmar", "n-resize",
153 | "narrower", "navy", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
154 | "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
155 | "ns-resize", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote",
156 | "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
157 | "outside", "overlay", "overline", "padding", "padding-box", "painted",
158 | "paused", "persian", "plus-darker", "plus-lighter", "pointer", "portrait",
159 | "pre", "pre-line", "pre-wrap", "preserve-3d", "progress", "push-button",
160 | "radio", "read-only", "read-write", "read-write-plaintext-only", "relative",
161 | "repeat", "repeat-x", "repeat-y", "reset", "reverse", "rgb", "rgba",
162 | "ridge", "right", "round", "row-resize", "rtl", "run-in", "running",
163 | "s-resize", "sans-serif", "scroll", "scrollbar", "se-resize", "searchfield",
164 | "searchfield-cancel-button", "searchfield-decoration",
165 | "searchfield-results-button", "searchfield-results-decoration",
166 | "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
167 | "single", "skip-white-space", "slide", "slider-horizontal",
168 | "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
169 | "small", "small-caps", "small-caption", "smaller", "solid", "somali",
170 | "source-atop", "source-in", "source-out", "source-over", "space", "square",
171 | "square-button", "start", "static", "status-bar", "stretch", "stroke",
172 | "sub", "subpixel-antialiased", "super", "sw-resize", "table",
173 | "table-caption", "table-cell", "table-column", "table-column-group",
174 | "table-footer-group", "table-header-group", "table-row", "table-row-group",
175 | "telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai",
176 | "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
177 | "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
178 | "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
179 | "transparent", "ultra-condensed", "ultra-expanded", "underline", "up",
180 | "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
181 | "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
182 | "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
183 | "visibleStroke", "visual", "w-resize", "wait", "wave", "white", "wider",
184 | "window", "windowframe", "windowtext", "x-large", "x-small", "xor",
185 | "xx-large", "xx-small", "yellow"
186 | ]);
187 |
188 | function keySet(array) { var keys = {}; for (var i = 0; i < array.length; ++i) keys[array[i]] = true; return keys; }
189 | function ret(style, tp) {type = tp; return style;}
190 |
191 | function tokenBase(stream, state) {
192 | var ch = stream.next();
193 | if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("def", stream.current());}
194 | else if (ch == "/" && stream.eat("*")) {
195 | state.tokenize = tokenCComment;
196 | return tokenCComment(stream, state);
197 | }
198 | else if (ch == "<" && stream.eat("!")) {
199 | state.tokenize = tokenSGMLComment;
200 | return tokenSGMLComment(stream, state);
201 | }
202 | else if (ch == "=") ret(null, "compare");
203 | else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
204 | else if (ch == "\"" || ch == "'") {
205 | state.tokenize = tokenString(ch);
206 | return state.tokenize(stream, state);
207 | }
208 | else if (ch == "#") {
209 | stream.eatWhile(/[\w\\\-]/);
210 | return ret("atom", "hash");
211 | }
212 | else if (ch == "!") {
213 | stream.match(/^\s*\w*/);
214 | return ret("keyword", "important");
215 | }
216 | else if (/\d/.test(ch)) {
217 | stream.eatWhile(/[\w.%]/);
218 | return ret("number", "unit");
219 | }
220 | else if (ch === "-") {
221 | if (/\d/.test(stream.peek())) {
222 | stream.eatWhile(/[\w.%]/);
223 | return ret("number", "unit");
224 | } else if (stream.match(/^[^-]+-/)) {
225 | return ret("meta", type);
226 | }
227 | }
228 | else if (/[,+>*\/]/.test(ch)) {
229 | return ret(null, "select-op");
230 | }
231 | else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
232 | return ret("qualifier", type);
233 | }
234 | else if (ch == ":") {
235 | return ret("operator", ch);
236 | }
237 | else if (/[;{}\[\]\(\)]/.test(ch)) {
238 | return ret(null, ch);
239 | }
240 | else {
241 | stream.eatWhile(/[\w\\\-]/);
242 | return ret("property", "variable");
243 | }
244 | }
245 |
246 | function tokenCComment(stream, state) {
247 | var maybeEnd = false, ch;
248 | while ((ch = stream.next()) != null) {
249 | if (maybeEnd && ch == "/") {
250 | state.tokenize = tokenBase;
251 | break;
252 | }
253 | maybeEnd = (ch == "*");
254 | }
255 | return ret("comment", "comment");
256 | }
257 |
258 | function tokenSGMLComment(stream, state) {
259 | var dashes = 0, ch;
260 | while ((ch = stream.next()) != null) {
261 | if (dashes >= 2 && ch == ">") {
262 | state.tokenize = tokenBase;
263 | break;
264 | }
265 | dashes = (ch == "-") ? dashes + 1 : 0;
266 | }
267 | return ret("comment", "comment");
268 | }
269 |
270 | function tokenString(quote) {
271 | return function(stream, state) {
272 | var escaped = false, ch;
273 | while ((ch = stream.next()) != null) {
274 | if (ch == quote && !escaped)
275 | break;
276 | escaped = !escaped && ch == "\\";
277 | }
278 | if (!escaped) state.tokenize = tokenBase;
279 | return ret("string", "string");
280 | };
281 | }
282 |
283 | return {
284 | startState: function(base) {
285 | return {tokenize: tokenBase,
286 | baseIndent: base || 0,
287 | stack: []};
288 | },
289 |
290 | token: function(stream, state) {
291 |
292 | // Use these terms when applicable (see http://www.xanthir.com/blog/b4E50)
293 | //
294 | // rule** or **ruleset:
295 | // A selector + braces combo, or an at-rule.
296 | //
297 | // declaration block:
298 | // A sequence of declarations.
299 | //
300 | // declaration:
301 | // A property + colon + value combo.
302 | //
303 | // property value:
304 | // The entire value of a property.
305 | //
306 | // component value:
307 | // A single piece of a property value. Like the 5px in
308 | // text-shadow: 0 0 5px blue;. Can also refer to things that are
309 | // multiple terms, like the 1-4 terms that make up the background-size
310 | // portion of the background shorthand.
311 | //
312 | // term:
313 | // The basic unit of author-facing CSS, like a single number (5),
314 | // dimension (5px), string ("foo"), or function. Officially defined
315 | // by the CSS 2.1 grammar (look for the 'term' production)
316 | //
317 | //
318 | // simple selector:
319 | // A single atomic selector, like a type selector, an attr selector, a
320 | // class selector, etc.
321 | //
322 | // compound selector:
323 | // One or more simple selectors without a combinator. div.example is
324 | // compound, div > .example is not.
325 | //
326 | // complex selector:
327 | // One or more compound selectors chained with combinators.
328 | //
329 | // combinator:
330 | // The parts of selectors that express relationships. There are four
331 | // currently - the space (descendant combinator), the greater-than
332 | // bracket (child combinator), the plus sign (next sibling combinator),
333 | // and the tilda (following sibling combinator).
334 | //
335 | // sequence of selectors:
336 | // One or more of the named type of selector chained with commas.
337 |
338 | if (stream.eatSpace()) return null;
339 | var style = state.tokenize(stream, state);
340 |
341 | // Changing style returned based on context
342 | var context = state.stack[state.stack.length-1];
343 | if (style == "property") {
344 | if (context == "propertyValue"){
345 | if (valueKeywords[stream.current()]) {
346 | style = "string-2";
347 | } else if (colorKeywords[stream.current()]) {
348 | style = "keyword";
349 | } else {
350 | style = "variable-2";
351 | }
352 | } else if (context == "rule") {
353 | if (!propertyKeywords[stream.current()]) {
354 | style += " error";
355 | }
356 | } else if (!context || context == "@media{") {
357 | style = "tag";
358 | } else if (context == "@media") {
359 | if (atMediaTypes[stream.current()]) {
360 | style = "attribute"; // Known attribute
361 | } else if (/^(only|not)$/i.test(stream.current())) {
362 | style = "keyword";
363 | } else if (stream.current().toLowerCase() == "and") {
364 | style = "error"; // "and" is only allowed in @mediaType
365 | } else if (atMediaFeatures[stream.current()]) {
366 | style = "error"; // Known property, should be in @mediaType(
367 | } else {
368 | // Unknown, expecting keyword or attribute, assuming attribute
369 | style = "attribute error";
370 | }
371 | } else if (context == "@mediaType") {
372 | if (atMediaTypes[stream.current()]) {
373 | style = "attribute";
374 | } else if (stream.current().toLowerCase() == "and") {
375 | style = "operator";
376 | } else if (/^(only|not)$/i.test(stream.current())) {
377 | style = "error"; // Only allowed in @media
378 | } else if (atMediaFeatures[stream.current()]) {
379 | style = "error"; // Known property, should be in parentheses
380 | } else {
381 | // Unknown attribute or property, but expecting property (preceded
382 | // by "and"). Should be in parentheses
383 | style = "error";
384 | }
385 | } else if (context == "@mediaType(") {
386 | if (propertyKeywords[stream.current()]) {
387 | // do nothing, remains "property"
388 | } else if (atMediaTypes[stream.current()]) {
389 | style = "error"; // Known property, should be in parentheses
390 | } else if (stream.current().toLowerCase() == "and") {
391 | style = "operator";
392 | } else if (/^(only|not)$/i.test(stream.current())) {
393 | style = "error"; // Only allowed in @media
394 | } else {
395 | style += " error";
396 | }
397 | } else {
398 | style = "error";
399 | }
400 | } else if (style == "atom") {
401 | if(!context || context == "@media{") {
402 | style = "builtin";
403 | } else if (context == "propertyValue") {
404 | if (!/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) {
405 | style += " error";
406 | }
407 | } else {
408 | style = "error";
409 | }
410 | } else if (context == "@media" && type == "{") {
411 | style = "error";
412 | }
413 |
414 | // Push/pop context stack
415 | if (type == "{") {
416 | if (context == "@media" || context == "@mediaType") {
417 | state.stack.pop();
418 | state.stack[state.stack.length-1] = "@media{";
419 | }
420 | else state.stack.push("rule");
421 | }
422 | else if (type == "}") {
423 | state.stack.pop();
424 | if (context == "propertyValue") state.stack.pop();
425 | }
426 | else if (type == "@media") state.stack.push("@media");
427 | else if (context == "@media" && /\b(keyword|attribute)\b/.test(style))
428 | state.stack.push("@mediaType");
429 | else if (context == "@mediaType" && stream.current() == ",") state.stack.pop();
430 | else if (context == "@mediaType" && type == "(") state.stack.push("@mediaType(");
431 | else if (context == "@mediaType(" && type == ")") state.stack.pop();
432 | else if (context == "rule" && type == ":") state.stack.push("propertyValue");
433 | else if (context == "propertyValue" && type == ";") state.stack.pop();
434 | return style;
435 | },
436 |
437 | indent: function(state, textAfter) {
438 | var n = state.stack.length;
439 | if (/^\}/.test(textAfter))
440 | n -= state.stack[state.stack.length-1] == "propertyValue" ? 2 : 1;
441 | return state.baseIndent + n * indentUnit;
442 | },
443 |
444 | electricChars: "}"
445 | };
446 | });
447 |
448 | CodeMirror.defineMIME("text/css", "css");
449 |
--------------------------------------------------------------------------------