/*
 * SocialEngineMods Apps v3.00
 * http://www.SocialEngineMods.Net
 *
 * Copyright SocialEngineMods.Net
 * This code is NOT an open source
 *
 */



/* EXTENSIONS */



Array.prototype.in_array = function(p_val) {
   for(var i = 0, l = this.length; i < l; i++) {
       if(this[i] == p_val) {
           return true;
       }
   }
   return false;
}



function semods_add_row(name, id) {

  if (typeof id == 'undefined') id = '';
  
  var el = document.getElementById(name+'_template').cloneNode(true);
  el.id = id;
  var moreRow = document.getElementById(name+"_addmorerow");
  moreRow.parentNode.insertBefore(el, moreRow)
  return el;
    
}



// Teach IE manners
//if(typeof(window.external) != 'undefined'){
if( SEMods.Browser.isIE || SEMods.Browser.isOpera ){
  document.getElementsByName = function(name, tag){
	  if(!tag){
		  tag = '*';
	  }
	  var elems = document.getElementsByTagName(tag);
	  var res = []
	  for(var i=0;i<elems.length;i++){
		  att = elems[i].getAttribute('name');
		  if(att == name) {
			  res.push(elems[i]);
		  }
	  }
	  return res;
  }

}


function hideMenuEx() {
  if($(open_menu)) { hideMenu($(open_menu)); }
}


function apps_open_support_ticket(subject, message) {
   var form = document.createElement("FORM");
   form.action = "admin_semods_support.php";
   form.method = "POST";
   form.encoding = "multipart/encoded";
   
   var elem = document.createElement("INPUT");
   elem.type = "text";
   elem.name = "subject";
   elem.value = escape(subject);
   form.appendChild(elem);

   elem = document.createElement("INPUT");
   elem.type = "text";
   elem.name = "message";
   elem.value = escape(message);
   form.appendChild(elem);

   elem = document.createElement("INPUT");
   elem.type = "text";
   elem.name = "fresh";
   elem.value = 1;
   form.appendChild(elem);
 
   document.body.appendChild(form);
   
   form.submit();
}


function apps_notify_new_messages() {
  var elems = document.getElementsByTagName("A");
  for(var i=0;i<elems.length;i++) {
     if(elems[i].href.match(/admin_apps_messages.php/)) {
        elems[i].style['backgroundColor'] = "#FFF4A5";
        break;
     }
  }
}


/* MORE APPS MENU */
function apps_menu_moreapps_onclick() {
   var apps = SEMods.B.ge("menu_dropdown_apps");
   var moreapps = SEMods.B.ge("menu_dropdown_moreapps");
   if(moreapps) {
      moreapps.style.left = SEMods.B.findX(apps) + 20 + 'px';
      moreapps.style.top = SEMods.B.findY(apps) - 6 + 'px';
      showMenu("menu_dropdown_moreapps");
   }
}


/* MORE TOP BAR MENU */
function apps_menu_main_more() {

  // find our anchor
  var position_elem = null;
  elems = document.getElementsByTagName("A");
  for(var i=0;i<elems.length;i++) {
    if((elems[i].className == 'top_menu_item') && elems[i].href.match(/javascript:apps_menu_main_more/) ) {
      position_elem = elems[i];
      break;
    }
  }

  // no luck
  if(!position_elem)
    return;
  
  position_elem.blur();
  
  /* A is enclosed in DIV which is inside DIV */
  position_elem = position_elem.parentNode.parentNode;
  var moreapps = SEMods.B.ge("menu_main_more_apps");
  if(moreapps) {
    ff_offset = SEMods.B.isFireFox ? 0 : 1;
    moreapps.style.left = SEMods.B.findX(position_elem) + 'px';
    //moreapps.style.top = SEMods.B.findY(position_elem) + position_elem.offsetHeight - 6 + 1 + 'px';
    moreapps.style.top = SEMods.B.findY(position_elem) + ff_offset + 'px';
    showMenu("menu_main_more_apps");
  }
}





/* APP PAGE */

function app_show_profile_onClick(app_id) {
  
  SEMods.B.hide("app_show_conf");  
  SEMods.B.show("app_show_progress");  
  SEMods.Apps.placeApp( app_id, SEMods.B.ge("app_show_profile").checked*1, 1, 0, app_show_updated);   
  
}

function app_show_userhome_onClick(app_id) {

  SEMods.B.hide("app_show_conf");  
  SEMods.B.show("app_show_progress");  
  SEMods.Apps.placeApp( app_id, SEMods.B.ge("app_show_userhome").checked*1, 2, 0, app_show_updated );   
  
}

function app_show_updated() {
  SEMods.B.hide("app_show_progress");  
  SEMods.B.show("app_show_conf");  
}




/* USER APPS */

function apps_uninstall(app_id, page_id, view_id) {
  SEMods.Apps.removeApp(app_id, page_id, view_id);
  SEMods.B.hide('approw_'+app_id);
}


function apps_show_error_message(error_message) {
   elem = SEMods.B.ge("apps_error_message_div");
   if(!elem) {
      return;
   }
   if(error_message && (error_message != '')) {
      elem.innerHTML = error_message;
   }
   mooFaceboxExShow("", "#apps_error_message_div");
}

/* PAGES */

function apps_inplace_edit(app_id) {
  
  hideMenuEx();
  SEMods.Apps.ProfileDragDrop.editContent(app_id);
  
}

function apps_edit_box(app_id) {
  hideMenuEx();
  SEMods.Apps.ProfileDragDrop.editContent(app_id);
}


function apps_get_appbox(app_id) {
  if(app_id.indexOf('_') != -1) {
    app_id = app_id.split('_')[1];
  }
  appbox = SEMods.B.ge('app_'+app_id);
  // try harder
  if(!appbox)
    appbox = SEMods.B.ge('core_'+app_id);
  // try harder
  if(!appbox)
    appbox = SEMods.B.ge('plugin_'+app_id);
  // try harder
  if(!appbox)
    appbox = SEMods.B.ge('widget_'+app_id);
  return appbox;
}


function app_boxdialog(app_id, position) {
  // plugin_XXX, ...
  if(app_id.indexOf('_') != -1) {
    app_id = app_id.split('_')[1];
  }
  box = SEMods.B.ge("appsettings_app_"+app_id);
  appbox = apps_get_appbox(app_id);
    
  var top = SEMods.B.findY( appbox );
  var left = SEMods.B.findX( appbox ) + appbox.offsetWidth - 1;

  box.style.left = -9999 + 'px';
  box.style.top = -9999 + 'px';
  showMenu("appsettings_app_"+app_id);
  //SEMods.B.show(box);

  // check if off screen
  if((left + box.offsetWidth) > document.body.offsetWidth) {
    left -= box.offsetWidth;
    box.className = "apps_settingsbox1";
  }

  box.style.left = left + 'px';
  box.style.top = top + 'px';

  showMenu("appsettings_app_"+app_id);
}


function app_tabdialog(app_id) {
  box = SEMods.B.ge("appsettings_"+app_id);
  appbox = SEMods.B.ge(app_id);
  if(!appbox || !box) 
    return;
  // get our master 
  do{
   appbox = appbox.previousSibling; 
  } while(appbox.nodeType != 1)
  
  var left = SEMods.B.findX( appbox ) + appbox.offsetWidth - 10 ;
  var top = SEMods.B.findY( appbox ) - 1 + 3;

  box.style.left = left + 'px';
  box.style.top = top + 'px';
  //SEMods.B.show(box);
  showMenu("appsettings_"+app_id);
}


function apps_show_grip_item(app_id, app_name) {
  // find last shown tab and hide it
  var elems = document.getElementsByName("profile_tabs_wrap", "TD");
  for(var i=elems.length-1; i>=0; i--) {
    if(elems[i].style.display != 'none') {
      // found it
      elems[i].style.display = 'none';
      break;
    }
  }

  try {
    hideMenu(SEMods.B.ge("tabs_grip"));
  }
  catch(ex) {
  }

  SEMods.B.ge("profile_tabs_wrap_"+app_name).style.display='';

  loadProfileTab(app_name);
}

function appbox_uninstall(app_id) {
  clean_app_id = app_id;
  if(app_id.indexOf('_') != -1) {
    clean_app_id = app_id.split('_')[1];
  }
  hideMenu(SEMods.B.ge("appsettings_app_"+clean_app_id));
  SEMods.Apps.ProfileDragDrop.removeApp(app_id);
  appbox = apps_get_appbox(app_id);
  SEMods.B.hide(appbox);
}

function apps_removebox(app_id) {
  clean_app_id = app_id;
  if(app_id.indexOf('_') != -1) {
    clean_app_id = app_id.split('_')[1];
  }
  hideMenu(SEMods.B.ge("appsettings_app_"+clean_app_id));
  SEMods.Apps.ProfileDragDrop.removeBox(app_id);
  appbox = apps_get_appbox(app_id);
  SEMods.B.hide(appbox);
}

function appbox_moveto_sidebar(app_id) {
  clean_app_id = app_id;
  if(app_id.indexOf('_') != -1) {
    clean_app_id = app_id.split('_')[1];
  }
  SEMods.B.hide("appsettings_app_"+clean_app_id);

  // menu options
  SEMods.B.hide("appsettings_app_"+clean_app_id+"_moveto_sidebar");
  SEMods.B.show("appsettings_app_"+clean_app_id+"_moveto_apptab");

  SEMods.Apps.ProfileDragDrop.moveToContainer(app_id, "root", 0);
  loadProfileTab("profile");
}

function appbox_moveto_apptab(app_id) {
  clean_app_id = app_id;
  if(app_id.indexOf('_') != -1) {
    clean_app_id = app_id.split('_')[1];
  }
  SEMods.B.hide("appsettings_app_"+clean_app_id);

  // menu options
  SEMods.B.show("appsettings_app_"+clean_app_id+"_moveto_sidebar");
  SEMods.B.hide("appsettings_app_"+clean_app_id+"_moveto_apptab");

  SEMods.Apps.ProfileDragDrop.moveToContainer(app_id, "apptab", 0);

   // show the apps tab
  SEMods.B.ge("profile_tabs_wrap_apps").style.display='';
   
  loadProfileTab("apps");
}


function apps_add_totab_dialog() {
  box = SEMods.B.ge("add_to_tab");
  appbox = SEMods.B.ge("profile_tabs_add");
  var left = SEMods.B.findX( appbox ) + appbox.clientWidth - 5;
  var top = SEMods.B.findY( appbox );


  box.style.left = left + 'px';
  box.style.top = top + 'px';
  showMenu("add_to_tab");
}

function apps_tab_grip_dialog() {
  box = SEMods.B.ge("tabs_grip");
  appbox = SEMods.B.ge("profile_tabs_grip");
  var left = SEMods.B.findX( appbox ) + appbox.clientWidth - 4;
  var top = SEMods.B.findY( appbox );


  box.style.left = left + 'px';
  box.style.top = top + 'px';
  showMenu("tabs_grip");
}

function appbox_moveto_tab(app_id) {
  hideMenu(SEMods.B.ge("add_to_tab"));
  SEMods.Apps.ProfileDragDrop.moveBoxToTabs(app_id);
}

function appbox_remove_from_tab(app_id) {
  hideMenu(SEMods.B.ge("appsettings_"+app_id));
  SEMods.Apps.ProfileDragDrop.removeBoxFromTabs(app_id);
}











/* SEMods.Apps */ 


SEMods.Apps = function () {};

SEMods.Apps = {
  api_endpoint : 'ajax_semods_apps.php?',
  api_content_endpoint : 'appcontent.php?',     // MUST end with "?"
  app_url : '',
  
  removeApp : function (app_id, page_id, view_id) {
    var ajax = new SEMods.Ajax();
	var params = 'task=removeapp' + '&appid=' + app_id;

    if (typeof page_id != 'undefined') params += '&pid=' + page_id;
    if (typeof view_id != 'undefined') params += '&vid=' + view_id;
   
    ajax.post(this.api_endpoint, params );
    
  },
  
  placeApp : function(app_id, show, page_id, view_id, placeApp_callback) {
    if (typeof view_id == 'undefined')
      view_id = 0;
    if(show == 0)
      task = 'removebox';
    else
      task = 'placeapp';

    new SEMods.Apps.AppPlacer( task, app_id, page_id, view_id, placeApp_callback );
    
  },
  
  hideNotification : function (id) {
    SEMods.B.hide("appnotify_"+id);
    var ajax = new SEMods.Ajax();
    ajax.post( this.api_endpoint, 'task=hidenotification' + '&notificationid=' + id );
  },
  
  cleanAppId : function(app_id) {
    clean_app_id = app_id;
    if(app_id.indexOf('_') != -1) {
      clean_app_id = app_id.split('_')[1];
    }
    return clean_app_id;
  }

};



/* SEMods.Apps.Language */ 



SEMods.Apps.Language = function () {};


SEMods.Apps.Language = {
   
}



/*** TABS ***/

SEMods.Apps.Tabs = function () {};

SEMods.Apps.Tabs = {
  
  instance : 'apps_tab1',
  visible_tab : '',
  full_screen : false,
  full_screen_exclude : ["profile","friends","comments"],
  
  
  loadProfileTab : function(tabId, full_screen) {
   
    // FULL SCREEN
    if(this.full_screen) {

      // show back if profile,friends,comments
      if(this.full_screen_exclude.in_array(tabId)) {
        //document.getElementById("profile_leftside").style.display = SEMods.B.isIE ? "inline" : "table-row";
        document.getElementById("profile_leftside").style.display = "";
      } else {
        document.getElementById("profile_leftside").style.display = "none";
      }

    }
    
    // no selected tab - just loaded
    if(this.visible_tab == '') {
      var elems = document.getElementsByName("profile_tabs_wrap", "TD");
      if(elems.length>0) {
        guess_tab_id = elems[0].id;
        guess_tab_id = guess_tab_id.substring(18);
        this.visible_tab = guess_tab_id;
      }
    }
  
    if(tabId == this.visible_tab) {
     return false;
    }
    
    // show appsetting box
    if(elem = SEMods.B.ge('profile_tabs_'+tabId)) {
     cells = elem.getElementsByTagName("TD");
     for(i=0;i<cells.length;i++) {
       if(cells[i].className == "apps_tabsetting") {
         SEMods.B.show(cells[i]);
         // TR -> TBODY -> TABLE
         cells[i].parentNode.parentNode.parentNode.className = "apps_activetab";
         break;
       }
     }
    }
       
    // hide appsetting box
    if(elem = SEMods.B.ge('profile_tabs_'+this.visible_tab)) {
     cells = elem.getElementsByTagName("TD");
     for(i=0;i<cells.length;i++) {
       if(cells[i].className == "apps_tabsetting") {
         SEMods.B.hide(cells[i]);
         cells[i].parentNode.parentNode.parentNode.className = "apps_inactivetab";
         break;
       }
     }
    }
       
    if($('profile_'+tabId)) {
         $('profile_tabs_'+tabId).className = this.instance + '2';
     $('profile_'+tabId).style.display = "block";
     if($('profile_tabs_'+this.visible_tab)) {
           $('profile_tabs_'+this.visible_tab).className = this.instance;
       $('profile_'+this.visible_tab).style.display = "none";
     }
     this.visible_tab = tabId;
    }
    
  }
  
}
  



SEMods.Apps.AppPlacer = function(task, app_id, page_id, view_id, placeApp_callback) {
  this.app_id = app_id;
  this.page_id = page_id;
  this.view_id = view_id;
  this.placeApp_callback = placeApp_callback;
  this.init(task);
};

SEMods.Apps.AppPlacer.prototype = {
  app_id : '',

  init : function(task) {
    clean_app_id = SEMods.Apps.cleanAppId(this.app_id);
    var ajax = new SEMods.Ajax( this.onSetPagePlacementSuccess.bind(this), this.onSetPagePlacementFail.bind(this) );
	var params = 'task=' + task + '&pid=' + this.page_id + '&vid=' + this.view_id + '&appid=' + clean_app_id + '&user=' + SEMods.Apps.ProfileDragDrop.owner;
    ajax.post(SEMods.Apps.api_endpoint, params );
  },

  onSetPagePlacementSuccess : function(obj, responseText) {
	var r = [];
	try {
	  r = eval('('+responseText+')');
	} catch(e) {
	  r.status = 1;
	};
  
    if(this.placeApp_callback)
      this.placeApp_callback(this.app_id);
      
	if(r.status == 0) {
      
	} else {
      apps_show_error_message( r.err_msg ? r.err_msg : '' );
    }
	
  },

  onSetPagePlacementFail : function(obj, responseText) {
    if(this.placeApp_callback)
      this.placeApp_callback();

      apps_show_error_message();
  }
  
}




SEMods.Apps.Utils = {};

SEMods.Apps.Utils = {

  /* parse and load scripts from ajaxed response */
  parseHTML : function(_source) {
    var source = _source;
    var scripts = new Array();
    
    // Strip out tags
    while(source.indexOf("<script") > -1 || source.indexOf("</script") > -1) {
        var s = source.indexOf("<script");
        var s_e = source.indexOf(">", s);
        var e = source.indexOf("</script", s);
        var e_e = source.indexOf(">", e);
        
        script_meta = source.substring(s+8, s_e);
        script_src = script_meta.match(/src="([^"]*)"/);
        script_src = script_src ? script_src[1] : '';

       // Add to scripts array
        scripts.push( {'data' : source.substring(s_e+1, e), 'src' :  script_src, 'type' : 'script' } );
          
        // Add to scripts array
//          scripts.push(source.substring(s_e+1, e));
        // Strip from source
        source = source.substring(0, s) + source.substring(e_e+1);
    }
    
    // Loop through every script collected and eval it
    for(var i=0; i<scripts.length; i++) {
        try {
//            script = document.createElement("script");
//			script.type = "text/javascript";

          // otherwise
          //var head = document.getElementsByTagName("head")[0] || document.documentElement,
          var head = document.getElementsByTagName("head")[0] || document.documentElement,
              script = document.createElement("script");

          script.type = "text/javascript";
        
          // if src
          if(scripts[i].src) {
             script.src = scripts[i].src;
             
          } else {
          
             if ( SEMods.B.isIE )
                script.text = scripts[i].data;
             else
                script.appendChild( document.createTextNode( scripts[i].data ) );
          }
          
          // Use insertBefore instead of appendChild  to circumvent an IE6 bug.
          // This arises when a base node is used (#2709).
          head.insertBefore( script, head.firstChild );
          //head.removeChild( script );
          
            //eval(scripts[i]);
        }
        catch(ex) {
            // do what you want here when a script fails
        }
    }
    
    
    // only needed for IE (and also doesnt seem to work.. update yes!!! now this works!!)
    // TODO: clean code - applyStyles / applyScripts
    //if(SEMods.Browser.isIE) {

    // and styles - do this with "link rel=stylesheet" ? <style> has no src
      var scripts = new Array();
      
      while(source.indexOf("<style") > -1 || source.indexOf("</style") > -1) {
          var s = source.indexOf("<style");
          var s_e = source.indexOf(">", s);
          var e = source.indexOf("</style", s);
          var e_e = source.indexOf(">", e);
          
          script_meta = source.substring(s+7, s_e);
          script_src = script_meta.match(/src="([^"]*)"/);
          script_src = script_src ? script_src[1] : '';
  
         // Add to scripts array
          scripts.push( {'data' : source.substring(s_e+1, e), 'src' :  script_src, 'type': 'css' } );
            
          // Add to scripts array
  //          scripts.push(source.substring(s_e+1, e));
          // Strip from source
          source = source.substring(0, s) + source.substring(e_e+1);
      }
  
      // Loop through every script collected and eval it
      for(var i=0; i<scripts.length; i++) {
          try {
  //            script = document.createElement("script");
  //			script.type = "text/javascript";
  
            // otherwise
            //var head = document.getElementsByTagName("head")[0] || document.documentElement,
            var head = document.getElementsByTagName("head")[0] || document.documentElement,
                script = document.createElement("style");
  
            script.type = 'text/css';
          
            
               if ( SEMods.B.isIE )
                  script.styleSheet.cssText = scripts[i].data;
               else
                  script.appendChild( document.createTextNode( scripts[i].data ) );
            
            // Use insertBefore instead of appendChild  to circumvent an IE6 bug.
            // This arises when a base node is used (#2709).
            head.insertBefore( script, head.firstChild );
            //head.removeChild( script );
            
              //eval(scripts[i]);
          }
          catch(ex) {
              // do what you want here when a script fails
          }
      }
      
    //}
    
    
    // Return the cleaned source
    return source;
   }
  
}




SEMods.Apps.ContentEditor = function ( page_id, view_id, app_id, app_block_id, stripe_id, placement, container, owner, editinplace ) {

  this.page_id = page_id;
  this.view_id = view_id;
  this.app_id = app_id;
  this.app_block_id = app_block_id;
  this.stripe_id = stripe_id;
  this.placement = placement;
  this.container = container;
  this.owner = owner;
  this.editinplace = editinplace;

  this.init();
  
};


SEMods.Apps.ContentEditor.prototype = {
  xx : '',
  
  init : function () {

  var params = 'task=editcontent' +
               '&pageid=' + this.page_id +
               '&viewid=' + this.view_id +
               '&id=' + this.app_id +
               '&appid=' + this.app_block_id +
               '&stripe=' + this.stripe_id +
               '&placement=' + this.placement +
               '&container=' + this.container +
               '&user=' + this.owner;

   if(this.editinplace == 1) {

    content_box = SEMods.B.ge("appcontent_"+this.app_block_id);
    content_box.innerHTML = "Loading...";

    var ajax = new SEMods.Ajax( this.onEditContentLoadSuccess.bind(this), this.onEditContentLoadFail.bind(this) );
      
                 
    ajax.post(SEMods.Apps.api_content_endpoint, params );
    
   } else if(this.editinplace == 2) {
    
    // TBD: full screen or not
      TBEX_show('EDIT',SEMods.Apps.api_content_endpoint + params + '&TBEX_iframe=true','','',1);
    
   } else {
    
    document.location = "user_apps_canvas.php?id=" + this.app_id +"&pageid=" + this.page_id + '&viewid=' + this.view_id + '&task=editcontent' + '&returnafteredit=' + encodeURIComponent(document.location);
    
   }
  
  
  },
  
  attachEvents : function() {
    
  },
  
  onSubmit : function(e) {
    var values = [];
    var elems = this.form.getElementsByTagName( "INPUT" );
    for(var i=0; i<elems.length;i++) {
      if(elems[i].type == "radio" || elems[i].type == "checkbox") {
         if(elems[i].checked) {
            values.push( encodeURIComponent(elems[i].name) + '=' + encodeURIComponent(elems[i].value) );
         }
      } else {
         values.push( encodeURIComponent(elems[i].name) + '=' + encodeURIComponent(elems[i].value) );
      }
    }

    var elems = this.form.getElementsByTagName( "SELECT" );
    for(var i=0; i<elems.length;i++) {
      values.push( encodeURIComponent(elems[i].name) + '=' + encodeURIComponent(elems[i].value) );
    }

    var elems = this.form.getElementsByTagName( "TEXTAREA" );
    for(var i=0; i<elems.length;i++) {
      values.push( elems[i].name + '=' + escape(elems[i].value) );
    }
    
    // add our values
    
    values.push( 'pageid=' + this.page_id );
    values.push( 'viewid=' + this.view_id);
    values.push( 'id=' + this.app_id );
    values.push( 'appid=' + this.app_block_id );
    values.push( 'stripe=' + this.stripe_id );
    values.push( 'placement=' + this.placement );
    values.push( 'container=' + this.container );
    values.push( 'user=' + this.owner );

    values.push( 'task=doajaxsave' );

    values = values.join("&");
    
    content_box = SEMods.B.ge("appcontent_"+this.app_block_id);
    content_box.innerHTML = "Saving...";

    // save may return errors with editing content again
    var ajax = new SEMods.Ajax( this.onEditContentLoadSuccess.bind(this), this.onEditContentSaveFail.bind(this) );
      
      
    ajax.post(SEMods.Apps.api_content_endpoint, values);

    return this._cancelEvent(e);
  },

  _cancelEvent : function(e) {
	  var e = e ? e : window.event;
		  
	  if(e.preventDefault)
		  e.preventDefault();
  
	  if(e.stopPropagation) 
		  e.stopPropagation(); 
  
	  e.cancelBubble = true;
  
	  e.returnValue = false;
	  return false;
  },
  
  onCancel : function() {

    var contentbox = SEMods.B.ge("appcontent_" + this.app_block_id);
    
    SEMods.Apps.ProfileDragDrop.reloadContentEx ( this.app_block_id );
    
  },

  onEditContentSaveSuccess : function(obj, responseText) {
	var r = [];
	try {
	  r = eval('('+responseText+')');
	} catch(e) {
	  r.status = 1;
	  r.html = '';
	};
  
	if(r.status == 0) {
      var contentbox = SEMods.B.ge("appcontent_" + this.app_block_id);
	  contentbox.innerHTML = r.html.replace(/<script(.|\s)*?\/script>/g, "");
    } else {
      apps_show_error_message( r.err_msg ? r.err_msg : '' );
    }
    
  },

  onEditContentSaveFail : function(obj, responseText) {
   apps_show_error_message();
  },
  
  onEditContentLoadSuccess : function(obj, responseText) {
	var r = [];
	try {
	  r = eval('('+responseText+')');
	} catch(e) {
	  r.status = 1;
	  r.html = '';
	};
  
	if(r.status == 0) {
      var contentbox = SEMods.B.ge("appcontent_" + this.app_block_id);
	  contentbox.innerHTML = SEMods.Apps.Utils.parseHTML( r.html );
      
      // hook edit form submit / cancel events

      var elems = contentbox.getElementsByTagName( "FORM" );
      for(var i=0;i<elems.length;i++) {
        if(elems[i].name == "form_editcontent") {
          this.form = elems[i];
          SEMods.B.addEvent( elems[i], "submit", this.onSubmit.bind(this) );
        }
      }

      // form oncancel
      var elems = contentbox.getElementsByTagName( "INPUT" );
      for(var i=0;i<elems.length;i++) {
        if(elems[i].name == "form_editcontent_cancel") {
          SEMods.B.addEvent( elems[i], "click", this.onCancel.bind(this) );
        }
      }
      
	} else {
      apps_show_error_message( r.err_msg ? r.err_msg : '' );
    }
	
  },

  onEditContentLoadFail : function(obj, responseText) {
    apps_show_error_message();
  }

  
}




SEMods.Apps.ProfileDragDrop = function (e) {};

/*
 * stripes - 
 * 
 *
 */

SEMods.Apps.ProfileDragDrop = {
  dropTargets : null,
  stripes : null,          // columns where apps can be placed
  api_endpoint : 'ajax_semods_apps.php?',
  api_content_endpoint : 'appcontent.php?',     // MUST end with "?"
  dropTarget : null,	// rectangular drop box
  objects : [],		// array of boxes, populated on profile.tpl
  stripes_map : [],  // data map stripeid -> stripetype (wide/narrow)
  header_class : 'header',
  page_id : 2, // TBD
  view_id : 0, // TBD
  header_control_element : "TD", // header elements boxes   div(new way) or td (old way)
  enforce_placements : true,    // if force app placements according to supported ones (forced: profile, userhome; not forced: home, ... admin managed)
  auto_save_layout : true,       // auto save layout after box is placed
  flying : false,
  owner : '',        // page owner

  removeApp : function(app_id) {
    var ajax = new SEMods.Ajax( this.onMoveBoxSuccess.bind(this), this.onMoveBoxFail.bind(this) );
	var params = 'task=removeapp&pid=' + this.page_id + '&vid=' + this.view_id + '&appid=' + app_id + '&user=' + this.owner; 
    ajax.post(this.api_endpoint, params );
  },

  removeBox : function(app_id) {
    var ajax = new SEMods.Ajax( this.onMoveBoxSuccess.bind(this), this.onMoveBoxFail.bind(this) );
	var params = 'task=removebox&pid=' + this.page_id + '&vid=' + this.view_id + '&appid=' + app_id + '&user=' + this.owner; 
    ajax.post(this.api_endpoint, params );
  },

  moveBoxToTabs : function(app_id) {
    var ajax = new SEMods.Ajax( this.onMoveBoxSuccess.bind(this), this.onMoveBoxFail.bind(this) );
	var params = 'task=movetotabs&pid=' + this.page_id + '&vid=' + this.view_id + '&appid=' + app_id + '&user=' + this.owner; 
    ajax.post(this.api_endpoint, params );
  },
  
  removeBoxFromTabs : function(app_id) {
    var ajax = new SEMods.Ajax( this.onMoveBoxSuccess.bind(this), this.onMoveBoxFail.bind(this) );
	var params = 'task=removefromtabs&pid=' + this.page_id + '&vid=' + this.view_id + '&appid=' + app_id + '&user=' + this.owner; 
    ajax.post(this.api_endpoint, params );
  },
  
  onMoveBoxSuccess : function(obj, responseText) {
	var r = [];
	try {
	  r = eval('('+responseText+')');
	} catch(e) {
	  r.status = 1;
      r.appid = '';
	};
  
	if(r.status == 0) {
      
      if(r.reload)
        document.location = document.location;

      if(r.url) {
         document.location = r.url;
      }
      
	} else {
      apps_show_error_message( r.err_msg ? r.err_msg : '' );
    }
	
  },

  onMoveBoxFail : function(obj, responseText) {
      apps_show_error_message();
  },
  
  getAppBox : function(app_id) {
    if(app_id.indexOf('_') != -1) {
      app_id = app_id.split('_')[1];
    }
    appbox = SEMods.B.ge('app_'+app_id);
    // try harder
    if(!appbox)
      appbox = SEMods.B.ge('core_'+app_id);
    // try harder
    if(!appbox)
      appbox = SEMods.B.ge('plugin_'+app_id);
    if(!appbox)
      appbox = SEMods.B.ge('widget_'+app_id);
    return appbox;
  },
  
  moveToContainer : function(app_id, container, stripe_id) {

   this.buildStripes();

    var stripe;
    for(var i in SEMods.Apps.ProfileDragDrop.stripes) {
      stripe = SEMods.Apps.ProfileDragDrop.stripes[i];
      if(stripe.id == stripe_id && stripe.c == container) {
        elem = this.getAppBox(app_id);
        elem = elem.parentNode.removeChild(elem);
        stripe.e.appendChild( elem );
        box = this.getBoxIdentity(app_id);
        box.container = container;
        box.stripe = stripe_id;
        moved = true;
        break;
      }
    }

    if(moved) {
      if(box.contentvaries) {
        this.reloadContent(app_id, stripe_id, container );
      }
      this.updateLayout(true);
    }
   
  },
  
  buildDropTargets : function() {

	var elem;
	this.dropTargets = new Array();
    for(var obj in this.objects) {
	  
	  // empty box, id not assigned
	  if(!this.objects[obj].box)
		continue;
	  
		elem = this.objects[obj].box;
        
        if(!this.dropTargets[this.objects[obj].container])
         this.dropTargets[this.objects[obj].container] = new Array();
         
        this.dropTargets[this.objects[obj].container].push(
                               { 'x' : SEMods.B.findX(elem),
								 'y' : SEMods.B.findY(elem),
								 'x1': SEMods.B.findX(elem) + elem.offsetWidth,
								 'y1': SEMods.B.findY(elem) + elem.offsetHeight,
								 'e' : elem } );
    }

	return this.dropTargets;
  },
  
  getDropTargets : function(container) {
	return this.dropTargets ? this.dropTargets[container] : this.buildDropTargets();
  },
  
  
  /*
   * find all our elements with attributes "stripe" and "container"
   *
   */ 
  buildStripes : function() {
	this.stripes = [];

    var tdtags = this.getElementsByName_compat( "semods_container", "DIV" );

    for(var tdtag=0;tdtag<tdtags.length;tdtag++) {

      if( tdtags[tdtag].getAttribute('stripe') && tdtags[tdtag].getAttribute('container')) {
         x = SEMods.B.findX(tdtags[tdtag]);
         y = SEMods.B.findY(tdtags[tdtag]);

		var stripe = { 	'x'  : x,
						'y'	 : y,
						'x1' : x + tdtags[tdtag].offsetWidth,
						'y1' : y + tdtags[tdtag].offsetHeight,
						'e'	 : tdtags[tdtag],
                        'id' : tdtags[tdtag].getAttribute('stripe'),
                        'c'  : tdtags[tdtag].getAttribute('container')
                        };
			
         // need this? 
		if(tdtags[tdtag].lastChild) {
		  for(var node = tdtags[tdtag].lastChild; node.previousSibling; node = node.previousSibling) {
			// text
			if(node.nodeType != 3)	{
			  stripe.y1 = SEMods.B.findY(node) + node.offsetHeight;
			  break;
			}
		  }
		} else {
			stripe.y1 = stripe.y + 10;
		}

		this.stripes.push( stripe );
		
	  }
	
	}
	
  },
  
  getStripe : function( x, y ) {
	for(var stripe in this.stripes) {
	  if( (x > this.stripes[stripe].x) && (x < this.stripes[stripe].x1) ) {
		return this.stripes[stripe];
	  }
	}
    
    return null;
  },
  
  getElementsByName_compat : function(name, tag) {
    if(!tag){
      tag = '*';
    }
   
    if(SEMods.B.isIE) {

      var elems = document.getElementsByTagName(tag);
      var res = []
      for(var i=0;i<elems.length;i++) {
        att = elems[i].getAttribute('name');
        if(att == name) {
          res.push(elems[i]);
        }
      }
      return res;
      
    } else {
      return document.getElementsByName(name, tag);
    }
   
   
  },
  
  app_profiledragdrop_onload : function (e, elem) {
	
	// attach events to TD 'header' and build boxes array
	this.dropTargets = new Array();

    var elems = this.getElementsByName_compat( "semods_appbox", "DIV" );
    for(var i=0; i<elems.length; i++) {
    
      var elem;

      box = this.getBoxIdentity(elems[i].id);

      var tdtags = elems[i].getElementsByTagName(this.header_control_element);
    
      for(var tdtag=0; tdtag<tdtags.length; tdtag++) {
  
        if(tdtags[tdtag].className == this.header_class) {
          
          if(!box.locked || !this.enforce_placements) {
            
          // its moveable
          tdtags[tdtag].style.cursor = "move";

          if(SEMods.B.isIE) {
            SEMods.B.addEvent( tdtags[tdtag], "mousedown", function(e) {SEMods.Apps.ProfileDragDrop.app_profiledragdrop_mousedown(e);});
          }
          else {
            SEMods.B.addEvent( tdtags[tdtag], "mousedown", function(e) {SEMods.Apps.ProfileDragDrop.app_profiledragdrop_mousedown(e, this);} );
          }
          
          } else {
            // TODO
            // tdtags[tdtag].style.cursor = "block";
          }
          
          // add settings box - check if exists first
          if(!this.no_appsettings) {
          
            header_elem = document.createElement("DIV");
            header_elem.className = "apps_settings_titlediv";
            header_elem.innerHTML = tdtags[tdtag].innerHTML;
  
            selem = document.createElement("DIV");
            selem.id = elems[i].id + "_settingsdiv";
            selem.className = "apps_settings";
            if(SEMods.B.isIE) {
              SEMods.B.addEvent( selem, "click", function(e) { var src = (e.srcElement) ? e.srcElement : e.target; app_boxdialog(src.id);} );
            } else {
              SEMods.B.addEvent( selem, "click", function() { app_boxdialog(this.id);} );
            }
                      
            tdtags[tdtag].innerHTML = '';
            tdtags[tdtag].appendChild(header_elem);
            tdtags[tdtag].appendChild(selem);
  
            // if control header is div, make a fix
            if(this.header_control_element == "DIV") {
              clearfix_elem = document.createElement("DIV");
              clearfix_elem.style['clear'] = "both";
              tdtags[tdtag].appendChild(clearfix_elem);
            }

          }
  
          tdtags[tdtag].app_id = elems[i].id;
  
          
          // can be objects dont have this id?
          this.objects[elems[i].id].box = elems[i];
         
         // no need to search further
         break;
        }
        
      } // TD

    } // semods_appbox


  
	// helpers
	var div = document.createElement("DIV");
	div.className = 'app_profiledragdrop_flyingbox';
	div.style.display = 'none'; // or via css
	this.flying_box	= div;
	document.body.insertBefore( div, document.body.firstChild );

	// drop target rectangular box ?
	div = document.createElement("DIV");
    div.className = 'app_profiledragdrop_droptarget';
	this.drop_box = div;
    // borders: -2*2
    // bottom-margin: -10
	
  },
  
  add_new_objects : function( newobjects, options ) {

    if (typeof options == 'undefined' || typeof options.header_class == 'undefined') {
      header_class = "header";
    }

    if (typeof options == 'undefined' || typeof options.header_control_element == 'undefined' ) {
      header_control_element = "TD";
    }

    for(var obj in newobjects) {
      
      var elem = SEMods.B.ge(obj);
      
      if(elem) {
        
        var tdtags = elem.getElementsByTagName(header_control_element);
      
        for(var tdtag=0; tdtag<tdtags.length; tdtag++) {
    
          if(tdtags[tdtag].className == header_class) {
            
            // its moveable
            tdtags[tdtag].style.cursor = "move";
  
            if(SEMods.B.isIE) {
              SEMods.B.addEvent( elem, "mousedown", function(e) {SEMods.Apps.ProfileDragDrop.app_profiledragdrop_mousedown(e);});
            }
            else {
              SEMods.B.addEvent( elem, "mousedown", function(e) {SEMods.Apps.ProfileDragDrop.app_profiledragdrop_mousedown(e, this);} );
            }
  

          // add settings box 
            header_elem = document.createElement("DIV");
            header_elem.className = "apps_settings_titlediv";
            header_elem.innerHTML = tdtags[tdtag].innerHTML;
  
            selem = document.createElement("DIV");
            selem.id = obj;
            selem.className = "apps_settings";
            if(SEMods.B.isIE) {
              SEMods.B.addEvent( selem, "click", function(e) { var src = (e.srcElement) ? e.srcElement : e.target; app_boxdialog(src.id);} );
            } else {
              SEMods.B.addEvent( selem, "click", function() { app_boxdialog(this.id);} );
            }
                      
            tdtags[tdtag].innerHTML = '';
            tdtags[tdtag].appendChild(header_elem);
            tdtags[tdtag].appendChild(selem);
  
            // if control header is div, make a fix
            if(header_control_element == "DIV") {
              clearfix_elem = document.createElement("DIV");
              clearfix_elem.style['clear'] = "both";
              tdtags[tdtag].appendChild(clearfix_elem);
            }
  
  
            tdtags[tdtag].app_id = obj;
            
            // add to global objects list
            this.objects[obj] = newobjects[obj];
            this.objects[obj].box = elem;

            // add callback
            if (typeof options != 'undefined' && typeof options.onDrop != 'undefined' ) {
              this.objects[obj].onDrop = options.onDrop;
            }
      
          }
        }
      }
    }
   
  },
  
  app_profiledragdrop_mousedown : function (e, elem) {
    if(this.flying)
      return;
    
    var src = (e.srcElement) ? e.srcElement : e.target;
    
  
    // click on the injected title div. go one step up
    if(src.className == "apps_settings_titlediv") {
      src = src.parentNode;
    }
    
	// check it's "our" td
	if(!src.app_id)
        return;
      
    new SEMods.Apps.ProfileDragDrop.FlyingBox ( SEMods.Apps.ProfileDragDrop, e, this.objects[src.app_id].box );

    // Page editor hide menu hack
    try {
      if(SEMods.Apps.PageEditor.apps_pageeditmenu_hideall) {
        SEMods.Apps.PageEditor.apps_pageeditmenu_hideall();
      }
    }
    catch(ex) {}
  },
  
  getBoxIdentity : function(id) {
	return this.objects[id];
  },

  showWarningBox : function(x, y, minLeft, maxLeft) {
	if(!this.warning_box) {
	  this.warning_box = SEMods.B.ge("apps_profiledragdrop_warningbox");
	}

	this.warning_box.style.top = y + 30 + 'px';

	SEMods.B.show( this.warning_box );
	
	var boxX = x - this.warning_box.offsetWidth / 2;
	
	
	if((boxX + this.warning_box.offsetWidth + 10)> maxLeft)
	  boxX = maxLeft - this.warning_box.offsetWidth - 10;
	else if(boxX < minLeft)
	  boxX = minLeft + 10;

	this.warning_box.style.left = boxX + 'px';
	

  },

  hideWarningBox : function() {
	if(this.warning_box) {
	  SEMods.B.hide( this.warning_box );
	}
  },
  
  reloadContentEx : function( app_id ) {

   var identity = this.getBoxIdentity( app_id );
   
   this.reloadContent( app_id, identity.stripe, identity.container );
   
  },
  
  // TBD: if multiple apps are loading - how to handle failed callbacks??
   // appid, stripeid, pageid, viewid
  reloadContent : function( app_id, stripe, container ) {

    clean_app_id = SEMods.Apps.cleanAppId(app_id);

   // set "loading"
   content_box = SEMods.B.ge("appcontent_"+app_id);
   content_box.innerHTML = "Loading...";
   
    var ajax = new SEMods.Ajax( this.onReloadContentSuccess.bind(this), this.onReloadContentFail.bind(this) );
      
   // stripe id -> stripe type
   var stripe_type = this.stripes_map[container][stripe];
   var params = 'task=ajaxload&pageid=' + this.page_id + '&viewid=' + this.view_id + '&id=' + clean_app_id + '&appid=' + app_id + '&stripe=' + stripe  + '&placement=' + stripe_type  + '&container=' + container + '&user=' + this.owner;
   ajax.post(this.api_content_endpoint, params );
   
  },
  
  editContent : function( app_id ) {
   
   var identity = this.getBoxIdentity( app_id );
   clean_app_id = SEMods.Apps.cleanAppId(app_id);
   var stripe_type = this.stripes_map[identity.container][identity.stripe];
  
   new SEMods.Apps.ContentEditor( this.page_id,
                                  this.view_id,
                                  clean_app_id,
                                  app_id,
                                  identity.stripe,
                                  stripe_type,
                                  identity.container,
                                  this.owner,
                                  identity.editinplace
                                  );
   
  },

  
  onReloadContentSuccess : function(obj, responseText) {
	var r = [];
	try {
	  r = eval('('+responseText+')');
	} catch(e) {
	  r.status = 1;
	  r.html = '';
      r.appid = '';
	};
  
	if(r.appid != '' && r.html != '') {
	  SEMods.B.ge("appcontent_" + r.appid).innerHTML = SEMods.Apps.Utils.parseHTML( r.html );
	} else {
      apps_show_error_message( r.err_msg ? r.err_msg : '' );
    }
	
  },
  
  
  onReloadContentFail : function(obj, r) {
    apps_show_error_message( r.err_msg ? r.err_msg : '' );
  },
  
 
  updateLayout : function(rebuild_stripes) {

    if(!this.auto_save_layout)
      return;
    
    this._updateLayout(rebuild_stripes);

  },
  
  _updateLayout : function(rebuild_stripes) {

    this.buildLayout();    
	
	var params = 'task=updatelayout&pid=' + this.page_id + '&vid=' + this.view_id  + '&user=' + this.owner + '&layout=' + SEMods.Apps.JSON.encode(this.layout);
    var ajax = new SEMods.Ajax( );
    ajax.post(this.api_endpoint, params );

  },
  
  buildLayout : function() {

    if(!this.stripes)
      this.buildStripes();

    layout = {};
    stripes = SEMods.Apps.ProfileDragDrop.stripes;
	for(var i=0;i<stripes.length;i++) {
	  if(!layout[stripes[i].c])
        layout[stripes[i].c] = [];
      layout[stripes[i].c][""+stripes[i].id] = [];
    }
	  
	var boxes = document.getElementsByName("semods_appbox", "DIV");

	for(var b=0;b<boxes.length;b++) {
      identity = this.getBoxIdentity( boxes[b].id );
      // non existing container (ex: nulltab) - skip. TBD: is this flexible enough? or should we save it as well?
      if(!layout[identity.container] || !layout[identity.container][identity.stripe])
        continue;
	  layout[identity.container][identity.stripe].push( boxes[b].id );
	}

    SEMods.Apps.ProfileDragDrop.layout = layout;
    
  }
  
};





















// master - shortcut for SEMods.Apps.ProfileDragDrop
// e - mouse event
// elem - appbox
//
SEMods.Apps.ProfileDragDrop.FlyingBox = function (master, e, elem) {

  this.disableSelection( elem );
  this.master = master;
  this.master.flying = true;
  
  this.srcElement = elem;
  this.init(e, elem);
  
  // hide all box menus
  if (typeof hideMenu != 'undefined') {
    hideMenuEx();
  }
};


SEMods.Apps.ProfileDragDrop.FlyingBox.prototype = {
  master : null,
  obj : null,
  srcElement : null,
  offsetX : 0,
  offsetY : 0,
  curDropTarget : null,
  identity : [],
  autoScrollSpeed : 10,
  mouseX : 0,
  mouseY : 0,
  mouseDocX : 0,
  mouseDocY : 0,
  lazyMouseY : 0,
  scrollVelocity : 0,
  mouseDownSaver : null,
  

  init: function(e, elem) {

  // rebuild drop targets
    SEMods.Apps.ProfileDragDrop.dropTargets = null;

  // the "stripes" (columns) should be always same width, but for now..
    SEMods.Apps.ProfileDragDrop.buildStripes();

	this.identity = SEMods.Apps.ProfileDragDrop.getBoxIdentity( this.srcElement.id );
	
	//if(this.identity.positionLocked) 
	
	this.createElement(e);
	
	this.documentHeight = document.documentElement.clientHeight;	
	this.documentScrollHeight = document.documentElement.scrollHeight + 100 + this.obj.offsetHeight;

	
    this._addEvent( document.body, "mouseup", this.onMouseUp.bind(this) );
    //this._addEvent( document.body, "dragend", this.onMouseUp.bind(this) );

	document.body.selectstart = function() { return false; };
	// ?
    this._addEvent( document.body, "selectstart", function() { return false; } );
//    this.disableSelection( document.body );

    this._addEvent( document.body, "mousemove", this.onMouseMove.bind(this) );
    //this._addEvent( document.body, "drag", this.onMouseMove.bind(this) );
	
	// THIS ONE DISABLES TEXT SELECTON (opera)
	this.mouseDownSaver = document.onmousedown;
	document.onmousedown = function() { return false; };
  },
  
  disableSelection : function (element) {
    this.eventsaver_onselectstart = element.onselectstart;
    element.onselectstart = function() {return false;};
    element.unselectable = "on";
    element.style.MozUserSelect = "none";
  },

  enableSelection : function ( element ) {
    element.onselectstart = this.eventsaver_onselectstart;
    element.unselectable = "off";
    element.style.MozUserSelect = "";
  },

  autoScroll : function(e) {
	
	// opera auto scrolls by itself
	if(SEMods.Browser.isOpera)
	  return;
	
	if(e.clientY<50 || e.clientY>(this.documentHeight-50)){
		if(e.clientY<50 && !this.autoScrollActive){
			this.autoScrollActive = true;
			this.scrollVelocity = this.autoScrollSpeed*-1;
			setTimeout(this.autoScroller.bind(this), 5);
		}
		
		if(e.clientY>(this.documentHeight-50) && document.documentElement.scrollHeight<=this.documentScrollHeight && !this.autoScrollActive){
			this.autoScrollActive = true;
			this.scrollVelocity = this.autoScrollSpeed;
			setTimeout(this.autoScroller.bind(this), 5);
		}
	}else{
		this.autoScrollActive = false;
	}		

	
  },         
  
  autoScroller : function(direction,yPos) {
		  
	if(document.documentElement.scrollHeight>this.documentScrollHeight && this.scrollVelocity>0)return;
	window.scrollBy(0,this.scrollVelocity);
	if(!this.obj)return;

	if(this.scrollVelocity<0){
		if(document.documentElement.scrollTop>0){
			//this.obj.style.top = (el_y - mouse_y + yPos + document.documentElement.scrollTop) + 'px';		
			this.obj.style.top = parseInt(this.obj.style.top) + this.scrollVelocity + 'px';
			this.lazyMouseY += this.scrollVelocity;
		}else{
			this.autoScrollActive = false;
		}
	}else{
//		if(yPos>(this.documentHeight-50)){	
		if(this.mouseY>(this.documentHeight-50)){	
//			dragObject.style.top = (el_y - mouse_y + yPos + document.documentElement.scrollTop) + 'px';			
			this.obj.style.top = parseInt(this.obj.style.top) + this.scrollVelocity + 'px';		
			this.lazyMouseY += this.scrollVelocity;
		}else{
            
			this.autoScrollActive = false;
		}
	}
	
	this.mouseMoveHandler( this.mouseDocX, this.mouseDocY + this.lazyMouseY );
	
	if(this.autoScrollActive)setTimeout(this.autoScroller.bind(this), 5);
  },


  

  
  createElement : function(e) {

	this.master.flying_box.style.width = this.srcElement.offsetWidth + 'px';
	this.master.flying_box.style.height = this.srcElement.offsetHeight + 'px';
	this.master.flying_box.style.display = 'block';
	
    this.master.drop_box.style.height = (this.srcElement.offsetHeight > 200 ? 200 : this.srcElement.offsetHeight) + 'px';

    this.master.drop_box.style.width = '99%';
                    
	this.master.flying_box.style.left = SEMods.B.findX( this.srcElement ) + 'px';
	this.master.flying_box.style.top = SEMods.B.findY( this.srcElement ) + 'px';
	
	this.offsetX = SEMods.B.mousePosX(e) - SEMods.B.findX( this.srcElement ); 
	this.offsetY = SEMods.B.mousePosY(e) - SEMods.B.findY( this.srcElement );
	
    // check if possibly dragging from top bar appslist which has fixed position
    // 30 - approx size of header

    if(Math.abs(this.offsetY) > 30) {

      // fix scroll
      var scrollTop = 0;
      var scrollLeft = 0;
      obj = this.srcElement;
      if (obj.parentNode) {
        while (obj.parentNode) {
          scrollTop += obj.scrollTop;
          scrollLeft += obj.scrollLeft;
          obj = obj.parentNode;
        }
      }
      
      this.offsetY += scrollTop;
      this.offsetX += scrollLeft;

      this.offsetX -= (document.documentElement && document.documentElement.scrollTop) ? 2*document.documentElement.scrollLeft : 2*document.body.scrollLeft;
      this.offsetY -= (document.documentElement && document.documentElement.scrollTop) ? 2*document.documentElement.scrollTop : 2*document.body.scrollTop;
    }
    
    // if still miss, just center it
    if(Math.abs(this.offsetY) > 30) {
      this.offsetY = 15;
    }
    
	this.obj = this.master.flying_box;
    
    this.curDropTarget = this.master.drop_box;
	this.curDropTarget.stripe = this.master.objects[this.srcElement.id].stripe;
	this.curDropTarget.container = this.master.objects[this.srcElement.id].container;

    this.master.flying_box.appendChild( this.srcElement.parentNode.replaceChild( this.master.drop_box, this.srcElement ) );
	
  },
  
  
  mouseMoveHandler : function(x, y) {
	
    if(!SEMods.Apps.ProfileDragDrop.lock_vertical_move) {
      this.obj.style.left = x - this.offsetX + 'px';
    }
	this.obj.style.top = y - this.offsetY + 'px';
  
	// check if supports landing on this stripe
	var stripe = SEMods.Apps.ProfileDragDrop.getStripe( x, y );
    if(stripe == null)
      return;

	var stripe_id = stripe.id;

    if(SEMods.Apps.ProfileDragDrop.enforce_placements) {
      if(this.identity.stripes.in_array(stripe_id) && (this.identity.container == stripe.c)) {
        SEMods.Apps.ProfileDragDrop.hideWarningBox();
      } else {
        SEMods.Apps.ProfileDragDrop.showWarningBox( x, y - this.offsetY, x - this.offsetX, x - this.offsetX + this.obj.offsetWidth );
        return;
      }
    }
	
	var elem = null;

	var targetX, targetY;
	var target;
	var found_placement = false;

    // if inside curdroptarget - nothing
    var curDropTargetX = SEMods.B.findX( this.curDropTarget );
    var curDropTargetY =  SEMods.B.findY( this.curDropTarget );

    if( (x >= curDropTargetX) && (x <= curDropTargetX+this.curDropTarget.offsetWidth) && (y >= curDropTargetY) && (y <= curDropTargetY+this.curDropTarget.offsetHeight) ) {
      return;
    }
    
	
    // TBD: drop on other container - ex: admin of tabbed profile layout
	var targets = SEMods.Apps.ProfileDragDrop.getDropTargets(this.identity.container);

	for(var i=0; i<targets.length; i++) {
	  target = targets[i];
	  if(this.srcElement == target.e)
		continue;
	
		targetX = SEMods.B.findX( target.e );
		targetY =  SEMods.B.findY( target.e );

	  // inside the box width
	  if( (x >= targetX) && (x <= targetX + target.e.offsetWidth)) {
		
		// top half
		if( (y > (targetY-20)) && (y < (targetY + target.e.offsetHeight/2))) {
		  found_placement = true;

          // thats us
          if(this.curDropTarget != target.e.previousSibling ) {
            target.e.parentNode.insertBefore( this.curDropTarget, target.e );
          }
		  break;
		}
  
		// bottom half
		if( (y >= (targetY + target.e.offsetHeight/2) ) && (y <= (targetY + target.e.offsetHeight))) {
		  found_placement = true;

		  if(target.e.nextSibling) {
            //console.log( this.curDropTarget == target.e.nextSibling );
            if(this.curDropTarget != target.e.nextSibling) {
              target.e.parentNode.insertBefore( this.curDropTarget, target.e.nextSibling );
            }
		  } else {
            //console.log( this.curDropTarget == target.e.previousSibling );
			target.e.parentNode.appendChild( this.curDropTarget, target.e );
		  }
		  break;
		}
		
	  }
	}

   var node = null;
   
	// try on stripes - in boundaries
	if(!found_placement) {
      for(var i=0; i<SEMods.Apps.ProfileDragDrop.stripes.length; i++) {
		stripe = SEMods.Apps.ProfileDragDrop.stripes[i];

		if( (x >= stripe.x) && (x <= stripe.x1) && (y >= stripe.y) && (y <= stripe.y+stripe.e.offsetHeight) ) {

		  // find bottom elem
		  
		  var y1=stripe.y;
            for(var i=stripe.e.childNodes.length-1; i>=0; i--) {
              node = stripe.e.childNodes[i];
              // element node
              // added name check
              if(node.nodeType == 1) {
                y1 = SEMods.B.findY(node) + node.offsetHeight;
                break;
              }
            }
		  
		  if( y > y1 ) {
			
            if(node != this.curDropTarget) {
              stripe.e.appendChild( this.curDropTarget );
            }
            found_placement = true;
            break;
			  
		  }
          
          // if nothing satisfied, put as a top item
         if(stripe.e.firstChild != this.curDropTarget) {
            stripe.e.insertBefore( this.curDropTarget, stripe.e.firstChild );
            found_placement = true;
            break;
         }

        }
      }
    }


	// try on stripes - out of boundaries
	if(!found_placement) {
      for(var i=0; i<SEMods.Apps.ProfileDragDrop.stripes.length; i++) {
		stripe = SEMods.Apps.ProfileDragDrop.stripes[i];

		if( (x >= stripe.x) && (x <= stripe.x1) ) {
        
         if (y <= stripe.y) {

            if(stripe.e.firstChild != this.curDropTarget) {
               stripe.e.insertBefore( this.curDropTarget, stripe.e.firstChild );
            }
            
         } else if (y >= stripe.y+stripe.e.offsetHeight) {

            if(stripe.e.lastChild != this.curDropTarget) {
               stripe.e.appendChild( this.curDropTarget );
            }

         }
         

         found_placement = true;
         break;
        }
      }
    }


   var node = null;

	if(found_placement) {
	  this.curDropTarget.stripe = stripe_id;
	  this.curDropTarget.container = stripe.c;  // hmm?
	}


  // hack test
	//return this._cancelEvent(e);

  },

  onMouseMove : function(e) {
    
    //console.debug("mousemove");
    
	var x = SEMods.B.mousePosX(e);
	var y = SEMods.B.mousePosY(e);

	this.lazyMouseY = 0;
	this.mouseX = e.clientX;
	this.mouseY = e.clientY;

	this.mouseDocX = x;
	this.mouseDocY = y;


	this.mouseMoveHandler( x, y );
	this.autoScroll(e);
	
	return this._cancelEvent(e);
  
  },
 
  onMouseUp : function(e) {
	
	if (!e) var e = window.event;
	var src = (e.srcElement) ? e.srcElement : e.target;

	if(this.curDropTarget) {
    
      if(this.identity.stripe != this.curDropTarget.stripe) {
         stripe_switched = true;
      } else {
         stripe_switched = false;
      }
      this.curDropTarget.parentNode.replaceChild( this.srcElement, this.curDropTarget );
	  this.master.flying_box.style.display = 'none';
	  this.identity.stripe = this.curDropTarget.stripe;
      
      // NOTE: this is needed in admin remix, but currently user can't drag between containers (!)
	  this.identity.container = this.curDropTarget.container;
	  
	}
	
	SEMods.Apps.ProfileDragDrop.hideWarningBox();
	
    this.master.flying = false;

    this._removeEvent( document.body, "mouseup" );
    this._removeEvent( document.body, "dragend" );

    this._removeEvent( document.body, "mousemove" );
    this._removeEvent( document.body, "drag" );

    this._removeEvent( document.body, "selectstart" );

    this.enableSelection( this.srcElement );
    
	document.onmousedown = this.mouseDownSaver;

    if(stripe_switched && this.identity.contentvaries) {
      // appid, stripeid, pageid, viewid
       SEMods.Apps.ProfileDragDrop.reloadContent(this.srcElement.id, this.identity.stripe, this.identity.container);
    }
    
    if(this.identity.onDrop) {
      this.identity.onDrop(this.identity);
    }
    
    SEMods.Apps.ProfileDragDrop.updateLayout();
  },

  _addEvent : function($obj, $event, $handler) {
	  var fn = $handler;
  
	  if (!$obj.attachedEvents)
		  $obj.attachedEvents = new Array();
  
	  if ($obj.attachedEvents[$event])
		  this._removeEvent($obj, $event);
  
	  $obj.attachedEvents[$event] = fn;
  
	  if (typeof $obj.addEventListener != 'undefined') 
		  $obj.addEventListener($event, $handler, false);
	  else if (typeof $obj.attachEvent != 'undefined') 
		  $obj.attachEvent('on' + $event, $handler);
  },

  _removeEvent : function($obj, $event) {
	  if (!$obj.attachedEvents || !$obj.attachedEvents[$event])
		  return;
  
	  if (typeof $obj.removeEventListener != 'undefined') 
		  $obj.removeEventListener($event, $obj.attachedEvents[$event], false);
	  else if (typeof $obj.detachEvent != 'undefined') 
		  $obj.detachEvent('on' + $event, $obj.attachedEvents[$event]);
  },

  _cancelEvent : function(e) {
	  var e = e ? e : window.event;
		  
	  if(e.preventDefault)
		  e.preventDefault();
  
	  if(e.stopPropagation) 
		  e.stopPropagation(); 
  
	  e.cancelBubble = true;
  
	  e.returnValue = false;
	  return false;
  }
  
}





/* JSON ENCODER */

SEMods.Apps.JSON = new function(){

	this.encode = function(){
		var	self = arguments.length ? arguments[0] : this,
			result, tmp;
		if(self === null)
			result = "null";
		else if(self !== undefined && (tmp = $[typeof self](self))) {
			switch(tmp){
				case	Array:
					result = [];
					for(var	i = 0, j = 0, k = self.length; j < k; j++) {
						if(self[j] !== undefined && (tmp = JSON.encode(self[j])))
							result[i++] = tmp;
					};
					result = "[".concat(result.join(","), "]");
					break;
				case	Boolean:
					result = String(self);
					break;
				case	Date:
					result = '"'.concat(self.getFullYear(), '-', d(self.getMonth() + 1), '-', d(self.getDate()), 'T', d(self.getHours()), ':', d(self.getMinutes()), ':', d(self.getSeconds()), '"');
					break;
				case	Function:
					break;
				case	Number:
					result = isFinite(self) ? String(self) : "null";
					break;
				case	String:
					result = '"'.concat(self.replace(rs, s).replace(ru, u), '"');
					break;
				default:
					var	i = 0, key;
					result = [];
					for(key in self) {
						if(self[key] !== undefined && (tmp = JSON.encode(self[key])))
							result[i++] = '"'.concat(key.replace(rs, s).replace(ru, u), '":', tmp);
					};
					result = "{".concat(result.join(","), "}");
					break;
			}
		};
		return result;
	};
	
	/*
	Method: toDate
		transforms a JSON encoded Date string into a native Date object.
	
	Arguments:
		[String/Number] - Optional JSON Date string or server time if this method is not a String prototype. Server time should be an integer, based on seconds since 1970/01/01 or milliseconds / 1000 since 1970/01/01.
	
	Returns:
		Date - Date object or undefined if string is not a valid Date
	
	Example [Basic]:
		>var	serverDate = JSON.toDate("2007-04-05T08:36:46");
		>alert(serverDate.getMonth());	// 3 (months start from 0)
	
	Example [Prototype]:
		>String.prototype.parseDate = JSON.toDate;
		>
		>alert("2007-04-05T08:36:46".parseDate().getDate());	// 5
	
	Example [Server Time]:
		>var	phpServerDate = JSON.toDate(<?php echo time(); ?>);
		>var	csServerDate = JSON.toDate(<%=(DateTime.Now.Ticks/10000-62135596800000)%>/1000);
	
	Example [Server Time Prototype]:
		>Number.prototype.parseDate = JSON.toDate;
		>var	phpServerDate = (<?php echo time(); ?>).parseDate();
		>var	csServerDate = (<%=(DateTime.Now.Ticks/10000-62135596800000)%>/1000).parseDate();
	
	Note:
		This method accepts an integer or numeric string too to mantain compatibility with generic server side time() function.
		You can convert quickly mtime, ctime, time and other time based values.
		With languages that supports milliseconds you can send total milliseconds / 1000 (time is set as time * 1000)
	*/
	this.toDate = function(){
		var	self = arguments.length ? arguments[0] : this,
			result;
		if(rd.test(self)){
			result = new Date;
			result.setHours(i(self, 11, 2));
			result.setMinutes(i(self, 14, 2));
			result.setSeconds(i(self, 17, 2));
			result.setMonth(i(self, 5, 2) - 1);
			result.setDate(i(self, 8, 2));
			result.setFullYear(i(self, 0, 4));
		}
		else if(rt.test(self))
			result = new Date(self * 1000);
		return result;
	};
	
	/* Section: Properties - Private */
	
	/*
	Property: Private
	
	List:
		Object - 'c' - a dictionary with useful keys / values for fast encode convertion
		Function - 'd' - returns decimal string rappresentation of a number ("14", "03", etc)
		Function - 'e' - safe and native code evaulation
		Function - 'i' - returns integer from string ("01" => 1, "15" => 15, etc)
		Array - 'p' - a list with different "0" strings for fast special chars escape convertion
		RegExp - 'rc' - regular expression to check JSON strings (different for IE5 or old browsers and new one)
		RegExp - 'rd' - regular expression to check a JSON Date string
		RegExp - 'rs' - regular expression to check string chars to modify using c (char) values
		RegExp - 'rt' - regular expression to check integer numeric string (for toDate time version evaluation)
		RegExp - 'ru' - regular expression to check string chars to escape using "\u" prefix
		Function - 's' - returns escaped string adding "\\" char as prefix ("\\" => "\\\\", etc.)
		Function - 'u' - returns escaped string, modifyng special chars using "\uNNNN" notation
		Function - 'v' - returns boolean value to skip object methods or prototyped parameters (length, others), used for optional decode filter function
		Function - '$' - returns object constructor if it was not cracked (someVar = {}; someVar.constructor = String <= ignore them)
		Function - '$$' - returns boolean value to check native Array and Object constructors before convertion
	*/
	var	c = {"\b":"b","\t":"t","\n":"n","\f":"f","\r":"r",'"':'"',"\\":"\\","/":"/"},
		d = function(n){return n<10?"0".concat(n):n},
		e = function(c,f,e){e=eval;delete eval;if(typeof eval==="undefined")eval=e;f=eval(""+c);eval=e;return f},
		i = function(e,p,l){return 1*e.substr(p,l)},
		p = ["","000","00","0",""],
		rc = null,
		rd = /^[0-9]{4}\-[0-9]{2}\-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/,
		rs = /(\x5c|\x2F|\x22|[\x0c-\x0d]|[\x08-\x0a])/g,
		rt = /^([0-9]+|[0-9]+[,\.][0-9]{1,3})$/,
		ru = /([\x00-\x07]|\x0b|[\x0e-\x1f])/g,
		s = function(i,d){return "\\".concat(c[d])},
		u = function(i,d){
			var	n=d.charCodeAt(0).toString(16);
			return "\\u".concat(p[n.length],n)
		},
		v = function(k,v){return $[typeof result](result)!==Function&&(v.hasOwnProperty?v.hasOwnProperty(k):v.constructor.prototype[k]!==v[k])},
		$ = {
			"boolean":function(){return Boolean},
			"function":function(){return Function},
			"number":function(){return Number},
			"object":function(o){return o instanceof o.constructor?o.constructor:null},
			"string":function(){return String},
			"undefined":function(){return null}
		},
		$$ = function(m){
			function $(c,t){t=c[m];delete c[m];try{e(c)}catch(z){c[m]=t;return 1}};
			return $(Array)&&$(Object)
		};
	try{rc=new RegExp('^("(\\\\.|[^"\\\\\\n\\r])*?"|[,:{}\\[\\]0-9.\\-+Eaeflnr-u \\n\\r\\t])+?$')}
	catch(z){rc=/^(true|false|null|\[.*\]|\{.*\}|".*"|\d+|\d+\.\d+)$/}
};







/*** PAGE EDITOR ***/









SEMods.Apps.PageEditor = function() {};

SEMods.Apps.PageEditor = {
  apps_pagemenu_active : null,
  layout : {},
  page_id : 0,
  view_id : 0,
  editor_elem : null,
  editor_elem_html : '',
  editor_elem_slide_direction : 0,
  slide_timer : 0,
  slide_chain : [],
  status : 0,   // 0 - unloaded, 1 - loading, 2 - loaded
  designmode : 0, // 0 - no, 1 - full, 2 - mini

  pageeditor_slide : function() {
  
    var m = parseInt(this.editor_elem.style.top);
    var delta = Math.round(Math.max(2, Math.min(12, Math.abs(m)/3))) ;

    // slideout
    if(this.editor_elem_slide_direction == 0) {

      if(m >= 0) {
        this.slide_timer = 0;
        
        next = this.slide_chain.pop();
        if(next) {
          next();
        }
        return;
      }

    } else {
      
      if(m <= -this.editor_elem.offsetHeight) {
        this.slide_timer = 0;

        next = this.slide_chain.pop();
        if(next) {
          next();
        }

        return;
      }
      
      delta = -delta;
      
    }
    this.editor_elem.style.top = m + delta + "px";
    
    this.slide_timer = setTimeout(this.pageeditor_slide.bind(this), 50);
  },

  load_page_editor : function (page_id, view_id) {

    if(this.status > 0)
      return;
    
    this.status = 1;  // loading
    
    this.editor_elem = document.createElement("DIV");
    this.editor_elem.id = "pageeditor_wrapper";
    this.editor_elem.innerHTML = "<div id='pageeditor_topbar' Xstyle='height:30px'><div style='padding: 5px'><img style='float:left;margin-right: 4px' src='./images/apps_ajaxprogress1.gif'>Loading...</div></div>";
    
    //editor_elem.style.display = "none";
    this.editor_elem.style.top = -100 + 'px';
    
    
    document.body.appendChild(this.editor_elem);
    this.editor_elem.style.top = -this.editor_elem.offsetHeight + 'px';
    this.slide_timer = setTimeout(this.pageeditor_slide.bind(this), 50);
  
    this.page_id = page_id;
    this.view_id = view_id;
    var ajax = new SEMods.Ajax( this.onLayoutPageEditorSuccess.bind(this), this.onLayoutPageEditorFail.bind(this) );
    var params = 'task=loadpageeditor&pid=' + this.page_id + '&vid=' + this.view_id + '&user=' + SEMods.Apps.ProfileDragDrop.owner; 
    ajax.post(SEMods.Apps.api_endpoint, params );
  },
  
  
  onAppPlaceCallback : function(identity) {
    
    // not dropped anywhere on the page
    if(identity.stripe == -1) {
      return;
    }
      
    // already in place
    if(identity.placed) {
      return;
    }
    
    identity.placed = true;
    
    SEMods.Apps.placeApp( identity.id, 1, SEMods.Apps.ProfileDragDrop.page_id, SEMods.Apps.ProfileDragDrop.view_id, SEMods.Apps.PageEditor.onAppPlaceFinished );

  },

  onAppPlaceFinished : function(app_id) {
    SEMods.Apps.ProfileDragDrop.updateLayout();
    // full design - load content
    if(SEMods.Apps.PageEditor.designmode == 1) {
      SEMods.B.show('appcontent_'+app_id);
      SEMods.Apps.ProfileDragDrop.reloadContentEx ( app_id );
    }
  },
  
  onLayoutPageEditorSuccess : function(obj, responseText) {
	var r = [];
	try {
	  r = eval('('+responseText+')');
	} catch(e) {
	  r.status = 1;
	};

    this.slide_chain.unshift( function() {this.editor_elem_slide_direction = 1; this.slide_timer = setTimeout(this.pageeditor_slide.bind(this), 50); }.bind(this) );
  
	if(r.status == 0) {
      
      this.layout = r.layout;
      this.page_id = r.layout.page_id;
      this.view_id = r.layout.view_id;
      this.status = 2;

      this.editor_elem_html = r.html;
      
      this.slide_chain.unshift( function() { this.editor_elem_slide_direction = 0; this.editor_elem.innerHTML = this.editor_elem_html; SEMods.Apps.ProfileDragDrop.add_new_objects( this.layout.newobjects, {'onDrop' : SEMods.Apps.PageEditor.onAppPlaceCallback } ); this.slide_timer = setTimeout(this.pageeditor_slide.bind(this), 50); }.bind(this) );

      // pull out settings boxes to prevent weird positioning problem
      this.slide_chain.unshift( function() { var elem = SEMods.B.ge("pageeditor_appsettings");if(elem) { document.body.appendChild( elem.parentNode.removeChild( elem ) );}}.bind(this) );

	} else {

      this.status = 0;
      apps_show_error_message( r.err_msg ? r.err_msg : '' );

    }
    
    
    if(this.slide_timer == 0) {
      var func = this.slide_chain.pop()
      func();
    }

  },

  onLayoutPageEditorFail : function(obj, responseText) {

      apps_show_error_message();
  },
  
  save_layout : function() {
    var ajax = new SEMods.Ajax( this.onSaveLayoutSuccess.bind(this), this.onSaveLayoutFail.bind(this) );
    var params = 'task=savepagelayout&pid=' + this.page_id + '&vid=' + this.view_id + '&user=' + SEMods.Apps.ProfileDragDrop.owner;
    params += '&layout=' + SEMods.Apps.JSON.encode(this.layout);
    ajax.post(SEMods.Apps.api_endpoint, params );
  },

  onSaveLayoutSuccess : function(obj, responseText) {
	var r = [];
	try {
	  r = eval('('+responseText+')');
	} catch(e) {
	  r.status = 1;
	};
      
	if(r.status == 0) {
      document.location = document.location;
	} else {
      apps_show_error_message( r.err_msg ? r.err_msg : '' );
    }
  },

  onSaveLayoutFail : function(obj, responseText) {
      apps_show_error_message();
  },
  
  apps_layoutmenu_onclick : function(id) {

    if(!SEMods.B.ge('widget_'+id).disabled) {
      SEMods.B.ge('widget_'+id).checked = !SEMods.B.ge('widget_'+id).checked;
      this.layout.widgets[id] = SEMods.B.ge('widget_'+id).checked*1;
    }

  },
  
  apps_pageeditmenu_onclick : function(id) {

    var apps_pagemenu_wasactive = this.apps_pagemenu_active;
    this.apps_pageeditmenu_hideall();
    if(apps_pagemenu_wasactive != id) {
      SEMods.B.ge("menubutton_"+id).className = "pageeditor_button_active";
      SEMods.B.show("pageeditor_menu_"+id);
      this.apps_pagemenu_active = id;
    }
  },
  
  apps_pageeditmenu_hideall : function() {
    if(this.apps_pagemenu_active) {
      SEMods.B.ge("menubutton_"+this.apps_pagemenu_active).className = "pageeditor_button";
      SEMods.B.hide("pageeditor_menu_"+this.apps_pagemenu_active);
      this.apps_pagemenu_active = null;
    }
  },
  
  apps_layout_select : function (id) {
    var elems = SEMods.Apps.ProfileDragDrop.getElementsByName_compat("apps_layout_selector", "A");
    for(var i=0;i<elems.length;i++) {
      elems[i].className = "ymenu_item layout_unselected";
    }
    SEMods.B.ge("apps_layout_selector_"+id).className = "ymenu_item layout_selected";
    this.layout.layout_id = id;
  },

  _cancelEvent : function(e) {
	  var e = e ? e : window.event;
		  
	  if(e.preventDefault)
		  e.preventDefault();
  
	  if(e.stopPropagation) 
		  e.stopPropagation(); 
  
	  e.cancelBubble = true;
  
	  e.returnValue = false;
	  return false;
  }
  
}








/* PAGINATOR */

SEMods.Paginator = function(ajax_endpoint, total_items, nohide) {
  this.ajax_endpoint = ajax_endpoint;
  this.total_items = total_items;
  if(nohide) this.nohide = true;
}

SEMods.Paginator.prototype = {
  obj : null,
  ajax_endpoint : '',
  current_page : 1,
  total_items : 1,
  last_visible_item : 1,
  ajaxProgressElem : 'paginator_ajax_progress',
  ajaxContentElem : 'ajax_content',
  nohide : false,
  params : '',
  onError_callback : null,
  
  set_url : function(url) {
    this.ajax_endpoint = url;
  },
  
  set_params : function(params) {
    this.params = params;
  },
  
  paginate_left : function () {
	SEMods.B.ge("left_paginator").blur();
	
	if(this.current_page == 1)
	  return false;
	
	this.paginate(this.current_page - 1);
  },

  paginate_right : function () {
	SEMods.B.ge("right_paginator").blur();
  
	if(this.total_items == this.last_visible_item)
	  return false;
  
    this.paginate(this.current_page + 1);
  },

  paginate : function (page) {
	SEMods.B.toggle( this.ajaxProgressElem, this.ajaxContentElem );
  
	var ajax = new SEMods.Ajax( this.onPaginateSuccess.bind(this), this.onPaginateFail.bind(this) );
	
	var params = "task=getitems" + "&p=" + page + this.params;
	
	ajax.post( this.ajax_endpoint,  params );
  
  },
  
  refresh : function() {
    this.paginate( this.current_page );
  },
  
  hideAll : function() {
	SEMods.B.hide( this.ajaxProgressElem, this.ajaxContentElem, "paginator" );
  },

  showAll : function() {
	SEMods.B.show( this.ajaxContentElem );
	if((this.current_page == 1) && (this.last_visible_item == this.total_items)) {
	  
	}
	else
	  SEMods.B.show("paginator");
	  
  },

  onPaginateSuccess : function (ajaxObj, responseText) {
	var r = [];
	try {
	  r = eval('('+responseText+')');
	  
	} catch(e) {
	  r.status = 1;
	  r.html = 'Error loading content.';
	};
    
    // firefox
    if(typeof r != 'object') {
      r = [];
	  r.status = 1;
	  r.html = 'Error loading content.';
    }
  
	if(r.status == 0) {
	  this.current_page = r.page;
	  this.total_items = r.total;
	  this.last_visible_item = r.to;
	  
	  SEMods.B.ge("page_from").innerHTML = r.from;
	  SEMods.B.ge("page_to").innerHTML = r.to;
	  SEMods.B.ge("total_items").innerHTML = r.total;
	  
	  if(this.total_items == 0) {
		//SEMods.B.hide("voter_votes");
		//SEMods.B.show("voter_no_votes");
	  } else {
  
		//SEMods.B.show("voter_votes");
		//SEMods.B.hide("voter_no_votes");
  
		if((this.current_page == 1) && (this.last_visible_item == this.total_items)) {
		  if(!this.nohide)
            SEMods.B.hide("paginator");
		}
		else {
		  SEMods.B.show("paginator");
		}
		
	  }
	  
	  if(this.current_page == 1) {
		SEMods.B.ge("left_paginator").className = "paginator_disabled";
	  }
	  else {
		SEMods.B.ge("left_paginator").className = "";
	  }
  
	  if(r.total == r.to) {
		SEMods.B.ge("right_paginator").className = "paginator_disabled";
	  }
	  else {
		SEMods.B.ge("right_paginator").className = "";
	  }
	} else if(this.onError_callback) {
      this.onError_callback();
	}
	
	SEMods.B.ge( this.ajaxContentElem ).innerHTML = r.html;
	SEMods.B.toggle( this.ajaxProgressElem, this.ajaxContentElem )
  },

  onPaginateFail : function (ajaxObj, respText) {
	SEMods.B.ge( this.ajaxContentElem ).innerHTML = "Error";
	SEMods.B.toggle( this.ajaxProgressElem, this.ajaxContentElem )

	if(this.onError_callback) {
      this.onError_callback();
    }
  }
  
}

