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.