

jQuery.fn.setTaskWidth = function() {
  var i = 0;
  this.each(function() { i++; });
  
  var barSize = $('#innerTaskLayer').xWidth();
    var padding = 4;
  var size  = Math.min(200, barSize / i - padding);
  var floor = Math.floor(size);
  var rest = size - floor;
  var buffer = 0;
  
  this.each(function() {
    var add = 0;
    buffer += rest;
    if(buffer > 1) {
      buffer--;
      add = 1;
    }
    $(this).css('width',floor + add);
    //barSize -= floor + add;
  });
  return this;
};


jQuery.fn.correctTaskTitle = function() {
  this.each(function() {
    var width = parseInt($(this).css('width'));
    width -= 30;
    var letters = (width/6) -2;
    if(this.title && this.title.length > letters) {
     $('#'+this.id+' span').html(this.title.substr(0,letters)+'...')
    } else {
     $('#'+this.id+' span').html(this.title)
    }
    
  });
  return this;
};


/**
 * Opacity function for jQuery
 *
 * @name   .opacity
 * @cat    Plugins/Effects
 * @author Woody Gilk/woody.gilk@gmail.com
 *
 * @example $(this).opacity(.2);
 */
$.fn.opacity = function(amount) {
        if (amount > 1) amount = 1;
        if (amount < 0) amount = 0;
        if ($.browser.msie) {
                amount = (parseFloat(amount) * 100);
                this.css('filter', 'alpha(opacity='+amount+')');
        } else {
                this.css('opacity', amount);
                this.css('-moz-opacity', amount);
        }
        return this;
}


/*
jQuery.fn.xMoveTo = function(x,y) {
  this.each(function() {
     xMoveTo(this,x,y);
  });
  return this;
};


jQuery.fn.xMoveBy = function(x,y) {
  this.each(function() {
     xMoveTo(this,xLeft(this)+x,xTop(this)+y);
  });
  return this;
};


jQuery.fn.xEnableDrag = function(start, move, stop) {
  this.each(function() {
     xEnableDrag(this, start, move, stop);
  });
  return this;
}
*/


jQuery.fn.fitListSize = function() {
  var as, max, width;
  this.each(function() {
    as = $(this).children('li').children('a');
    max = 0;
    as.each(function(){ // get longest link
      width = 8 * this.innerHTML.length + 10;
      max = Math.max(max, width);
    });
    
    as.each(function(){
      $(this).css('width', max + 'px')
    });
    
    $(this).css('width', (max+50) +'px')
    
  });
  return this;
};


jQuery.fn._fitToMax = function() {
  var max = 0;
  this.each(function() {
    var width = 8 * this.innerHTML.length + 10;
    max = Math.max(max, width);
  });
  this.each(function() {
    $(this).css('width', max + 'px')
  });
  return this;
}


//------------ Basic jQuery extensions

jQuery.fn.noSelect = function() {
  this.attr('unselectable','on');
  this.addClass('unSelectable');
  return this;
};


jQuery.fn.position = function(noWidth) {
 var obj = this[0], x = 0; y = 0;
 if(!noWidth) {
   var width = this.width(), height = this.height();
 }
 var i = 0, p;
 
 
 while(obj) {
   i++;
   p = obj.offsetParent;
   x +=  obj.offsetLeft;
   y +=  obj.offsetTop;
   if(p) {
     x = Math.min(x, p.offsetWidth);
     y = Math.min(y, p.offsetHeight);
   }
   obj = p;
 }
 return noWidth ? {top:y, left:x, x:x, y:y}
       :  {top:y, left:x, bottom:y+height, right:x+width, width:width, height:height, x:x, y:y};
};


jQuery.fn.dump = function(msg) {
  var out = '', i = 0;
  this.each(function() {
    i++;
    if(this === document)
      return out = out + 'document\n';
    if(this === window)
      return out = out + 'window\n';
    if(this instanceof window.constructor)
      return out = out + 'frame name='+this.name+'\n';
    out = out + this.tagName + ' id="' + this.id + '" class="' + this.className + '"\n';
  });
  msg = msg || '';
  console.log('jQuery dump '+msg+' ('+i+' Element'+(i===1 ? '' : 's')+'): \n'+out);
  return this;
};


// real and virtual events
(function(){
  
  var controlKeys = [0, 8, 9, 13, 35, 36, 37, 38, 39, 40, 45, 46]; // backspace tab enter pos1 end arrows insert delete
  var throughKeys = [8, 9, 13, 35, 36, 37, 39, 45, 46]; // backspace tab enter pos1 end left right insert delete
  
  jQuery.fn.xBind = function(eType, f, from) {
    
    var xf = function(ev){
      try{
        f.apply(this, [ev]);
      } catch(e) {
              }
    };
    
    switch(eType){
      // virtual events: type, oneClick, saveClick
      case 'safeClick':
        // lock for 300 ms after click, prevents double execution
        this.bind('click', function(e){
          var delay = this._stamp ? ((new Date()).getTime() - this._stamp) : false;
          this._stamp = (new Date()).getTime();
          if(!delay || delay > 300)
            xf.apply(this, [e]);
        });
        break;
      case 'oneClick':
        // wait and cancel if doubleclick
        this.xBind('safeClick', function(e){
          var self = this;
          setTimeout(function(){
            if(self._doubleclicked) {
              self._doubleclicked = false;
              return;
            }
            xf.apply(self, [e]);
          }, 200);
        });
        this.bind('dblclick', function(){
          this._doubleclicked = true;
        });
        break;
      case 'type':
        // 500ms after last keystroke
        var timeout;
        this.bind('keypress', function(e){
          var self = this, cc = e && (e.charCode || e.keyCode);
          if(contain(controlKeys, cc)) {
            
            switch(cc) {
              case 13: // Enter
                this.next.focus();
                this.onFocusOut();
                return false;
            }
            
            return contain(throughKeys, cc);
          }
          
          if(timeout)
            window.clearTimeout(timeout);
          timeout = setTimeout(function(){
             xf.apply(self, [e]);
          }, 500);
          return true;
        });
        break;
      case 'mouseSelect':
        this.bind('mouseOver', function(e){
          if(sys.mouse.leftButtonDown()) {
            xf.apply(this, [e]);
          }
        }).bind('click', xf);
        break;
        
      default:
        this.bind(eType,xf);
    }
    return this;
  };
  
  function contain(array, item) {
    var i;
    for(i=0; i < array.length; i++) {
      if(array[i] === item)
        return true;
    }
    return false
  }
  
})();


// encapsulate the makef function
(function(){
  
  function makef(name, obj){
    return function(){
      var args = arguments;
      obj.each(function(){
        this[name].apply(this, args);
      });
      return obj;
    };
  }
  
  
  // decorator and composite pattern
  jQuery.fn.decorate =function(functs){
    var name, names =[],  self = this;
    this.each(function(){
      for(name in functs) {
        this[name] = functs[name];
      }
    });
    
    for(name in functs) {
      names.push(name);
      this[name] = makef(name, this);
    }
    
    this._isDecorated = true;
    this._decoratedNames = names;
    return this;
  };
  
  
  
  // use: $('.items').where(function(){ return this.style.color == 'red'; }).css('color','green');
  jQuery.fn.where = function(cond){
    var elems = [], others = [], self = this;
    this.each(function(){
      if(cond.apply(this))
        elems.push(this);
      else
        others.push(this);
    });
    var result = $(elems), ot = $(others);  
    if(this._isDecorated) {
      this._decoratedNames.each(function(){
         result[this] = makef(this, result);
         ot[this] = makef(this, ot);
      });
    }
    result.others = ot;
    return result;
  };
  
})();



// attach attributes to dom elements via html
// use in controller: 
//      win.setContent('<div class="getMe myId:123">test</div>');
//      $win('.getMe').initClasses();
//      console.log('myId is ' + $win('.getMe')[0].myId);
jQuery.fn.initClasses = function(){
  this.each(function(){
    var self = this, cl, cls;
    if(! this.className.match(':')) return;
    cls = this.className.split(' ');
    while(cl = cls.shift()) {
      if(cl.match(/:[^:]+/)) {
        var pair = /^([^:]+):([^:]+)$/.exec(cl);
        if(typeof(assert) === 'function')
          assert(pair instanceof Array && pair.length === 3, 'initClasses Error: '+self.tagName+' "'+self.className+'" ');
        // numbers with leading zeros and overlong numbers will be treated as string.
        var val = pair[2].match(/^\-?([1-9][0-9]{0,15}|0)$/) ? parseInt(pair[2]) :
                                                     decodeURIComponent(pair[2]);
        self[pair[1]] = val;
      }
    }
  });
  return this;
};



(function() {
  
  var scripts = {}, callbacks = {};
  
  jQuery.fn.requireScript = function(url, callback) {
    var key = url.hash();
    if(scripts[key] === 'done') {
      callback();
      return this;
    }
    callbacks[key] = callbacks[key] || [];
    callbacks[key].push(callback);
    if(scripts[key] === 'loading')
      return this;
    scripts[key] = 'loading';
    jQuery.getScript(url, function(){
      scripts[key] = 'done';
      callbacks[key].each(function(){ this(); });
    });
  };
})();


// stuff from X Library


jQuery.preventDefault = function(e){
  if (e && e.preventDefault) e.preventDefault();
  else if (window.event) window.event.returnValue = false;
};


jQuery.stopPropagation = function(e) {
  
  if (e && e.stopPropagation) e.stopPropagation();
  else if (window.event) window.event.cancelBubble = true;

  // swoppen.com hack
  e = e || window.event;
  //console.log('x: on'+e.type+' typeof='+typeof(document['on'+e.type]));
  try {
       // console.log('stopPropagation try trigger '+e.type);
       $(document).trigger(e.type);
  } catch(er) {
    // console.log('x error: '+(e.message || e.error));
  }
  // if(!e.type.match(/over|out|down/)) console.log('xStopPropagation '+e.type);
  if(e.type == 'click' && e.clientX) {
    sys.mouse.set(e);  // lehbert 20.12.2007
  }
  if(e.type == 'mousedown') {
    sys.mouse.setDown(e); // lehbert 02.02.2008
  }
  if(e.type == 'mouseup') {
    sys.mouse.setUp(e);  // lehbert 02.02.2008
  }
  
  // /swoppen.com hack
};


// xWidth && xHeight from X Library moved to jQuery.
(function(){

  function xGetComputedStyle(oEle, sProp, bInt) {
      var s, p = 'undefined';
      var dv = document.defaultView;
      if(dv && dv.getComputedStyle){
        s = dv.getComputedStyle(oEle,'');
        if (s) p = s.getPropertyValue(sProp);
      }
      else if(oEle.currentStyle) {
        // convert css property name to object property name for IE
        var a = sProp.split('-');
        sProp = a[0];
        for (var i=1; i<a.length; ++i) {
          c = a[i].charAt(0);
          sProp += a[i].replace(c, c.toUpperCase());
        }   
        p = oEle.currentStyle[sProp];
      }
      else return null;
      return bInt ? (parseInt(p) || 0) : p;
  }


jQuery.fn.xWidth = function(w) {
  var e;
  if(!(e=this[0])) return 0;
  if(w == null) w = -1;
  

  var css = [e.style].allDefined();
  
  if (e == document || e.tagName.toLowerCase() == 'html' || e.tagName.toLowerCase() == 'body') {
    w = $(document).width();
  }
  else if(css && [e.offsetWidth].allDefined() && [e.style.width].allString()) {
    
    if(w>=0) {
      var pl=0,pr=0,bl=0,br=0;
      if (document.compatMode=='CSS1Compat') {
        var gcs = xGetComputedStyle;
        pl=gcs(e,'padding-left',1);
        if (pl !== null) {
          pr=gcs(e,'padding-right',1);
          bl=gcs(e,'border-left-width',1);
          br=gcs(e,'border-right-width',1);
        }
        // Should we try this as a last resort?
        // At this point getComputedStyle and currentStyle do not exist.
        else if([e.offsetWidth, e.style.width].allDefined()){
          e.style.width=w+'px';
          pl=e.offsetWidth-w;
        }
      }
      w-=(pl+pr+bl+br);
      if(isNaN(w)||w<0) return;
      else e.style.width=w+'px';
    }
    w=e.offsetWidth;
  }
  else if(css && [e.style.pixelWidth].allDefined()) {
    if(w >= 0) e.style.pixelWidth = w;
    w = e.style.pixelWidth;
  }
  return w;
}

jQuery.fn.xHeight = function(h) {
  var e;
  if(!(e=this[0])) return 0;
  if(h == null) h = -1;
  
  
  var css= [e.style].allDefined();
  
  if (e == document || e.tagName.toLowerCase() == 'html' || e.tagName.toLowerCase() == 'body') {
    h = $(document).height();
  }
  else if(css && [e.offsetHeight].allDefined() && [e.style.height].allString()) {
    if(h>=0) {
      var pt=0,pb=0,bt=0,bb=0;
      if (document.compatMode=='CSS1Compat') {
        var gcs = xGetComputedStyle;
        pt=gcs(e,'padding-top',1);
        if (pt !== null) {
          pb=gcs(e,'padding-bottom',1);
          bt=gcs(e,'border-top-width',1);
          bb=gcs(e,'border-bottom-width',1);
        }
        // Should we try this as a last resort?
        // At this point getComputedStyle and currentStyle do not exist.
        else if([e.offsetHeight, e.style.height].allDefined()){
          e.style.height=h+'px';
          pt=e.offsetHeight-h;
        }
      }
      h-=(pt+pb+bt+bb);
      if(isNaN(h)||h<0) return;
      else e.style.height=h+'px';
    }
    h=e.offsetHeight;
  }
  else if(css && [e.style.pixelHeight].allDefined()) {
    if(h>=0) e.style.pixelHeight=h;
    h=e.style.pixelHeight;
  }
  return h;
};

jQuery.fn.xResizeTo = function(x, y) {
  this.xWidth(x);
  this.xHeight(y);
  return this;
};


})();


jQuery.fn.xMoveTo = function(x, y) {
  // assert(![x, y].allNumber(), 'xMoveTo: Number Expected');
  this.each(function(){
      this.style.left = x+'px';
      this.style.top  = y+'px';
  });
  return this;
};


jQuery.fn.xMoveBy = function(x, y) {
  if(![x, y].allNumber()) return false;
  this.each(function(){
    var l = parseInt(this.style.left),
        t = parseInt(this.style.top);
      this.style.left = ((isNaN(l) ? 0 : l) + x) + 'px';
      this.style.top  = ((isNaN(t) ? 0 : t) + y) + 'px';
    return true;
  });
  return this;
};

jQuery.fn.xTop = function(y) {
  if(!this[0])
    throw new Error('xTop called on empty jQuery');  
  if(!isNaN(y)) 
    this[0].style.top = y+'px';
  return parseInt(this[0].style.top);
};

jQuery.fn.xLeft = function(x) {
  if(!this[0])
    throw new Error('xLeft called on empty jQuery');
  if(!isNaN(x)) 
    this[0].style.left = x+'px';
  return parseInt(this[0].style.left);
};



// enableDrag
(function() {
  
  var elem = null, client ={}, pos = {}, d = $(document), dummy = function(){};
  
  jQuery.fn.enableDrag = function(start, drag, stop) {
  
    this.each(function() {
                // console.log('enableDrag '+this.id);
                if(this.___dragEnabled) return;
                   this.___start   = start || dummy;
                   this.___drag    = drag  || dummy;
                   this.___stop    = stop  || dummy;
                   this.___disable = dis;
                   $(this).bind('mousedown', md);
                   this.__dragEnabled = true;
               });
    
  };
  
  function md(e) {
    // console.log('start elem '+this.id);
    e = e || event;
    $.preventDefault(e);
    client = {width:  d.width(), 
              height: d.height()};
    elem = this;
    pos = {x:e.pageX, y:e.pageY};
    $(this).bind('mouseup', mu)
    elem.___start(e.pageX, e.pageY, e);
  }
  
  
  function dis() {
    var t = this;
    // console.log('disableDrag '+t.id);
    $(t).unbind('mousedown', md)
        .unbind('mouseup', mu);
    t.___start       = null;
    t.___drag        = null;
    t.___stop        = null;
    t.___disable     = null;
    t.___dragEnabled = null;
  }  
  
  function mu(e) {
    if(!elem) return;
    // console.log('stop elem '+this.id+' - '+elem.id);
    e = e || event;
    $.preventDefault(e);
    // $(this).unbind('mouseup', mu);
    elem.___stop(e.pageX, e.pageY, e);
    elem = null;
    // console.log('elem stopped: '+elem);
  }
  
  jQuery.fn.disableDrag = function() {
    this.each(function(){
      if(typeof(this.___disable) === 'function')
        this.___disable();
    });
  };
  
  $(document)
  .bind('mouseup', mu)
  .bind('mousemove', function(e) {
    if(!elem) return;
    e = e || event;
    $.preventDefault(e);
    // swoppen.com hack - clipping (when Mouse is outside Webpage)
    var pageX = Math.max(0, e.pageX);
    var pageY = Math.max(0, e.pageY);
    pageX = Math.min(pageX,  client.width);
    pageY = Math.min(pageY,  client.height);
    var dx = pageX - pos.x;
    var dy = pageY - pos.y;
    pos.x = pageX;
    pos.y = pageY;
    //  /swoppen.com hack
    if(elem.___drag)
      elem.___drag(dx, dy, e);
    else
      $(elem).moveBy(dx, dy);
  });
  
})();





/*
// xEnableDrag, Copyright 2002,2003,2004,2005 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL

//// Private Data
var _xDrgMgr = {ele:null, mm:false};
//// Public Functions
function xEnableDrag(id,fS,fD,fE)
{
  var ele = xGetElementById(id);
  ele.xDraggable = true;
  ele.xODS = fS;
  ele.xOD = fD;
  ele.xODE = fE;
  xAddEventListener(ele, 'mousedown', _xOMD, false);
  if (!_xDrgMgr.mm) {
    _xDrgMgr.mm = true;
    xAddEventListener(document, 'mousemove', _xOMM, false);
  }
}
//// Private Event Listeners
function _xOMD(e) // drag start
{
  // swoppen.com hack  - clipping
  _xDrgMgr.xCH = xClientHeight();
  _xDrgMgr.xCW = xClientWidth();
  // /swoppen.com hack
  var evt = new xEvent(e);
  var ele = evt.target;
  while(ele && !ele.xDraggable) {
    ele = xParent(ele);
  }
  if (ele) {
    xPreventDefault(e);
    ele.xDPX = evt.pageX;
    ele.xDPY = evt.pageY;
    _xDrgMgr.ele = ele;
    xAddEventListener(document, 'mouseup', _xOMU, false);
    if (ele.xODS) {
      ele.xODS(ele, evt.pageX, evt.pageY, evt);
    }
  }
}
function _xOMM(e) // drag
{
  var evt = new xEvent(e);
  if (_xDrgMgr.ele) {
    xPreventDefault(e);
    var ele = _xDrgMgr.ele;
    // swoppen.com hack - clipping (when Mouse is outside Webpage)
    var pageX = Math.max(0, evt.pageX);
    var pageY = Math.max(0, evt.pageY);
    pageX = Math.min(pageX, _xDrgMgr.xCW);
    pageY = Math.min(pageY, _xDrgMgr.xCH);
    var dx = pageX - ele.xDPX;
    var dy = pageY - ele.xDPY;
    ele.xDPX = pageX;
    ele.xDPY = pageY;
    //  /swoppen.com hack
    if (ele.xOD) {
      ele.xOD(ele, dx, dy);
    }
    else {
      xMoveTo(ele, xLeft(ele) + dx, xTop(ele) + dy);
    }
  }  
}
function _xOMU(e) // drag end
{
  if (_xDrgMgr.ele) {
    xPreventDefault(e);
    xRemoveEventListener(document, 'mouseup', _xOMU, false);
    if (_xDrgMgr.ele.xODE) {
      var evt = new xEvent(e);
      _xDrgMgr.ele.xODE(_xDrgMgr.ele, evt.pageX, evt.pageY);
    }
    _xDrgMgr.ele = null;
  }  
}
// xEvalTextarea, Copyright 2001-2005 Michael Foster (Cross-Browser.com)
// Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
*/



