Subversion Repositories PHPX

Rev

Rev 28 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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