neyric/wireit

View on GitHub
src/terminal/js/terminal.js.old

Summary

Maintainability
Test Coverage
YUI.add("terminal", function (Y){

/**
 * Terminals represent the end points of the "wires"
 * @class Terminal
 * @constructor
 * @param {HTMLElement} parentEl Element that will contain the terminal
 * @param {Object} options Configuration object
 * @param {Container} container (Optional) Container containing this terminal
 */
Y.Terminal = function (parentEl, options, container) {

    /**
    * @attribute name
     * @description Name of the terminal
    * @type String
    * @default null
    */
    this.name = null;

   /**
    * @attribute parentEl
     * @description DOM parent element
    * @type DOMElement
    */
   this.parentEl = parentEl;
   
   /**
    * @attribute container
     * @description Container (optional). Parent container of this terminal
    * @type Y.Container
    */
   this.container = container;
   
   /**
    * @attribute wires
     * @description List of the associated wires
    * @type Array
    */
    this.wires = [];
   
   
   this.setOptions(options);
   
   /**
    * Event that is fired when a wire is added
    * You can register this event with myTerminal.on('eventAddWire',function (e,params) { var wire=params[0];}, scope);
    * @event eventAddWire
    */
   this.publish('eventAddWire');
   
   /**
    * Event that is fired when a wire is removed
    * You can register this event with myTerminal.on('eventRemoveWire', function (e,params) { var wire=params[0];}, scope);
    * @event eventRemoveWire
    */
   this.publish('eventRemoveWire');
   
   /**
    * DIV dom element that will display the Terminal
    * @attribute el
    * @type {HTMLElement}
    */
   this.el = null;
   
   
   this.render();
   
   // Create the TerminalProxy object to make the terminal editable
   if(this.editable) {
      
      // Make this terminal a drop target
      /*var drop = new Y.DD.Drop({ node: this.el });
      
      //this.dd = new Y.TerminalProxy(this, this.ddConfig);
      */
      
      this._makeEditable();
      
      this.scissors = new Y.WireScissors(this);
   }
};

Y.Terminal.prototype = {

   
    _makeEditable: function () {
        
        // Make the contentBox draggable with a DDProxy
        var drag = new Y.DD.Drag({ 
            node: this.el, //this.get('contentBox'),
         groups: ['terminal'] // TODO: this.get('groups')
        }).plug(Y.Plugin.DDProxy, {
            cloneNode: true,
            moveOnEnd: false
        });
        
        var that = this, x, y, magnetX, magnetY;
        
        // on drag start, create the wire between 2 fake terminals
        drag.on('drag:start', function (ev) {
            // save the position
            x = ev.pageX;    y = ev.pageY;
            //console.log("drag:start");
            
            drag.wire = new Y.BezierWire(
               { 
                  getXY: function () {    return [ev.pageX,ev.pageY]; }, 
                  addWire: function () {},
                  direction: this.direction
               } ,
                { 
                   getXY: function () {    return [magnetX || x, magnetY || y]; }, 
                   addWire: function () {} ,
                  direction: [0,1] // TODO
                }, 
                document.body 
                
                /*,
                plugins: [ 
                {fn: Y.WireBezierPlugin, cfg:{bezierTangentNorm:300} }
                ]*/
              );
            
            // Render the wire into the layer contentBox
            //drag.wire.render( document.body ); // that.get('parent').get('parent').get('contentBox')
            
        }, this);
        
        // on drag, redraw the wire
        drag.on('drag:drag', function (ev) {
            x = ev.pageX;
            y = ev.pageY;
            drag.wire.draw();
        });
        // on drop hit, set the wire src and tgt terminals
        drag.on('drag:drophit', function (ev) {
            //drag.wire.set('src', that);
            //drag.wire.set('tgt', ev.drop.terminal);
            drag.wire.terminal1 = that;
            drag.wire.terminal2 = ev.drop.terminal;
        });
        // on drop miss, destroy the wire
        drag.on('drag:dropmiss', function (ev) {
            drag.wire.destroy();
            drag.wire = null;
        });
        drag.on('drag:enter', function (ev) {
            var pos = ev.drop.terminal.getXY();
            magnetX = pos[0];
            magnetY = pos[1];
        });
        drag.on('drag:exit', function (ev) {
            magnetX = null;
            magnetY = null;
        });
        
        this.drag = drag;
        
        
        // Create the Drop object
        var drop = new Y.DD.Drop({
            node: this.el, //this.get('contentBox'),
            groups: ['terminal'] // TODO: this.get('groups')
        });
        drop.terminal = this;
        this.drop = drop;
    },

    /** 
    * @attribute xtype
    * @description String representing this class for exporting as JSON
    * @default "WireIt.Terminal"
    * @type String
    */
   xtype: "Y.Terminal",

    /**
    * @attribute direction
     * @description direction vector of the wires when connected to this terminal
    * @type Array
    * @default [0,1]
    */
    direction: [0,1],
    
    /**
    * @attribute fakeDirection
     * @description direction vector of the "editing" wire when it started from this terminal
    * @type Array
    * @default [0,-1]
    */
    fakeDirection: [0,-1],

    /**
    * @attribute editable
     * @description boolean that makes the terminal editable
    * @type Boolean
    * @default true
    */
    editable: true,
    
    /**
    * @attribute nMaxWires
     * @description maximum number of wires for this terminal
    * @type Integer
    * @default Infinity
    */
    nMaxWires: Infinity,

    /**
    * @attribute wireConfig
     * @description Options for the wires connected to this terminal
    * @type Object
    * @default {}
    */
    wireConfig: {},
    
    /**
    * @attribute editingWireConfig
     * @description Options for the wires connected to this terminal
    * @type Object
    * @default {}
    */
    editingWireConfig: {},
    
    /** 
    * @attribute className
    * @description CSS class name for the terminal element
    * @default "WireIt-Terminal"
    * @type String
    */
    className: "WireIt-Terminal",
    
    /** 
    * @attribute connectedClassName
    * @description CSS class added to the terminal when it is connected
    * @default "WireIt-connected"
    * @type String
    */
    connectedClassName: "WireIt-Terminal-connected",
    
    /** 
    * @attribute dropinviteClassName
    * @description CSS class added for drop invitation
    * @default "WireIt-dropinvite"
    * @type String
    */
    dropinviteClassName: "WireIt-Terminal-dropinvite",

    /** 
    * @attribute offsetPosition
    * @description offset position from the parentEl position. Can be an array [top,left] or an object {left: 100, bottom: 20} or {right: 10, top: 5} etc...
    * @default null
    * @type Array
    */
    offsetPosition: null,
    
    /**
    * @attribute alwaysSrc
     * @description forces this terminal to be the src terminal in the wire config
    * @type Boolean
    * @default false
    */
    alwaysSrc: false,
    
    /**
    * @attribute ddConfig
     * @description configuration of the Y.TerminalProxy object
    * @type Object
    * @default {}
    */
    ddConfig: false,


   /**
    * Set the options by putting them in this (so it overrides the prototype default)
    * @method setOptions
    */
   setOptions: function (options) {
      for(var k in options) {
            if( options.hasOwnProperty(k) ) {
                this[k] = options[k];
            }
        }
        
        // Set fakeDirection to the opposite of direction
        if(options.direction && !options.fakeDirection) {
            this.fakeDirection = [ -options.direction[0], -options.direction[1] ];
        }
        
        // Set the editingWireConfig to the wireConfig if specified
        if(options.wireConfig && !options.editingWireConfig) {
            this.editingWireConfig = this.wireConfig;
        }
   },

   /**
    * Show or hide the drop invitation. (by adding/removing this.options.dropinviteClassName CSS class)
    * @method setDropInvitation
    * @param {Boolean} display Show the invitation if true, hide it otherwise
    */
   setDropInvitation: function (display) {
      if(display) {
         Y.one(this.el).addClass(this.dropinviteClassName);
      }
      else {
         Y.one(this.el).removeClass(this.dropinviteClassName);
      }
   },

   /**
    * Render the DOM of the terminal
    * @method render
    */
   render: function () {
   
      // Create the DIV element
      this.el = Y.WireIt.cn('div', {className: this.className} );
      if(this.name) { this.el.title = this.name; }

      // Set the offset position
      this.setPosition(this.offsetPosition);
   
      // Append the element to the parent
      this.parentEl.appendChild(this.el);
   },

    /**
     * Set the position of the terminal with the given pos
     * @param {Object | Array} pos The position. It can be used in two ways: setPosition({left: 10, top: 10}) or setPosition([10, 10]) or setPosition({bottom: 10, right: 10})
     */
   setPosition: function (pos) {
        if(pos) {
            // Clear the current position
            this.el.style.left = "";
            this.el.style.top = "";
            this.el.style.right = "";
            this.el.style.bottom = "";
        
            // Kept old version [x,y] for retro-compatibility
            if( Y.Lang.isArray(pos) ) {
                this.el.style.left = pos[0]+"px";
                this.el.style.top = pos[1]+"px";
            }
            // New version: {top: 32, left: 23}
            else if( Y.Lang.isObject(pos) ) {
                for(var key in pos) {
                    if(pos.hasOwnProperty(key) && pos[key] !== ""){ //This will ignore the number 0 since 0 == "" in javascript (firefox 3.0
                        this.el.style[key] = pos[key]+"px";
                    }
                }
            }
        }
    },
    
   /**
    * Add a wire to this terminal.
    * @method addWire
    * @param {Wire} wire Wire instance to add
    */
   addWire: function (wire) {
   
      this.wires.push(wire);
   
      Y.one(this.el).addClass(this.connectedClassName);
   
      this.fire('eventAddWire', wire);
   },

   /**
    * Remove a wire
    * @method removeWire
    * @param {Wire} wire Wire instance to remove
    */
   removeWire: function (wire) {
      var index = Y.Array.indexOf(this.wires, wire);
      if( index != -1 ) {
         
         this.wires[index].destroy();
         
         this.wires[index] = null;
         this.wires = Y.Wirecompact(this.wires);
      
         // Remove the connected class if it has no more wires:
         if(this.wires.length === 0) {
            Y.one(this.el).removeClass(this.connectedClassName);
         }
      
         // Fire the event
         this.fire('eventRemoveWire', wire);
      }
   },

   /**
    * This function is a temporary test. I added the border width while traversing the DOM and
    * I calculated the offset to center the wire in the terminal just after its creation
    * @method getXY
    */
   getXY: function () {
   
      var layerEl = this.container && this.container.layer ? this.container.layer.el : document.body;

      var obj = this.el;
        var curleft = 0, curtop = 0;
        if (obj.offsetParent) {
            do {
                curleft += obj.offsetLeft;
                curtop += obj.offsetTop;
                obj = obj.offsetParent;
          } while ( !!obj && obj != layerEl && !Y.one(obj).hasClass("WireIt-Layer"));
        }

        return [curleft+15,curtop+15];
   },

   /**
    * Remove the terminal from the DOM
    * @method remove
    */
   remove: function () {
      // This isn't very nice but...
      // the method Wire.remove calls Terminal.removeWire to remove the reference
      while(this.wires.length > 0) {
         this.wires[0].remove();
      }
      this.parentEl.removeChild(this.el);
      
      // Remove all event listeners
      // TODO: YAHOO.util.Event.purgeElement(this.el);
      
      // Remove scissors widget
      if(this.scissors) {
         // TODO: YAHOO.util.Event.purgeElement(this.scissors.get('element'));
      }
      
   },

   /**
    * Returns a list of all the terminals connecter to this terminal through its wires.
    * @method getConnectedTerminals
    * @return  {Array}  List of all connected terminals
    */
   getConnectedTerminals: function () {
      var terminalList = [];
      if(this.wires) {
         for(var i = 0 ; i < this.wires.length ; i++) {
            terminalList.push(this.wires[i].getOtherTerminal(this));
         }
      }
      return terminalList;
   },

   /**
    * Redraw all the wires connected to this terminal
    * @method redrawAllWires
    */
   redrawAllWires: function () {
      if(this.wires) {
         for(var i = 0 ; i < this.wires.length ; i++) {
            this.wires[i].redraw();
         }
      }
   },
   
   /** 
    * Remove all wires
    * @method removeAllWires
    */
   removeAllWires: function () {
      while(this.wires.length > 0) {
         this.wires[0].remove();
      }
   }

};

Y.augment(Y.Terminal, Y.EventTarget);

}, '0.7.0',{
  requires: ['dd-drop','wire-base','terminal-proxy','scissors']
});