[ Index ]
 

Code source de Horde 3.1.3

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/templates/javascript/ -> tree.js (source)

   1  /**
   2   * Horde Tree Javascript Class
   3   *
   4   * Provides the javascript class to create dynamic trees.
   5   *
   6   * Copyright 2003-2006 Marko Djukic <marko@oblo.com>
   7   *
   8   * See the enclosed file COPYING for license information (GPL). If you did not
   9   * receive this file, see http://www.fsf.org/copyleft/gpl.html.
  10   *
  11   * $Horde: horde/templates/javascript/tree.js,v 1.62.2.11 2006/01/01 21:29:15 jan Exp $
  12   *
  13   * @author  Marko Djukic <marko@oblo.com>
  14   * @package Horde_Tree
  15   * @since   Horde 3.0
  16   */
  17  function Horde_Tree(instanceName)
  18  {
  19      /* Set up this class instance for function calls from the page. */
  20      this._instanceName = instanceName;
  21  
  22      /* Image variables. */
  23      this.imgDir         = '<?php echo $GLOBALS['registry']->getImageDir('horde') . '/tree'; ?>';
  24      this.imgBlank       = 'blank.png';
  25      this.imgFolder      = 'folder.png';
  26      this.imgFolderOpen  = 'folderopen.png';
  27  
  28      /* Variables that change based on text direction. */
  29  <?php if (empty($GLOBALS['nls']['rtl'][$GLOBALS['language']])): ?>
  30      this.floatDir       = 'float:left;';
  31      this.imgLine        = 'line.png';
  32      this.imgJoin        = 'join.png';
  33      this.imgJoinBottom  = 'joinbottom.png';
  34      this.imgPlus        = 'plus.png';
  35      this.imgPlusBottom  = 'plusbottom.png';
  36      this.imgPlusOnly    = 'plusonly.png';
  37      this.imgMinus       = 'minus.png';
  38      this.imgMinusBottom = 'minusbottom.png';
  39      this.imgMinusOnly   = 'minusonly.png';
  40      this.imgNullOnly    = 'nullonly.png';
  41      this.imgLeaf        = 'leaf.png';
  42  <?php else: ?>
  43      this.floatDir       = 'float:right;';
  44      this.imgLine        = 'rev-line.png';
  45      this.imgJoin        = 'rev-join.png';
  46      this.imgJoinBottom  = 'rev-joinbottom.png';
  47      this.imgPlus        = 'rev-plus.png';
  48      this.imgPlusBottom  = 'rev-plusbottom.png';
  49      this.imgPlusOnly    = 'rev-plusonly.png';
  50      this.imgMinus       = 'rev-minus.png';
  51      this.imgMinusBottom = 'rev-minusbottom.png';
  52      this.imgMinusOnly   = 'rev-minusonly.png';
  53      this.imgNullOnly    = 'rev-nullonly.png';
  54      this.imgLeaf        = 'rev-leaf.png';
  55  <?php endif; ?>
  56  
  57      /* Tree building variables. */
  58      this.renderStatic   = false;
  59      this.target         = '';
  60      this.header         = new Array();
  61      this.rootNodes      = new Array();
  62      this.nodes          = new Array();
  63      this.node_pos       = new Array();
  64      this.dropline       = new Array();
  65      this.output         = '';
  66  }
  67  
  68  Horde_Tree.prototype.setImgDir = function(imgDir)
  69  {
  70      this.imgDir = imgDir;
  71  }
  72  
  73  Horde_Tree.prototype.renderTree = function(rootNodes, renderStatic)
  74  {
  75      this.rootNodes = rootNodes;
  76      this.renderStatic = renderStatic;
  77      this.nodes = eval('n_' + this._instanceName);
  78      this.header = eval('h_' + this._instanceName);
  79      this.options = eval('o_' + this._instanceName);
  80      this.target = 't_' + this._instanceName;
  81      this._renderTree();
  82  }
  83  
  84  Horde_Tree.prototype._renderTree = function()
  85  {
  86      this.output = '';
  87      if (!this.options['hideHeaders']) {
  88          this.output = this._buildHeader();
  89      }
  90      for (var i = 0; i < this.rootNodes.length; i++) {
  91          this.buildTree(this.rootNodes[i]);
  92      }
  93      document.getElementById(this.target).innerHTML = this.output;
  94      this._correctWidthForScrollbar();
  95      // If using alternating row shading, work out correct shade.
  96      if (this.options['alternate']) {
  97          this.stripe();
  98      }
  99  }
 100  
 101  /**
 102   * Returns the HTML code for a header row, if necessary.
 103   *
 104   * @access private
 105   *
 106   * @return string  The HTML code of the header row or an empty string.
 107   */
 108  Horde_Tree.prototype._buildHeader = function()
 109  {
 110      if (!this.header.length) {
 111          return '';
 112      }
 113  
 114      var html = '<div>';
 115      for (var i = 0; i < this.header.length; i++) {
 116          html += '<div';
 117          if (this.header[i]['class']) {
 118              html += ' class="' + this.header[i]['class'] + '"';
 119          }
 120  
 121          var style = this.floatDir;
 122          if (this.header[i]['width']) {
 123              style += 'width:' + this.header[i]['width'] + ';';
 124          }
 125          if (this.header[i]['align']) {
 126              style += 'text-align:' + this.header[i]['align'] + ';';
 127          }
 128  
 129          html += ' style="' + style + '"';
 130          html += '>';
 131          html += this.header[i]['html'] ? this.header[i]['html'] : '&nbsp;';
 132          html += '</div>';
 133      }
 134  
 135      return html + '</div>';
 136  }
 137  
 138  /**
 139   * Recursive function to walk through the tree array and build
 140   * the output.
 141   */
 142  Horde_Tree.prototype.buildTree = function(nodeId)
 143  {
 144      this.output += this.buildLine(nodeId);
 145  
 146      if (typeof(this.nodes[nodeId]['children']) != 'undefined') {
 147          var numSubnodes = this.nodes[nodeId]['children'].length;
 148          if (numSubnodes > 0) {
 149              if (this.nodes[nodeId]['expanded']) {
 150                  rowStyle = 'display:block;';
 151              } else {
 152                  rowStyle = 'display:none;';
 153              }
 154              this.output += '<div id="nodeChildren_' + nodeId + '" style="' + rowStyle + '">';
 155  
 156              for (var c = 0; c < numSubnodes; c++) {
 157                  var childNodeId = this.nodes[nodeId]['children'][c];
 158                  this.node_pos[childNodeId] = new Array();
 159                  this.node_pos[childNodeId]['pos'] = c + 1;
 160                  this.node_pos[childNodeId]['count'] = numSubnodes;
 161                  this.buildTree(childNodeId);
 162              }
 163  
 164              this.output += '</div>';
 165          }
 166      }
 167  
 168      return true;
 169  }
 170  
 171  Horde_Tree.prototype.buildLine = function(nodeId)
 172  {
 173      var style = '';
 174      var rowClass = 'treeRow';
 175      if (this.nodes[nodeId]['class']) {
 176          rowClass += ' ' + this.nodes[nodeId]['class'];
 177      }
 178  
 179      var line = '<div class="' + rowClass + '">';
 180  
 181      // If we have headers, track which logical "column" we're in for
 182      // any given cell of content.
 183      var column = 0;
 184  
 185      if (typeof(this.nodes[nodeId]['extra']) != 'undefined' &&
 186          typeof(this.nodes[nodeId]['extra'][0]) != 'undefined') {
 187          var extra = this.nodes[nodeId]['extra'][0];
 188          for (var c = 0; c < extra.length; c++) {
 189              style = this.floatDir;
 190              if (this.header[column] && this.header[column]['width']) {
 191                  style += 'width:' + this.header[column]['width'] + ';';
 192              }
 193              line += '<div style="' + style + '">' + extra[c] + '</div>';
 194              column++;
 195          }
 196          for (var d = c; d < extraColsLeft; d++) {
 197              style = this.floatDir;
 198              if (this.header[column] && this.header[column]['width']) {
 199                  style += 'width:' + this.header[column]['width'] + ';';
 200              }
 201              line += '<div style="' + style + '">&nbsp;</div>';
 202              column++;
 203          }
 204      } else {
 205          for (var c = 0; c < extraColsLeft; c++) {
 206              style = this.floatDir;
 207              if (this.header[column] && this.header[column]['width']) {
 208                  style += 'width:' + this.header[column]['width'] + ';';
 209              }
 210              line += '<div style="' + style + '">&nbsp;</div>';
 211              column++;
 212          }
 213      }
 214  
 215      style = this.floatDir;
 216      if (this.header[column] && this.header[column]['width']) {
 217          style += 'width:' + this.header[column]['width'] + ';';
 218      }
 219      line += '<div style="' + style + '">';
 220  
 221      if (this.options['multiline']) {
 222          line += '<table cellspacing="0"><tr><td>';
 223      }
 224  
 225      for (var i = this.renderStatic ? 1 : 0; i < this.nodes[nodeId]['indent']; i++) {
 226          if (this.dropline[i] && this.options['lines']) {
 227              line += '<img src="' + this.imgDir + '/' + this.imgLine + '" alt="|&nbsp;&nbsp;&nbsp;" height="20" width="20" />';
 228          } else {
 229              line += '<img src="' + this.imgDir + '/' + this.imgBlank + '" alt="&nbsp;&nbsp;&nbsp;" height="20" width="20" />';
 230          }
 231      }
 232      line += this._setNodeToggle(nodeId);
 233      if (this.options['multiline']) {
 234          line += '</td><td>';
 235      }
 236      line += this._setLabel(nodeId);
 237  
 238      if (this.options['multiline']) {
 239          line += '</td></tr></table>';
 240      }
 241  
 242      line += '</div>';
 243      column++;
 244  
 245      if (typeof(this.nodes[nodeId]['extra']) != 'undefined' &&
 246          typeof(this.nodes[nodeId]['extra'][1]) != 'undefined') {
 247          var extra = this.nodes[nodeId]['extra'][1];
 248          for (var c = 0; c < extra.length; c++) {
 249              style = this.floatDir;
 250              if (this.header[column] && this.header[column]['width']) {
 251                  style += 'width:' + this.header[column]['width'] + ';';
 252              }
 253              line += '<div style="' + style + '">' + extra[c] + '</div>';
 254              column++;
 255          }
 256          for (var d = c; d < extraColsRight; d++) {
 257              style = this.floatDir;
 258              if (this.header[column] && this.header[column]['width']) {
 259                  style += 'width:' + this.header[column]['width'] + ';';
 260              }
 261              line += '<div style="' + style + '">&nbsp;</div>';
 262              column++;
 263          }
 264      } else {
 265          for (var c = 0; c < extraColsRight; c++) {
 266              style = this.floatDir;
 267              if (this.header[column] && this.header[column]['width']) {
 268                  style += 'width:' + this.header[column]['width'] + ';';
 269              }
 270              line += '<div style="' + style + '">&nbsp;</div>';
 271              column++;
 272          }
 273      }
 274      line += '</div>';
 275  
 276      return line;
 277  }
 278  
 279  Horde_Tree.prototype._setLabel = function(nodeId)
 280  {
 281      label = this.nodes[nodeId]['label'];
 282  
 283      if (this.nodes[nodeId]['url']) {
 284          var urlClass = '';
 285          if (this.nodes[nodeId]['urlclass']) {
 286              urlClass = ' class="' + this.nodes[nodeId]['urlclass'] + '"';
 287          } else if (this.options['urlclass']) {
 288              urlClass = ' class="' + this.options['urlclass'] + '"';
 289          }
 290  
 291          var target = '';
 292          if (this.nodes[nodeId]['target']) {
 293              target = ' target="' + this.nodes[nodeId]['target'] + '"';
 294          } else if (this.options['target']) {
 295              target = ' target="' + this.options['target'] + '"';
 296          }
 297  
 298          var onclick = '';
 299          if (this.nodes[nodeId]['onclick']) {
 300              onclick = ' onclick="' + this.nodes[nodeId]['onclick'] + '"';
 301          }
 302  
 303          return '<a' + urlClass + ' href="' + this.nodes[nodeId]['url'] + '"' + target + onclick + '>' + this._setNodeIcon(nodeId) + label + '</a>';
 304      } else {
 305          return '<span class="toggle" onclick="' + this._instanceName + '.toggle(\'' + nodeId + '\')">' + this._setNodeIcon(nodeId) + label + '</span>';
 306      }
 307  }
 308  
 309  Horde_Tree.prototype._setNodeToggle = function(nodeId)
 310  {
 311      var attrib = '';
 312      if (this.nodes[nodeId]['indent'] == '0' &&
 313          typeof(this.nodes[nodeId]['children']) != 'undefined') {
 314          // Top level with children.
 315          this.dropline[0] = false;
 316          if (this.renderStatic) {
 317              return '';
 318          } else {
 319              attrib = ' style="cursor:pointer" onclick="' + this._instanceName + '.toggle(\'' + nodeId + '\')"';
 320          }
 321      } else if (this.nodes[nodeId]['indent'] != '0' &&
 322                 typeof(this.nodes[nodeId]['children']) == 'undefined') {
 323          // Node no children.
 324          if (this.node_pos[nodeId]['pos'] < this.node_pos[nodeId]['count']) {
 325              // Not last node.
 326              this.dropline[this.nodes[nodeId]['indent']] = true;
 327          } else {
 328              this.dropline[this.nodes[nodeId]['indent']] = false;
 329          }
 330      } else if (typeof(this.nodes[nodeId]['children']) != 'undefined') {
 331          // Node with children.
 332          if (this.node_pos[nodeId]['pos'] < this.node_pos[nodeId]['count']) {
 333              // Not last node.
 334              this.dropline[this.nodes[nodeId]['indent']] = true;
 335          } else {
 336              // Last node.
 337              this.dropline[this.nodes[nodeId]['indent']] = false;
 338          }
 339          if (!this.renderStatic) {
 340              attrib = ' style="cursor:pointer" onclick="' + this._instanceName + '.toggle(\'' + nodeId + '\')"';
 341          }
 342      } else {
 343          // Top level node with no children.
 344          if (this.renderStatic) {
 345              return '';
 346          }
 347          this.dropline[0] = false;
 348      }
 349  
 350      nodeToggle = this._getNodeToggle(nodeId);
 351      img = '<img id="nodeToggle_' + nodeId + '" src="' + this.imgDir + '/' + nodeToggle[0] + '" ';
 352      if (nodeToggle[1]) {
 353          img += 'alt="' + nodeToggle[1] + '" ';
 354      }
 355      img += attrib + ' height="20" width="20" />';
 356      return img;
 357  }
 358  
 359  Horde_Tree.prototype._getNodeToggle = function(nodeId)
 360  {
 361      var nodeToggle = new Array('', '');
 362      if (this.nodes[nodeId]['indent'] == '0' &&
 363          typeof(this.nodes[nodeId]['children']) != 'undefined') {
 364          // Top level with children.
 365          if (this.renderStatic) {
 366              return nodeToggle;
 367          } else if (!this.options['lines']) {
 368              nodeToggle[0] = this.imgBlank;
 369              nodeToggle[1] = '&nbsp;&nbsp;&nbsp;'
 370          } else if (this.nodes[nodeId]['expanded']) {
 371              nodeToggle[0] = this.imgMinusOnly;
 372              nodeToggle[1] = '-';
 373          } else {
 374              nodeToggle[0] = this.imgPlusOnly;
 375              nodeToggle[1] = '+';
 376          }
 377      } else if (this.nodes[nodeId]['indent'] != '0' &&
 378          typeof(this.nodes[nodeId]['children']) == 'undefined') {
 379          // Node no children.
 380          if (this.node_pos[nodeId]['pos'] < this.node_pos[nodeId]['count']) {
 381              // Not last node.
 382              if (this.options['lines']) {
 383                  nodeToggle[0] = this.imgJoin;
 384                  nodeToggle[1] = '|-';
 385              } else {
 386                  nodeToggle[0] = this.imgBlank;
 387                  nodeToggle[1] = '&nbsp;&nbsp;&nbsp;';
 388              }
 389          } else {
 390              // Last node.
 391              if (this.options['lines']) {
 392                  nodeToggle[0] = this.imgJoinBottom;
 393                  nodeToggle[1] = '`-';
 394              } else {
 395                  nodeToggle[0] = this.imgBlank;
 396                  nodeToggle[1] = '&nbsp;&nbsp;&nbsp;';
 397              }
 398          }
 399      } else if (typeof(this.nodes[nodeId]['children']) != 'undefined') {
 400          // Node with children.
 401          if (this.node_pos[nodeId]['pos'] < this.node_pos[nodeId]['count']) {
 402              // Not last node.
 403              if (!this.options['lines']) {
 404                  nodeToggle[0] = this.imgBlank;
 405                  nodeToggle[1] = '&nbsp;&nbsp;&nbsp;';
 406              } else if (this.renderStatic) {
 407                  nodeToggle[0] = this.imgJoin;
 408                  nodeToggle[1] = '|-';
 409              } else if (this.nodes[nodeId]['expanded']) {
 410                  nodeToggle[0] = this.imgMinus;
 411                  nodeToggle[1] = '-';
 412              } else {
 413                  nodeToggle[0] = this.imgPlus;
 414                  nodeToggle[1] = '+';
 415              }
 416          } else {
 417              // Last node.
 418              if (!this.options['lines']) {
 419                  nodeToggle[0] = this.imgBlank;
 420                  nodeToggle[1] = '&nbsp;';
 421              } else if (this.renderStatic) {
 422                  nodeToggle[0] = this.imgJoinBottom;
 423                  nodeToggle[1] = '`-';
 424              } else if (this.nodes[nodeId]['expanded']) {
 425                  nodeToggle[0] = this.imgMinusBottom;
 426                  nodeToggle[1] = '-';
 427              } else {
 428                  nodeToggle[0] = this.imgPlusBottom;
 429                  nodeToggle[1] = '+';
 430              }
 431          }
 432      } else {
 433          // Top level node with no children.
 434          if (this.renderStatic) {
 435              return nodeToggle;
 436          }
 437          if (this.options['lines']) {
 438              nodeToggle[0] = this.imgNullOnly;
 439              nodeToggle[1] = '&nbsp;&nbsp;';
 440          } else {
 441              nodeToggle[0] = this.imgBlank;
 442              nodeToggle[1] = '&nbsp;&nbsp;&nbsp;';
 443          }
 444      }
 445  
 446      return nodeToggle;
 447  }
 448  
 449  Horde_Tree.prototype._setNodeIcon = function(nodeId)
 450  {
 451      var imgDir = (typeof(this.nodes[nodeId]['icondir']) != 'undefined') ?
 452          this.nodes[nodeId]['icondir'] :
 453          this.imgDir;
 454      if (imgDir) {
 455          imgDir += '/';
 456      }
 457  
 458      if (typeof(this.nodes[nodeId]['icon']) != 'undefined') {
 459          // Node has a user defined icon.
 460          if (!this.nodes[nodeId]['icon']) {
 461              return '';
 462          }
 463          if (typeof(this.nodes[nodeId]['iconopen']) != 'undefined' && this.nodes[nodeId]['expanded']) {
 464              img = this.nodes[nodeId]['iconopen'];
 465          } else {
 466              img = this.nodes[nodeId]['icon'];
 467          }
 468      } else {
 469          // Use standard icon set.
 470          if (typeof(this.nodes[nodeId]['children']) != 'undefined') {
 471              // Node with children.
 472              img = (this.nodes[nodeId]['expanded']) ? this.imgFolderOpen
 473                                                     : this.imgFolder;
 474          } else {
 475              // Node no children.
 476              img = this.imgLeaf;
 477          }
 478      }
 479  
 480      var imgtxt = '<img src="' + imgDir + img + '"';
 481  
 482      if (typeof(this.nodes[nodeId]['iconalt']) != 'undefined') {
 483          imgtxt += ' alt="' + this.nodes[nodeId]['iconalt'] + '"';
 484      }
 485  
 486      return imgtxt + ' /> ';
 487  }
 488  
 489  Horde_Tree.prototype.toggle = function(nodeId)
 490  {
 491      this.nodes[nodeId]['expanded'] = !this.nodes[nodeId]['expanded'];
 492      if (this.nodes[nodeId]['expanded']) {
 493          if (node = document.getElementById('nodeChildren_' + nodeId)) {
 494              node.style.display = 'block';
 495          }
 496      } else {
 497          if (node = document.getElementById('nodeChildren_' + nodeId)) {
 498              node.style.display = 'none';
 499          }
 500      }
 501  
 502      // If using alternating row shading, work out correct shade.
 503      if (this.options['alternate']) {
 504          this.stripe();
 505      }
 506  
 507      nodeToggle = this._getNodeToggle(nodeId);
 508      if (toggle = document.getElementById('nodeToggle_' + nodeId)) {
 509          toggle.src = this.imgDir + '/' + nodeToggle[0];
 510          toggle.alt = nodeToggle[1];
 511      }
 512  
 513      this.saveState(nodeId, this.nodes[nodeId]['expanded'])
 514  }
 515  
 516  Horde_Tree.prototype.stripe = function()
 517  {
 518      // The element to start striping.
 519      var id = arguments[0] ? arguments[0] : this.target;
 520  
 521      // The flag we'll use to keep track of whether the current row is
 522      // odd or even.
 523      var even = arguments[1] ? arguments[1] : false;
 524  
 525      // Obtain a reference to the tree parent element.
 526      var tree = document.getElementById(id);
 527      if (!tree) {
 528          return even;
 529      }
 530  
 531      // Iterate over each child div.
 532      for (var i = 0; i < tree.childNodes.length; i++) {
 533          if (tree.childNodes[i].id.indexOf('nodeChildren') != -1) {
 534              if (this.nodes[tree.childNodes[i].id.replace('nodeChildren_', '')]['expanded']) {
 535                  even = this.stripe(tree.childNodes[i].id, even);
 536              }
 537          } else {
 538              tree.childNodes[i].className = tree.childNodes[i].className.replace(' rowEven', '').replace(' rowOdd', '');
 539              tree.childNodes[i].className += even ? ' rowEven' : ' rowOdd';
 540  
 541              // Flip from odd to even, or vice-versa.
 542              even = !even;
 543          }
 544      }
 545  
 546      return even;
 547  }
 548  
 549  Horde_Tree.prototype.saveState = function(nodeId, expanded)
 550  {
 551      var newCookie = '';
 552      var oldCookie = this._getCookie(this._instanceName + '_expanded');
 553      if (expanded) {
 554          // Expand requested so add to cookie.
 555          newCookie = (oldCookie) ? oldCookie + ',' : '';
 556          newCookie = newCookie + nodeId;
 557      } else {
 558          // Collapse requested so remove from cookie.
 559          var nodes = oldCookie.split(',');
 560          var newNodes = new Array();
 561          for (var i = 0; i < nodes.length; i++) {
 562              if (nodes[i] != nodeId) {
 563                  newNodes[newNodes.length] = nodes[i];
 564              }
 565          }
 566          newCookie = newNodes.join(',');
 567      }
 568      this._setCookie(this._instanceName + '_expanded', newCookie);
 569  }
 570  
 571  Horde_Tree.prototype._getCookie = function(name)
 572  {
 573      var dc = document.cookie;
 574      var prefix = name + '=exp';
 575      var begin = dc.indexOf('; ' + prefix);
 576      if (begin == -1) {
 577          begin = dc.indexOf(prefix);
 578          if (begin != 0) {
 579              return '';
 580          }
 581      } else {
 582          begin += 2;
 583      }
 584      var end = document.cookie.indexOf(';', begin);
 585      if (end == -1) {
 586          end = dc.length;
 587      }
 588      return unescape(dc.substring(begin + prefix.length, end));
 589  }
 590  
 591  Horde_Tree.prototype._setCookie = function(name, value)
 592  {
 593      var curCookie = name + '=exp' + escape(value);
 594      curCookie += ';DOMAIN=<?php echo $GLOBALS['conf']['cookie']['domain']; ?>;PATH=<?php echo $GLOBALS['conf']['cookie']['path']; ?>;';
 595      document.cookie = curCookie;
 596  }
 597  
 598  Horde_Tree.prototype._correctWidthForScrollbar = function()
 599  {
 600  <?php if ($GLOBALS['browser']->hasQuirk('scrollbar_in_way')): ?>
 601      // Correct for frame scrollbar in IE by determining if a scrollbar is present,
 602      // and if not readjusting the marginRight property to 0
 603      // See http://www.xs4all.nl/~ppk/js/doctypes.html for why this works
 604      if (document.documentElement.clientHeight == document.documentElement.offsetHeight) {
 605          // no scrollbar present, take away extra margin
 606          document.body.style.marginRight = '0';
 607      } else {
 608          document.body.style.marginRight = '15px';
 609      }
 610  <?php endif; ?>
 611  }


Généré le : Sun Feb 25 18:01:28 2007 par Balluche grâce à PHPXref 0.7