Author: sevein
Date: Mon Jun 25 16:49:26 2012
New Revision: 11803

Log:
Backport of the 2.0 treeview, adding debouncing scroll event and some other js 
improvements

Added:
   trunk/apps/qubit/modules/informationobject/templates/treeViewSuccess.php   
(contents, props changed)
   trunk/images/arrow-sprites.png   (contents, props changed)
Modified:
   trunk/apps/qubit/modules/informationobject/actions/treeViewAction.class.php
   
trunk/apps/qubit/modules/informationobject/actions/treeViewComponent.class.php
   trunk/apps/qubit/modules/informationobject/templates/_treeView.php
   trunk/css/graphic.css
   trunk/js/treeView.js

Modified: 
trunk/apps/qubit/modules/informationobject/actions/treeViewAction.class.php
==============================================================================
--- trunk/apps/qubit/modules/informationobject/actions/treeViewAction.class.php 
Mon Jun 25 11:04:00 2012        (r11802)
+++ trunk/apps/qubit/modules/informationobject/actions/treeViewAction.class.php 
Mon Jun 25 16:49:26 2012        (r11803)
@@ -19,12 +19,80 @@
 
 class InformationObjectTreeViewAction extends sfAction
 {
+  const SIBLINGS = 10;
+
   public function execute($request)
   {
-    $this->response->setHttpHeader('Content-Type', 'application/json; 
charset=utf-8');
+    if (isset($this->getRoute()->resource))
+    {
+      $this->resource = $this->getRoute()->resource;
+    }
+    else
+    {
+      $this->resource = QubitInformationObject::getRoot();
+    }
+
+    $sql = 'SELECT
+        io.*,
+        i18n.*,
+        slug.slug,
+        pubstat.status_id as publication_status_id
+      FROM '.QubitInformationObject::TABLE_NAME.' io
+      JOIN '.QubitInformationObjectI18n::TABLE_NAME.' i18n
+        ON io.id = i18n.id
+      JOIN '.QubitSlug::TABLE_NAME.' slug
+        ON io.id = slug.object_id
+      JOIN '.QubitStatus::TABLE_NAME.' pubstat
+        ON io.id = pubstat.object_id
+      WHERE
+        io.parent_id = ?
+        AND i18n.culture = ?';
+
+    switch ($request->show)
+    {
+      case 'all':
+      case 'item':
+      default:
+
+        $sql .= '
+          ORDER BY io.lft ASC
+          LIMIT '.self::SIBLINGS;
+
+        $this->items = QubitPdo::fetchAll($sql, array(
+          $this->resource->id,
+          $this->context->user->getCulture()));
+
+        break;
+
+      case 'nextSiblings':
+
+        $sql .= '
+            AND io.lft > ?
+          ORDER BY io.lft ASC
+          LIMIT '.self::SIBLINGS;
+
+        $this->items = QubitPdo::fetchAll($sql, array(
+          $this->resource->parentId,
+          $this->context->user->getCulture(),
+          $this->resource->lft));
+
+        break;
+
+      case 'prevSiblings':
+
+        $sql .= '
+            AND io.lft < ?
+          ORDER BY io.lft DESC
+          LIMIT '.self::SIBLINGS;
 
-    $this->resource = $this->getRoute()->resource;
+        // Notice usage of array_reverse to invert the order
+        $this->items = array_reverse(
+          QubitPdo::fetchAll($sql, array(
+            $this->resource->parentId,
+            $this->context->user->getCulture(),
+            $this->resource->lft)));
 
-    return 
$this->renderText(json_encode($this->resource->getChildYuiNodes($request)));
+        break;
+    }
   }
 }

Modified: 
trunk/apps/qubit/modules/informationobject/actions/treeViewComponent.class.php
==============================================================================
--- 
trunk/apps/qubit/modules/informationobject/actions/treeViewComponent.class.php  
    Mon Jun 25 11:04:00 2012        (r11802)
+++ 
trunk/apps/qubit/modules/informationobject/actions/treeViewComponent.class.php  
    Mon Jun 25 16:49:26 2012        (r11803)
@@ -19,26 +19,154 @@
 
 class InformationObjectTreeViewComponent extends sfComponent
 {
+  const SIBLINGS = 10;
+
   public function execute($request)
   {
     $this->resource = $request->getAttribute('sf_route')->resource;
+    $this->parent = $this->resource->parent;
+
+    $this->treeview = array();
+
+    // Find ancestors
+    $sql = 'SELECT
+        io.*,
+        i18n.*,
+        slug.slug,
+        pubstat.status_id as publication_status_id
+      FROM '.QubitInformationObject::TABLE_NAME.' io
+      JOIN '.QubitInformationObjectI18n::TABLE_NAME.' i18n
+        ON io.id = i18n.id
+      JOIN '.QubitSlug::TABLE_NAME.' slug
+        ON io.id = slug.object_id
+      JOIN '.QubitStatus::TABLE_NAME.' pubstat
+        ON io.id = pubstat.object_id
+      WHERE
+        io.id != '.QubitInformationObject::ROOT_ID.'
+        AND i18n.culture = ?
+        AND io.lft < ?
+        AND io.rgt > ?
+      ORDER BY io.lft';
+
+    $this->treeview['ancestors'] = QubitPdo::fetchAll($sql, array(
+      $this->context->user->getCulture(),
+      $this->resource->lft,
+      $this->resource->rgt));
+
+    // Previous N siblings
+    $sql = 'SELECT
+        io.*,
+        i18n.*,
+        slug.slug,
+        pubstat.status_id as publication_status_id
+      FROM '.QubitInformationObject::TABLE_NAME.' io
+      JOIN '.QubitInformationObjectI18n::TABLE_NAME.' i18n
+        ON io.id = i18n.id
+      JOIN '.QubitSlug::TABLE_NAME.' slug
+        ON io.id = slug.object_id
+      JOIN '.QubitStatus::TABLE_NAME.' pubstat
+        ON io.id = pubstat.object_id
+      WHERE
+        io.parent_id = ?
+        AND i18n.culture = ?
+        AND io.lft < ?
+      ORDER BY io.lft DESC
+      LIMIT '.self::SIBLINGS;
 
-    // Get tree (limit 10 siblings and children)
-    $this->treeViewObjects = $this->resource->getFullYuiTree(10);
+    // Notice usage of array_reverse to invert the order
+    $this->treeview['prevSiblings'] = array_reverse(
+      QubitPdo::fetchAll($sql, array(
+        $this->resource->parentId,
+        $this->context->user->getCulture(),
+        $this->resource->lft)));
 
-    // Check if tree view worth it
-    if (1 > count($this->treeViewObjects))
+    // Next N siblings
+    $sql = 'SELECT
+        io.*,
+        i18n.*,
+        slug.slug,
+        pubstat.status_id as publication_status_id
+      FROM '.QubitInformationObject::TABLE_NAME.' io
+      JOIN '.QubitInformationObjectI18n::TABLE_NAME.' i18n
+        ON io.id = i18n.id
+      JOIN '.QubitSlug::TABLE_NAME.' slug
+        ON io.id = slug.object_id
+      JOIN '.QubitStatus::TABLE_NAME.' pubstat
+        ON io.id = pubstat.object_id
+      WHERE
+        io.parent_id = ?
+        AND i18n.culture = ?
+        AND io.lft > ?
+      ORDER BY io.lft ASC
+      LIMIT '.self::SIBLINGS;
+
+    $this->treeview['nextSiblings'] = QubitPdo::fetchAll($sql, array(
+      $this->resource->parentId,
+      $this->context->user->getCulture(),
+      $this->resource->lft));
+
+    // Slice prevSiblings and nextSiblings arrays
+    $prevSiblingsCount = count($this->treeview['prevSiblings']);
+    $nextSiblingsCount = count($this->treeview['nextSiblings']);
+
+    // Half part of total of siblings to be shown
+    $half = floor(self::SIBLINGS / 2);
+
+    // Calculate number of items to slice from prevSiblings
+    if ($prevSiblingsCount < self::SIBLINGS)
     {
-      return sfView::NONE;
+      $prevSiblingsSlice = $prevSiblingsCount - $half;
+
+      if ($prevSiblingsSlice < 0)
+      {
+        $prevSiblingsSlice = 0;
+      }
+    }
+    else if ($prevSiblingsCount == self::SIBLINGS)
+    {
+      if ($nextSiblingsCount < $half)
+      {
+        $prevSiblingsSlice = $nextSiblingsCount;
+      }
+      else
+      {
+        $prevSiblingsSlice = $half;
+      }
     }
 
-    $this->treeViewExpands = array();
-    foreach ($this->resource->ancestors->andSelf()->orderBy('lft') as $item)
+    // Calculate number of items to slice from nextSiblings
+    if ($nextSiblingsCount < self::SIBLINGS)
+    {
+      $nextSiblingsSlice = $nextSiblingsCount - $half;
+
+      if ($nextSiblingsSlice < 0)
+      {
+        $nextSiblingsSlice = 0;
+      }
+    }
+    else if ($nextSiblingsCount == self::SIBLINGS)
     {
-      $this->treeViewExpands[$item->id] = $item->id;
+      if ($prevSiblingsCount < $half)
+      {
+        $nextSiblingsSlice = $prevSiblingsCount;
+      }
+      else
+      {
+        $nextSiblingsSlice = $half;
+      }
+    }
+
+    function array_cut($operation, &$array, $iterate)
+    {
+      while (($iterate--) != false)
+      {
+        call_user_func_array("array_$operation", array(&$array));
+      }
+
+      return $array;
     }
 
-    // Is it draggable?
-    $this->treeViewDraggable = 
json_encode(QubitAcl::check(QubitInformationObject::getRoot(), 'update'));
+    array_cut('shift', $this->treeview['prevSiblings'], $prevSiblingsSlice);
+    array_cut('pop', $this->treeview['nextSiblings'], $nextSiblingsSlice);
   }
 }

Modified: trunk/apps/qubit/modules/informationobject/templates/_treeView.php
==============================================================================
--- trunk/apps/qubit/modules/informationobject/templates/_treeView.php  Mon Jun 
25 11:04:00 2012        (r11802)
+++ trunk/apps/qubit/modules/informationobject/templates/_treeView.php  Mon Jun 
25 16:49:26 2012        (r11803)
@@ -1,20 +1,59 @@
-<?php use_helper('Javascript') ?>
+<div id="treeview" data-current-id="<?php echo $resource->id ?>">
 
-<div class="section">
-  <div id="treeView"></div>
-</div>
+  <ul class="unstyled">
+    <li class="back" style="<?php echo QubitInformationObject::ROOT_ID == 
$resource->parentId ? 'display: none;' : '' ?>" data-xhr-location="<?php echo 
url_for(array('module' => 'informationobject', 'action' => 'treeView')) ?>">
+      <i></i>
+      <?php echo link_to(__('Show all'), array('module' => 
'informationobject', 'action' => 'browse')) ?>
+    </li>
+
+    <?php foreach ($treeview['ancestors'] as $item): ?>
+      <li class="ancestor" data-xhr-location="<?php echo 
url_for(array('module' => 'informationobject', 'action' => 'treeView', 'slug' 
=> $item->slug)) ?>">
+        <i></i>
+        <?php echo link_to($item->title, array('module' => 
'informationobject', 'slug' => $item->slug)) ?>
+        <strong>LOD</strong>
+      </li>
+    <?php endforeach; ?>
+
+    <?php if (isset($treeview['prevSiblings']) && 0 < 
count($treeview['prevSiblings'])): ?>
+      <?php if (1 < $treeview['prevSiblings'][0]->lft - $parent->lft): ?>
+        <li class="more" data-xhr-location="<?php echo url_for(array('module' 
=> 'informationobject', 'action' => 'treeView', 'slug' => 
$treeview['prevSiblings'][0]->slug)) ?>">
+          <a href="#">...</a>
+        </li>
+      <?php endif; ?>
+    <?php endif; ?>
+
+    <?php foreach ($treeview['prevSiblings'] as $prev): ?>
+      <?php $expand = 1 < $prev->rgt - $prev->lft ?>
+      <li class="<?php if ($expand) echo 'expand' ?>" data-xhr-location="<?php 
echo url_for(array('module' => 'informationobject', 'action' => 'treeView', 
'slug' => $prev->slug)) ?>">
+        <?php if ($expand) echo '<i></i>' ?>
+        <?php echo link_to($prev->title, array('module' => 
'informationobject', 'slug' => $prev->slug)) ?>
+        <strong>LOD</strong>
+      </li>
+    <?php endforeach; ?>
 
-<?php
+    <?php $expand = 1 < $resource->rgt - $resource->lft ?>
+    <li class="<?php if ($expand) echo 'expand' ?> active" 
data-xhr-location="<?php echo url_for(array($resource, 'module' => 
'informationobject', 'action' => 'treeView')) ?>">
+      <?php if ($expand) echo '<i></i>' ?>
+      <?php echo link_to($resource->title, array($resource, 'module' => 
'informationobject')) ?>
+      <strong>LOD</strong>
+    </li>
 
-$treeViewObjects = json_encode($treeViewObjects);
-$treeViewExpands = json_encode($treeViewExpands);
-$treeViewI18nLoading = __('Loading...');
-
-echo javascript_tag(<<<content
-Qubit.treeView.objects = $treeViewObjects;
-Qubit.treeView.expands = $treeViewExpands;
-Qubit.treeView.draggable = $treeViewDraggable;
-Qubit.treeView.i18nLoading = '$treeViewI18nLoading';
+    <?php foreach ($treeview['nextSiblings'] as $next): ?>
+      <?php $expand = 1 < $next->rgt - $next->lft ?>
+      <li class="<?php if ($expand) echo 'expand' ?>" data-xhr-location="<?php 
echo url_for(array('module' => 'informationobject', 'action' => 'treeView', 
'slug' => $next->slug)) ?>">
+        <?php if ($expand) echo '<i></i>' ?>
+        <?php echo link_to($next->title, array('module' => 
'informationobject', 'slug' => $next->slug)) ?>
+        <strong>LOD</strong>
+      </li>
+    <?php endforeach; ?>
 
-content
-);
+    <?php $last = isset($next) ? $next : $resource ?>
+    <?php if ($parent->rgt - $last->rgt > 1): ?>
+      <li class="more" data-xhr-location="<?php echo url_for(array('module' => 
'informationobject', 'action' => 'treeView', 'slug' => $last->slug)) ?>">
+        <a href="#">...</a>
+      </li>
+    <?php endif; ?>
+
+  </ul>
+
+</div>

Added: trunk/apps/qubit/modules/informationobject/templates/treeViewSuccess.php
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ trunk/apps/qubit/modules/informationobject/templates/treeViewSuccess.php    
Mon Jun 25 16:49:26 2012        (r11803)
@@ -0,0 +1,22 @@
+<?php if ('prevSiblings' == $sf_request->show && 0 < count($items) && 1 < 
($items[0]->lft - $resource->parent->lft)): ?>
+  <li class="more" data-xhr-location="<?php echo url_for(array('module' => 
'informationobject', 'action' => 'treeView', 'slug' => $items[0]->slug)) ?>">
+    <a href="#">...</a>
+  </li>
+<?php endif; ?>
+
+<?php foreach ($items as $item): ?>
+  <?php $expand = 1 < $item->rgt - $item->lft ?>
+  <li class="<?php if ($expand) echo 'expand' ?><?php if 
($sf_request->resourceId == $item->id) echo ' active' ?>" 
data-xhr-location="<?php echo url_for(array('module' => 'informationobject', 
'action' => 'treeView', 'slug' => $item->slug)) ?>">
+    <?php if ($expand) echo '<i></i>' ?>
+    <?php echo link_to($item->title, array('module' => 'informationobject', 
'slug' => $item->slug)) ?> <strong>LOD</strong>
+  </li>
+<?php endforeach; ?>
+
+<?php if ('prevSiblings' != $sf_request->show): ?>
+  <?php $parent = 'item' == $sf_request->show || 
QubitInformationObject::ROOT_ID == $resource->id ? $resource : 
$resource->parent ?>
+  <?php if ($parent->rgt - $item->rgt > 1): ?>
+    <li class="more" data-xhr-location="<?php echo url_for(array('module' => 
'informationobject', 'action' => 'treeView', 'slug' => $item->slug)) ?>">
+      <a href="#">...</a>
+    </li>
+  <?php endif; ?>
+<?php endif; ?>

Modified: trunk/css/graphic.css
==============================================================================
--- trunk/css/graphic.css       Mon Jun 25 11:04:00 2012        (r11802)
+++ trunk/css/graphic.css       Mon Jun 25 16:49:26 2012        (r11803)
@@ -247,3 +247,101 @@
 
   font-weight: bold;
 }
+
+/*********************************************************
+             TREEVIEW
+**********************************************************/
+
+#treeview
+{
+  max-height: 600px;
+  overflow: auto;
+  overflow-x: hidden;
+}
+
+#treeview ul
+{
+  margin: 0;
+  padding: 0;
+}
+
+#treeview li
+{
+  padding: 5px 0 5px 20px;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  overflow: hidden;
+}
+
+#treeview .ancestor
+{
+  background-color: #eee;
+}
+
+#treeview .back
+{
+  background: #ddd;
+}
+
+#treeview .back,
+#treeview .ancestor
+{
+  border-bottom: 1px solid #ccc;
+}
+
+#treeview .expand,
+#treeview .ancestor,
+#treeview .back
+{
+  padding-left: 0px;
+}
+
+#treeview .active
+{
+  font-weight: bold;
+}
+
+#treeview .more a
+{
+  background-color: #ccc;
+  padding: 0 8px;
+  font-weight: bold;
+  color: white !important;
+  text-decoration: none !important;
+  -webkit-border-radius: 2px;
+     -moz-border-radius: 2px;
+          border-radius: 2px;
+}
+
+#treeview i
+{
+  display: inline-block;
+  width: 10px;
+  height: 10px;
+  vertical-align: middle;
+  margin-right: 2px;
+  margin-left: 5px;
+  background-color: transparent;
+  background-image: url(../images/arrow-sprites.png);
+  background-repeat: no-repeat;
+  cursor: pointer;
+}
+
+#treeview .ancestor i { background-position: -10px 0px; } /* left */
+#treeview .immediate-ancestor i { background-position: 0px 0px; } /* left */
+#treeview .back i { background-position: -10px 0px; } /* left */
+#treeview .expand i { background-position: -20px 0px; } /* right */
+
+#treeview a:hover
+{
+  color: #0069d6;
+}
+
+
+
+
+
+
+
+
+

Added: trunk/images/arrow-sprites.png
==============================================================================
Binary file. No diff available.

Modified: trunk/js/treeView.js
==============================================================================
--- trunk/js/treeView.js        Mon Jun 25 11:04:00 2012        (r11802)
+++ trunk/js/treeView.js        Mon Jun 25 16:49:26 2012        (r11803)
@@ -1,294 +1,454 @@
-// $Id$
+/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net)
+ * Licensed under the MIT License (LICENSE.txt).
+ *
+ * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
+ * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
+ * Thanks to: Seamus Leahy for adding deltaX and deltaY
+ *
+ * Version: 3.0.6
+ *
+ * Requires: 1.2.2+
+ */
+
+(function($) {
+
+var types = ['DOMMouseScroll', 'mousewheel'];
+
+if ($.event.fixHooks) {
+    for ( var i=types.length; i; ) {
+        $.event.fixHooks[ types[--i] ] = $.event.mouseHooks;
+    }
+}
+
+$.event.special.mousewheel = {
+    setup: function() {
+        if ( this.addEventListener ) {
+            for ( var i=types.length; i; ) {
+                this.addEventListener( types[--i], handler, false );
+            }
+        } else {
+            this.onmousewheel = handler;
+        }
+    },
 
-(function ($)
-  {
-    Qubit.treeView = Qubit.treeView || {};
+    teardown: function() {
+        if ( this.removeEventListener ) {
+            for ( var i=types.length; i; ) {
+                this.removeEventListener( types[--i], handler, false );
+            }
+        } else {
+            this.onmousewheel = null;
+        }
+    }
+};
 
-    Drupal.behaviors.treeView = {
-      attach: function (context)
-        {
-          // Build tree function
-          function build(objects, expands, parentId, parentNode)
-          {
-            while (objects.length > 0 && objects[0].parentId == parentId)
-            {
-              var object = objects.shift();
-              var textNode = new YAHOO.widget.TextNode(object, parentNode, 
expands[object.id] !== undefined);
-              textNode.isLeaf = object.isLeaf;
-              textNode.moveUrl = object.moveUrl;
-              textNode.expandUrl = object.expandUrl;
-
-              if (object.style == 'ygtvlabel currentTextNode')
-              {
-                textNode.highlight();
-                Qubit.treeView.currentNodeId = object.id;
-              }
+$.fn.extend({
+    mousewheel: function(fn) {
+        return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
+    },
 
-              addDragNDrop(textNode, parentNode);
+    unmousewheel: function(fn) {
+        return this.unbind("mousewheel", fn);
+    }
+});
 
-              build(objects, expands, object.id, textNode);
-            }
-          }
 
-          function loadNodeData(node, fnLoadComplete)
-          {
-            var nodeId = node.data.id;
+function handler(event) {
+    var orgEvent = event || window.event, args = [].slice.call( arguments, 1 
), delta = 0, returnValue = true, deltaX = 0, deltaY = 0;
+    event = $.event.fix(orgEvent);
+    event.type = "mousewheel";
 
-            if (Qubit.treeView.expands[nodeId])
-            {
-              return fnLoadComplete();
-            }
+    // Old school scrollwheel delta
+    if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta/120; }
+    if ( orgEvent.detail     ) { delta = -orgEvent.detail/3; }
 
-            jQuery.ajax({
+    // New school multidimensional scroll (touchpads) deltas
+    deltaY = delta;
 
-              data: { limit: 10 },
-              dataType: 'json',
-              timeout: 15000,
-              url: node.expandUrl,
-
-              error: fnLoadComplete,
-
-              success: function (data)
-                {
-                  for (var i = 0; i < data.length; i++)
-                  {
-                    var textNode = new YAHOO.widget.TextNode(data[i], node, 
false);
-                    textNode.isLeaf = data[i].isLeaf;
-                    textNode.moveUrl = data[i].moveUrl;
-                    textNode.expandUrl = data[i].expandUrl;
-
-                    if (Qubit.treeView.currentNodeId == data[i].id)
-                    {
-                      textNode.labelStyle = 'ygtvlabel currentTextNode';
-                    }
-
-                    addDragNDrop(textNode, node);
-                  }
-
-                  return fnLoadComplete();
-                }
-              });
-            }
+    // Gecko
+    if ( orgEvent.axis !== undefined && orgEvent.axis === 
orgEvent.HORIZONTAL_AXIS ) {
+        deltaY = 0;
+        deltaX = -1*delta;
+    }
 
-            function addDragNDrop(textNode, parentNode)
-            {
-              var dd = new YAHOO.util.DDProxy(textNode.labelElId);
+    // Webkit
+    if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = 
orgEvent.wheelDeltaY/120; }
+    if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = 
-1*orgEvent.wheelDeltaX/120; }
 
-              dd.invalidHandleTypes = {};
+    // Add event and delta to the front of the arguments
+    args.unshift(event, delta, deltaX, deltaY);
 
-              dd.clickValidator = function (event)
-                {
-                  if (!Qubit.treeView.draggable || textNode.parent.isRoot())
-                  {
-                    YAHOO.util.Event.preventDefault(event);
+    return ($.event.dispatch || $.event.handle).apply(this, args);
+}
 
-                    return false;
-                  }
+})(jQuery);
 
-                  return true;
-                };
 
-              dd.onDragDrop = function (event, id)
-                {
-                  var newParent = parentNode.tree.getNodeByElement($('#' + 
id)[0]);
+(function ($) {
 
-                  if (parentNode.contentElId == newParent.contentElId)
-                  {
-                    return false;
-                  }
+  "use strict";
 
-                  if ($(textNode.getEl()).has(newParent.getEl()).length)
-                  {
-                    return false;
-                  }
+  /**
+   * Debounces a function. Returns a function that calls the original fn 
function only if no invocations have been made
+   * within the last quietMillis milliseconds.
+   *
+   * @param quietMillis number of milliseconds to wait before invoking fn
+   * @param fn function to be debounced
+   * @return debounced version of fn
+   */
+  function debounce (quietMillis, fn)
+  {
+    var timeout;
+    return function ()
+      {
+        window.clearTimeout(timeout);
+        timeout = window.setTimeout(fn, quietMillis);
+      };
+  }
 
-                  jQuery.ajax({
-                    data: { parent: newParent.href },
-                    type: 'POST',
-                    url: textNode.moveUrl
-                  });
+  function killEvent (event)
+  {
+    event.preventDefault();
+    event.stopPropagation();
+  }
 
-                  parentNode.tree.popNode(textNode);
+  function indexOf (value, array)
+  {
+    var i = 0, l = array.length, v;
 
-                  if (!parentNode.hasChildren())
-                  {
-                    parentNode.isLeaf = true;
-                  }
+    if (typeof value === "undefined")
+    {
+      return -1;
+    }
+
+    if (value.constructor === String)
+    {
+      for (; i < l; i = i + 1)
+      {
+        if (value.localeCompare(array[i]) === 0)
+        {
+          return i;
+        }
+      }
+    }
+    else
+    {
+      for (; i < l; i = i + 1)
+      {
+        v = array[i];
+        if (v.constructor === String)
+        {
+          if (v.localeCompare(value) === 0)
+          {
+            return i;
+          }
+        }
+        else
+        {
+          if (v === value)
+          {
+            return i;
+          }
+        }
+      }
+    }
 
-                  parentNode.refresh();
+    return -1;
+  }
 
-                  $('.ygtvlabel', '#' + 
parentNode.getChildrenElId()).each(function ()
-                    {
-                      var dd = 
YAHOO.util.DragDropMgr.getDDById($(this).attr('id'));
+  var Treeview = function (element)
+    {
+      this.$element = element;
+      this.$showAllButton = this.$element.find('li:first');
+      this.loading = false;
+
+      // Store the current resource id to highlight it
+      // during the treeview browsing
+      this.resourceId = this.$element.data('current-id');
 
-                      dd.unreg();
+      this.init();
+    };
 
-                      dd.init($(this).attr('id'));
+  Treeview.prototype = {
 
-                      dd.invalidHandleTypes = {};
-                    });
+    constructor: Treeview,
 
-                  if (newParent.expanded)
-                  {
-                    textNode.appendTo(newParent);
+    init: function()
+      {
+        this.$element
+          .on('click.treeview.qubit', 'li', $.proxy(this.click, this))
+          .bind('scroll', $.proxy(this.scroll, this))
+          .bind('scroll-debounced', $.proxy(this.debouncedScroll, this))
 
-                    newParent.refresh();
+        // Prevent out-of-bounds scrollings via mousewheel
+        if ($.fn.mousewheel)
+        {
+          this.$element.bind('mousewheel', $.proxy(this.mousewheel, this));
+        }
 
-                    $('.ygtvlabel', '#' + 
newParent.getChildrenElId()).each(function ()
-                      {
-                        var dd = 
YAHOO.util.DragDropMgr.getDDById($(this).attr('id'));
+        var self = this;
+        this.notify = debounce(80, function (e)
+          {
+            self.$element.trigger('scroll-debounced', e);
+          });
 
-                        dd.unreg();
+        this.highlightLastAncestor();
+      },
 
-                        dd.init($(this).attr('id'));
+    mousewheel: function(e, delta, deltaX, deltaY)
+      {
+        var top = this.$element.scrollTop(), height;
+        if (deltaY > 0 && top - deltaY <= 0)
+        {
+          this.$element.scrollTop(0);
+          killEvent(e);
+        }
+        else if (deltaY < 0 && this.$element.get(0).scrollHeight - 
this.$element.scrollTop() + deltaY <= this.$element.height())
+        {
+          this.$element.scrollTop(this.$element.get(0).scrollHeight - 
this.$element.height());
+          killEvent(e);
+        }
+      },
 
-                        dd.invalidHandleTypes = {};
-                      });
-                  }
-                  else if (newParent.isLeaf)
-                  {
-                    newParent.isLeaf = false;
-                    newParent.refresh();
-                    newParent.applyParent();
-                    newParent.childrenRendered = false;
-                  }
-                };
+    scroll: function (e)
+      {
+        if (indexOf(e.target, this.$element.get()) >= 0)
+        {
+          this.notify(e);
+        }
+      },
+
+    debouncedScroll: function (e)
+      {
+        var $target = $(e.target);
+
+        e.preventDefault();
+
+        // Detect when users scrolls to the bottom
+        if ($target.scrollTop() + $target.innerHeight() >= 
$target.get(0).scrollHeight)
+        {
+          var self = this;
 
-            dd.onDragOver = function (event, id)
+          // Delay the trigger
+          window.setTimeout(function()
             {
-              var dest = $('#' + id);
-              var destEl = parentNode.tree.getNodeByElement(dest[0]);
-              var el = parentNode.tree.getNodeByElement(this.getEl());
+              self.$element.find('li.more:last').trigger('click');
+            }, 250);
+        }
+      },
+
+    click: function (e)
+      {
+        if (this.loading)
+        {
+          return;
+        }
+
+        var $li = 'LI' === e.target.tagName ? $(e.target) : 
$(e.target).closest('li');
 
-              if (el.parent.getElId() == destEl.getElId() || 
dest.hasClass('currentTextNode'))
-              {
-                return false;
-              }
+        if ($li.hasClass('more'))
+        {
+          killEvent(e);
+
+          return this.showMore($li);
+        }
+        else if ('I' === e.target.tagName)
+        {
+          if ($li.hasClass('back'))
+          {
+            return this.showAll($li);
+          }
+          else if ($li.hasClass('ancestor'))
+          {
+            if (!$li.next().hasClass('ancestor'))
+            {
+              return this;
+            }
 
-              if ($(el.getEl()).has(destEl.getEl()).length)
-              {
-                return false;
-              }
+            return this.showAncestor($li);
+          }
+          else if ($li.hasClass('expand'))
+          {
+            return this.showItem($li);
+          }
+        }
 
-              dest.addClass('onDragOver');
-            };
+        return this;
+      },
 
-            dd.onDragOut = function (event, id)
+    showAll: function ($element)
+      {
+        $.ajax({
+          url: $element.data('xhr-location'),
+          context: this,
+          dataType: 'html',
+          data: { show: 'all', resourceId: this.resourceId },
+          beforeSend: function ()
+            {
+              this.loading = true;
+            },
+          success: function (data)
+            {
+              $element
+                .hide()
+                .nextAll().remove().end()
+                .after(data);
+
+              this.highlightLastAncestor();
+            },
+          complete: function ()
             {
-              $('#' + id).removeClass('onDragOver');
-            };
+              this.loading = false;
+            },
+          error: function ()
+            {
+            }
+          });
+
+        return this;
+      },
 
-            dd.startDrag = function()
+    showItem: function($element)
+      {
+        $.ajax({
+          url: $element.data('xhr-location'),
+          context: this,
+          dataType: 'html',
+          data: { show: 'item', resourceId: this.resourceId },
+          beforeSend: function ()
             {
-              var el = $(this.getEl());
-              var proxyEl = $(this.getDragEl());
+              this.loading = true;
+            },
+          success: function (data)
+            {
+              this.$showAllButton
+
+                // Show "Show all" button
+                .show()
+
+                // Move cursor to last ancestor
+                .nextAll(':not(.ancestor,.showall):first').prev()
 
-              el.addClass('onDrag');
-              proxyEl.html(el.html());
-              proxyEl.addClass('proxyTextNode');
-            };
+                // Remove all siblings below
+                .nextAll().remove().end()
 
-            dd.endDrag = function ()
+                // Add new nodes
+                .after(data)
+
+                // Expanded node becomes now an ancestor
+                .after($element).next()
+                .removeClass('expand').addClass('ancestor');
+
+              this.highlightLastAncestor();
+            },
+          complete: function ()
             {
-              $(this.getEl()).removeClass('onDrag');
-            };
-          }
+              this.loading = false;
+            },
+          error: function ()
+            {
+            }
+          });
 
-          function seeAll(oArgs)
-          {
-            var node = oArgs.node;
-            var parentNode = node.parent;
+        return this;
+      },
 
-            if 
(jQuery(node.getContentEl()).children('a').is('.seeAllNode.XmlHttpRequest'))
+    showAncestor: function($element)
+      {
+        $.ajax({
+          url: $element.data('xhr-location'),
+          context: this,
+          dataType: 'html',
+          data: { show: 'item', resourceId: this.resourceId },
+          beforeSend: function ()
             {
-              // If current object is the last in the treeview, it may be out
-              // proper order, so reload data from position 9 (offset 8)
-              var offset = 10;
-              var lastChild = 
parentNode.children[parentNode.children.length-2];
-              if (Qubit.treeView.currentNodeId == lastChild.data.id)
-              {
-                offset = 9;
-              }
-
-              // Show loading text
-              
$(node.getContentEl()).children('a').text(Qubit.treeView.i18nLoading);
-
-              // Mark node as loading
-              node.isLoading = true;
-              node.tree.locked = true;
-              
$(node.getToggleEl()).addClass('ygtvloading').removeClass('ygtvln');
-
-              jQuery.ajax({
-                data: { 'offset': offset },
-                dataType: 'json',
-                url: parentNode.expandUrl,
-
-                success: function (data)
-                  {
-                    if (9 == offset)
-                    {
-                      Qubit.treeView.treeView.removeNode(lastChild);
-                    }
-
-                    for (var i = 0; i < data.length; i++)
-                    {
-                      var textNode = new YAHOO.widget.TextNode(data[i], 
parentNode, false);
-                      textNode.isLeaf = data[i].isLeaf;
-                      textNode.moveUrl = data[i].moveUrl;
-                      textNode.expandUrl = data[i].expandUrl;
-
-                      if (Qubit.treeView.currentNodeId == data[i].id)
-                      {
-                        textNode.labelStyle = 'ygtvlabel currentTextNode';
-                        textNode.highlight();
-                      }
-                    }
-
-                    // Turn off loading state
-                    node.isLoading = false;
-                    node.tree.locked = false;
-
-                    Qubit.treeView.treeView.removeNode(node);
-
-                    for (i in parentNode.children)
-                    {
-                      addDragNDrop(parentNode.children[i], parentNode);
-                    }
-
-                    parentNode.refresh();
-                  }
-              });
+              this.loading = true;
+            },
+          success: function (data)
+            {
+              $element
+
+                // Remove all the nodes below
+                .nextAll().remove().end()
+
+                // Add new nodes
+                .after(data);
 
-              // Don't jump to the top of the page (default behaviour)
-              oArgs.event.preventDefault();
+              this.highlightLastAncestor();
+            },
+          complete: function ()
+            {
+              this.loading = false;
+            },
+          error: function ()
+            {
             }
-          }
+          });
 
-          try
-          {
-            // Create a new tree
-            Qubit.treeView.treeView = new YAHOO.widget.TreeView('treeView');
-          }
-          catch (err)
-          {
-            return false;
-          }
+        return this;
+      },
 
-          // Turn dynamic loading on for entire tree
-          Qubit.treeView.treeView.setDynamicLoad(loadNodeData);
+    showMore: function($element)
+      {
+        var $a = $element.find('a');
+        var loadingId = window.setInterval(function()
+          {
+            $a.append('.');
+          }, 125);
 
-          // On click listener for 'See all' behaviour
-          Qubit.treeView.treeView.subscribe("clickEvent", seeAll);
+        $.ajax({
+          url: $element.data('xhr-location'),
+          context: this,
+          dataType: 'html',
+          data: { show: !$element.next().length ? 'nextSiblings' : 
'prevSiblings', resourceId: this.resourceId },
+          beforeSend: function()
+            {
+              this.loading = true;
+            },
+          success: function (data)
+            {
+              $element.replaceWith(data);
 
-          // Build tree
-          build(Qubit.treeView.objects, Qubit.treeView.expands, 
Qubit.treeView.objects[0].parentId, Qubit.treeView.treeView.getRoot());
+              this.highlightLastAncestor();
+            },
+          complete: function ()
+            {
+              this.loading = false;
 
-          // Render tree
-          Qubit.treeView.treeView.render();
+              window.clearTimeout(loadingId);
+            },
+          error: function ()
+            {
+            }
+          });
+      },
 
-          // Enable logger (useful for debugging)
-          // $('body').prepend('<div id="logw" style="position: absolute; top: 
10px; left: 10px; width: 320px; height: 400px;"></div>');
-          // var myLogReader = new YAHOO.widget.LogReader("logw");
-        }
+    highlightLastAncestor: function()
+      {
+        // Unfortunately I couldn't do this with CSS
+        this.$element.find('.ancestor:last').addClass('immediate-ancestor');
+      }
+  };
+
+  $.fn.treeview = function()
+    {
+      var $this = this;
+      var data = $this.data('treeview');
+      if (!data)
+      {
+        $this.data('treeview', new Treeview(this));
+      }
     };
-  })(jQuery);
+
+  $.fn.treeview.Constructor = Treeview;
+
+  $(function ()
+    {
+      var $treeview = $('#treeview');
+      if (0 < $treeview.length)
+      {
+        $treeview.treeview();
+      }
+    });
+
+})(window.jQuery);

-- 
You received this message because you are subscribed to the Google Groups 
"Qubit Toolkit Commits" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/qubit-commits?hl=en.

Reply via email to