Was du schon immer schreiben wolltest, aber niemanden interessiert!
30.06.2017 um 19:39
@Lemniskate
es geht voran. Die Positionierung neu geschrieben ( work in progress ). Bugs gefixed. Bissl umdesigned. Geiles Zeig gemacht. Geiles Zeug neu gemacht. Schlechtes Zeug @Lemniskate getauft und den ganzen Tag unterwegs gewesen:
/****/
var evolved_positioning = (function(){
__extends(evolved_positioning, Emitter);
evolved_positioning.prototype.Emitter = Emitter;
function evolved_positioning( options ){
this.options = {
is_within_main_scroll_area : false,
element : options.element, // the element to position
trigger : options.trigger?options.trigger:false, // the element triggered the position
width : options.width?options.width:280,
height : options.height?options.height:320,
callback : options.callback?options.callback:false,
add_distance : options.add_distance?options.add_distance:0,
adjust_height : options.adjust_height?true:false, // if true we adjust the height if needed
inner_element : options.inner_element?options.inner_element:false,
max_width :0,
max_height :0,
root_element :false,
is_within_fixed :false,
is_within_scroll :false,
trigger_width :0,
trigger_height :0,
trigger_left :0,
trigger_top :0,
align :options.align?options.align:false,
handle_as_offcanvas :options.handle_as_offcanvas?true:false,
trigger_offset :false,
overflow_canvas : document.body
};
options.init&&options.init.call(this);
this.set_max_dimensions( document.body );
if(options.handle_as_offcanvas&&options.adjust_height){
this.prepare_for_adjustable_height_popups();
}
this.set_trigger_dimensions( this.options.trigger );
this.get_target_element(this.options.element,function(_this){
if( ! _this.align ){
return _this.vertical_under();
} return _this.get_align_option();
});
};
evolved_positioning.main_scroll_area = 'x-scroll';
evolved_positioning.popup_selector = '._p0p';
evolved_positioning.default_margin_bottom = 10;
/** check if element is within the wanted area and replace it if needed**/
evolved_positioning.prototype.replace_element_if_needed = function( element, new_parent, callback ){
var a = childOf(element,new_parent);
if(a){ return callback(); }
if(!element.parentNode){
new_parent.appendChild(element);
return callback();
}
/** we need to add the element to the needed parent **/
a = element.parentNode.removeChild( element );
new_parent.appendChild(a);
return callback();
};
evolved_positioning.prototype.set_trigger_dimensions = function( trigger ){
var a = this.options.trigger, b = $(a).offset();
this.options.trigger_offset = b;
this.options.trigger_width = trigger.offsetWidth;
this.options.trigger_height = trigger.offsetHeight;
this.options.trigger_top = b.top;
this.options.trigger_left = b.left;
};
evolved_positioning.prototype.set_max_dimensions = function( target_element ){
this.options.max_width = target_element.offsetWidth;
this.options.max_height = Math.max(target_element.offsetHeight,target_element.scrollHeight);
if(this.options.is_within_scroll){
this.options.max_height=false;
}
}
evolved_positioning.prototype.prepare_for_adjustable_height_popups = function(){
/****/
var a = __APP__.PANEL.offsetHeight;
this.options.max_height = this.options.max_height-a-evolved_positioning.default_margin_bottom;
if(this.options.height>this.options.max_height){
this.options.height=this.options.max_height;
}
};
evolved_positioning.prototype.get_target_element = function( element, __callback ){
/****/
var _this = this, trigger = this.options.trigger;
if(this.options.handle_as_offcanvas){
return __callback(_this);
}
this.is_within_fixed( trigger, function(is_within_fixed){
if(!is_within_fixed){
/** not in a fixed element **/
_this.is_within_scroll( trigger, function(is_within_scroll){
if(is_within_scroll){
_this.options.trigger_left = crawl_parents(trigger,is_within_scroll);
_this.options.is_within_scroll = true;
var id = is_within_scroll.getAttribute('id');
if(id==evolved_positioning.main_scroll_area){
/** trigger was in a scrollable element **/
_this.replace_element_if_needed( element, is_within_scroll, function(){
_this.options.root_element = is_within_scroll;
/** get the offset top position for the trigger **/
_this.options.trigger_top = get_relative_position_top(trigger,is_within_scroll);
return __callback(_this);
});
} else{
_this.options.handle_as_offcanvas = true;
// _this.replace_element_if_needed( element, is_within_scroll, function(){});
return __callback(_this);
}
} else{
}
});
}
else{
/** in a fixed element **/
_this.options.is_within_fixed = true;
_this.options.handle_as_offcanvas = true;
return __callback(_this);
}
});
}
/** positioning element centered to trigger ( only horizontal centered ) **/
evolved_positioning.prototype.horizontal_center = function(){
var changed, d, width = this.options.width, max_width = this.options.max_width, element = this.options.element, trigger_left = this.options.trigger_left;
if(this.options.handle_as_offcanvas){
trigger_left=this.options.trigger_offset.left;
}
if( this.align == 'right' ){
/*d = this.trigger_offset.left+this.trigger_width-this.width;
this.element.classList.add('from-right');*/
}
else if( this.align == 'left' ){
/*d = 0;*/
}
else{
d = trigger_left-(width/2)+(this.options.trigger_width/2);
}
if( d+width > max_width ){
d=max_width-width-8;
element.classList.add('from-right');
}
if(d<=8){
d=8;
}
if( d < 24 ){
element.classList.remove('from-right');
element.classList.add('from-left');
}
if(element.style.left==d+'px'){
changed=false;
} else{
changed=true;
element.style.left = d+'px';
}
this.emit('has_horizontal',changed);
};
/** adjust width if needed and cache **/
evolved_positioning.prototype.adjust_dimensions_width = function(){
var element = this.options.element
,width = this.options.width
,cached_width = this.options.element.getAttribute('data-width');
if( ! cache ){
/** cache current width **/
element.setAttribute('data-width',width);
}
else{
/** if current true widht > cached_width we override **/
if( parseInt(cache) < width){
element.setAttribute('data-width',width);
} else{
width = parseInt(cache);
}
}
/** check if width is within allowed range **/
if( width >= this.options.max_width ){ width = this.options.max_width; }
/** we add a class for small elements, not only for smartphones (dirty I know...) **/
if( width < 300 ){
element.classList.add('smartphone');
} else{ element.classList.remove('smartphone'); }
this.options.width = width;
return width;
};
evolved_positioning.prototype.process = function(){
if( ! this.align ){ return this.center_under(); }
return this.get_align_option();
};
evolved_positioning.prototype.get_align_option = function(){
};
evolved_positioning.prototype.remove_css = function(element){
remove_class(element,['under','above']);
};
/** positioning element under a given element **/
evolved_positioning.prototype.vertical_under = function(){
var _this=this, element = this.options.element, trigger_top=this.options.trigger_top, pos='absolute', p, pp;
/** check if element overflows the bottm screen **/
if( this.check_overflows_bottom() ){
//console.log('el overflows bottom ');
//this.height = this.max_height-this.trigger_off.top-this.trigger_height-12;
if( this.check_overflows_top() ){
//console.log('el overflows bottom and above');
}
else{
//console.log('el overflows bottom but not above');
return this.vertical_above();
}
}
/** remove given classes **/
this.remove_css(element);
element.classList.add('under');
if( this.options.handle_as_offcanvas ){
trigger_top = this.options.trigger_offset.top;
pos='fixed';
} else{
}
this.horizontal_center();
/*if( _this.absolute && ! reply ){
var p = document.getElementById(_this.absolute), pp = p.scrollTop+_this.trigger_off.top+_this.trigger_height-p.offsetTop+_this.distance;
}
else{
pp = (_this.trigger_off.top+_this.trigger_height+_this.distance);
pos= 'fixed';
}*/
pp = (trigger_top+_this.options.trigger_height+_this.options.add_distance);
if(!_this.options.adjust_height){
var rounds=0;
while( rounds<300 && this.check_overflows_bottom( rounds*2 ) ){
pp=pp-2;
rounds++;
}
}
element.style.position = pos;
element.style.top = pp+'px';
element.style.width = _this.options.width+'px';
/*if(_this.fit){
_this.element.style.height = _this.height+'px';
if(_this.el2){
_this.el2.style.height = _this.height+'px';
}
}*/
};
/** positioning element above a given element **/
evolved_positioning.prototype.vertical_above = function(){
var _this=this, element = this.options.element, trigger_top=this.options.trigger_top, pos='absolute', p, pp;
/** remove given classes **/
this.remove_css(element);
element.classList.add('above');
if( this.options.handle_as_offcanvas ){
trigger_top = this.options.trigger_offset.top;
pos='fixed';
} else{
}
this.horizontal_center();
pp = (trigger_top-_this.options.add_distance-_this.options.height);
if(!_this.options.adjust_height){
var rounds=0;
while( rounds<300 && this.check_overflows_top( pp ) ){
pp=pp+2;
rounds++;
}
}
element.style.position = pos;
element.style.top = pp+'px';
element.style.width = _this.options.width+'px';
};
/** check if element overflows screen at the bottom **/
evolved_positioning.prototype.check_overflows_bottom = function( pp, callback ){
var canvas = this.options.overflow_canvas, canvas_height = canvas.offsetHeight,trigger_top=this.options.trigger_top;
//if(this.options.handle_as_offcanvas){
trigger_top=this.options.trigger_offset.top;
//}
if(!pp){
pp=0;
}
if( (trigger_top+this.options.trigger_height+this.options.height+this.options.add_distance)-pp>canvas_height ){ return true; }
return false;
};
/** check if element overflows screen at the top **/
evolved_positioning.prototype.check_overflows_top = function( pp,callback ){
var canvas = this.options.overflow_canvas, canvas_height = canvas.offsetHeight,trigger_top=this.options.trigger_top;
//if(this.options.handle_as_offcanvas){
trigger_top=(this.options.trigger_offset.top-this.options.add_distance-this.options.height);
//}
if(pp){
trigger_top=pp;
}
if( trigger_top<12 ){
return true;
}
return false;
};
/** check if element is within a fixed element **/
evolved_positioning.prototype.is_within_fixed = function( trigger, callback ){
check_if_element_is_within_fixed(trigger,callback);
};
/** check if trigger is within main scroll area **/
evolved_positioning.prototype.is_within_scroll = function( trigger, callback ){
var a = get_scroll_area( trigger );
return callback(a);
};
/** check if element is within a popup **/
evolved_positioning.prototype.is_within_popup = function( trigger, callback ){
var a = isAncestorOf( trigger, evolved_positioning.popup_selector, true );
return callback( a );
};
return evolved_positioning;
}).call(this);