~todd-deshane/openstack-manuals/working

« back to all changes in this revision

Viewing changes to doc/source/docbkx/openstack-compute-api-1.0/js/shjs/sh_main.js

  • Committer: Anne Gentle
  • Date: 2011-04-14 18:12:25 UTC
  • Revision ID: anne@openstack.org-20110414181225-owwk0h4saf7w9hhw
Added output files

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
SHJS - Syntax Highlighting in JavaScript
 
3
Copyright (C) 2007, 2008 gnombat@users.sourceforge.net
 
4
License: http://shjs.sourceforge.net/doc/gplv3.html
 
5
*/
 
6
 
 
7
if (! this.sh_languages) {
 
8
  this.sh_languages = {};
 
9
}
 
10
var sh_requests = {};
 
11
 
 
12
function sh_isEmailAddress(url) {
 
13
  if (/^mailto:/.test(url)) {
 
14
    return false;
 
15
  }
 
16
  return url.indexOf('@') !== -1;
 
17
}
 
18
 
 
19
function sh_setHref(tags, numTags, inputString) {
 
20
  var url = inputString.substring(tags[numTags - 2].pos, tags[numTags - 1].pos);
 
21
  if (url.length >= 2 && url.charAt(0) === '<' && url.charAt(url.length - 1) === '>') {
 
22
    url = url.substr(1, url.length - 2);
 
23
  }
 
24
  if (sh_isEmailAddress(url)) {
 
25
    url = 'mailto:' + url;
 
26
  }
 
27
  tags[numTags - 2].node.href = url;
 
28
}
 
29
 
 
30
/*
 
31
Konqueror has a bug where the regular expression /$/g will not match at the end
 
32
of a line more than once:
 
33
 
 
34
  var regex = /$/g;
 
35
  var match;
 
36
 
 
37
  var line = '1234567890';
 
38
  regex.lastIndex = 10;
 
39
  match = regex.exec(line);
 
40
 
 
41
  var line2 = 'abcde';
 
42
  regex.lastIndex = 5;
 
43
  match = regex.exec(line2);  // fails
 
44
*/
 
45
function sh_konquerorExec(s) {
 
46
  var result = [''];
 
47
  result.index = s.length;
 
48
  result.input = s;
 
49
  return result;
 
50
}
 
51
 
 
52
/**
 
53
Highlights all elements containing source code in a text string.  The return
 
54
value is an array of objects, each representing an HTML start or end tag.  Each
 
55
object has a property named pos, which is an integer representing the text
 
56
offset of the tag. Every start tag also has a property named node, which is the
 
57
DOM element started by the tag. End tags do not have this property.
 
58
@param  inputString  a text string
 
59
@param  language  a language definition object
 
60
@return  an array of tag objects
 
61
*/
 
62
function sh_highlightString(inputString, language) {
 
63
  if (/Konqueror/.test(navigator.userAgent)) {
 
64
    if (! language.konquered) {
 
65
      for (var s = 0; s < language.length; s++) {
 
66
        for (var p = 0; p < language[s].length; p++) {
 
67
          var r = language[s][p][0];
 
68
          if (r.source === '$') {
 
69
            r.exec = sh_konquerorExec;
 
70
          }
 
71
        }
 
72
      }
 
73
      language.konquered = true;
 
74
    }
 
75
  }
 
76
 
 
77
  var a = document.createElement('a');
 
78
  var span = document.createElement('span');
 
79
 
 
80
  // the result
 
81
  var tags = [];
 
82
  var numTags = 0;
 
83
 
 
84
  // each element is a pattern object from language
 
85
  var patternStack = [];
 
86
 
 
87
  // the current position within inputString
 
88
  var pos = 0;
 
89
 
 
90
  // the name of the current style, or null if there is no current style
 
91
  var currentStyle = null;
 
92
 
 
93
  var output = function(s, style) {
 
94
    var length = s.length;
 
95
    // this is more than just an optimization - we don't want to output empty <span></span> elements
 
96
    if (length === 0) {
 
97
      return;
 
98
    }
 
99
    if (! style) {
 
100
      var stackLength = patternStack.length;
 
101
      if (stackLength !== 0) {
 
102
        var pattern = patternStack[stackLength - 1];
 
103
        // check whether this is a state or an environment
 
104
        if (! pattern[3]) {
 
105
          // it's not a state - it's an environment; use the style for this environment
 
106
          style = pattern[1];
 
107
        }
 
108
      }
 
109
    }
 
110
    if (currentStyle !== style) {
 
111
      if (currentStyle) {
 
112
        tags[numTags++] = {pos: pos};
 
113
        if (currentStyle === 'sh_url') {
 
114
          sh_setHref(tags, numTags, inputString);
 
115
        }
 
116
      }
 
117
      if (style) {
 
118
        var clone;
 
119
        if (style === 'sh_url') {
 
120
          clone = a.cloneNode(false);
 
121
        }
 
122
        else {
 
123
          clone = span.cloneNode(false);
 
124
        }
 
125
        clone.className = style;
 
126
        tags[numTags++] = {node: clone, pos: pos};
 
127
      }
 
128
    }
 
129
    pos += length;
 
130
    currentStyle = style;
 
131
  };
 
132
 
 
133
  var endOfLinePattern = /\r\n|\r|\n/g;
 
134
  endOfLinePattern.lastIndex = 0;
 
135
  var inputStringLength = inputString.length;
 
136
  while (pos < inputStringLength) {
 
137
    var start = pos;
 
138
    var end;
 
139
    var startOfNextLine;
 
140
    var endOfLineMatch = endOfLinePattern.exec(inputString);
 
141
    if (endOfLineMatch === null) {
 
142
      end = inputStringLength;
 
143
      startOfNextLine = inputStringLength;
 
144
    }
 
145
    else {
 
146
      end = endOfLineMatch.index;
 
147
      startOfNextLine = endOfLinePattern.lastIndex;
 
148
    }
 
149
 
 
150
    var line = inputString.substring(start, end);
 
151
 
 
152
    var matchCache = [];
 
153
    for (;;) {
 
154
      var posWithinLine = pos - start;
 
155
 
 
156
      var stateIndex;
 
157
      var stackLength = patternStack.length;
 
158
      if (stackLength === 0) {
 
159
        stateIndex = 0;
 
160
      }
 
161
      else {
 
162
        // get the next state
 
163
        stateIndex = patternStack[stackLength - 1][2];
 
164
      }
 
165
 
 
166
      var state = language[stateIndex];
 
167
      var numPatterns = state.length;
 
168
      var mc = matchCache[stateIndex];
 
169
      if (! mc) {
 
170
        mc = matchCache[stateIndex] = [];
 
171
      }
 
172
      var bestMatch = null;
 
173
      var bestPatternIndex = -1;
 
174
      for (var i = 0; i < numPatterns; i++) {
 
175
        var match;
 
176
        if (i < mc.length && (mc[i] === null || posWithinLine <= mc[i].index)) {
 
177
          match = mc[i];
 
178
        }
 
179
        else {
 
180
          var regex = state[i][0];
 
181
          regex.lastIndex = posWithinLine;
 
182
          match = regex.exec(line);
 
183
          mc[i] = match;
 
184
        }
 
185
        if (match !== null && (bestMatch === null || match.index < bestMatch.index)) {
 
186
          bestMatch = match;
 
187
          bestPatternIndex = i;
 
188
          if (match.index === posWithinLine) {
 
189
            break;
 
190
          }
 
191
        }
 
192
      }
 
193
 
 
194
      if (bestMatch === null) {
 
195
        output(line.substring(posWithinLine), null);
 
196
        break;
 
197
      }
 
198
      else {
 
199
        // got a match
 
200
        if (bestMatch.index > posWithinLine) {
 
201
          output(line.substring(posWithinLine, bestMatch.index), null);
 
202
        }
 
203
 
 
204
        var pattern = state[bestPatternIndex];
 
205
 
 
206
        var newStyle = pattern[1];
 
207
        var matchedString;
 
208
        if (newStyle instanceof Array) {
 
209
          for (var subexpression = 0; subexpression < newStyle.length; subexpression++) {
 
210
            matchedString = bestMatch[subexpression + 1];
 
211
            output(matchedString, newStyle[subexpression]);
 
212
          }
 
213
        }
 
214
        else {
 
215
          matchedString = bestMatch[0];
 
216
          output(matchedString, newStyle);
 
217
        }
 
218
 
 
219
        switch (pattern[2]) {
 
220
        case -1:
 
221
          // do nothing
 
222
          break;
 
223
        case -2:
 
224
          // exit
 
225
          patternStack.pop();
 
226
          break;
 
227
        case -3:
 
228
          // exitall
 
229
          patternStack.length = 0;
 
230
          break;
 
231
        default:
 
232
          // this was the start of a delimited pattern or a state/environment
 
233
          patternStack.push(pattern);
 
234
          break;
 
235
        }
 
236
      }
 
237
    }
 
238
 
 
239
    // end of the line
 
240
    if (currentStyle) {
 
241
      tags[numTags++] = {pos: pos};
 
242
      if (currentStyle === 'sh_url') {
 
243
        sh_setHref(tags, numTags, inputString);
 
244
      }
 
245
      currentStyle = null;
 
246
    }
 
247
    pos = startOfNextLine;
 
248
  }
 
249
 
 
250
  return tags;
 
251
}
 
252
 
 
253
////////////////////////////////////////////////////////////////////////////////
 
254
// DOM-dependent functions
 
255
 
 
256
function sh_getClasses(element) {
 
257
  var result = [];
 
258
  var htmlClass = element.className;
 
259
  if (htmlClass && htmlClass.length > 0) {
 
260
    var htmlClasses = htmlClass.split(' ');
 
261
    for (var i = 0; i < htmlClasses.length; i++) {
 
262
      if (htmlClasses[i].length > 0) {
 
263
        result.push(htmlClasses[i]);
 
264
      }
 
265
    }
 
266
  }
 
267
  return result;
 
268
}
 
269
 
 
270
function sh_addClass(element, name) {
 
271
  var htmlClasses = sh_getClasses(element);
 
272
  for (var i = 0; i < htmlClasses.length; i++) {
 
273
    if (name.toLowerCase() === htmlClasses[i].toLowerCase()) {
 
274
      return;
 
275
    }
 
276
  }
 
277
  htmlClasses.push(name);
 
278
  element.className = htmlClasses.join(' ');
 
279
}
 
280
 
 
281
/**
 
282
Extracts the tags from an HTML DOM NodeList.
 
283
@param  nodeList  a DOM NodeList
 
284
@param  result  an object with text, tags and pos properties
 
285
*/
 
286
function sh_extractTagsFromNodeList(nodeList, result) {
 
287
  var length = nodeList.length;
 
288
  for (var i = 0; i < length; i++) {
 
289
    var node = nodeList.item(i);
 
290
    switch (node.nodeType) {
 
291
    case 1:
 
292
      if (node.nodeName.toLowerCase() === 'br') {
 
293
        var terminator;
 
294
        if (/MSIE/.test(navigator.userAgent)) {
 
295
          terminator = '\r';
 
296
        }
 
297
        else {
 
298
          terminator = '\n';
 
299
        }
 
300
        result.text.push(terminator);
 
301
        result.pos++;
 
302
      }
 
303
      else {
 
304
        result.tags.push({node: node.cloneNode(false), pos: result.pos});
 
305
        sh_extractTagsFromNodeList(node.childNodes, result);
 
306
        result.tags.push({pos: result.pos});
 
307
      }
 
308
      break;
 
309
    case 3:
 
310
    case 4:
 
311
      result.text.push(node.data);
 
312
      result.pos += node.length;
 
313
      break;
 
314
    }
 
315
  }
 
316
}
 
317
 
 
318
/**
 
319
Extracts the tags from the text of an HTML element. The extracted tags will be
 
320
returned as an array of tag objects. See sh_highlightString for the format of
 
321
the tag objects.
 
322
@param  element  a DOM element
 
323
@param  tags  an empty array; the extracted tag objects will be returned in it
 
324
@return  the text of the element
 
325
@see  sh_highlightString
 
326
*/
 
327
function sh_extractTags(element, tags) {
 
328
  var result = {};
 
329
  result.text = [];
 
330
  result.tags = tags;
 
331
  result.pos = 0;
 
332
  sh_extractTagsFromNodeList(element.childNodes, result);
 
333
  return result.text.join('');
 
334
}
 
335
 
 
336
/**
 
337
Merges the original tags from an element with the tags produced by highlighting.
 
338
@param  originalTags  an array containing the original tags
 
339
@param  highlightTags  an array containing the highlighting tags - these must not overlap
 
340
@result  an array containing the merged tags
 
341
*/
 
342
function sh_mergeTags(originalTags, highlightTags) {
 
343
  var numOriginalTags = originalTags.length;
 
344
  if (numOriginalTags === 0) {
 
345
    return highlightTags;
 
346
  }
 
347
 
 
348
  var numHighlightTags = highlightTags.length;
 
349
  if (numHighlightTags === 0) {
 
350
    return originalTags;
 
351
  }
 
352
 
 
353
  var result = [];
 
354
  var originalIndex = 0;
 
355
  var highlightIndex = 0;
 
356
 
 
357
  while (originalIndex < numOriginalTags && highlightIndex < numHighlightTags) {
 
358
    var originalTag = originalTags[originalIndex];
 
359
    var highlightTag = highlightTags[highlightIndex];
 
360
 
 
361
    if (originalTag.pos <= highlightTag.pos) {
 
362
      result.push(originalTag);
 
363
      originalIndex++;
 
364
    }
 
365
    else {
 
366
      result.push(highlightTag);
 
367
      if (highlightTags[highlightIndex + 1].pos <= originalTag.pos) {
 
368
        highlightIndex++;
 
369
        result.push(highlightTags[highlightIndex]);
 
370
        highlightIndex++;
 
371
      }
 
372
      else {
 
373
        // new end tag
 
374
        result.push({pos: originalTag.pos});
 
375
 
 
376
        // new start tag
 
377
        highlightTags[highlightIndex] = {node: highlightTag.node.cloneNode(false), pos: originalTag.pos};
 
378
      }
 
379
    }
 
380
  }
 
381
 
 
382
  while (originalIndex < numOriginalTags) {
 
383
    result.push(originalTags[originalIndex]);
 
384
    originalIndex++;
 
385
  }
 
386
 
 
387
  while (highlightIndex < numHighlightTags) {
 
388
    result.push(highlightTags[highlightIndex]);
 
389
    highlightIndex++;
 
390
  }
 
391
 
 
392
  return result;
 
393
}
 
394
 
 
395
/**
 
396
Inserts tags into text.
 
397
@param  tags  an array of tag objects
 
398
@param  text  a string representing the text
 
399
@return  a DOM DocumentFragment representing the resulting HTML
 
400
*/
 
401
function sh_insertTags(tags, text) {
 
402
  var doc = document;
 
403
 
 
404
  var result = document.createDocumentFragment();
 
405
  var tagIndex = 0;
 
406
  var numTags = tags.length;
 
407
  var textPos = 0;
 
408
  var textLength = text.length;
 
409
  var currentNode = result;
 
410
 
 
411
  // output one tag or text node every iteration
 
412
  while (textPos < textLength || tagIndex < numTags) {
 
413
    var tag;
 
414
    var tagPos;
 
415
    if (tagIndex < numTags) {
 
416
      tag = tags[tagIndex];
 
417
      tagPos = tag.pos;
 
418
    }
 
419
    else {
 
420
      tagPos = textLength;
 
421
    }
 
422
 
 
423
    if (tagPos <= textPos) {
 
424
      // output the tag
 
425
      if (tag.node) {
 
426
        // start tag
 
427
        var newNode = tag.node;
 
428
        currentNode.appendChild(newNode);
 
429
        currentNode = newNode;
 
430
      }
 
431
      else {
 
432
        // end tag
 
433
        currentNode = currentNode.parentNode;
 
434
      }
 
435
      tagIndex++;
 
436
    }
 
437
    else {
 
438
      // output text
 
439
      currentNode.appendChild(doc.createTextNode(text.substring(textPos, tagPos)));
 
440
      textPos = tagPos;
 
441
    }
 
442
  }
 
443
 
 
444
  return result;
 
445
}
 
446
 
 
447
/**
 
448
Highlights an element containing source code.  Upon completion of this function,
 
449
the element will have been placed in the "sh_sourceCode" class.
 
450
@param  element  a DOM <pre> element containing the source code to be highlighted
 
451
@param  language  a language definition object
 
452
*/
 
453
function sh_highlightElement(element, language) {
 
454
  sh_addClass(element, 'sh_sourceCode');
 
455
  var originalTags = [];
 
456
  var inputString = sh_extractTags(element, originalTags);
 
457
  var highlightTags = sh_highlightString(inputString, language);
 
458
  var tags = sh_mergeTags(originalTags, highlightTags);
 
459
  var documentFragment = sh_insertTags(tags, inputString);
 
460
  while (element.hasChildNodes()) {
 
461
    element.removeChild(element.firstChild);
 
462
  }
 
463
  element.appendChild(documentFragment);
 
464
}
 
465
 
 
466
function sh_getXMLHttpRequest() {
 
467
  if (window.ActiveXObject) {
 
468
    return new ActiveXObject('Msxml2.XMLHTTP');
 
469
  }
 
470
  else if (window.XMLHttpRequest) {
 
471
    return new XMLHttpRequest();
 
472
  }
 
473
  throw 'No XMLHttpRequest implementation available';
 
474
}
 
475
 
 
476
function sh_load(language, element, prefix, suffix) {
 
477
  if (language in sh_requests) {
 
478
    sh_requests[language].push(element);
 
479
    return;
 
480
  }
 
481
  sh_requests[language] = [element];
 
482
  var request = sh_getXMLHttpRequest();
 
483
  var url = prefix + 'sh_' + language + suffix;
 
484
  request.open('GET', url, true);
 
485
  request.onreadystatechange = function () {
 
486
    if (request.readyState === 4) {
 
487
      try {
 
488
        if (! request.status || request.status === 200) {
 
489
          eval(request.responseText);
 
490
          var elements = sh_requests[language];
 
491
          for (var i = 0; i < elements.length; i++) {
 
492
            sh_highlightElement(elements[i], sh_languages[language]);
 
493
          }
 
494
        }
 
495
        else {
 
496
          throw 'HTTP error: status ' + request.status;
 
497
        }
 
498
      }
 
499
      finally {
 
500
        request = null;
 
501
      }
 
502
    }
 
503
  };
 
504
  request.send(null);
 
505
}
 
506
 
 
507
/**
 
508
Highlights all elements containing source code on the current page. Elements
 
509
containing source code must be "pre" elements with a "class" attribute of
 
510
"sh_LANGUAGE", where LANGUAGE is a valid language identifier; e.g., "sh_java"
 
511
identifies the element as containing "java" language source code.
 
512
*/
 
513
function sh_highlightDocument(prefix, suffix) {
 
514
  var nodeList = document.getElementsByTagName('pre');
 
515
  for (var i = 0; i < nodeList.length; i++) {
 
516
    var element = nodeList.item(i);
 
517
    var htmlClasses = sh_getClasses(element);
 
518
    for (var j = 0; j < htmlClasses.length; j++) {
 
519
      var htmlClass = htmlClasses[j].toLowerCase();
 
520
      if (htmlClass === 'sh_sourcecode') {
 
521
        continue;
 
522
      }
 
523
      if (htmlClass.substr(0, 3) === 'sh_') {
 
524
        var language = htmlClass.substring(3);
 
525
        if (language in sh_languages) {
 
526
          sh_highlightElement(element, sh_languages[language]);
 
527
        }
 
528
        else if (typeof(prefix) === 'string' && typeof(suffix) === 'string') {
 
529
          sh_load(language, element, prefix, suffix);
 
530
        }
 
531
        else {
 
532
          throw 'Found <pre> element with class="' + htmlClass + '", but no such language exists';
 
533
        }
 
534
        break;
 
535
      }
 
536
    }
 
537
  }
 
538
}