Brian Silverman | 1a67511 | 2016-02-20 20:42:49 -0500 | [diff] [blame] | 1 | <xsl:stylesheet version="1.0" |
| 2 | xmlns:xsl="http://www.w3.org/1999/XSL/Transform" |
| 3 | xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" |
| 4 | xmlns:dc="http://purl.org/dc/elements/1.1/" |
| 5 | xmlns:dcq="http://purl.org/dc/qualifiers/1.0/" |
| 6 | xmlns:fo="http://www.w3.org/1999/XSL/Format" |
| 7 | xmlns:fn="http://www.w3.org/2005/xpath-functions"> |
| 8 | <xsl:output method="html"/> |
| 9 | <!-- Set to 1 to show explanations by default. Set to 0 to hide them --> |
| 10 | <xsl:variable name="show_explanation_default" select="0" /> |
| 11 | <!-- The characters within the Webdings font that show the triangles --> |
| 12 | <xsl:variable name="show_button_text" select="'▶'" /> |
| 13 | <xsl:variable name="hide_button_text" select="'▽'" /> |
| 14 | <!-- The suffix for names --> |
| 15 | <xsl:variable name="button_suffix" select="'__button'"/> |
| 16 | <xsl:variable name="body_suffix" select="'__body'"/> |
| 17 | <!-- For easy reference, the name of the button --> |
| 18 | <xsl:variable name="show_hide_all_button" select="'show_hide_all_button'"/> |
| 19 | |
| 20 | <!-- The top-level element --> |
| 21 | <xsl:template match="GUIDE"> |
| 22 | <HTML> |
| 23 | <HEAD> |
| 24 | <TITLE><xsl:value-of select="@title"/></TITLE> |
| 25 | <META http-equiv="Content-Type" content="text/html; charset=utf-8"/> |
| 26 | <LINK HREF="http://www.google.com/favicon.ico" type="image/x-icon" |
| 27 | rel="shortcut icon"/> |
| 28 | <LINK HREF="styleguide.css" |
| 29 | type="text/css" rel="stylesheet"/> |
| 30 | |
| 31 | <SCRIPT language="javascript" type="text/javascript"> |
| 32 | |
| 33 | function GetElementsByName(name) { |
| 34 | // Workaround a bug on old versions of opera. |
| 35 | if (document.getElementsByName) { |
| 36 | return document.getElementsByName(name); |
| 37 | } else { |
| 38 | return [document.getElementById(name)]; |
| 39 | } |
| 40 | } |
| 41 | |
| 42 | /** |
| 43 | * @param {string} namePrefix The prefix of the body name. |
| 44 | * @param {function(boolean): boolean} getVisibility Computes the new |
| 45 | * visibility state, given the current one. |
| 46 | */ |
| 47 | function ChangeVisibility(namePrefix, getVisibility) { |
| 48 | var bodyName = namePrefix + '<xsl:value-of select="$body_suffix"/>'; |
| 49 | var buttonName = namePrefix + '<xsl:value-of select="$button_suffix"/>'; |
| 50 | var bodyElements = GetElementsByName(bodyName); |
| 51 | var linkElement = GetElementsByName('link-' + buttonName)[0]; |
| 52 | if (bodyElements.length != 1) { |
| 53 | throw Error('ShowHideByName() got the wrong number of bodyElements: ' + |
| 54 | bodyElements.length); |
| 55 | } else { |
| 56 | var bodyElement = bodyElements[0]; |
| 57 | var buttonElement = GetElementsByName(buttonName)[0]; |
| 58 | var isVisible = bodyElement.style.display != "none"; |
| 59 | if (getVisibility(isVisible)) { |
| 60 | bodyElement.style.display = "inline"; |
| 61 | linkElement.style.display = "block"; |
| 62 | buttonElement.innerHTML = '<xsl:value-of select="$hide_button_text"/>'; |
| 63 | } else { |
| 64 | bodyElement.style.display = "none"; |
| 65 | linkElement.style.display = "none"; |
| 66 | buttonElement.innerHTML = '<xsl:value-of select="$show_button_text"/>'; |
| 67 | } |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | function ShowHideByName(namePrefix) { |
| 72 | ChangeVisibility(namePrefix, function(old) { return !old; }); |
| 73 | } |
| 74 | |
| 75 | function ShowByName(namePrefix) { |
| 76 | ChangeVisibility(namePrefix, function() { return true; }); |
| 77 | } |
| 78 | |
| 79 | function ShowHideAll() { |
| 80 | var allButton = GetElementsByName("show_hide_all_button")[0]; |
| 81 | if (allButton.innerHTML == '<xsl:value-of select="$hide_button_text"/>') { |
| 82 | allButton.innerHTML = '<xsl:value-of select="$show_button_text"/>'; |
| 83 | SetHiddenState(document.getElementsByTagName("body")[0].childNodes, "none", '<xsl:value-of select="$show_button_text"/>'); |
| 84 | } else { |
| 85 | allButton.innerHTML = '<xsl:value-of select="$hide_button_text"/>'; |
| 86 | SetHiddenState(document.getElementsByTagName("body")[0].childNodes, "inline", '<xsl:value-of select="$hide_button_text"/>'); |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | // Recursively sets state of all children |
| 91 | // of a particular node. |
| 92 | function SetHiddenState(root, newState, newButton) { |
| 93 | for (var i = 0; i != root.length; i++) { |
| 94 | SetHiddenState(root[i].childNodes, newState, newButton); |
| 95 | if (root[i].className == 'showhide_button') { |
| 96 | root[i].innerHTML = newButton; |
| 97 | } |
| 98 | if (root[i].className == 'stylepoint_body' || |
| 99 | root[i].className == 'link_button') { |
| 100 | root[i].style.display = newState; |
| 101 | } |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | |
| 106 | function EndsWith(str, suffix) { |
| 107 | var l = str.length - suffix.length; |
| 108 | return l >= 0 && str.indexOf(suffix, l) == l; |
| 109 | } |
| 110 | |
| 111 | function RefreshVisibilityFromHashParam() { |
| 112 | var hashRegexp = new RegExp('#([^&#]*)$'); |
| 113 | var hashMatch = hashRegexp.exec(window.location.href); |
| 114 | var anchor = hashMatch && GetElementsByName(hashMatch[1])[0]; |
| 115 | var node = anchor; |
| 116 | var suffix = '<xsl:value-of select="$body_suffix"/>'; |
| 117 | while (node) { |
| 118 | var id = node.id; |
| 119 | var matched = id && EndsWith(id, suffix); |
| 120 | if (matched) { |
| 121 | var len = id.length - suffix.length; |
| 122 | ShowByName(id.substring(0, len)); |
| 123 | if (anchor.scrollIntoView) { |
| 124 | anchor.scrollIntoView(); |
| 125 | } |
| 126 | |
| 127 | return; |
| 128 | } |
| 129 | node = node.parentNode; |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | window.onhashchange = RefreshVisibilityFromHashParam; |
| 134 | |
| 135 | window.onload = function() { |
| 136 | // if the URL contains "?showall=y", expand the details of all children |
| 137 | var showHideAllRegex = new RegExp("[\\?&](showall)=([^&#]*)"); |
| 138 | var showHideAllValue = showHideAllRegex.exec(window.location.href); |
| 139 | if (showHideAllValue != null) { |
| 140 | if (showHideAllValue[2] == "y") { |
| 141 | SetHiddenState(document.getElementsByTagName("body")[0].childNodes, |
| 142 | "inline", '<xsl:value-of select="$hide_button_text"/>'); |
| 143 | } else { |
| 144 | SetHiddenState(document.getElementsByTagName("body")[0].childNodes, |
| 145 | "none", '<xsl:value-of select="$show_button_text"/>'); |
| 146 | } |
| 147 | } |
| 148 | var showOneRegex = new RegExp("[\\?&](showone)=([^&#]*)"); |
| 149 | var showOneValue = showOneRegex.exec(window.location.href); |
| 150 | if (showOneValue) { |
| 151 | ShowHideByName(showOneValue[2]); |
| 152 | } |
| 153 | |
| 154 | |
| 155 | RefreshVisibilityFromHashParam(); |
| 156 | } |
| 157 | </SCRIPT> |
| 158 | </HEAD> |
| 159 | <BODY> |
| 160 | <H1><xsl:value-of select="@title"/></H1> |
| 161 | <xsl:apply-templates/> |
| 162 | </BODY> |
| 163 | </HTML> |
| 164 | </xsl:template> |
| 165 | |
| 166 | <xsl:template match="OVERVIEW"> |
| 167 | <xsl:variable name="button_text"> |
| 168 | <xsl:choose> |
| 169 | <xsl:when test="$show_explanation_default"> |
| 170 | <xsl:value-of select="$hide_button_text"/> |
| 171 | </xsl:when> |
| 172 | <xsl:otherwise> |
| 173 | <xsl:value-of select="$show_button_text"/> |
| 174 | </xsl:otherwise> |
| 175 | </xsl:choose> |
| 176 | </xsl:variable> |
| 177 | <DIV style="margin-left: 50%; font-size: 75%;"> |
| 178 | <P> |
| 179 | Each style point has a summary for which additional information is available |
| 180 | by toggling the accompanying arrow button that looks this way: |
| 181 | <SPAN class="showhide_button" style="margin-left: 0; float: none"> |
| 182 | <xsl:value-of select="$show_button_text"/></SPAN>. |
| 183 | You may toggle all summaries with the big arrow button: |
| 184 | </P> |
| 185 | <DIV style=" font-size: larger; margin-left: +2em;"> |
| 186 | <SPAN class="showhide_button" style="font-size: 180%; float: none"> |
| 187 | <xsl:attribute name="onclick"><xsl:value-of select="'javascript:ShowHideAll()'"/></xsl:attribute> |
| 188 | <xsl:attribute name="name"><xsl:value-of select="$show_hide_all_button"/></xsl:attribute> |
| 189 | <xsl:attribute name="id"><xsl:value-of select="$show_hide_all_button"/></xsl:attribute> |
| 190 | <xsl:value-of select="$button_text"/> |
| 191 | </SPAN> |
| 192 | Toggle all summaries |
| 193 | </DIV> |
| 194 | </DIV> |
| 195 | <xsl:call-template name="TOC"> |
| 196 | <xsl:with-param name="root" select=".."/> |
| 197 | </xsl:call-template> |
| 198 | <xsl:apply-templates/> |
| 199 | </xsl:template> |
| 200 | |
| 201 | <xsl:template match="PARTING_WORDS"> |
| 202 | <H2>Parting Words</H2> |
| 203 | <xsl:apply-templates/> |
| 204 | </xsl:template> |
| 205 | |
| 206 | <xsl:template match="CATEGORY"> |
| 207 | <DIV> |
| 208 | <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| 209 | <H2> |
| 210 | <xsl:variable name="category_name"> |
| 211 | <xsl:call-template name="anchorname"> |
| 212 | <xsl:with-param name="sectionname" select="@title"/> |
| 213 | </xsl:call-template> |
| 214 | </xsl:variable> |
| 215 | <xsl:attribute name="name"><xsl:value-of select="$category_name"/></xsl:attribute> |
| 216 | <xsl:attribute name="id"><xsl:value-of select="$category_name"/></xsl:attribute> |
| 217 | <xsl:value-of select="@title"/> |
| 218 | </H2> |
| 219 | <xsl:apply-templates/> |
| 220 | </DIV> |
| 221 | </xsl:template> |
| 222 | |
| 223 | <xsl:template match="STYLEPOINT"> |
| 224 | <DIV> |
| 225 | <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| 226 | <xsl:variable name="stylepoint_name"> |
| 227 | <xsl:call-template name="anchorname"> |
| 228 | <xsl:with-param name="sectionname" select="@title"/> |
| 229 | </xsl:call-template> |
| 230 | </xsl:variable> |
| 231 | <xsl:variable name="button_text"> |
| 232 | <xsl:choose> |
| 233 | <xsl:when test="$show_explanation_default"> |
| 234 | <xsl:value-of select="$hide_button_text"/> |
| 235 | </xsl:when> |
| 236 | <xsl:otherwise> |
| 237 | <xsl:value-of select="$show_button_text"/> |
| 238 | </xsl:otherwise> |
| 239 | </xsl:choose> |
| 240 | </xsl:variable> |
| 241 | <H3> |
| 242 | <A> |
| 243 | <xsl:attribute name="name"><xsl:value-of select="$stylepoint_name"/></xsl:attribute> |
| 244 | <xsl:attribute name="id"><xsl:value-of select="$stylepoint_name"/></xsl:attribute> |
| 245 | <xsl:value-of select="@title"/> |
| 246 | </A> |
| 247 | </H3> |
| 248 | <xsl:variable name="buttonName"> |
| 249 | <xsl:value-of select="$stylepoint_name"/><xsl:value-of select="$button_suffix"/> |
| 250 | </xsl:variable> |
| 251 | <xsl:variable name="onclick_definition"> |
| 252 | <xsl:text>javascript:ShowHideByName('</xsl:text> |
| 253 | <xsl:value-of select="$stylepoint_name"/> |
| 254 | <xsl:text>')</xsl:text> |
| 255 | </xsl:variable> |
| 256 | <SPAN class="link_button" id="link-{$buttonName}" name="link-{$buttonName}"> |
| 257 | <A> |
| 258 | <xsl:attribute name="href">?showone=<xsl:value-of select="$stylepoint_name"/>#<xsl:value-of select="$stylepoint_name"/></xsl:attribute> |
| 259 | link |
| 260 | </A> |
| 261 | </SPAN> |
| 262 | <SPAN class="showhide_button"> |
| 263 | <xsl:attribute name="onclick"><xsl:value-of select="$onclick_definition"/></xsl:attribute> |
| 264 | <xsl:attribute name="name"><xsl:value-of select="$buttonName"/></xsl:attribute> |
| 265 | <xsl:attribute name="id"><xsl:value-of select="$buttonName"/></xsl:attribute> |
| 266 | <xsl:value-of select="$button_text"/> |
| 267 | </SPAN> |
| 268 | <xsl:apply-templates> |
| 269 | <xsl:with-param name="anchor_prefix" select="$stylepoint_name" /> |
| 270 | </xsl:apply-templates> |
| 271 | </DIV> |
| 272 | </xsl:template> |
| 273 | |
| 274 | <xsl:template match="SUMMARY"> |
| 275 | <xsl:param name="anchor_prefix" /> |
| 276 | <DIV style="display:inline;"> |
| 277 | <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| 278 | <xsl:apply-templates/> |
| 279 | </DIV> |
| 280 | </xsl:template> |
| 281 | |
| 282 | <xsl:template match="BODY"> |
| 283 | <xsl:param name="anchor_prefix" /> |
| 284 | <DIV> |
| 285 | <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| 286 | <DIV class="stylepoint_body"> |
| 287 | <xsl:attribute name="name"><xsl:value-of select="$anchor_prefix"/><xsl:value-of select="$body_suffix"/></xsl:attribute> |
| 288 | <xsl:attribute name="id"><xsl:value-of select="$anchor_prefix"/><xsl:value-of select="$body_suffix"/></xsl:attribute> |
| 289 | <xsl:attribute name="style"> |
| 290 | <xsl:choose> |
| 291 | <xsl:when test="$show_explanation_default">display: inline</xsl:when> |
| 292 | <xsl:otherwise>display: none</xsl:otherwise> |
| 293 | </xsl:choose> |
| 294 | </xsl:attribute> |
| 295 | <xsl:apply-templates/> |
| 296 | </DIV> |
| 297 | </DIV> |
| 298 | </xsl:template> |
| 299 | |
| 300 | <xsl:template match="DEFINITION"> |
| 301 | <P> |
| 302 | <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| 303 | <SPAN class="stylepoint_section">Definition: </SPAN> |
| 304 | <xsl:apply-templates/> |
| 305 | </P> |
| 306 | </xsl:template> |
| 307 | |
| 308 | <xsl:template match="PROS"> |
| 309 | <P> |
| 310 | <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| 311 | <SPAN class="stylepoint_section">Pros: </SPAN> |
| 312 | <xsl:apply-templates/> |
| 313 | </P> |
| 314 | </xsl:template> |
| 315 | |
| 316 | <xsl:template match="CONS"> |
| 317 | <P> |
| 318 | <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| 319 | <SPAN class="stylepoint_section">Cons: </SPAN> |
| 320 | <xsl:apply-templates/> |
| 321 | </P> |
| 322 | </xsl:template> |
| 323 | |
| 324 | <xsl:template match="DECISION"> |
| 325 | <P> |
| 326 | <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| 327 | <SPAN class="stylepoint_section">Decision: </SPAN> |
| 328 | <xsl:apply-templates/> |
| 329 | </P> |
| 330 | </xsl:template> |
| 331 | |
| 332 | <xsl:template match="TODO"> |
| 333 | <P> |
| 334 | <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| 335 | <DIV style="font-size: 150%;">TODO: |
| 336 | <xsl:apply-templates/> |
| 337 | </DIV> |
| 338 | </P> |
| 339 | </xsl:template> |
| 340 | |
| 341 | <xsl:template match="SUBSECTION"> |
| 342 | <P> |
| 343 | <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| 344 | <SPAN class="stylepoint_subsection"><xsl:value-of select="@title"/> </SPAN> |
| 345 | <xsl:apply-templates/> |
| 346 | </P> |
| 347 | </xsl:template> |
| 348 | |
| 349 | <xsl:template match="SUBSUBSECTION"> |
| 350 | <P> |
| 351 | <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| 352 | <SPAN class="stylepoint_subsubsection"><xsl:value-of select="@title"/> </SPAN> |
| 353 | <xsl:apply-templates/> |
| 354 | </P> |
| 355 | </xsl:template> |
| 356 | |
| 357 | <xsl:template match="CODE_SNIPPET"> |
| 358 | <DIV> |
| 359 | <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| 360 | <PRE><xsl:call-template name="print_without_leading_chars"> |
| 361 | <xsl:with-param name="text" select="."/> |
| 362 | <xsl:with-param name="strip" select="1"/> |
| 363 | <xsl:with-param name="is_firstline" select="1"/> |
| 364 | <xsl:with-param name="trim_count"> |
| 365 | <xsl:call-template name="num_leading_spaces"> |
| 366 | <xsl:with-param name="text" select="."/> |
| 367 | <xsl:with-param name="max_so_far" select="1000"/> |
| 368 | </xsl:call-template> |
| 369 | </xsl:with-param> |
| 370 | </xsl:call-template></PRE> |
| 371 | </DIV> |
| 372 | </xsl:template> |
| 373 | |
| 374 | <xsl:template match="BAD_CODE_SNIPPET"> |
| 375 | <DIV> |
| 376 | <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| 377 | <PRE class="badcode"><xsl:call-template name="print_without_leading_chars"> |
| 378 | <xsl:with-param name="text" select="."/> |
| 379 | <xsl:with-param name="strip" select="1"/> |
| 380 | <xsl:with-param name="is_firstline" select="1"/> |
| 381 | <xsl:with-param name="trim_count"> |
| 382 | <xsl:call-template name="num_leading_spaces"> |
| 383 | <xsl:with-param name="text" select="."/> |
| 384 | <xsl:with-param name="max_so_far" select="1000"/> |
| 385 | </xsl:call-template> |
| 386 | </xsl:with-param> |
| 387 | </xsl:call-template></PRE> |
| 388 | </DIV> |
| 389 | </xsl:template> |
| 390 | |
| 391 | <xsl:template match="PY_CODE_SNIPPET"> |
| 392 | <DIV> |
| 393 | <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| 394 | <PRE><xsl:call-template name="print_python_code"> |
| 395 | <xsl:with-param name="text" select="."/> |
| 396 | </xsl:call-template></PRE> |
| 397 | </DIV> |
| 398 | </xsl:template> |
| 399 | |
| 400 | <xsl:template match="BAD_PY_CODE_SNIPPET"> |
| 401 | <DIV> |
| 402 | <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| 403 | <PRE class="badcode"><xsl:call-template name="print_python_code"> |
| 404 | <xsl:with-param name="text" select="."/> |
| 405 | </xsl:call-template></PRE> |
| 406 | </DIV> |
| 407 | </xsl:template> |
| 408 | |
| 409 | <xsl:template match="FUNCTION"> |
| 410 | <xsl:call-template name="print_function_name"> |
| 411 | <xsl:with-param name="text" select="."/> |
| 412 | </xsl:call-template> |
| 413 | </xsl:template> |
| 414 | |
| 415 | <xsl:template match="SYNTAX"> |
| 416 | <I> |
| 417 | <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| 418 | <xsl:apply-templates/> |
| 419 | </I> |
| 420 | </xsl:template> |
| 421 | |
| 422 | |
| 423 | <!-- This passes through any HTML elements that the |
| 424 | XML doc uses for minor formatting --> |
| 425 | <xsl:template match="a|address|blockquote|br|center|cite|code|dd|div|dl|dt|em|hr|i|img|li|ol|p|pre|span|table|td|th|tr|ul|var|A|ADDRESS|BLOCKQUOTE|BR|CENTER|CITE|CODE|DD|DIV|DL|DT|EM|HR|I|LI|OL|P|PRE|SPAN|TABLE|TD|TH|TR|UL|VAR"> |
| 426 | <xsl:element name="{local-name()}"> |
| 427 | <xsl:copy-of select="@*"/> |
| 428 | <xsl:apply-templates/> |
| 429 | </xsl:element> |
| 430 | </xsl:template> |
| 431 | |
| 432 | <!-- Builds the table of contents --> |
| 433 | <xsl:template name="TOC"> |
| 434 | <xsl:param name="root"/> |
| 435 | <DIV class="toc"> |
| 436 | <DIV class="toc_title">Table of Contents</DIV> |
| 437 | <TABLE> |
| 438 | <xsl:for-each select="$root/CATEGORY"> |
| 439 | <TR valign="top"> |
| 440 | <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| 441 | <TD> |
| 442 | <DIV class="toc_category"> |
| 443 | <A> |
| 444 | <xsl:attribute name="href"> |
| 445 | <xsl:text>#</xsl:text> |
| 446 | <xsl:call-template name="anchorname"> |
| 447 | <xsl:with-param name="sectionname" select="@title"/> |
| 448 | </xsl:call-template> |
| 449 | </xsl:attribute> |
| 450 | <xsl:value-of select="@title"/> |
| 451 | </A> |
| 452 | </DIV> |
| 453 | </TD><TD> |
| 454 | <DIV class="toc_stylepoint"> |
| 455 | <xsl:for-each select="./STYLEPOINT"> |
| 456 | <SPAN style="padding-right: 1em; white-space:nowrap;"> |
| 457 | <xsl:attribute name="class"><xsl:value-of select="@class"/></xsl:attribute> |
| 458 | <A> |
| 459 | <xsl:attribute name="href"> |
| 460 | <xsl:text>#</xsl:text> |
| 461 | <xsl:call-template name="anchorname"> |
| 462 | <xsl:with-param name="sectionname" select="@title"/> |
| 463 | </xsl:call-template> |
| 464 | </xsl:attribute> |
| 465 | <xsl:value-of select="@title"/> |
| 466 | </A> |
| 467 | </SPAN> |
| 468 | <xsl:text> </xsl:text> |
| 469 | </xsl:for-each> |
| 470 | </DIV> |
| 471 | </TD> |
| 472 | </TR> |
| 473 | </xsl:for-each> |
| 474 | </TABLE> |
| 475 | </DIV> |
| 476 | </xsl:template> |
| 477 | |
| 478 | <xsl:template name="TOC_one_stylepoint"> |
| 479 | <xsl:param name="stylepoint"/> |
| 480 | </xsl:template> |
| 481 | |
| 482 | <!-- Creates a standard anchor given any text. |
| 483 | Substitutes underscore for characters unsuitable for URLs --> |
| 484 | <xsl:template name="anchorname"> |
| 485 | <xsl:param name="sectionname"/> |
| 486 | <!-- strange quoting necessary to strip apostrophes --> |
| 487 | <xsl:variable name="bad_characters" select="" ()#'""/> |
| 488 | <xsl:value-of select="translate($sectionname,$bad_characters,'_____')"/> |
| 489 | </xsl:template> |
| 490 | |
| 491 | <!-- Given text, evaluates to the number of leading spaces. --> |
| 492 | <!-- TODO(csilvers): deal well with leading tabs (treat as 8 spaces?) --> |
| 493 | <xsl:template name="num_leading_spaces_one_line"> |
| 494 | <xsl:param name="text"/> |
| 495 | <xsl:param name="current_count"/> |
| 496 | <xsl:choose> |
| 497 | <xsl:when test="starts-with($text, ' ')"> |
| 498 | <xsl:call-template name="num_leading_spaces_one_line"> |
| 499 | <xsl:with-param name="text" select="substring($text, 2)"/> |
| 500 | <xsl:with-param name="current_count" select="$current_count + 1"/> |
| 501 | </xsl:call-template> |
| 502 | </xsl:when> |
| 503 | <xsl:otherwise> |
| 504 | <xsl:value-of select="$current_count"/> |
| 505 | </xsl:otherwise> |
| 506 | </xsl:choose> |
| 507 | </xsl:template> |
| 508 | |
| 509 | <!-- Given a block of text, each line terminated by \n, evaluates to |
| 510 | the indentation-level of that text; that is, the largest number |
| 511 | n such that every non-blank line starts with at least n spaces. --> |
| 512 | <xsl:template name="num_leading_spaces"> |
| 513 | <xsl:param name="text"/> |
| 514 | <xsl:param name="max_so_far"/> |
| 515 | <!-- TODO(csilvers): deal with case text doesn't end in a newline --> |
| 516 | <xsl:variable name="line" select="substring-before($text, '
')"/> |
| 517 | <xsl:variable name="rest" select="substring-after($text, '
')"/> |
| 518 | <xsl:variable name="num_spaces_this_line"> |
| 519 | <xsl:choose> |
| 520 | <xsl:when test="$line=''"> |
| 521 | <xsl:value-of select="$max_so_far"/> |
| 522 | </xsl:when> |
| 523 | <xsl:otherwise> |
| 524 | <xsl:call-template name="num_leading_spaces_one_line"> |
| 525 | <xsl:with-param name="text" select="$line"/> |
| 526 | <xsl:with-param name="current_count" select="0"/> |
| 527 | </xsl:call-template> |
| 528 | </xsl:otherwise> |
| 529 | </xsl:choose> |
| 530 | </xsl:variable> |
| 531 | <xsl:variable name="new_max_so_far"> |
| 532 | <xsl:choose> |
| 533 | <xsl:when test="$num_spaces_this_line < $max_so_far"> |
| 534 | <xsl:value-of select="$num_spaces_this_line"/> |
| 535 | </xsl:when> |
| 536 | <xsl:otherwise> |
| 537 | <xsl:value-of select="$max_so_far"/> |
| 538 | </xsl:otherwise> |
| 539 | </xsl:choose> |
| 540 | </xsl:variable> |
| 541 | <!-- now check if we're on the last line, and if not, recurse --> |
| 542 | <xsl:if test="$rest=''"> |
| 543 | <xsl:value-of select="$new_max_so_far"/> |
| 544 | </xsl:if> |
| 545 | <xsl:if test="not($rest='')"> |
| 546 | <xsl:call-template name="num_leading_spaces"> |
| 547 | <xsl:with-param name="text" select="$rest"/> |
| 548 | <xsl:with-param name="max_so_far" select="$new_max_so_far"/> |
| 549 | </xsl:call-template> |
| 550 | </xsl:if> |
| 551 | </xsl:template> |
| 552 | |
| 553 | <!-- Given text, determine the starting position of code. |
| 554 | This similar to num_leading_spaces_one_line but treats "Yes:" and "No:" |
| 555 | as spaces. Also, if there is no code on the first line, it searches |
| 556 | subsequent lines until a non-empty line is found. |
| 557 | Used to find the start of code in snippets like: |
| 558 | Yes: if(foo): |
| 559 | No : if(foo): |
| 560 | As well as: |
| 561 | Yes: |
| 562 | if (foo): |
| 563 | --> |
| 564 | <xsl:template name="code_start_index"> |
| 565 | <xsl:param name="text"/> |
| 566 | <xsl:param name="current_count"/> |
| 567 | <xsl:choose> |
| 568 | <xsl:when test="starts-with($text, ' ')"> |
| 569 | <xsl:call-template name="code_start_index"> |
| 570 | <xsl:with-param name="text" select="substring($text, 2)"/> |
| 571 | <xsl:with-param name="current_count" select="$current_count + 1"/> |
| 572 | </xsl:call-template> |
| 573 | </xsl:when> |
| 574 | <xsl:when test="starts-with($text, 'Yes:')"> |
| 575 | <xsl:call-template name="code_start_index"> |
| 576 | <xsl:with-param name="text" select="substring($text, 5)"/> |
| 577 | <xsl:with-param name="current_count" select="$current_count + 4"/> |
| 578 | </xsl:call-template> |
| 579 | </xsl:when> |
| 580 | <xsl:when test="starts-with($text, 'No:')"> |
| 581 | <xsl:call-template name="code_start_index"> |
| 582 | <xsl:with-param name="text" select="substring($text, 4)"/> |
| 583 | <xsl:with-param name="current_count" select="$current_count + 3"/> |
| 584 | </xsl:call-template> |
| 585 | </xsl:when> |
| 586 | <!-- This is only reached if the first line is entirely whitespace or |
| 587 | contains nothing but "Yes:" or "No:"--> |
| 588 | <xsl:when test="starts-with($text, '
')"> |
| 589 | <xsl:call-template name="code_start_index"> |
| 590 | <xsl:with-param name="text" select="substring($text, 2)"/> |
| 591 | <xsl:with-param name="current_count" select="0"/> |
| 592 | </xsl:call-template> |
| 593 | </xsl:when> |
| 594 | <xsl:otherwise> |
| 595 | <xsl:value-of select="$current_count"/> |
| 596 | </xsl:otherwise> |
| 597 | </xsl:choose> |
| 598 | </xsl:template> |
| 599 | |
| 600 | <!-- Helper for ends_with_colon. Determine whether the given line is nothing |
| 601 | but spaces and python-style comments. --> |
| 602 | <xsl:template name="is_blank_or_comment"> |
| 603 | <xsl:param name="line"/> |
| 604 | <xsl:choose> |
| 605 | <xsl:when test="$line = ''"> |
| 606 | <xsl:value-of select="1"/> |
| 607 | </xsl:when> |
| 608 | <xsl:when test="starts-with($line, '
')"> |
| 609 | <xsl:value-of select="1"/> |
| 610 | </xsl:when> |
| 611 | <xsl:when test="starts-with($line, '#')"> |
| 612 | <xsl:value-of select="1"/> |
| 613 | </xsl:when> |
| 614 | <xsl:when test="starts-with($line, ' ')"> |
| 615 | <xsl:call-template name="is_blank_or_comment"> |
| 616 | <xsl:with-param name="line" select="substring($line, 2)"/> |
| 617 | </xsl:call-template> |
| 618 | </xsl:when> |
| 619 | <xsl:otherwise> |
| 620 | <xsl:value-of select="0"/> |
| 621 | </xsl:otherwise> |
| 622 | </xsl:choose> |
| 623 | </xsl:template> |
| 624 | |
| 625 | <!-- Determine whether the given line ends with a colon. Note that Python |
| 626 | style comments are ignored so the following lines return True: |
| 627 | - def foo(): |
| 628 | - def foo(): # Bar |
| 629 | - if(foo): |
| 630 | |
| 631 | But some code may confuse this function. For example the following are |
| 632 | also consider to "end_with_colon" even though they don't for Python |
| 633 | - foo(": #") |
| 634 | - foo() # No need for : |
| 635 | --> |
| 636 | <xsl:template name="ends_with_colon"> |
| 637 | <xsl:param name="line"/> |
| 638 | <xsl:param name="found_colon"/> |
| 639 | <xsl:choose> |
| 640 | <xsl:when test="$line = ''"> |
| 641 | <xsl:value-of select="$found_colon"/> |
| 642 | </xsl:when> |
| 643 | <xsl:when test="starts-with($line, '
')"> |
| 644 | <xsl:value-of select="$found_colon"/> |
| 645 | </xsl:when> |
| 646 | <xsl:when test="starts-with($line, ' ')"> |
| 647 | <xsl:call-template name="ends_with_colon"> |
| 648 | <xsl:with-param name="line" select="substring($line, 2)"/> |
| 649 | <xsl:with-param name="found_colon" select="$found_colon"/> |
| 650 | </xsl:call-template> |
| 651 | </xsl:when> |
| 652 | <xsl:when test="starts-with($line, ':')"> |
| 653 | <xsl:variable name="rest_is_comment"> |
| 654 | <xsl:call-template name="is_blank_or_comment"> |
| 655 | <xsl:with-param name="line" select="substring($line, 2)"/> |
| 656 | </xsl:call-template> |
| 657 | </xsl:variable> |
| 658 | <xsl:choose> |
| 659 | <xsl:when test="$rest_is_comment = '1'"> |
| 660 | <xsl:value-of select="1"/> |
| 661 | </xsl:when> |
| 662 | <xsl:otherwise> |
| 663 | <xsl:call-template name="ends_with_colon"> |
| 664 | <xsl:with-param name="line" select="substring($line, 2)"/> |
| 665 | <xsl:with-param name="found_colon" select="0"/> |
| 666 | </xsl:call-template> |
| 667 | </xsl:otherwise> |
| 668 | </xsl:choose> |
| 669 | </xsl:when> |
| 670 | <xsl:otherwise> |
| 671 | <xsl:call-template name="ends_with_colon"> |
| 672 | <xsl:with-param name="line" select="substring($line, 2)"/> |
| 673 | <xsl:with-param name="found_colon" select="0"/> |
| 674 | </xsl:call-template> |
| 675 | </xsl:otherwise> |
| 676 | </xsl:choose> |
| 677 | </xsl:template> |
| 678 | |
| 679 | <!-- Prints one line of python code with proper indent and calls itself |
| 680 | recursively for the rest of the text. |
| 681 | This template uses "a", "b", "c" and "d" to refer to four key column |
| 682 | numbers. They are: |
| 683 | - a: the indentation common to all lines in a code snippet. This is |
| 684 | stripped out to allow for cleaner code in the xml. |
| 685 | - b: the indentation of the most out-dented line of code. This is |
| 686 | different from "a" when code is labelled with "Yes:" or "No:" |
| 687 | - c: the indentation of the current python block, in other words, the |
| 688 | indentation of the first line of this block, which is the |
| 689 | indentation of the last line we saw that ended with a colon. |
| 690 | - d: the "total" indentation of the line, ignorng possible "Yes:" or |
| 691 | "No:" text on the line. |
| 692 | |
| 693 | For example, for the last line of the following code snippet, the |
| 694 | positions of a, b, c and d are indicated below: |
| 695 | Yes: def Foo(): |
| 696 | if bar(): |
| 697 | a += 1 |
| 698 | baz() |
| 699 | a b c d |
| 700 | |
| 701 | The algorithm is: |
| 702 | 1) Split the text into first line and the rest. Note that the |
| 703 | substring-before function is supposed to handle the case where the |
| 704 | character is not present in the string but does not so we |
| 705 | automatically ignore the last line of the snippet which is always |
| 706 | empty (the closing snippet tag). This is consistent with the |
| 707 | behavior or print_without_leading_chars. |
| 708 | 2) If the current is empty (only whitespace), print newline and call |
| 709 | itself recursively on the rest of the text with the rest of the |
| 710 | parameters unchanged. |
| 711 | 3) Otherwise, measure "d" |
| 712 | 4) Measure "c" by taking: |
| 713 | - the value of "d" if the previous line ended with a colon or the |
| 714 | current line is outdented compare to the previous line |
| 715 | - the indent of the previous line otherwise |
| 716 | 5) Print line[a:c] (Note that we ignore line[0:a]) |
| 717 | 6) Print line[b:c] in an external span (in order to double the block |
| 718 | indent in external code). |
| 719 | 7) Print line[c:<end>] with function names processed to produce both |
| 720 | internal and external names. |
| 721 | 8) If there are more lines, recurse. |
| 722 | --> |
| 723 | <xsl:template name="print_python_line_recursively"> |
| 724 | <xsl:param name="text"/> |
| 725 | <xsl:param name="a"/> |
| 726 | <xsl:param name="b"/> |
| 727 | <xsl:param name="previous_indent"/> |
| 728 | <xsl:param name="previous_ends_with_colon"/> |
| 729 | <xsl:param name="is_first_line"/> |
| 730 | <xsl:variable name="line" select="substring-before($text, '
')"/> |
| 731 | <xsl:variable name="rest" select="substring-after($text, '
')"/> |
| 732 | <xsl:choose> |
| 733 | <xsl:when test="substring($line, $b) = '' and not($rest = '')"> |
| 734 | <xsl:if test="not($is_first_line = '1')"> |
| 735 | <xsl:text>
</xsl:text> |
| 736 | </xsl:if> |
| 737 | <xsl:call-template name="print_python_line_recursively"> |
| 738 | <xsl:with-param name="text" select="$rest"/> |
| 739 | <xsl:with-param name="a" select="$a"/> |
| 740 | <xsl:with-param name="b" select="$b"/> |
| 741 | <xsl:with-param name="previous_indent" select="$previous_indent"/> |
| 742 | <xsl:with-param name="previous_ends_with_colon" |
| 743 | select="$previous_ends_with_colon"/> |
| 744 | <xsl:with-param name="is_first_line" select="0"/> |
| 745 | </xsl:call-template> |
| 746 | </xsl:when> |
| 747 | <xsl:otherwise> |
| 748 | <xsl:variable name="indent_after_b"> |
| 749 | <xsl:call-template name="num_leading_spaces_one_line"> |
| 750 | <xsl:with-param name="text" select="substring($line, $b + 1)"/> |
| 751 | <xsl:with-param name="current_count" select="0"/> |
| 752 | </xsl:call-template> |
| 753 | </xsl:variable> |
| 754 | <xsl:variable name="d" select="$b + $indent_after_b"/> |
| 755 | <xsl:variable name="c"> |
| 756 | <xsl:choose> |
| 757 | <xsl:when test="$previous_ends_with_colon = '1' or |
| 758 | $previous_indent > $d"> |
| 759 | <xsl:value-of select="$d"/> |
| 760 | </xsl:when> |
| 761 | <xsl:otherwise> |
| 762 | <xsl:value-of select="$previous_indent"/> |
| 763 | </xsl:otherwise> |
| 764 | </xsl:choose> |
| 765 | </xsl:variable> |
| 766 | |
| 767 | <xsl:value-of select="substring($line, $a + 1, $c - $a)"/> |
| 768 | <span class="external"> |
| 769 | <xsl:value-of select="substring($line, $b + 1, $c - $b)"/> |
| 770 | </span> |
| 771 | <xsl:call-template name="munge_function_names_in_text"> |
| 772 | <xsl:with-param name="stripped_line" |
| 773 | select="substring($line, $c + 1)"/> |
| 774 | </xsl:call-template> |
| 775 | <xsl:if test="not(substring($rest, $a) = '')"> |
| 776 | <xsl:text>
</xsl:text> |
| 777 | <xsl:call-template name="print_python_line_recursively"> |
| 778 | <xsl:with-param name="text" select="$rest"/> |
| 779 | <xsl:with-param name="a" select="$a"/> |
| 780 | <xsl:with-param name="b" select="$b"/> |
| 781 | <xsl:with-param name="previous_indent" select="$c"/> |
| 782 | <xsl:with-param name="previous_ends_with_colon"> |
| 783 | <xsl:call-template name="ends_with_colon"> |
| 784 | <xsl:with-param name="line" select="$line"/> |
| 785 | <xsl:with-param name="found_colon" select="0"/> |
| 786 | </xsl:call-template> |
| 787 | </xsl:with-param> |
| 788 | <xsl:with-param name="is_first_line" select="0"/> |
| 789 | </xsl:call-template> |
| 790 | </xsl:if> |
| 791 | </xsl:otherwise> |
| 792 | </xsl:choose> |
| 793 | </xsl:template> |
| 794 | |
| 795 | <!-- Print python code with internal and external styles. |
| 796 | In order to conform with PEP-8 externally, we identify 2-space indents |
| 797 | and an external-only 4-space indent. |
| 798 | Function names that are marked with $$FunctionName/$$ have an external |
| 799 | lower_with_underscore version added. --> |
| 800 | <xsl:template name="print_python_code"> |
| 801 | <xsl:param name="text"/> |
| 802 | |
| 803 | <xsl:variable name="a"> |
| 804 | <xsl:call-template name="num_leading_spaces"> |
| 805 | <xsl:with-param name="text" select="."/> |
| 806 | <xsl:with-param name="max_so_far" select="1000"/> |
| 807 | </xsl:call-template> |
| 808 | </xsl:variable> |
| 809 | |
| 810 | <xsl:variable name="b"> |
| 811 | <xsl:call-template name="code_start_index"> |
| 812 | <xsl:with-param name="text" select="$text"/> |
| 813 | <xsl:with-param name="current_count" select="0"/> |
| 814 | </xsl:call-template> |
| 815 | </xsl:variable> |
| 816 | |
| 817 | <xsl:call-template name="print_python_line_recursively"> |
| 818 | <xsl:with-param name="text" select="$text"/> |
| 819 | <xsl:with-param name="a" select="$a"/> |
| 820 | <xsl:with-param name="b" select="$b"/> |
| 821 | <xsl:with-param name="previous_indent" select="$b"/> |
| 822 | <xsl:with-param name="previous_ends_with_colon" select="0"/> |
| 823 | <xsl:with-param name="is_first_line" select="1"/> |
| 824 | </xsl:call-template> |
| 825 | </xsl:template> |
| 826 | |
| 827 | <!-- Given a block of text, each line terminated by \n, and a number n, |
| 828 | emits the text with the first n characters of each line |
| 829 | deleted. If strip==1, then we omit blank lines at the beginning |
| 830 | and end of the text (but not the middle!) --> |
| 831 | <!-- TODO(csilvers): deal well with leading tabs (treat as 8 spaces?) --> |
| 832 | <xsl:template name="print_without_leading_chars"> |
| 833 | <xsl:param name="text"/> |
| 834 | <xsl:param name="trim_count"/> |
| 835 | <xsl:param name="strip"/> |
| 836 | <xsl:param name="is_firstline"/> |
| 837 | <!-- TODO(csilvers): deal with case text doesn't end in a newline --> |
| 838 | <xsl:variable name="line" select="substring-before($text, '
')"/> |
| 839 | <xsl:variable name="rest" select="substring-after($text, '
')"/> |
| 840 | <xsl:variable name="stripped_line" select="substring($line, $trim_count+1)"/> |
| 841 | <xsl:choose> |
| 842 | <!-- $line (or $rest) is considered empty if we'd trim the entire line --> |
| 843 | <xsl:when test="($strip = '1') and ($is_firstline = '1') and |
| 844 | (string-length($line) <= $trim_count)"> |
| 845 | </xsl:when> |
| 846 | <xsl:when test="($strip = '1') and |
| 847 | (string-length($rest) <= $trim_count)"> |
| 848 | <xsl:value-of select="$stripped_line"/> |
| 849 | </xsl:when> |
| 850 | <xsl:otherwise> |
| 851 | <xsl:value-of select="$stripped_line"/> |
| 852 | <xsl:text>
</xsl:text> |
| 853 | </xsl:otherwise> |
| 854 | </xsl:choose> |
| 855 | <xsl:if test="not($rest='')"> |
| 856 | <xsl:call-template name="print_without_leading_chars"> |
| 857 | <xsl:with-param name="text" select="$rest"/> |
| 858 | <xsl:with-param name="trim_count" select="$trim_count"/> |
| 859 | <xsl:with-param name="strip" select="$strip"/> |
| 860 | <xsl:with-param name="is_firstline" select="0"/> |
| 861 | </xsl:call-template> |
| 862 | </xsl:if> |
| 863 | </xsl:template> |
| 864 | |
| 865 | <!-- Given a line of code, find function names that are marked with $$ /$$ and |
| 866 | print out the line with the internal and external versions of the |
| 867 | function names.--> |
| 868 | <xsl:template name="munge_function_names_in_text"> |
| 869 | <xsl:param name="stripped_line"/> |
| 870 | <xsl:choose> |
| 871 | <xsl:when test="contains($stripped_line, '$$')"> |
| 872 | <xsl:value-of select="substring-before($stripped_line, '$$')"/> |
| 873 | <xsl:call-template name="print_function_name"> |
| 874 | <xsl:with-param name="text" select="substring-after(substring-before($stripped_line, '/$$'), '$$')"/> |
| 875 | </xsl:call-template> |
| 876 | <xsl:call-template name="munge_function_names_in_text"> |
| 877 | <xsl:with-param name="stripped_line" select="substring-after($stripped_line, '/$$')"/> |
| 878 | </xsl:call-template> |
| 879 | </xsl:when> |
| 880 | <xsl:otherwise> |
| 881 | <xsl:value-of select="$stripped_line"/> |
| 882 | </xsl:otherwise> |
| 883 | </xsl:choose> |
| 884 | </xsl:template> |
| 885 | |
| 886 | <!-- Given a function name, print out both the internal and external version |
| 887 | of the function name in their respective spans.--> |
| 888 | <xsl:template name="print_function_name"> |
| 889 | <xsl:param name="text"/> |
| 890 | <xsl:call-template name="convert_camel_case_to_lowercase_with_under"> |
| 891 | <xsl:with-param name="text" select="$text"/> |
| 892 | </xsl:call-template> |
| 893 | </xsl:template> |
| 894 | |
| 895 | <!-- Given a single word of text convert it from CamelCase to |
| 896 | lower_with_under. |
| 897 | This means replacing each uppercase character with _ followed by the |
| 898 | lowercase version except for the first character which is replaced |
| 899 | without adding the _.--> |
| 900 | <xsl:template name="convert_camel_case_to_lowercase_with_under"> |
| 901 | <xsl:param name="text"/> |
| 902 | <xsl:param name="is_recursive_call"/> |
| 903 | <xsl:variable name="first_char" select="substring($text, 1, 1)"/> |
| 904 | <xsl:variable name="rest" select="substring($text, 2)"/> |
| 905 | <xsl:choose> |
| 906 | <xsl:when test="contains('ABCDEFGHIJKLMNOPQRSTUVWXYZ', $first_char)"> |
| 907 | <xsl:if test="$is_recursive_call='1'"> |
| 908 | <xsl:text>_</xsl:text> |
| 909 | </xsl:if> |
| 910 | <xsl:value-of select="translate($first_char, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')"/> |
| 911 | </xsl:when> |
| 912 | <xsl:otherwise> |
| 913 | <xsl:value-of select="$first_char" /> |
| 914 | </xsl:otherwise> |
| 915 | </xsl:choose> |
| 916 | <xsl:if test="not($rest='')"> |
| 917 | <xsl:call-template name="convert_camel_case_to_lowercase_with_under"> |
| 918 | <xsl:with-param name="text" select="$rest"/> |
| 919 | <xsl:with-param name="is_recursive_call" select="1"/> |
| 920 | </xsl:call-template> |
| 921 | </xsl:if> |
| 922 | </xsl:template> |
| 923 | </xsl:stylesheet> |
| 924 | |