├── 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 |
21 | 22 | 23 |
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 |

iconPHPView 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",
    • 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 | 


--------------------------------------------------------------------------------