
//- Popup -----------------------------------------------------------------
// •needs:	jquery & jquery.disable.text.select


function Popup(name, body_poppedup_class, sedentary) {
  if (document.getElementById) {
	var popup_id = name+"-layer";
	this.body = document.getElementsByTagName('body')[0];
	if (body_poppedup_class) this.poppedup_class = body_poppedup_class;
	this.content_class = name+"-body";
	this.closer_class = 'closer';

	var popup = document.getElementById(popup_id);
	if (!popup) { // create popup div if page doesn’t provide it
		popup = document.createElement('div');
		popup.id = popup_id;
		popup.className = "popup-layer";
		popup.innerHTML = '<a class="'+this.closer_class+'" href="#close-popup:'+popup.id+'">×</a>\
<div class="'+this.content_class+' popup-body">\
</div>';
		// add closer’s popup hider
		var _ = this;
		var closer = popup.firstChild;
		closer.onclick = function(){ _.hide(); return false };
		this.body.appendChild(popup);
	}
	if (!sedentary) {
		var _ = this;
		popup.onmousedown = function(e){_.start_moving(e)};
	}
	this.popup_block = popup;

	this.moving = false;// current & offset must be x,y pairs when true
	this.hide();
  } else { throw new Error("Popup needs getElementById which is not supported") }
}


Popup.prototype.get_current_position = (function($){return function(){
	// the parseInts effectively convert 40% into 40px (only safe for px)
	/*return { x: parseInt( $(this.popup_block).css('left') ),
	         y: parseInt( $(this.popup_block).css('top') ) };*/
	var _o = $(this.popup_block).offset();
	// correct for any scrolling (assuming popup is position:fixed)
	if ($(this.popup_block).css('position') == "fixed") {
		_o.top -= $("html").scrollTop();
		_o.left -= $("html").scrollLeft();
	}
	return { x: _o.left, y: _o.top };
} })(jQuery);

// dimensions if not constrained by document’s width/height (call when hidden)
Popup.prototype.get_natural_dimensions = function () {
	// display has to be block to get dimensions; hidden & opacity
	//  prevent flicker/jump to top left when offsetWidth’s checked
	var saved = { top:  this.popup_block.style.top,
	              left: this.popup_block.style.left,
	              display: this.popup_block.style.display,
	              visibility: this.popup_block.style.visibility,
	              zIndex: this.popup_block.style.zIndex };
	if (this.popup_block.style.opacity != undefined)
		saved.opacity = this.popup_block.style.opacity;
	with (this.popup_block) { style.zIndex = '-100';
	                          style.visibility = 'hidden';
	                          if (style.opacity != undefined)
	                            style.opacity = 0;
		                  style.top = '0px';
	                          style.left = '0px';
	                          style.display = 'block'; }
	// this is slightly off
	var p = { w: this.popup_block.offsetWidth,
	          h: this.popup_block.offsetHeight };
	with (this.popup_block) { style.display = saved.display;
	                          style.top = saved.top;
	                          style.left = saved.left;
	                          if (style.opacity != undefined)
	                            style.opacity = saved.opacity;
	                          style.visibility = saved.visibility;
	                          style.zIndex = saved.zIndex; }
	return p;
}

Popup.prototype.is_showing = function () {
	return this.popup_block.style.display != 'none';
}

Popup.prototype.show = function () { with (this) {
	if (is_showing()) return; // already showing
	// remove any properties that were saved during moves
	if (popup_block.style.width) popup_block.style.width = '';
	// display invisibly (so position can be determined w/o visible jump)
	var dim = get_natural_dimensions();
	popup_block.style.visibility = 'hidden';
	popup_block.style.display = 'block';
	//var dim = { w: 100, h: 100 };
	var current = get_current_position();
	//var current = { w: 150, h: 100 };
	var dim = { w: popup_block.offsetWidth, h: popup_block.offsetHeight };
	//popup_block.dimensions = dim; // for no-move-beyond-boundaries
	// if popup’s outside of visible window, reset it
	if (current.x < 0 || document.body.clientWidth < current.x + dim.w
	 || current.y < 0 || document.body.clientHeight < current.y + dim.h ) {
	  popup_block.style.left = '';
	  popup_block.style.top  = '';
	}
	if (current.y + dim.h > document.body.clientHeight) {
		popup_block.style.top -= 200;
	}
	if (this.poppedup_class) {
		this.remove_poppedup_class = undefined;// prevent double-shading
		jQuery(body).addClass(poppedup_class);
	}
	// reveal properly position popup
	popup_block.style.visibility = '';
} }

Popup.prototype.hide = function () { with (this) {
	popup_block.style.display = 'none';
	//popup_block.dimensions = undefined; // for no-move-beyond-boundaries
	// this remove_poppedup_class delay stuff keeps a dialog from closing,
	//  the background unshading, and a notification that pops up within a
	//  half second shading the background again
	if (this.poppedup_class) {
		this.remove_poppedup_class = true;
		var _ = this;
		setTimeout(function(){if (_.remove_poppedup_class) jQuery(_.body).removeClass(_.poppedup_class)}, 500);
	}
} }


Popup.prototype.start_moving = (function($){return function (e) { with (this) {
	if (!e) var e = window.event;
	var clicked_node = e.target ? e.target : e.srcElement;
	// was mouse clicked on something inside the popup?
	while ((clicked_node && clicked_node.id != popup_block.id)
	     && !$(clicked_node).hasClass(content_class)
	     && !$(clicked_node).hasClass(closer_class)
	     && clicked_node.tagName != "body") {
		clicked_node = document.all ? clicked_node.parentElement
		                            : clicked_node.parentNode }
	if (clicked_node.id == popup_block.id) {// on/in popup drag area so move
		this.offset = { x: e.clientX, y: e.clientY };
		this.current = get_current_position();
		this.moving = true;
		// don’t resize when moving
		var _b = $(popup_block);
		if ( isNaN(parseInt(_b.css('width'))) ) {
			// problems getting width w/ ie8:
			// padding incorrectly detected as 1px, regardless of
			// real value; clientWidth/offsetWidth/the jQuery
			// width functions don't return real values, so..
			var _i = _b.find(".popup-body");
			//inside_alert("layer b is "+_b.width()+", body i is "+_i.width());
			var _w = _i.outerWidth();
			$(popup_block).css('width', _w+"px");
		}
		var _ = this;
		this.move_listener = function(e){_.move_popup(e)};
		$(document).bind('mousemove', this.move_listener);
		//add_event_listener(document, 'mousemove', function(e){_.move_popup(e)});
		this.done_listener = function(e){_.done_moving(e)};
		$(document).bind('mouseup', this.done_listener);
		//add_event_listener(document, 'mouseup', function(e){_.done_moving(e)});

		// prevent random selections of dialog content while moving
		$(popup_block).disableTextSelect();
		//disable_element_selection(popup_block);

		// for no-move-beyond-boundaries
		//this.available_width = document.body.clientWidth - parseInt( getStyle(document.body, 'margin-left') ) - parseInt( getStyle(document.body, 'margin-right') );
		//this.available_height = document.body.clientHeight - parseInt( getStyle(document.body, 'margin-top') ) - parseInt( getStyle(document.body, 'margin-bottom') );
	} //else alert("Clicked id " + clicked_node.id);
} } })(jQuery);

Popup.prototype.move_popup = function (e) { with (this) {
	if (!e) var e = window.event;
	if (moving) {
		popup_block.style.left = (current.x + e.clientX - offset.x)+"px";
		popup_block.style.top  = (current.y + e.clientY - offset.y)+"px";
		/*free_l = current.x + e.clientX - offset.x;
		//setTimeout(function(){inside_alert("width "+popup_block.dimensions.w); moving = false}, 10);
		h_displacement = free_l + popup_block.dimensions.w;
		popup_block.style.left = (h_displacement > available_width
			? available_width - popup_block.dimensions.w
			: free_l)+"px";
		free_t = current.y + e.clientY - offset.y;
		v_displacement = free_t + popup_block.dimensions.h;
		popup_block.style.top = (v_displacement > available_height
			? available_height - popup_block.dimensions.h
			: free_t)+"px";*/
	}
	return false;  
} }

Popup.prototype.done_moving = (function($){return function (e) { with (this) {
	$(popup_block).enableTextSelect();
	//enable_element_selection(popup_block);
	moving = false;
	// cleanup
	$(document).unbind('mousemove', this.move_listener);
	this.move_listener = undefined;	//remove_event_listener(move_listener);
	$(document).unbind('mouseup', this.done_listener);
	this.done_listener = undefined;	//remove_event_listener(done_listener);
	this.current = undefined; this.offset = undefined;
	// for no-move-beyond-boundaries
	//this.available_width = undefined;
	//this.available_height = undefined;
} } })(jQuery);


Popup.prototype.backend = (function($){return function (content) { with (this) {
	var html_content_class = 'html-content';
	var el = $(popup_block).find("."+content_class).eq(0);
	/* if the content_class can’t be found, guess instead of failing */
	var popup_body = $(el).length ? el.get(0) : popup_block.childNodes[1];
	var is_html_content = function () {
		return $(popup_body).hasClass(html_content_class);
	};
	var change_content = function (new_content) {
		var former_content = popup_body.childNodes[0];
		// replacing a dom node with itself crashes netscape 8.1
		if (former_content == new_content) return;
		if (former_content) {
			popup_body.removeChild(former_content);
			// if former_content was taken from the page body..
			//former_content.style.display = 'none';
			//body.appendChild(former_content);
		}
		if (new_content)
			popup_body.appendChild(new_content);
	};
	if (typeof(content) == 'string') {
		if (!is_html_content()) {
			change_content();
			$(popup_body).addClass(html_content_class);
		}
		popup_body.innerHTML = content;
	}
	else if (typeof(content) == 'object') { /* ie. a dom node */
		if (is_html_content()) {
			$(popup_body).removeClass(html_content_class);
			popup_body.innerHTML = '';
			popup_body.appendChild(content);
		}
		else
			change_content(content);
	}
	show();
	// let page know popup’s changed content
	$(document).trigger('popup-content-changed', popup_body);
	// Gecko 1.7 doesn’† size invisible popups properly w/o a style adjust
	if ( navigator.product == "Gecko"
	  && navigator.userAgent.match(/rv:1.7/) ) with (popup.style) {
		visibility = "hidden";
		var saved = width;
		width = "100px";
		setTimeout(function(){width = saved; visibility = ""}, 10);
	}
	return false;
} } })(jQuery);


Popup.prototype.popup_dom_node = function (node) { return this.backend(node) }
Popup.prototype.popup_html = function (html) { return this.backend(html) }

