Index: ui/transformations_ui.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/transformations/ui/transformations_ui.info,v
retrieving revision 1.3
diff -u -r1.3 transformations_ui.info
--- ui/transformations_ui.info	30 Mar 2009 12:50:01 -0000	1.3
+++ ui/transformations_ui.info	12 Jun 2009 12:00:36 -0000
@@ -4,5 +4,7 @@
 package = Transformations
 dependencies[] = transformations
 dependencies[] = ctools
+dependencies[] = jquery_update
+dependencies[] = jquery_ui
 core = 6.x
 php = 5.2
Index: ui/transformations_ui.pipeline.edit.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/transformations/ui/transformations_ui.pipeline.edit.inc,v
retrieving revision 1.13
diff -u -r1.13 transformations_ui.pipeline.edit.inc
--- ui/transformations_ui.pipeline.edit.inc	9 Apr 2009 19:31:26 -0000	1.13
+++ ui/transformations_ui.pipeline.edit.inc	12 Jun 2009 12:00:37 -0000
@@ -119,11 +119,13 @@
   }
   $blocks[TfPipeline::Output]['input']['keys'][] = TfPipeline::NewOutboundConnection;
 
+  $jsOperations = array();
+  
   // Big pile of confusing code that generates the blocks and connection buttons.
   foreach ($blocks as $operationId => $block) {
     $operationElements[$operationId] = array(
       '#value' => '',
-      '#prefix' => '<div class="transformations-operation-block">'
+      '#prefix' => '<div  id="' . $operationId . '"  class="transformations-operation-block">'
         . '<div class="transformations-operation-block-table">',
       '#suffix' => '</div></div>',
     );
@@ -232,6 +234,7 @@
       '#suffix' => '</div>',
     );
 
+    $jsOperations[$operationId] = array();
     // Construct input/output connection elements, as form buttons.
     foreach (array('input', 'output') as $keyType) {
       $otherKeyType = ($keyType == 'input') ? 'output' : 'input';
@@ -366,6 +369,9 @@
           $description = '';
         }
 
+        $jsElement = array('key' => $key, 'keyType' => $keyType);
+        $jsOperations[$operationId][$elementId] = $jsElement;
+
         // The connector button for the input/output slot.
         $element = array(
           '#type' => 'submit',
@@ -377,7 +383,7 @@
           '#disabled' => $isEditingOperation &&
             (!$isConnectingTo[$otherKeyType] || $_GET['edit-op'] == $operationId),
           '#attributes' => array(),
-          '#prefix' => '<div class="transformations-operation-' . $keyType . '">',
+          '#prefix' => '<div   id="' . $elementId . '"  class="transformations-operation-' . $keyType . '">',
           '#suffix' => '</div>',
           '#submit' => array('transformations_ui_pipeline_operation_connect'),
         );
@@ -445,10 +451,19 @@
     } // end of foreach (array('input', 'output'))
   }
 
+
+  jquery_ui_add(array('ui.resizable', 'ui.resizable'));
+  jquery_ui_add(array('ui.draggable', 'ui.droppable'));
   // Add JavaScript and connection info enabling it to highlight opposite keys.
   drupal_add_js(drupal_get_path('module', 'transformations_ui') . '/transformations_ui.js');
   drupal_add_js(array('transformationsUiConnections' => $connectionElements), 'setting');
 
+  drupal_add_js(drupal_get_path('module', 'transformations_ui') . '/transfomations_operations.js');
+  drupal_add_js(drupal_get_path('module', 'transformations_ui') . '/transformations_pipeline_edit.js');
+
+  drupal_add_js(array('transformationsOperations' => $jsOperations), 'setting');  
+  drupal_add_js(array('transformationsPipeID' => $form['#pipeline_id']), 'setting');
+
   if (empty($operationElements)) {
     $form['operations'] = array(
       '#value' => t('No operations have yet been defined for this pipeline.'),
@@ -457,8 +472,8 @@
   else {
     $form['operations'] = array(
       '#value' => '',
-      '#prefix' => '<div class="clear-block transformations-operation-blocks">',
-      '#suffix' => '</div>',
+      '#prefix' => '<div id="transformations-operation-editPanel"  class="clear-block transformations-operation-blocks">',
+      '#suffix' => '<div class="ui-resizable-handle" id="transformations-grippie">v</div></div>',
     );
     $form['operations'] += $operationElements;
   }
Index: ui/transformations_ui.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/transformations/ui/transformations_ui.module,v
retrieving revision 1.7
diff -u -r1.7 transformations_ui.module
--- ui/transformations_ui.module	7 Apr 2009 10:20:58 -0000	1.7
+++ ui/transformations_ui.module	12 Jun 2009 12:00:36 -0000
@@ -108,6 +108,35 @@
     'type' => MENU_CALLBACK,
   ) + $base;
 
+  //Ajax callbacks  
+  $items['build/transformations/ajax/connect'] = array(
+    'title' => 'transformations_ajax_connect',
+    'page callback' => 'transformations_ui_pipeline_ajax_connect',
+    'type' => MENU_CALLBACK,
+    'file' => 'transformations_ui.pipeline.ajax.inc',
+  ) + $base;
+  
+  $items['build/transformations/ajax/disconnect'] = array(
+    'title' => 'transformations_ajax_disconnect',
+    'page callback' => 'transformations_ui_pipeline_ajax_disconnect',
+    'type' => MENU_CALLBACK,
+    'file' => 'transformations_ui.pipeline.ajax.inc',
+  ) + $base;
+  
+  $items['build/transformations/ajax/save_position'] = array(
+    'title' => 'transformations_ajax_save_position',
+    'page callback' => 'transformations_ui_ajax_save_position',
+    'type' => MENU_CALLBACK,
+    'file' => 'transformations_ui.pipeline.ajax.inc',
+  ) + $base;
+  
+  $items['build/transformations/ajax/get_position'] = array(
+    'title' => 'transformations_ajax_get_position',
+    'page callback' => 'transformations_ui_ajax_get_position',
+    'type' => MENU_CALLBACK,
+    'file' => 'transformations_ui.pipeline.ajax.inc',
+  ) + $base;
+  
   return $items;
 }
 
Index: ui/transformations_ui.css
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/transformations/ui/transformations_ui.css,v
retrieving revision 1.1
diff -u -r1.1 transformations_ui.css
--- ui/transformations_ui.css	19 Mar 2009 19:12:54 -0000	1.1
+++ ui/transformations_ui.css	12 Jun 2009 12:00:36 -0000
@@ -1,5 +1,17 @@
 /* $Id: transformations_ui.css,v 1.1 2009/03/19 19:12:54 jpetso Exp $ */
 
+#transformations-operation-editPanel{
+  position: relative;
+  width:100;
+  overflow: none;
+  border: 1px solid;
+  padding-bottom: 15px;
+}
+
+.transformations-ui-pipline-edit {
+  width: 100%; 
+}
+
 .transformations-operation-blocks {
   margin-top: 1em;
 }
@@ -10,7 +22,9 @@
 }
 
 .transformations-operation-block-table {
+  position:relative;
   display: table;
+  background-color:white;
   border: 2px silver solid;
   padding: 0;
   padding-top: 0.2em;
@@ -34,6 +48,7 @@
 
 .transformations-operation-block-header-cell div {
   display: inline;
+  cursor:pointer;
 }
 
 .transformations-operation-block-header-label {
@@ -106,19 +121,86 @@
   display: table-cell;
   vertical-align: top;
   padding-right: 10px;
+  width: 10em;
 }
 
 .transformations-operation-block-outputs {
-  display: table-cell;
+  float: right;
   vertical-align: top;
+  cursor: pointer;
 }
 
 .transformations-operation-output {
   text-align: right;
   clear: right;
+  width: 12em;
 }
 
 .transformations-operation-output input {
   text-align: right;
-  float: right;
+  display: inline;
+}
+
+.transformations-operation-output span{
+  color: black;
+  border: 1px solid;
+  cursor: pointer;
+ }
+
+
+.transformations-operation-input input{
+  display: inline;
 }
+
+.transformations-operation-input span{
+  margin-right: 5px;
+  border: 1px solid;
+}
+
+.transformations-operation-input a:link{
+  color: black;
+  text-decoration: none;
+}
+
+.transformations-operation-input a:visited{
+  color: black;
+  text-decoration: none;
+}
+
+.transformations-operation-input a:hover{
+  color: black;
+  text-decoration: none;
+}
+
+.transformations-element-drag{
+  text-align: right;
+  border: 1px solid brown;
+  padding-right: 20px;
+  background-color: #AA4444;
+}
+
+.transformations-operation-action{
+  cursor: pointer;
+}
+ 
+ .transformations-input-hover{
+  background-color: skyblue;
+}
+ 
+ .transformations-operation-output-draghelper{
+  font-size: 8pt;
+  width: 16px;
+  height: 16px;
+  text-align: center;
+  vertical-align: middle;
+}
+
+#transformations-grippie{
+  position: absolute;
+  bottom: 0px;
+  width: 100%;
+  background: #eeeeee;
+  border-top: 1px solid darkgrey;
+  text-align: center;
+  cursor: s-resize;
+}
\ No newline at end of file
Index: ui/transformations_ui.pipeline.ajax.inc
===================================================================
RCS file: ui/transformations_ui.pipeline.ajax.inc
diff -N ui/transformations_ui.pipeline.ajax.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ui/transformations_ui.pipeline.ajax.inc	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,117 @@
+<?php
+// $Id$
+/**
+ * @file
+ * Transformations UI -
+ * An interface for managing transformation pipelines.
+ * 
+ * 
+ */
+
+
+/**
+ * Connects a pipeline with parameters form javascript
+ * and saves it into the cache.
+ */
+function transformations_ui_pipeline_ajax_connect($pipeline_id, $output_opID, $output_key, $input_opID, $input_key) {
+  $pipeline = transformations_ui_persisted_pipeline_load($pipeline_id);
+  if (empty($pipeline)) {
+    print drupal_to_js(false); 
+    return;
+  }
+
+  if (isset($output_opID) && isset($output_key)) {
+    $source = array(
+      'entity' => $output_opID,
+      'key' => $output_key
+    );
+  }
+  else{
+    print drupal_to_js(false); 
+    return;
+  }
+
+  if (isset($input_opID) && isset($input_key)) {
+    $target = array(
+      'entity' => $input_opID,
+      'key' => $input_key
+    );
+  }
+  else{
+    print drupal_to_js(false); 
+    return;
+  }
+
+  $pipeline->connect($source['entity'], $source['key'], $target['entity'], $target['key']);
+  transformations_ui_pipeline_persist($pipeline);
+  
+  print drupal_to_js(true);
+}
+
+/**
+ * Disconnect a Parameter
+ */
+function transformations_ui_pipeline_ajax_disconnect($pipeline_id, $operationId, $key, $keyType){
+  $pipeline = transformations_ui_persisted_pipeline_load($pipeline_id);
+  if (empty($pipeline)) {
+    print drupal_to_js(false); 
+    return;
+  }
+
+  if (isset($operationId) && isset($key) && isset($keyType)) {
+    if ($keyType == 'input') {
+      $pipeline->disconnectTarget($operationId, $key);
+    }
+    elseif ($keyType == 'output') {
+      $pipeline->disconnectSource($operationId, $key);
+    }
+    transformations_ui_pipeline_persist($pipeline);
+    print drupal_to_js(true); 
+    return;
+  }else{
+    print drupal_to_js(false); 
+    return;
+  }
+}
+
+
+/**
+ * Saves the position of the moved operation
+ */
+function transformations_ui_ajax_save_position($pipeline_id, $operation_id, $z_index, $top, $left) {
+  $pipeline = transformations_ui_persisted_pipeline_load($pipeline_id);
+  if (empty($pipeline)) {
+    print drupal_to_js(false); 
+    return;
+  }
+
+  if (isset($top) && isset($left) && isset($operation_id)) {
+    $pipeline->setProperty('transformations_ui:position:' . $operation_id, array( 'z-index'=>$z_index, 'top'=>$top, 'left'=>$left));
+    transformations_ui_pipeline_persist($pipeline);
+    
+    print drupal_to_js(true); 
+    return;
+  }
+  else{
+    print drupal_to_js(false); 
+    return;    
+  } 
+}
+
+/**
+ * Get the Position of an operation
+ */
+function transformations_ui_ajax_get_position($pipeline_id, $operation_id) {
+  $pipeline = transformations_ui_persisted_pipeline_load($pipeline_id);
+  if (empty($pipeline)) {
+    print drupal_to_js(false); 
+    return;
+  }
+
+  if (!isset($operation_id)) {
+    print drupal_to_js(false); 
+    return;
+  }
+
+  print drupal_to_js($pipeline->property("transformations_ui:position:" . $operation_id));
+}
Index: ui/transformations_pipeline_edit.js
===================================================================
RCS file: ui/transformations_pipeline_edit.js
diff -N ui/transformations_pipeline_edit.js
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ui/transformations_pipeline_edit.js	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,144 @@
+// $Id$
+
+// OperationElement
+Drupal.transformationsUi_Element = function(id, type, key, operation_id){
+  this.id = id;
+  this.type = type;
+  this.key = key;
+  this.operation = operation_id;
+};
+
+// Grippey Object
+Drupal.transformationsUi_Grippie = function(){
+  this.object = '';
+  this.height = 0;
+}
+
+// Global JS vars
+var elements = new Array();
+var pipeId = null;
+var grippie = new Drupal.transformationsUi_Grippie();
+
+
+Drupal.behaviors.transformationsUiConnections = function() {
+  pipeId = Drupal.settings.transformationsPipeID;
+
+  var operations = Drupal.settings.transformationsOperations;
+
+  // Saves alle elements into a global array and replaces the submit buttons with divs and links.
+  for(var operationId in operations){
+    for(var elementId in operations[operationId]){
+      var element = operations[operationId][elementId];
+      elements[elementId] = new Drupal.transformationsUi_Element(elementId, element.keyType, element.key, operationId);
+      var input = '#'+elementId+" > input";
+      if(element.keyType == 'input' && operationId != '4'){
+        $(input).replaceWith("<span style='" + $(input).attr('style') 
+            + "' ><a href='?q=admin/build/transformations/" + pipeId 
+            + "/edit/input/" + operationId + "/" + element.key + "' >" 
+            + $(input).attr('value') + "</a></span>");
+      }
+      else{
+        var parent = $(input).parent();
+        var div = $(input).replaceWith("<span style='" + $(input).attr('style') 
+            + "' >" + $(input).attr('value') + "</span>");
+
+        // Disconnects two Elements by clicking on the output and reloads the page.
+        parent.children('span:first').click(function(){
+          var elementId = $(this).parent().attr('id');
+          var operationId = elements[elementId].operation;
+          var key = elements[elementId].key;
+          var type = elements[elementId].type;
+          
+          
+          var arguments = pipeId + '/' + operationId + '/' + key + '/' + type;  
+          $.get('?q=build/transformations/ajax/disconnect/' + arguments, null, function(data){
+            window.location.reload();
+          });
+        });
+      }
+    }
+
+  }
+
+  // This allows the user to resize to editPanel were the operation blocks lies.
+  // It works like the grippie from Drupal, but grippie is for textareas only;
+  $('#transformations-operation-editPanel').resizable({
+    maxWidth : $('#transformations-operation-editPanel').width(),
+    minWidth : $('#transformations-operation-editPanel').width(),
+    minHeight : $('#transformations-operation-editPanel').height(),
+    handles : { s : $('#transformations-grippie')}
+  });
+  Drupal.transformationsUi_initDragDrop();
+}
+
+
+/*
+ * Initialize all drag-&drop-able elements
+ */
+Drupal.transformationsUi_initDragDrop = function(){
+  //Set the position for each operation 
+  $("#transformations-operation-editPanel .transformations-operation-block").each(function(){
+    var div_operation = this.id;
+    var arguments = pipeId + "/" + this.id;
+    
+    $.get('?q=build/transformations/ajax/get_position/'+arguments, null, function(data){
+      var result = Drupal.parseJson(data);
+      $('#'+div_operation).css('top', result.top+'px');
+      $('#'+div_operation).css('left', result.left+'px');
+
+      // This looks for the lowest position and saves it with the operation id into the grippie object.
+      var top = $('#'+div_operation).position().top + $('#'+div_operation).height(); 
+      if(top > grippie.height){
+        grippie.height = top + 20;
+        grippie.object = div_operation;
+        $('#transformations-operation-editPanel').resizable('option', 'minHeight', grippie.height);
+        $('#transformations-operation-editPanel').css('height', grippie.height + "px");
+      }
+    });
+    
+  });
+
+  //Init all draggable operation blocks
+  $(".transformations-operation-block").draggable({
+    stack:{group:"#transformations-operation-editPanel .transformations-operation-block", min: 1},
+    containment: "parent", 
+    handle: ".transformations-operation-block-header-cell",
+    stop: function(event, ui){      
+      var arguments = pipeId + "/" + $(this).attr('id') + "/" + $(this).css('z-index')  + "/" + ui.position.top  + "/" + ui.position.left;
+      $.get('?q=build/transformations/ajax/save_position/'+arguments);
+
+      // If a operation block was moved, the minHeight from the editPanel might be also needed to so set, otherwise the user 
+      // will be able to drag a operation block out of the editPanel. The minHeight will also be set, if the lowest object was moved
+      var top = $(this).height()+$(this).position().top;
+      if(top > grippie.height){
+        grippie.height = top + 20;
+        grippie.object = $(this).attr('id');
+        $('#transformations-operation-editPanel').resizable('option', 'minHeight', grippie.height);
+      }
+    }
+  });
+
+  //Init all draggable outputs
+  $(".transformations-operation-output").draggable({
+    cursor: 'move',
+    helper: 'clone',
+    opacity: 0.5
+  });
+
+  //Init all droppable inputs
+  $(".transformations-operation-input").droppable({
+    hoverClass: 'transformations-input-hover',
+    drop: function(event, ui){
+      var idInput = $(this).attr('id');
+      var idOutput = $(ui.draggable).attr('id');
+      var input = elements[idInput];
+      var output = elements[idOutput];
+      if(input!=null && output!=null){        
+        arguments = pipeId + '/' + output.operation + '/' + output.key + '/' + input.operation + '/' + input.key;        
+        $.get('?q=build/transformations/ajax/connect/'+arguments,null,function(data){
+          window.location.reload();
+        });
+      }
+    }
+  });
+};
