1// Licensed under the Apache License, Version 2.0 (the "License"); you may not 2// use this file except in compliance with the License. You may obtain a copy of 3// the License at 4// 5// http://www.apache.org/licenses/LICENSE-2.0 6// 7// Unless required by applicable law or agreed to in writing, software 8// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10// License for the specific language governing permissions and limitations under 11// the License. 12 13function LoadData () 14{ 15 gTypeNames = []; 16 ComplexTypeNames = []; 17 SimpleTypeNames = []; 18 for (var sName in Data) 19 { 20 gTypeNames.push(sName); 21 switch(Data[sName].type) 22 { 23 case "complex-type": 24 ComplexTypeNames.push(sName); 25 break; 26 27 case "simple-type": 28 SimpleTypeNames.push(sName); 29 break; 30 } 31 } 32 document.getElementById("message").innerHTML = "there are " + ComplexTypeNames.length + " complex types and " 33 + SimpleTypeNames.length +" simple types"; 34} 35 36 37 38 39function InitializeSearch () 40{ 41 CurrentTypeName = ""; 42 TypeHistory = Array(); 43 LoadData(); 44 ShowType("A:ST_Overlap"); 45} 46 47 48 49 50function CheckInput (aField, aEvent) 51{ 52 switch(aEvent.keyCode) 53 { 54 case 38: 55 --selection_index; 56 if (selection_index < 0) 57 selection_index = matches.length-1; 58 break; 59 case 40: 60 ++selection_index; 61 if (selection_index >= matches.length) 62 selection_index = 0; 63 break; 64 default: 65 matches = GetMatches(aField.value); 66 selection_index = 0; 67 } 68 69 ShowMatches(matches, selection_index); 70} 71 72 73 74 75function GetMatches (sPattern) 76{ 77 var aLcPatterns = sPattern.toLowerCase().split(/\s+/); 78 79 var nTypeCount = gTypeNames.length; 80 81 var aMatches = []; 82 for (index=0; index<nTypeCount; ++index) 83 { 84 var sTypeName = gTypeNames[index]; 85 var aParts = new Array(sTypeName); 86 var sLcTypeName = sTypeName.toLowerCase(); 87 var bIsMatch = true; 88 var nSearchStart = 0; 89 for (nPatternIndex=0; nPatternIndex<aLcPatterns.length && bIsMatch; ++nPatternIndex) 90 { 91 var sPattern = aLcPatterns[nPatternIndex]; 92 var nMatchStart = sLcTypeName.indexOf(sPattern, nSearchStart); 93 if (nMatchStart >= 0) 94 { 95 var nMatchEnd = nMatchStart + sPattern.length; 96 aParts.push(sTypeName.substring(nSearchStart, nMatchStart)); 97 aParts.push(sTypeName.substring(nMatchStart, nMatchEnd)); 98 nSearchStart = nMatchEnd; 99 } 100 else 101 { 102 // Only some patterns are matched. 103 bIsMatch = false; 104 } 105 } 106 if (bIsMatch) 107 { 108 if (nMatchEnd < sTypeName.length-1) 109 aParts.push(sTypeName.substring(nMatchEnd)); 110 aMatches.push(aParts); 111 } 112 } 113 return aMatches; 114} 115 116 117 118 119/** Show the matching types. 120 * As there can be a great many matching types, some sort of abbreviation is necessary. 121 * Format all matches into lines of n entries. 122 * Show the line containing the selected match and the ones before and after. 123 * Show also the number of ommited matches. 124 */ 125function ShowMatches (aMatches, nSelectionIndex) 126{ 127 var sText = ""; 128 129 var nHalfRange = 10; 130 var nMatchesPerLine = 5; 131 var nLineCount = Math.floor((aMatches.length+nMatchesPerLine-1) / nMatchesPerLine); 132 var nLineOfSelection = Math.floor(nSelectionIndex / nMatchesPerLine); 133 var nFirstDisplayedLine = nLineOfSelection>0 ? nLineOfSelection-1 : 0; 134 var nLastDisplayedLine = nLineOfSelection<nLineCount-1 ? nLineOfSelection+1 : nLineCount-1; 135 136 for (nLineIndex=nFirstDisplayedLine; nLineIndex<=nLastDisplayedLine; ++nLineIndex) 137 { 138 var nLineStartIndex = nLineIndex * nMatchesPerLine; 139 var nLineEndIndex = nLineStartIndex + nMatchesPerLine - 1; 140 if (nLineEndIndex >= aMatches.length) 141 nLineEndIndex = aMatches.length-1; 142 143 sText += "<tr>" 144 for (nIndex=nLineStartIndex; nIndex<=nLineEndIndex; ++nIndex) 145 { 146 var aMatch = aMatches[nIndex]; 147 var sTypeName = aMatch[0]; 148 var sMatch = ""; 149 for (nPartIndex=1; nPartIndex<aMatch.length; ++nPartIndex) 150 { 151 if ((nPartIndex%2)==0) 152 sMatch += "<span class=\"match-highlight\">"+aMatch[nPartIndex]+"</span>"; 153 else 154 sMatch += aMatch[nPartIndex]; 155 } 156 sText += "<td>" 157 if (nIndex == nSelectionIndex) 158 { 159 sText += " <span class=\"typelink current-match\">" + sMatch + "</span>"; 160 } 161 else 162 { 163 sText += " " + GetTypeLink(sMatch, sTypeName, -1); 164 } 165 sText += "</td>" 166 } 167 168 sText += "</tr>"; 169 } 170 if (nFirstDisplayedLine > 0) 171 sText = "<tr><td>["+(nFirstDisplayedLine*nMatchesPerLine)+" matches] ...</td><tr>" + sText; 172 if (nLastDisplayedLine+1 < nLineCount) 173 sText += "<tr><td>... ["+((nLineCount-nLastDisplayedLine-1)*nMatchesPerLine)+" matches]</td></tr>"; 174 175 document.getElementById('matches').innerHTML = "<table>"+sText+"</table>"; 176 if (aMatches.length == 0) 177 { 178 document.getElementById('match-count').innerHTML = "no match:"; 179 } 180 else 181 { 182 if (aMatches.length == 1) 183 document.getElementById('match-count').innerHTML = "single match:"; 184 else 185 document.getElementById('match-count').innerHTML = aMatches.length+" matches:"; 186 187 ShowType(aMatches[nSelectionIndex][0]); 188 } 189} 190 191 192 193 194function GetTopLevelNodeForTypeName(sTypeName) 195{ 196 if (sTypeName in Data) 197 return Data[sTypeName]; 198 else 199 alert(sTypeName +" is not a known complex type, simple type, or group"); 200} 201 202 203 204 205/** Show the specified type. 206 * When nHistoryIndex is not -1 then the history is shortened to that (before that) index. 207 */ 208function ShowType (sTypeName, nHistoryIndex) 209{ 210 if (nHistoryIndex == -1) 211 { 212 if (CurrentTypeName != "") 213 { 214 TypeHistory.push(CurrentTypeName); 215 ShowHistory(); 216 } 217 } 218 else 219 { 220 TypeHistory = TypeHistory.slice(0,nHistoryIndex); 221 ShowHistory(); 222 } 223 CurrentTypeName = sTypeName; 224 225 var aElement = document.getElementById('result'); 226 227 // Remove the old content. 228 while(aElement.childNodes.length > 0) 229 aElement.removeChild(aElement.firstChild); 230 231 // Create the new content. 232 var list = CreateDomTreeForType(GetTopLevelNodeForTypeName(sTypeName), "ul"); 233 234 // Show the new content. 235 aElement.appendChild(list); 236} 237 238 239 240 241/** Create a dom sub tree for the given OOXML type that is ready for insertion into the global DOM tree. 242 */ 243function CreateDomTreeForType (aNode, sType) 244{ 245 var aEntry = document.createElement(sType); 246 247 if (typeof aNode==='undefined') 248 { 249 aEntry.innerHTML = "undefined node"; 250 } 251 else if (typeof aNode.type==='undefined') 252 { 253 aEntry.innerHTML = "unknown type"; 254 } 255 else 256 { 257 switch(aNode.type) 258 { 259 case "attribute": 260 aEntry.innerHTML = CreateValueTable([ 261 "attribute", 262 "type:", GetTypeLink(aNode["value-type"], aNode["value-type"], -1), 263 "use:", aNode.use]); 264 break; 265 266 case "attribute-reference": 267 aEntry.innerHTML = CreateReference(aNode["referenced-attribute"]); 268 break; 269 270 case "builtin": 271 aEntry.innerHTML = CreateValueTable( 272 ["builtin", 273 "name:", aNode['builtin-type'] 274 ]); 275 break; 276 277 case "complex-type": 278 aEntry.innerHTML = aNode.type + " " + aNode.name; 279 break; 280 281 case "complex-type-reference": 282 aEntry.innerHTML = CreateReference(aNode["referenced-complex-type"]); 283 break; 284 285 case "group": 286 aEntry.innerHTML = aNode.type + " " + aNode.name; 287 break; 288 289 case "group-reference": 290 aEntry.innerHTML = CreateReference("group", aNode["referenced-group"]); 291 break; 292 293 case "element": 294 aEntry.innerHTML = "element <b>" + aNode["tag"] + "</b> -> " + GetTypeLink(aNode["result-type"], aNode["result-type"], -1); 295 break; 296 297 case "occurrence": 298 aEntry.innerHTML = aNode.minimum +" -> " + aNode.maximum; 299 break; 300 301 case "restriction": 302 aEntry.innerHTML = CreateRestrictionRepresentation(aNode); 303 break; 304 305 case "sequence": 306 aEntry.innerHTML = "sequence"; 307 break; 308 309 case "simple-type": 310 aEntry.innerHTML = aNode.type + " " + aNode.name; 311 break; 312 313 case "simple-type-reference": 314 aEntry.innerHTML = CreateReference("simple-type", aNode["referenced-simple-type"]); 315 break; 316 317 default: 318 aEntry.innerHTML = aNode.type; 319 break; 320 } 321 322 // Add nodes for attributes. 323 var aAttributes= aNode["attributes"]; 324 if ( ! (typeof aAttributes==='undefined' || aAttributes.length == 0)) 325 { 326 var aAttributeList = document.createElement("ul"); 327 aEntry.appendChild(aAttributeList); 328 329 for (var nIndex=0; nIndex<aAttributes.length; ++nIndex) 330 { 331 var aAttributeEntry = CreateDomTreeForType(aAttributes[nIndex], "li"); 332 aAttributeList.appendChild(aAttributeEntry); 333 } 334 } 335 336 // Add nodes for children. 337 var aChildren = aNode["children"]; 338 if ( ! (typeof aChildren==='undefined' || aChildren.length == 0)) 339 { 340 var aChildrenList = document.createElement("ul"); 341 aEntry.appendChild(aChildrenList); 342 343 for (var nIndex=0; nIndex<aChildren.length; ++nIndex) 344 { 345 var aChildrenEntry = CreateDomTreeForType(aChildren[nIndex], "li"); 346 aChildrenList.appendChild(aChildrenEntry); 347 } 348 } 349 } 350 return aEntry; 351} 352 353 354 355 356function GetTypeLink (sText, sTarget, nIndex) 357{ 358 return "<span class=\"typelink\" id=\""+sTarget+"\" onclick=\"ShowType('"+sTarget+"',"+nIndex+")\">"+sText+"</span>"; 359} 360 361 362 363 364function CreateValueTable (aValues) 365{ 366 var sResult = "<table class=\"value-table\"><tr><td>"+aValues[0]+"</td><td>"+aValues[1]+"</td><td>"+aValues[2]+"</td></tr>"; 367 for (nIndex=3; nIndex<aValues.length; nIndex+=2) 368 { 369 sResult += "<tr><td></td><td>"+aValues[nIndex]+"</td><td>"+aValues[nIndex+1]+"</td></tr>"; 370 } 371 sResult += "</table>"; 372 return sResult; 373} 374 375 376 377 378function CreateReference (sWhat, sTypeName) 379{ 380 return "reference to "+sWhat+" "+GetTypeLink(sTypeName, sTypeName, -1) + " " 381 +CreateButton( 382 sTypeName, 383 "show", 384 "ToggleTypeReferenceExpansion('"+sTypeName+"')") 385 +"<br><span id=\"expansion-"+sTypeName+"\"></span>"; 386} 387 388 389 390 391function CreateButton (sId, sText, sExpandAction) 392{ 393 return "<span class=\"button\" id=\"button-"+sId+"\" onClick=\""+sExpandAction+"\">"+sText+"</span>"; 394} 395 396 397 398 399function ToggleTypeReferenceExpansion(sTypeName) 400{ 401 var aButton = document.getElementById("button-"+sTypeName); 402 var aExpansion = document.getElementById("expansion-"+sTypeName); 403 if (aButton.innerHTML == "show") 404 { 405 aExpansion.appendChild(CreateDomTreeForType(Data[sTypeName], "span")); 406 aButton.innerHTML = "hide"; 407 } 408 else 409 { 410 aExpansion.innerHTML = ""; 411 aButton.innerHTML = "show"; 412 } 413} 414 415 416 417 418function ShowHistory () 419{ 420 var aElement = document.getElementById('history'); 421 var sContent = "History:"; 422 for (nIndex=0; nIndex<TypeHistory.length; ++nIndex) 423 { 424 if (nIndex == 0) 425 sContent += " "; 426 else 427 sContent += ", "; 428 sContent += GetTypeLink(TypeHistory[nIndex], TypeHistory[nIndex], nIndex); 429 } 430 aElement.innerHTML = sContent; 431} 432 433 434 435 436function CreateRestrictionRepresentation (aNode) 437{ 438 var aTableData = ["restriction", "based on:", GetTypeLink(aNode['base-type'], aNode['base-type'], -1)]; 439 AddValue(aNode, "enumeration", aTableData); 440 AddValue(aNode, "pattern", aTableData); 441 AddValue(aNode, "length", aTableData); 442 return CreateValueTable(aTableData); 443} 444 445 446 447function AddValue (aMap, sKey, aTableData) 448{ 449 if (sKey in aMap) 450 { 451 aTableData.push(sKey+":"); 452 aTableData.push(aMap[sKey]); 453 } 454} 455