 0096cc3c55
			
		
	
	0096cc3c55
	
	
	
		
			
			This makes the search box link to google.com/search with a "site:XYZ" restrict. I have also investigated Google Custom Search Engine, but the UI feels antiquated, and the search results overlaid properly beyond my CSS/HTML skills. Tested: A: 1. Add this option to _replace_macros_impl in tools/bzl/asciidoc.bzl 2. bazel build Documentation/cmd-index-activate.html 3. chrome $PWD/bazel-bin/Documentation/cmd-index-activate.html 4. Verify that the search box links to google.com B: 5. Revert asciidoc.bzl, bazel build release. 6. Verify that internal search works. Change-Id: Ia319803d6a9bfa20ea39c035891208bd5a55a162
		
			
				
	
	
		
			315 lines
		
	
	
		
			9.4 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			315 lines
		
	
	
		
			9.4 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/env python
 | |
| # coding=utf-8
 | |
| # Copyright (C) 2013 The Android Open Source Project
 | |
| #
 | |
| # Licensed under the Apache License, Version 2.0 (the "License");
 | |
| # you may not use this file except in compliance with the License.
 | |
| # You may obtain a copy of the License at
 | |
| #
 | |
| # http://www.apache.org/licenses/LICENSE-2.0
 | |
| #
 | |
| # Unless required by applicable law or agreed to in writing, software
 | |
| # distributed under the License is distributed on an "AS IS" BASIS,
 | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| # See the License for the specific language governing permissions and
 | |
| # limitations under the License.
 | |
| 
 | |
| from optparse import OptionParser
 | |
| import re
 | |
| import sys
 | |
| 
 | |
| PAT_GERRIT = re.compile(r'^GERRIT')
 | |
| PAT_INCLUDE = re.compile(r'^(include::.*)(\[\])$')
 | |
| PAT_GET = re.compile(r'^get::([^ \t\n]*)')
 | |
| PAT_TITLE = re.compile(r'^\.(.*)')
 | |
| PAT_STARS = re.compile(r'^\*\*\*\*')
 | |
| PAT_SEARCHBOX = re.compile(r'^SEARCHBOX')
 | |
| 
 | |
| GERRIT_UPLINK = """
 | |
| 
 | |
| ++++
 | |
| <hr style=\"
 | |
|   height: 2px;
 | |
|   color: silver;
 | |
|   margin-top: 1.2em;
 | |
|   margin-bottom: 0.5em;
 | |
| \">
 | |
| ++++
 | |
| 
 | |
| """
 | |
| 
 | |
| GET_TITLE = '<div class="title">%s</div>'
 | |
| 
 | |
| GET_MACRO = """
 | |
| 
 | |
| ++++
 | |
| <div class="listingblock">
 | |
| %s
 | |
| <div class="content">
 | |
| <a id=\"{0}\" onmousedown="javascript:
 | |
|   var i = document.URL.lastIndexOf(\'/Documentation/\');
 | |
|   var url = document.URL.substring(0, i) + \'{0}\';
 | |
|   document.getElementById(\'{0}\').href = url;">
 | |
|     GET {0} HTTP/1.0
 | |
| </a>
 | |
| </div>
 | |
| </div>
 | |
| ++++
 | |
| 
 | |
| """
 | |
| 
 | |
| SEARCH_BOX = """
 | |
| 
 | |
| ++++
 | |
| <div style="
 | |
|   position:fixed;
 | |
|   top:0px;
 | |
|   right:0px;
 | |
|   text-align:
 | |
|   right;
 | |
|   padding-top:2px;
 | |
|   padding-right:0.5em;
 | |
|   padding-bottom:2px;">
 | |
| <input size="40"
 | |
|   style="line-height: 0.75em;font-size: 0.75em;"
 | |
|   id="docSearch"
 | |
|   type="text">
 | |
| <button style="
 | |
|   background:none!important;
 | |
|   border:none;
 | |
|   padding:0!important;
 | |
|   vertical-align:bottom;
 | |
|   font-family:'Open Sans','DejaVu Sans',sans-serif;
 | |
|   font-size:0.8em;
 | |
|   color:#1d4b8f;
 | |
|   text-decoration:none;"
 | |
|   type="button"
 | |
|   id="searchBox">
 | |
|   Search
 | |
| </button>
 | |
|   %s
 | |
| </div>
 | |
| ++++
 | |
| """
 | |
| 
 | |
| BUILTIN_SEARCH = """
 | |
| <script type="text/javascript">
 | |
| var f = function() {
 | |
|   window.location = '../#/Documentation/q/' +
 | |
|     encodeURIComponent(document.getElementById("docSearch").value);
 | |
| }
 | |
| document.getElementById("searchBox").onclick = f;
 | |
| document.getElementById("docSearch").onkeypress = function(e) {
 | |
|   if (13 == (e.keyCode ? e.keyCode : e.which)) {
 | |
|     f();
 | |
|   }
 | |
| }
 | |
| </script>
 | |
| """
 | |
| 
 | |
| GOOGLE_SITE_SEARCH = """
 | |
| <script type="text/javascript">
 | |
| var f = function() {
 | |
|   window.location = 'https://www.google.com/search?q=' +
 | |
|      encodeURIComponent(document.getElementById("docSearch").value +
 | |
|      ' site:@SITE@');
 | |
| }
 | |
| document.getElementById("searchBox").onclick = f;
 | |
| document.getElementById("docSearch").onkeypress = function(e) {
 | |
|   if (13 == (e.keyCode ? e.keyCode : e.which)) {
 | |
|     f();
 | |
|   }
 | |
| }
 | |
| </script>
 | |
| """
 | |
| 
 | |
| 
 | |
| LINK_SCRIPT = """
 | |
| 
 | |
| ++++
 | |
| <script type="text/javascript">
 | |
|     decorate(document.getElementsByTagName('h1'));
 | |
|     decorate(document.getElementsByTagName('h2'));
 | |
|     decorate(document.getElementsByTagName('h3'));
 | |
|     decorate(document.getElementsByTagName('h4'));
 | |
| 
 | |
|     var divs = document.getElementsByTagName('div');
 | |
|     var arr = new Array();
 | |
|     var excluded = getExcludedIds();
 | |
|     for(var i = 0; i < divs.length; i++) {
 | |
|       var d = divs[i];
 | |
|       var id = d.getAttribute('id');
 | |
|       if (id != null && !(id in excluded)) {
 | |
|         arr[arr.length] = d;
 | |
|       }
 | |
|     }
 | |
|     decorate(arr);
 | |
| 
 | |
|     var anchors = document.getElementsByTagName('a');
 | |
|     arr = new Array();
 | |
|     for(var i = 0; i < anchors.length; i++) {
 | |
|       var a = anchors[i];
 | |
|       // if the anchor has no id there is no target to
 | |
|       // which we can link
 | |
|       if (a.getAttribute('id') != null) {
 | |
|         // if the anchor is empty there is no content which
 | |
|         // can receive the mouseover event, an empty anchor
 | |
|         // applies to the element that follows, move the
 | |
|         // element that follows into the anchor so that there
 | |
|         // is content which can receive the mouseover event
 | |
|         if (a.firstChild == null) {
 | |
|           var next = a.nextSibling;
 | |
|           if (next != null) {
 | |
|             next.parentNode.removeChild(next);
 | |
|             a.appendChild(next);
 | |
|           }
 | |
|         }
 | |
|         arr[arr.length] = a;
 | |
|       }
 | |
|     }
 | |
|     decorate(arr);
 | |
| 
 | |
|     function decorate(e) {
 | |
|       for(var i = 0; i < e.length; i++) {
 | |
|         e[i].onmouseover = function (evt) {
 | |
|           var element = this;
 | |
|           // do nothing if the link icon is currently showing
 | |
|           var a = element.firstChild;
 | |
|           if (a != null && a instanceof Element
 | |
|               && a.getAttribute('id') == 'LINK') {
 | |
|             return;
 | |
|           }
 | |
| 
 | |
|           // if there is no id there is no target to link to
 | |
|           var id = element.getAttribute('id');
 | |
|           if (id == null) {
 | |
|             return;
 | |
|           }
 | |
| 
 | |
|           // create and show a link icon that links to this element
 | |
|           a = document.createElement('a');
 | |
|           a.setAttribute('id', 'LINK');
 | |
|           a.setAttribute('href', '#' + id);
 | |
|           a.setAttribute('style', 'position: absolute;'
 | |
|               + ' left: ' + (element.offsetLeft - 16 - 2 * 4) + 'px;'
 | |
|               + ' padding-left: 4px; padding-right: 4px;');
 | |
|           var span = document.createElement('span');
 | |
|           span.setAttribute('style', 'height: ' + element.offsetHeight + 'px;'
 | |
|               + ' display: inline-block; vertical-align: baseline;'
 | |
|               + ' font-size: 16px; text-decoration: none; color: grey;');
 | |
|           a.appendChild(span);
 | |
|           var link = document.createTextNode('🔗');
 | |
|           span.appendChild(link);
 | |
|           element.insertBefore(a, element.firstChild);
 | |
| 
 | |
|           // remove the link icon when the mouse is moved away,
 | |
|           // but keep it shown if the mouse is over the element, the link or
 | |
|           // the icon
 | |
|           hide = function(evt) {
 | |
|             if (document.elementFromPoint(evt.clientX, evt.clientY) != element
 | |
|                 && document.elementFromPoint(evt.clientX, evt.clientY) != a
 | |
|                 && document.elementFromPoint(evt.clientX, evt.clientY) != span
 | |
|                 && document.elementFromPoint(evt.clientX, evt.clientY) != link
 | |
|                 && element.contains(a)) {
 | |
|               element.removeChild(a);
 | |
|             }
 | |
|           }
 | |
|           element.onmouseout = hide;
 | |
|           a.onmouseout = hide;
 | |
|           span.onmouseout = hide;
 | |
|           link.onmouseout = hide;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     function getExcludedIds() {
 | |
|       var excluded = {};
 | |
|       excluded['header'] = true;
 | |
|       excluded['toc'] = true;
 | |
|       excluded['toctitle'] = true;
 | |
|       excluded['content'] = true;
 | |
|       excluded['preamble'] = true;
 | |
|       excluded['footer'] = true;
 | |
|       excluded['footer-text'] = true;
 | |
|       return excluded;
 | |
|     }
 | |
| </script>
 | |
| 
 | |
| ++++
 | |
| 
 | |
| """
 | |
| 
 | |
| opts = OptionParser()
 | |
| opts.add_option('-o', '--out', help='output file')
 | |
| opts.add_option('-s', '--src', help='source file')
 | |
| opts.add_option('-x', '--suffix', help='suffix for included filenames')
 | |
| opts.add_option('-b', '--searchbox', action="store_true", default=True,
 | |
|                 help="generate the search boxes")
 | |
| opts.add_option('--no-searchbox', action="store_false", dest='searchbox',
 | |
|                 help="don't generate the search boxes")
 | |
| opts.add_option('--site-search', action="store", metavar="SITE",
 | |
|                 help=("generate the search box using google. SITE should " +
 | |
|                       "point to the domain/path of the site, eg. " +
 | |
|                       "gerrit-review.googlesource.com/Documentation"))
 | |
| options, _ = opts.parse_args()
 | |
| 
 | |
| if options.site_search:
 | |
|   SEARCH_BOX = (SEARCH_BOX %
 | |
|                 GOOGLE_SITE_SEARCH.replace("@SITE@", options.site_search))
 | |
| else:
 | |
|   SEARCH_BOX = SEARCH_BOX % BUILTIN_SEARCH
 | |
| 
 | |
| 
 | |
| try:
 | |
|     try:
 | |
|         out_file = open(options.out, 'w', errors='ignore')
 | |
|         src_file = open(options.src, 'r', errors='ignore')
 | |
|     except TypeError:
 | |
|         out_file = open(options.out, 'w')
 | |
|         src_file = open(options.src, 'r')
 | |
|     last_line = ''
 | |
|     ignore_next_line = False
 | |
|     last_title = ''
 | |
|     for line in src_file:
 | |
|         if PAT_GERRIT.match(last_line):
 | |
|             # Case of "GERRIT\n------" at the footer
 | |
|             out_file.write(GERRIT_UPLINK)
 | |
|             last_line = ''
 | |
|         elif PAT_SEARCHBOX.match(last_line):
 | |
|             # Case of 'SEARCHBOX\n---------'
 | |
|             if options.searchbox:
 | |
|                 out_file.write(SEARCH_BOX)
 | |
|             last_line = ''
 | |
|         elif PAT_INCLUDE.match(line):
 | |
|             # Case of 'include::<filename>'
 | |
|             match = PAT_INCLUDE.match(line)
 | |
|             out_file.write(last_line)
 | |
|             last_line = match.group(1) + options.suffix + match.group(2) + '\n'
 | |
|         elif PAT_STARS.match(line):
 | |
|             if PAT_TITLE.match(last_line):
 | |
|                 # Case of the title in '.<title>\n****\nget::<url>\n****'
 | |
|                 match = PAT_TITLE.match(last_line)
 | |
|                 last_title = GET_TITLE % match.group(1)
 | |
|             else:
 | |
|                 out_file.write(last_line)
 | |
|                 last_title = ''
 | |
|         elif PAT_GET.match(line):
 | |
|             # Case of '****\nget::<url>\n****' in rest api
 | |
|             url = PAT_GET.match(line).group(1)
 | |
|             out_file.write(GET_MACRO.format(url) % last_title)
 | |
|             ignore_next_line = True
 | |
|         elif ignore_next_line:
 | |
|             # Handle the trailing '****' of the 'get::' case
 | |
|             last_line = ''
 | |
|             ignore_next_line = False
 | |
|         else:
 | |
|             out_file.write(last_line)
 | |
|             last_line = line
 | |
|     out_file.write(last_line)
 | |
|     out_file.write(LINK_SCRIPT)
 | |
|     out_file.close()
 | |
| except IOError as err:
 | |
|     sys.stderr.write(
 | |
|         "error while expanding %s to %s: %s" % (options.src, options.out, err))
 | |
|     exit(1)
 |