diff options
author | kalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-27 04:22:45 +0000 |
---|---|---|
committer | kalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-27 04:22:45 +0000 |
commit | 5b300db2d57a342011f945706b48691683aaefbf (patch) | |
tree | 6e14bfc744dad1de20ed8384555b85506997b1e4 | |
parent | f66bb610f4568c8219ae25d8a1d2b724cf2cb073 (diff) | |
download | chromium_src-5b300db2d57a342011f945706b48691683aaefbf.zip chromium_src-5b300db2d57a342011f945706b48691683aaefbf.tar.gz chromium_src-5b300db2d57a342011f945706b48691683aaefbf.tar.bz2 |
json_schema_compiler: add features to the previewserver.py:
- make the URL path reflect the navigation location.
- make the renderered file determined by the hashtag (which gives support for
things like going back/forward etc).
- make the chosen highlighter cached in localStorage for refreshes.
BUG=
TEST=
Review URL: https://chromiumcodereview.appspot.com/9452042
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@123710 0039d316-1c4b-4281-b951-d872f2087c98
-rwxr-xr-x[-rw-r--r--] | tools/json_schema_compiler/previewserver.py | 201 |
1 files changed, 144 insertions, 57 deletions
diff --git a/tools/json_schema_compiler/previewserver.py b/tools/json_schema_compiler/previewserver.py index 348b5d4..a861800 100644..100755 --- a/tools/json_schema_compiler/previewserver.py +++ b/tools/json_schema_compiler/previewserver.py @@ -1,4 +1,5 @@ -#!/usr/bin/env/python +#!/usr/bin/env python + # Copyright (c) 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -36,10 +37,8 @@ class CompilerHandler(BaseHTTPRequestHandler): body = code.Code() try: - if parsed_url.path.split('/')[1] == 'nav': - self._ListFoldersAndJsons(parsed_url, head, body) - elif os.path.isdir(request_path): - self._ShowFrameset(parsed_url, head, body) + if os.path.isdir(request_path): + self._ShowPanels(parsed_url, head, body) else: self._ShowCompiledFile(parsed_url, head, body) finally: @@ -57,7 +56,7 @@ class CompilerHandler(BaseHTTPRequestHandler): path = parsed_url.path.replace('/nav', '') return os.path.normpath(os.curdir + path) - def _ShowFrameset(self, parsed_url, head, body): + def _ShowPanels(self, parsed_url, head, body): """Show the previewer frame structure. Frames can be accessed in javascript (from a iframe) by using @@ -75,6 +74,14 @@ class CompilerHandler(BaseHTTPRequestHandler): .Append('}') .Append('#nav_pane {') .Append(' width: 20%;') + .Append(' height: 100%;') + .Append(' overflow-x: hidden;') + .Append(' overflow-y: scroll;') + .Append(' display: inline-block;') + .Append('}') + .Append('#nav_pane ul {') + .Append(' list-style-type: none;') + .Append(' padding: 0 0 0 1em;') .Append('}') .Append('#cc_pane {') .Append(' width: 40%;') @@ -84,15 +91,81 @@ class CompilerHandler(BaseHTTPRequestHandler): .Append('}') .Append('</style>') ) + body.Append( - '<iframe src="/nav/%(path)s?%(query)s"></iframe>' + '<div id="nav_pane">%s</div>' '<iframe id="h_pane"></iframe>' - '<iframe id="cc_pane"></iframe>' % { - 'path': parsed_url.path, - 'query': parsed_url.query - } + '<iframe id="cc_pane"></iframe>' % + self._RenderNavPane(parsed_url.path[1:]) ) + # The Javascript that interacts with the nav pane and panes to show the + # compiled files as the URL or highlighting options change. + body.Append('''<script type="text/javascript"> +// Calls a function for each highlighter style <select> element. +function forEachHighlighterStyle(callback) { + var highlighterStyles = + document.getElementsByClassName('highlighter_styles'); + for (var i = 0; i < highlighterStyles.length; ++i) + callback(highlighterStyles[i]); +} + +// Called when anything changes, such as the highlighter or hashtag. +function updateEverything() { + var highlighters = document.getElementById('highlighters'); + var highlighterName = highlighters.value; + + // Cache in localStorage for when the page loads next. + localStorage.highlightersValue = highlighterName; + + // Show/hide the highlighter styles. + var highlighterStyleName = ''; + forEachHighlighterStyle(function(highlighterStyle) { + if (highlighterStyle.id === highlighterName + '_styles') { + highlighterStyle.removeAttribute('style') + highlighterStyleName = highlighterStyle.value; + } else { + highlighterStyle.setAttribute('style', 'display:none') + } + + // Cache in localStorage for when the page next loads. + localStorage[highlighterStyle.id + 'Value'] = highlighterStyle.value; + }); + + // Set the iframe targets. + var targetName = window.location.hash; + targetName = targetName.substring('#'.length); + targetName = targetName.substring(0, targetName.length - '.json'.length); + + if (targetName !== '') { + var basePath = window.location.pathname; + var highlighterQuery = 'highlighter=' + highlighterName + '&' + + 'style=' + highlighterStyleName; + document.getElementById("h_pane").src = + basePath + '/' + targetName + '.h?' + highlighterQuery; + document.getElementById("cc_pane").src = + basePath + '/' + targetName + '.cc?' + highlighterQuery; + } +} + +// Initial load: set the values of highlighter and highlighterStyles from +// localStorage. +(function() { +var cachedValue = localStorage.highlightersValue; +if (cachedValue) + document.getElementById('highlighters').value = cachedValue; + +forEachHighlighterStyle(function(highlighterStyle) { + var cachedValue = localStorage[highlighterStyle.id + 'Value']; + if (cachedValue) + highlighterStyle.value = cachedValue; +}); +})(); + +window.addEventListener('hashchange', updateEverything, false); +updateEverything(); +</script>''') + def _ShowCompiledFile(self, parsed_url, head, body): """Show the compiled version of a json file given the path to the compiled file. @@ -164,55 +237,66 @@ class CompilerHandler(BaseHTTPRequestHandler): return (query_dict.get('highlighter', ['pygments'])[0], query_dict.get('style', ['colorful'])[0]) - def _ListFoldersAndJsons(self, parsed_url, head, body): - """List folders and .json files in given directory. + def _RenderNavPane(self, path): + """Renders an HTML nav pane. + + This consists of a select element to set highlight style, and a list of all + files at |path| with the appropriate onclick handlers to open either + subdirectories or JSON files. """ - request_path = self._GetRequestPath(parsed_url, strip_nav=True) - (highlighter_param, style_param) = self._GetHighlighterParams(parsed_url) - - body.Append('<select onChange="' - 'document.location.href=\'%s?highlighter=\' + this.value">' % - parsed_url.path) - for key, value in self.server.highlighters.items(): - body.Append('<option %s value="%s">%s</option>' % - ('selected="true"' if key == highlighter_param else '', - key, value.DisplayName())) - body.Append('</select><br />') - - highlighter = self.server.highlighters[highlighter_param] - styles = sorted(highlighter.GetStyles()) - if styles: - body.Append('<select onChange="' - 'document.location.href=\'%s?highlighter=%s&style=\' ' - '+ this.value">' % (parsed_url.path, highlighter_param)) + html = code.Code() + + # Highlighter chooser. + html.Append('<select id="highlighters" onChange="updateEverything()">') + for name, highlighter in self.server.highlighters.items(): + html.Append('<option value="%s">%s</option>' % + (name, highlighter.DisplayName())) + html.Append('</select>') + + html.Append('<br/>') + + # Style for each highlighter. + # The correct highlighting will be shown by Javascript. + for name, highlighter in self.server.highlighters.items(): + styles = sorted(highlighter.GetStyles()) + if not styles: + continue + + html.Append('<select class="highlighter_styles" id="%s_styles" ' + 'onChange="updateEverything()">' % name) for style in styles: - body.Append('<option %s>%s</option>' % - ('selected="true"' if style == style_param else '', style)) - - body.Append('</select><br />') - - if not os.path.samefile(os.curdir, request_path): - body.Append('<a href="%s?%s">../</a><br />' % - (os.path.split(os.path.normpath(parsed_url.path))[0], - parsed_url.query)) - files = os.listdir(request_path) - for filename in sorted(files): - full_path = os.path.join(request_path, filename) + html.Append('<option>%s</option>' % style) + html.Append('</select>') + + html.Append('<br/>') + + # The files, with appropriate handlers. + html.Append('<ul>') + + # Make path point to a non-empty directory. This can happen if a URL like + # http://localhost:8000 is navigated to. + if path == '': + path = os.curdir + + # Firstly, a .. link if this isn't the root. + if not os.path.samefile(os.curdir, path): + normpath = os.path.normpath(os.path.join(path, os.pardir)) + html.Append('<li><a href="/%s">%s/</a>' % (normpath, os.pardir)) + + # Each file under path/ + for filename in sorted(os.listdir(path)): + full_path = os.path.join(path, filename) (file_root, file_ext) = os.path.splitext(full_path) if os.path.isdir(full_path): - body.Append('<a href="/nav/%s/">%s/</a><br />' % - (full_path, filename)) + html.Append('<li><a href="/%s/">%s/</a>' % (full_path, filename)) elif file_ext == '.json': - body.Append('<a href="#%(file_root)s" onClick="' - 'parent.document.getElementById(\'cc_pane\').src=' - '\'/%(file_root)s.cc?%(query)s\'; ' - 'parent.document.getElementById(\'h_pane\').src=' - '\'/%(file_root)s.h?%(query)s\';' - '">%(filename)s</a><br />' % { - 'file_root': file_root, - 'filename': filename, - 'query': parsed_url.query, - }) + # iframes will automatically update via the hash change event. + html.Append('<li><a href="#%s">%s</a>' % + (filename, filename)) + + html.Append('</ul>') + + return html.Render() class PreviewHTTPServer(HTTPServer, object): def __init__(self, server_address, handler, highlighters): @@ -230,7 +314,11 @@ if __name__ == '__main__': (opts, argv) = parser.parse_args() try: - print('Starting httpserver on port %d' % opts.port) + print('Starting previewserver on port %d' % opts.port) + print('The extension documentation can be found at:') + print('') + print(' http://localhost:%d/chrome/common/extensions/api' % opts.port) + print('') server = PreviewHTTPServer(('', opts.port), CompilerHandler, { 'pygments': pygments_highlighter.PygmentsHighlighter(), @@ -239,5 +327,4 @@ if __name__ == '__main__': }) server.serve_forever() except KeyboardInterrupt: - print('Shutting down server') server.socket.close() |