Subversion Repositories PHPX

Rev

Rev 19 | Rev 21 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 19 Rev 20
1
<?php
1
<?php
2
2
3
require_once 'global.inc';
3
require_once 'global.inc';
4
4
5
define('FEATURES_ENCODING',
-
 
6
  mb_detect_encoding(file_get_contents($_SERVER['SCRIPT_FILENAME'])));
5
$encoding = mb_detect_encoding(file_get_contents($_SERVER['SCRIPT_FILENAME']));
-
 
6
if ($encoding === 'ASCII') $encoding = 'iso-8859-1';
-
 
7
define('FEATURES_ENCODING', $encoding);
7
8
8
/**
9
/**
9
 * A list of language features with URNs definitions
10
 * A list of language features with URNs definitions
10
 * for reference links.
11
 * for reference links.
11
 */
12
 */
12
class FeatureList
13
class FeatureList
13
{
14
{
14
  public $versions = array();
15
  public $versions = array();
15
 
16
 
16
  /**
17
  /**
17
   * Versions of implementations that are considered safe.
18
   * Versions of implementations that are considered safe.
18
   * A feature is considered safe if it does not require
19
   * A feature is considered safe if it does not require
19
   * an implementation version above these versions.
20
   * an implementation version above these versions.
20
   *
21
   *
21
   * @var Array[string=>string]
22
   * @var Array[string=>string]
22
   */
23
   */
23
  public $safeVersions = array();
24
  public $safeVersions = array();
24
 
25
 
25
  /**
26
  /**
26
   * URNs that can be used for reference links.
27
   * URNs that can be used for reference links.
27
   *
28
   *
28
   * @var Array[string=>string]
29
   * @var Array[string=>string]
29
   */
30
   */
30
  protected $urns = array();
31
  protected $urns = array();
31
 
32
 
32
  /**
33
  /**
33
   * <code>true</code> generates form controls for submitting test case
34
   * <code>true</code> generates form controls for submitting test case
34
   * results
35
   * results
35
   *
36
   *
36
   * @var bool
37
   * @var bool
37
   */
38
   */
38
  protected $testcase = false;
39
  protected $testcase = false;
39
 
40
 
40
  /**
41
  /**
41
   * The list of language features
42
   * The list of language features
42
   *
43
   *
43
   * @var array[Features]
44
   * @var array[Features]
44
   */
45
   */
45
  protected $items = array();
46
  protected $items = array();
46
 
47
 
47
  /**
48
  /**
48
   * Determines the number of printed items the table headings should be repeated
49
   * Determines the number of printed items the table headings should be repeated
49
   *
50
   *
50
   * @var int
51
   * @var int
51
   */
52
   */
52
  protected $headerRepeat = 25;
53
  protected $headerRepeat = 25;
53
54
54
  /**
55
  /**
55
   * Initializes the FeatureList object
56
   * Initializes the FeatureList object
56
   *
57
   *
57
   * @param array|Object $a
58
   * @param array|Object $a
58
   * @return FeatureList
59
   * @return FeatureList
59
   */
60
   */
60
  public function __construct($a)
61
  public function __construct($a)
61
  {
62
  {
62
    $aVars = get_class_vars(get_class($this));
63
    $aVars = get_class_vars(get_class($this));
63
   
64
   
64
65
65
    foreach ($aVars as $key => $value)
66
    foreach ($aVars as $key => $value)
66
    {
67
    {
67
      if (isset($a[$key]))
68
      if (isset($a[$key]))
68
      {
69
      {
69
        $this->$key = $a[$key];
70
        $this->$key = $a[$key];
70
      }
71
      }
71
    }
72
    }
72
73
73
    /* Inform items of ourself so that URNs can be used for links */
74
    /* Inform items of ourself so that URNs can be used for links */
74
    if (is_array($this->items))
75
    if (is_array($this->items))
75
    {
76
    {
76
      foreach ($this->items as &$item)
77
      foreach ($this->items as &$item)
77
      {
78
      {
78
        $item->setList($this);
79
        $item->setList($this);
79
      }
80
      }
80
    }
81
    }
81
   
82
   
82
    /* resolve URN references that are URNs */
83
    /* resolve URN references that are URNs */
83
    if (is_array($this->urns))
84
    if (is_array($this->urns))
84
    {
85
    {
85
      foreach ($this->urns as &$urn)
86
      foreach ($this->urns as &$urn)
86
      {
87
      {
87
        if (($url = $this->resolveURN($urn)))
88
        if (($url = $this->resolveURN($urn)))
88
        {
89
        {
89
          $urn = $url;
90
          $urn = $url;
90
        }
91
        }
91
      }
92
      }
92
    }
93
    }
93
  }
94
  }
94
 
95
 
95
  /*
96
  /*
96
   * Protected properties may be read, but not written
97
   * Protected properties may be read, but not written
97
   */
98
   */
98
  public function __get($property)
99
  public function __get($property)
99
  {
100
  {
100
    if (property_exists(get_class($this), $property))
101
    if (property_exists(get_class($this), $property))
101
    {
102
    {
102
      return $this->$property;
103
      return $this->$property;
103
    }
104
    }
104
  }
105
  }
105
 
106
 
106
  public function printHeaders()
107
  public function printHeaders()
107
  {
108
  {
108
    foreach ($this->versions as $key => $ver)
109
    foreach ($this->versions as $key => $ver)
109
    {
110
    {
110
      if ($key || $this->testcase)
111
      if ($key || $this->testcase)
111
      {
112
      {
112
?>
113
?>
113
          <th><?php echo $ver; ?></th>
114
          <th><?php echo $ver; ?></th>
114
<?php
115
<?php
115
      }
116
      }
116
    }
117
    }
117
  }
118
  }
118
   
119
   
119
  /**
120
  /**
120
   * Prints the list of features.
121
   * Prints the list of features.
121
   *
122
   *
122
   * @see Feature::printMe()
123
   * @see Feature::printMe()
123
   */
124
   */
124
  public function printItems()
125
  public function printItems()
125
  {
126
  {
126
    $counter = 0;
127
    $counter = 0;
127
    $headerRepeat = $this->headerRepeat;
128
    $headerRepeat = $this->headerRepeat;
128
    $repeatHeaders = ($headerRepeat > 1);
129
    $repeatHeaders = ($headerRepeat > 1);
129
   
130
   
130
    foreach ($this->items as $feature)
131
    foreach ($this->items as $feature)
131
    {
132
    {
132
      if ($feature instanceof Feature)
133
      if ($feature instanceof Feature)
133
      {
134
      {
134
        /*
135
        /*
135
         * TODO: Disabled header repetition until footnote ref. name/ID
136
         * TODO: Disabled header repetition until footnote ref. name/ID
136
         * problem has been solved
137
         * problem has been solved
137
         */
138
         */
138
//        if ($repeatHeaders
139
//        if ($repeatHeaders
139
//            && $counter > 1
140
//            && $counter > 1
140
//            && $counter % $headerRepeat === 0)
141
//            && $counter % $headerRepeat === 0)
141
//        {
142
//        {
142
//          echo <<<HTML
143
//          echo <<<HTML
143
//        <tr class="header">
144
//        <tr class="header">
144
//          <th>Feature</th>
145
//          <th>Feature</th>
145
//          {$this->printHeaders()}
146
//          {$this->printHeaders()}
146
//        </tr>
147
//        </tr>
147
//HTML;
148
//HTML;
148
//        }
149
//        }
149
       
150
       
150
        $feature->printMe();
151
        $feature->printMe();
151
       
152
       
152
        $counter++;
153
        $counter++;
153
      }
154
      }
154
    }
155
    }
155
  }
156
  }
156
 
157
 
157
  /**
158
  /**
158
   * Resolves a URN according to the value of the
159
   * Resolves a URN according to the value of the
159
   * object's <code>$urn</code> property.
160
   * object's <code>$urn</code> property.
160
   *
161
   *
161
   * @param string $urn
162
   * @param string $urn
162
   *   URN to be resolved
163
   *   URN to be resolved
163
   * @return string|boolean
164
   * @return string|boolean
164
   *   The resolved URN if successful,
165
   *   The resolved URN if successful,
165
   *   <code>false</code> otherwise.
166
   *   <code>false</code> otherwise.
166
   */
167
   */
167
  public function resolveURN($urn)
168
  public function resolveURN($urn)
168
  {
169
  {
169
    if (is_array($this->urns))
170
    if (is_array($this->urns))
170
    {
171
    {
171
      $reURN = '|^(.+?):(?!//)|';
172
      $reURN = '|^(.+?):(?!//)|';
172
     
173
     
173
      if (preg_match($reURN, $urn, $m) && isset($this->urns[$m[1]]))
174
      if (preg_match($reURN, $urn, $m) && isset($this->urns[$m[1]]))
174
      {
175
      {
175
        return preg_replace($reURN, $this->urns[$m[1]], $urn);
176
        return preg_replace($reURN, $this->urns[$m[1]], $urn);
176
      }
177
      }
177
    }
178
    }
178
179
179
    return $urn;
180
    return $urn;
180
  }
181
  }
181
}
182
}
182
183
183
/**
184
/**
184
 * A language feature.
185
 * A language feature.
185
 */
186
 */
186
class Feature
187
class Feature
187
{
188
{
188
  /**
189
  /**
189
   * Fragment identifiers to be defined for quickly accessing
190
   * Fragment identifiers to be defined for quickly accessing
190
   * the feature description.
191
   * the feature description.
191
   *
192
   *
192
   * @var Array[String]
193
   * @var Array[String]
193
   */
194
   */
194
  protected $anchors = array();
195
  protected $anchors = array();
195
 
196
 
196
  /**
197
  /**
197
   * Value of the explanatory <code>title</code> attribute for the feature.
198
   * Value of the explanatory <code>title</code> attribute for the feature.
198
   *
199
   *
199
   * @var string
200
   * @var string
200
   */
201
   */
201
  protected $title = '';
202
  protected $title = '';
202
 
203
 
203
  /**
204
  /**
204
   * Name or example code of the feature
205
   * Name or example code of the feature
205
   *
206
   *
206
   * @var string
207
   * @var string
207
   */
208
   */
208
  protected $content = '';
209
  protected $content = '';
209
   
210
   
210
  /**
211
  /**
211
   * Description of the feature.  Displayed directly if code is missing,
212
   * Description of the feature.  Displayed directly if code is missing,
212
   * otherwise used as `title' attribute value.
213
   * otherwise used as `title' attribute value.
213
   *
214
   *
214
   * @var string
215
   * @var string
215
   */
216
   */
216
  protected $descr = '';
217
  protected $descr = '';
217
 
218
 
218
  /**
219
  /**
219
   * Versions that support this feature
220
   * Versions that support this feature
220
   *
221
   *
221
   * @var Array
222
   * @var Array
222
   */
223
   */
223
  protected $versions = array();
224
  protected $versions = array();
224
   
225
   
225
  /**
226
  /**
226
   * Reference to the FeatureList that this feature belongs to
227
   * Reference to the FeatureList that this feature belongs to
227
   *
228
   *
228
   * @var FeatureList
229
   * @var FeatureList
229
   */
230
   */
230
  protected $list = null;
231
  protected $list = null;
231
 
232
 
232
  public function setList(&$oList)
233
  public function setList(&$oList)
233
  {
234
  {
234
    $this->list =& $oList;
235
    $this->list =& $oList;
235
  }
236
  }
236
237
237
  /**
238
  /**
238
   * Creates a new Feature object, using values from the passed parameters
239
   * Creates a new Feature object, using values from the passed parameters
239
   * array.
240
   * array.
240
   *
241
   *
241
   * @param array|Object $params
242
   * @param array|Object $params
242
   * @return Feature
243
   * @return Feature
243
   */
244
   */
244
  public function __construct($params = array())
245
  public function __construct($params = array())
245
  {
246
  {
246
    $aVars = get_class_vars(__CLASS__);
247
    $aVars = get_class_vars(__CLASS__);
247
   
248
   
248
    foreach ($aVars as $key => $value)
249
    foreach ($aVars as $key => $value)
249
    {
250
    {
250
      if (isset($params[$key]))
251
      if (isset($params[$key]))
251
      {
252
      {
252
        $this->$key = $params[$key];
253
        $this->$key = $params[$key];
253
      }
254
      }
254
    }
255
    }
255
  }
256
  }
256
 
257
 
257
  /**
258
  /**
258
   * Determines whether one version is greater than another.
259
   * Determines whether one version is greater than another.
259
   *
260
   *
260
   * @param string $v1  Version string #1
261
   * @param string $v1  Version string #1
261
   * @param string $v2  Version string #2
262
   * @param string $v2  Version string #2
262
   * @return bool
263
   * @return bool
263
   *   <code>true</code> if the version <var>$v1</var> is greater than
264
   *   <code>true</code> if the version <var>$v1</var> is greater than
264
   *   the version <var>$v2</var>, <code>false</code> otherwise
265
   *   the version <var>$v2</var>, <code>false</code> otherwise
265
   */
266
   */
266
  protected static function _versionIsGreater($v1, $v2)
267
  protected static function _versionIsGreater($v1, $v2)
267
  {
268
  {
268
    $v1 = explode('.', $v1);
269
    $v1 = explode('.', $v1);
269
    $v2 = explode('.', $v2);
270
    $v2 = explode('.', $v2);
270
   
271
   
271
    foreach ($v1 as $key => $value)
272
    foreach ($v1 as $key => $value)
272
    {
273
    {
273
      if ((int)$value <= (int)$v2[$key])
274
      if ((int)$value <= (int)$v2[$key])
274
      {
275
      {
275
        return false;
276
        return false;
276
      }
277
      }
277
    }
278
    }
278
   
279
   
279
    return true;
280
    return true;
280
  }
281
  }
281
 
282
 
282
  /**
283
  /**
283
   * Returns <code>' class="safe"'</code> if the feature
284
   * Returns <code>' class="safe"'</code> if the feature
284
   * can be considered safe.  The required information
285
   * can be considered safe.  The required information
285
   * is stored in the <code>safeVersions</code> property
286
   * is stored in the <code>safeVersions</code> property
286
   * of the associated <code>FeatureList</code> object.
287
   * of the associated <code>FeatureList</code> object.
287
   *
288
   *
288
   * @return string
289
   * @return string
289
   * @see FeatureList::defaultSafeVersions
290
   * @see FeatureList::defaultSafeVersions
290
   */
291
   */
291
  protected function getSafeStr()
292
  protected function getSafeStr()
292
  {
293
  {
293
    if (!is_null($this->list))
294
    if (!is_null($this->list))
294
    {
295
    {
295
      foreach ($this->list->safeVersions as $impl => &$safeVer)
296
      foreach ($this->list->safeVersions as $impl => &$safeVer)
296
      {
297
      {
297
        $thisImplVer =& $this->versions[$impl];
298
        $thisImplVer =& $this->versions[$impl];
298
        if (is_array($thisImplVer))
299
        if (is_array($thisImplVer))
299
        {
300
        {
300
          if (isset($thisImplVer['tested']) && !is_bool($thisImplVer['tested']))
301
          if (isset($thisImplVer['tested']) && !is_bool($thisImplVer['tested']))
301
          {
302
          {
302
            $thisImplVer =& $thisImplVer['tested'];
303
            $thisImplVer =& $thisImplVer['tested'];
303
          }
304
          }
304
          else
305
          else
305
        {
306
        {
306
            $thisImplVer =& $thisImplVer[0];
307
            $thisImplVer =& $thisImplVer[0];
307
          }
308
          }
308
        }
309
        }
309
       
310
       
310
        /* DEBUG */
311
        /* DEBUG */
311
        // echo " $impl=$thisImplVer ";
312
        // echo " $impl=$thisImplVer ";
312
       
313
       
313
        if (preg_match('/^-?$/', $thisImplVer) || self::_versionIsGreater($thisImplVer, $safeVer))
314
        if (preg_match('/^-?$/', $thisImplVer) || self::_versionIsGreater($thisImplVer, $safeVer))
314
        {
315
        {
315
          return '';
316
          return '';
316
        }
317
        }
317
      }
318
      }
318
     
319
     
319
      return ' class="safe"';
320
      return ' class="safe"';
320
    }
321
    }
321
    else
322
    else
322
    {
323
    {
323
      return '';
324
      return '';
324
    }
325
    }
325
  }
326
  }
326
 
327
 
327
  protected function getTitleStr()
328
  protected function getTitleStr()
328
  {
329
  {
329
    if (!empty($this->title))
330
    if (!empty($this->title))
330
    {
331
    {
331
      return " title=\"{$this->title}\"";
332
      return " title=\"{$this->title}\"";
332
    }
333
    }
333
    else
334
    else
334
    {
335
    {
335
      return '';
336
      return '';
336
    }
337
    }
337
  }
338
  }
338
 
339
 
339
  protected function getAnchors()
340
  protected function getAnchors()
340
  {
341
  {
341
    $result = array();
342
    $result = array();
342
 
343
 
343
    foreach ($this->anchors as $anchor)
344
    foreach ($this->anchors as $anchor)
344
    {
345
    {
345
      $result[] = "<a name=\"{$anchor}\"";
346
      $result[] = "<a name=\"{$anchor}\"";
346
     
347
     
347
      if (preg_match('/^[a-z][a-z0-9_:.-]*/i', $anchor))
348
      if (preg_match('/^[a-z][a-z0-9_:.-]*/i', $anchor))
348
      {
349
      {
349
        $result[] = " id=\"{$anchor}\"";
350
        $result[] = " id=\"{$anchor}\"";
350
      }
351
      }
351
     
352
     
352
      $result[] = '></a>';
353
      $result[] = '></a>';
353
    }
354
    }
354
   
355
   
355
    return join('', $result);
356
    return join('', $result);
356
  }
357
  }
357
358
358
  protected function getAssumed($v)
359
  protected function getAssumed($v)
359
  {
360
  {
360
    if (is_array($v) && isset($v['assumed']) && $v['assumed'])
361
    if (is_array($v) && isset($v['assumed']) && $v['assumed'])
361
    {
362
    {
362
      return ' class="assumed"';
363
      return ' class="assumed"';
363
    }
364
    }
364
   
365
   
365
    return '';
366
    return '';
366
  }
367
  }
367
368
368
  protected function getTested($v)
369
  protected function getTested($v)
369
  {
370
  {
370
    if (is_array($v) && isset($v['tested']) && $v['tested'])
371
    if (is_array($v) && isset($v['tested']) && $v['tested'])
371
    {
372
    {
372
      return ' class="tested"';
373
      return ' class="tested"';
373
    }
374
    }
374
   
375
   
375
    return '';
376
    return '';
376
  }
377
  }
377
 
378
 
378
  /**
379
  /**
379
   * Returns the version of a feature.
380
   * Returns the version of a feature.
380
   *
381
   *
381
   * @param string|VersionInfo $vInfo
382
   * @param string|VersionInfo $vInfo
382
   * @return mixed
383
   * @return mixed
383
   */
384
   */
384
  protected function getVer($vInfo)
385
  protected function getVer($vInfo)
385
  {
386
  {
386
    if (is_array($vInfo))
387
    if (is_array($vInfo))
387
    {
388
    {
388
      /* TODO: Return all versions: documented, assumed, and tested */
389
      /* TODO: Return all versions: documented, assumed, and tested */
389
      $vNumber = (isset($vInfo['tested'])
390
      $vNumber = (isset($vInfo['tested'])
390
                  && gettype($vInfo['tested']) !== 'boolean')
391
                  && gettype($vInfo['tested']) !== 'boolean')
391
                     ? $vInfo['tested']
392
                     ? $vInfo['tested']
392
                     : $vInfo[0];
393
                     : $vInfo[0];
393
      $section = isset($vInfo['section'])
394
      $section = isset($vInfo['section'])
394
                   ? ' <span class="section" title="Specification section">['
395
                   ? ' <span class="section" title="Specification section">['
395
                      . $vInfo['section'] . ']</span>'
396
                      . $vInfo['section'] . ']</span>'
396
                   : '';
397
                   : '';
397
     
398
     
398
      if (isset($vInfo['urn']))
399
      if (isset($vInfo['urn']))
399
      {
400
      {
400
        if ($this->list instanceof FeatureList)
401
        if ($this->list instanceof FeatureList)
401
        {
402
        {
402
          $url = $this->list->resolveURN($vInfo['urn']);
403
          $url = $this->list->resolveURN($vInfo['urn']);
403
          $vNumber = '<a href="' . $url . '">' . $vNumber
404
          $vNumber = '<a href="' . $url . '">' . $vNumber
404
            . ($section ? $section : '') . '</a>';
405
            . ($section ? $section : '') . '</a>';
405
        }
406
        }
406
      }
407
      }
407
      else if ($section)
408
      else if ($section)
408
      {
409
      {
409
        $vNumber .= $section;
410
        $vNumber .= $section;
410
      }
411
      }
411
412
412
      $vInfo = $vNumber;
413
      $vInfo = $vNumber;
413
    }
414
    }
414
415
415
    return ($vInfo === '-')
416
    return ($vInfo === '-')
416
      ? '<span title="Not supported">&#8722;</span>'
417
      ? '<span title="Not supported">&#8722;</span>'
417
      : $vInfo;
418
      : $vInfo;
418
  }
419
  }
419
 
420
 
420
  /**
421
  /**
421
   * Returns a syntax-highlighted version of a string
422
   * Returns a syntax-highlighted version of a string
422
   *
423
   *
423
   * @param string $s
424
   * @param string $s
424
   * @return string
425
   * @return string
425
   */
426
   */
426
  protected static function shl($s)
427
  protected static function shl($s)
427
  {
428
  {
428
    /* stub */
429
    /* stub */
429
    return $s;
430
    return $s;
430
  }
431
  }
431
 
432
 
432
  public function printMe()
433
  public function printMe()
433
  {
434
  {
434
    ?>
435
    ?>
435
<tr<?php echo $this->getSafeStr(); ?>>
436
<tr<?php echo $this->getSafeStr(); ?>>
436
          <th<?php echo $this->getTitleStr(); ?>><?php
437
          <th<?php echo $this->getTitleStr(); ?>><?php
437
            echo $this->getAnchors();
438
            echo $this->getAnchors();
438
            echo /*preg_replace_callback(
439
            echo /*preg_replace_callback(
439
              '#(<code>)(.+?)(</code>)#',
440
              '#(<code>)(.+?)(</code>)#',
440
              array('self', 'shl'),*/
441
              array('self', 'shl'),*/
441
              preg_replace('/&hellip;/', '&#8230;', $this->content)/*)*/;
442
              preg_replace('/&hellip;/', '&#8230;', $this->content)/*)*/;
442
            ?></th>
443
            ?></th>
443
<?php
444
<?php
444
    $versions = $this->versions;
445
    $versions = $this->versions;
445
    $testcase = false;
446
    $testcase = false;
446
    if (!is_null($this->list))
447
    if (!is_null($this->list))
447
    {
448
    {
448
      $versions =& $this->list->versions;
449
      $versions =& $this->list->versions;
449
      $testcase = $this->list->testcase;
450
      $testcase = $this->list->testcase;
450
    }
451
    }
451
452
452
    static $row = 0;
453
    static $row = 0;
453
    $row++;
454
    $row++;
454
   
455
   
455
    $column = 0;
456
    $column = 0;
456
    $thisVersions =& $this->versions;
457
    $thisVersions =& $this->versions;
457
   
458
   
458
    foreach ($versions as $key => $value)
459
    foreach ($versions as $key => $value)
459
    {
460
    {
460
      $column++;
461
      $column++;
461
      $id = "td$row-$column";
462
      $id = "td$row-$column";
462
      $ver = isset($thisVersions[$key]) ? $thisVersions[$key] : '';
463
      $ver = isset($thisVersions[$key]) ? $thisVersions[$key] : '';
463
      if ($key || $testcase)
464
      if ($key || $testcase)
464
      {
465
      {
465
?>
466
?>
466
          <td<?php
467
          <td<?php
467
            if (!$key)
468
            if (!$key)
468
            {
469
            {
469
              echo " id='$id'";
470
              echo " id='$id'";
470
            }
471
            }
471
           
472
           
472
            echo $this->getAssumed($ver) . $this->getTested($ver);
473
            echo $this->getAssumed($ver) . $this->getTested($ver);
473
           
474
           
474
            if (!$key)
475
            if (!$key)
475
            {
476
            {
476
              if (!empty($ver))
477
              if (!empty($ver))
477
              {
478
              {
478
                echo ' title="Test code: '
479
                echo ' title="Test code: '
479
                  . htmlspecialchars(
480
                  . htmlspecialchars(
480
                      preg_replace('/\\\(["\'])/', '\1',
481
                      preg_replace('/\\\(["\'])/', '\1',
481
                        reduceWhitespace($ver)
482
                        reduceWhitespace($ver)
482
                      ),
483
                      ),
483
                      ENT_COMPAT,
484
                      ENT_COMPAT,
484
                      FEATURES_ENCODING
485
                      FEATURES_ENCODING
485
                    )
486
                    )
486
                  . '"';
487
                  . '"';
487
              }
488
              }
488
              else
489
              else
489
            {
490
            {
490
                echo ' title="Not applicable: No automated test case'
491
                echo ' title="Not applicable: No automated test case'
491
                  . ' is available for this feature.  If possible, please'
492
                  . ' is available for this feature.  If possible, please'
492
                  . ' click the feature code in the first column to run'
493
                  . ' click the feature code in the first column to run'
493
                  . ' a manual test."';
494
                  . ' a manual test."';
494
              }
495
              }
495
            }
496
            }
496
            else
497
            else
497
          {
498
          {
498
              echo ' title="'
499
              echo ' title="'
499
                . htmlspecialchars(
500
                . htmlspecialchars(
500
                    preg_replace('/<.*?>/', '', $value),
501
                    preg_replace('/<.*?>/', '', $value),
501
                    ENT_COMPAT, FEATURES_ENCODING)
502
                    ENT_COMPAT, FEATURES_ENCODING)
502
                . '"';
503
                . '"';
503
            }
504
            }
504
            ?>><?php
505
            ?>><?php
505
            if ($key)
506
            if ($key)
506
            {
507
            {
507
              echo $this->getVer($ver);
508
              echo $this->getVer($ver);
508
             
509
             
509
              /* General footnotes support: include footnotes.class.php to enable */
510
              /* General footnotes support: include footnotes.class.php to enable */
510
              if (is_array($ver) && isset($ver['footnote']) && $ver['footnote'])
511
              if (is_array($ver) && isset($ver['footnote']) && $ver['footnote'])
511
              {
512
              {
512
                echo $ver['footnote'];
513
                echo $ver['footnote'];
513
              }
514
              }
514
            }
515
            }
515
            else
516
            else
516
          {
517
          {
517
              if (!empty($ver) && $testcase)
518
              if (!empty($ver) && $testcase)
518
              {
519
              {
519
                ?><script type="text/javascript">
520
                ?><script type="text/javascript">
520
  // <![CDATA[
521
  // <![CDATA[
521
  var s = test(<?php echo $ver; ?>,
522
  var s = test(<?php echo $ver; ?>,
522
    '<input title="Supported" name="<?php echo htmlspecialchars($this->title, ENT_COMPAT, FEATURES_ENCODING); ?>" value="+" readonly>',
523
    '<input title="Supported" name="<?php echo htmlspecialchars($this->title, ENT_COMPAT, FEATURES_ENCODING); ?>" value="+" readonly>',
523
    '<input title="Not supported" name="<?php echo htmlspecialchars($this->title, ENT_COMPAT, FEATURES_ENCODING); ?>" value="&#8722;" readonly>');
524
    '<input title="Not supported" name="<?php echo htmlspecialchars($this->title, ENT_COMPAT, FEATURES_ENCODING); ?>" value="&#8722;" readonly>');
524
  jsx.tryThis("document.write(s);",
525
  jsx.tryThis("document.write(s);",
525
          "document.getElementById('<?php echo $id; ?>').appendChild("
526
          "document.getElementById('<?php echo $id; ?>').appendChild("
526
          + "document.createTextNode(s));");
527
          + "document.createTextNode(s));");
527
  // ]]>
528
  // ]]>
528
</script><?php
529
</script><?php
529
              }
530
              }
530
              else
531
              else
531
            {
532
            {
532
                echo '<abbr>N/A</abbr>';
533
                echo '<abbr>N/A</abbr>';
533
              }
534
              }
534
            }
535
            }
535
            ?></td>
536
            ?></td>
536
<?php
537
<?php
537
      }
538
      }
538
    }
539
    }
539
?>
540
?>
540
        </tr>
541
        </tr>
541
<?php
542
<?php
542
  }
543
  }
543
}
544
}
544
 
545
 
545
?>
546
?>
546
 
547