PageSourceSearch

https://whentowork.com/js/pop-pos.js

js whentowork.com collected 2026-10-02 07:36:05 UTC 10,390 bytes, 263 lines download raw bytes

1function getAbsolutePos(el) {
2	var SL = 0, ST = 0;
3	var is_div = /^div$/i.test(el.tagName);
4	if (is_div && el.scrollLeft)
5		SL = el.scrollLeft;
6	if (is_div && el.scrollTop)
7		ST = el.scrollTop;
8	var r = { x: el.offsetLeft - SL, y: el.offsetTop - ST };
9	if (el.offsetParent) {
10		var tmp = getAbsolutePos(el.offsetParent);
11		r.x += tmp.x;
12		r.y += tmp.y;
13	}
14	return r;
15};
16
17if (!Object.assign) {
18  Object.defineProperty(Object, 'assign', {
19    enumerable: false,
20    configurable: true,
21    writable: true,
22    value: function(target) {
23      'use strict';
24      if (target === undefined || target === null) {
25        throw new TypeError('Cannot convert first argument to object');
26      }
27
28      var to = Object(target);
29      for (var i = 1; i < arguments.length; i++) {
30        var nextSource = arguments[i];
31        if (nextSource === undefined || nextSource === null) {
32          continue;
33        }
34        nextSource = Object(nextSource);
35
36        var keysArray = Object.keys(Object(nextSource));
37        for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
38          var nextKey = keysArray[nextIndex];
39          var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
40          if (desc !== undefined && desc.enumerable) {
41            to[nextKey] = nextSource[nextKey];
42          }
43        }
44      }
45      return to;
46    }
47  });
48}
49
50//function getRelativePositionEx(parent,layerEl,anchor,position,AbsPosFunc) {
51function getRelativePositionEx(anchor,layerEl,position,	parent,AbsPosFunc) {
52	//"anchor" of the element we want to pin the popup layer to
53	//position: top/bottom/left/right/center
54	//"layerEl" is the div/layer that we're trying to position relative to "anchor"
55	//Optional "parent" provides context for locating "anchor". defaults to document
56	//Optional AbsPosFunc is called to get the absolute position of the anchor element
57	//Returns {'left': x, 'top': y}, where x & y are in whole document coordinates, i.e. not adjusted for scroll position(s).
58
59	/* For testing
60		function ShowRect(l,t,w,h) {
61		var testEl = document.getElementById('test');
62		if (!testEl) {
63			testEl = document.createElement('div');
64			document.body.appendChild(testEl);
65		}	
66		testEl.id = 'test';
67		testEl.style.position = 'absolute';
68		testEl.style.float = 'left';
69		testEl.style.backgroundColor = 'green';
70		testEl.style.borderStyle = 'solid';
71		testEl.style.borderWidth = '1px';
72		testEl.style.borderColor = 'red';
73		testEl.style.left = (l-1)+'px';
74		testEl.style.top = (t-1)+'px';
75		testEl.style.width = (w)+'px';
76		testEl.style.height = (h)+'px';
77	}
78	*/
79	
80	if (anchor.constructor === ({}).constructor) pos = anchor //explicit positioning using json object
81	  else { //Position relative to anchor
82		if (!parent) parent = document;
83		var anchorEl;
84		if (typeof anchor === 'string') anchorEl = parent.querySelector((/^[^#\.]/.test(anchor)?'#':'')+anchor) //if not starts with "#" or ".", then prepend "#" for search-by-id
85			else anchorEl = anchor;
86		if (!anchorEl) {
87			alert('Anchor id "'+anchor+'" does not exist!');
88			return false;
89		}
90		
91		//Default positioning at anchor pos x,y
92		var pos;
93		if (AbsPosFunc) pos = AbsPosFunc(anchorEl)
94		  else {
95			if (anchorEl.getBoundingClientRect) {
96				var info = anchorEl.getBoundingClientRect(); // assume anchorEl is already rendered
97				pos = {x: (info.x||info.left) + window.pageXOffset, y: (info.y||info.top) + window.pageYOffset};
98			} else pos = getAbsolutePos(anchorEl);
99		  }	
100		layerEl.left = pos.x; 
101		layerEl.top = pos.y;
102		// layerEl's width & height may not be explicitly assigned, so we will "secretly" measure the rendered element
103		// and make explicit assignments to offsetWidth & offsetHeight for use by subsequent code.
104		var saveVis = layerEl.style.visibility;
105		var saveDisp = layerEl.style.display;
106		layerEl.style.position = 'absolute'; //Needed for consistent position measurement/application of pageXOffset/pageYOffset ("fixed" changes behavior!)
107		layerEl.style.visibility = 'hidden'; //Don't show it yet because we're going to move it eventually
108		layerEl.style.display = 'block'; //so getBoundingClientRect() can measure it
109		if (layerEl.getBoundingClientRect) {
110			var info = layerEl.getBoundingClientRect();
111			layerEl.offsetWidth = info.width;
112			layerEl.offsetHeight = info.height;
113		} else {
114			layerEl.offsetWidth = 300;
115			layerEl.offsetHeight = 381;
116		}
117		
118		if (anchorEl == document||anchorEl == window) { //for this case, position should always be "center" 
119			pos.x = 0;
120			pos.y = 0;
121			pos.width = window.innerWidth;
122			pos.height = window.innerHeight;
123		} else {
124			pos.width = anchorEl.offsetWidth;
125			pos.height = anchorEl.offsetHeight;
126		}
127	}
128	//At this point, pos holds the position and size in the entire scrollable canvas
129	function getScrollbarWidth() {
130		var outer = document.createElement("div");
131		outer.style.visibility = "hidden";
132		outer.style.width = "100px";
133		outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
134
135		document.body.appendChild(outer);
136
137		var widthNoScroll = outer.offsetWidth;
138		// force scrollbars
139		outer.style.overflow = "scroll";
140
141		// add innerdiv
142		var inner = document.createElement("div");
143		inner.style.width = "100%";
144		outer.appendChild(inner);        
145
146		var widthWithScroll = inner.offsetWidth;
147
148		// remove divs
149		outer.parentNode.removeChild(outer);
150
151		return widthNoScroll - widthWithScroll;
152	}	
153	var savePos = Object.assign({}, pos);
154	var requestedPos;
155	var preferredPos;
156	var scrollBarSize = 20;
157	var scrollbarSize = getScrollbarWidth();
158    var viewsize = {
159      width: document.body.clientWidth || window.innerWidth,
160      height: document.body.clientHeight || window.innerHeight
161    }	
162	var sbSizeVert = (document.body.scrollHeight > viewsize.height) ? scrollbarSize : 0;
163	var sbSizeHorz = (document.body.scrollWidth > viewsize.width) ? scrollbarSize : 0;
164	
165	var clientWidth = window.innerWidth-sbSizeVert;
166	var clientHeight = window.innerHeight-sbSizeHorz;
167	
168	function BottomOrTopCorrections(reqAbove) {
169		//Check clearance on the bottom
170		if (pos.y+layerEl.offsetHeight- window.pageYOffset > clientHeight) //Doesn't fit on the bottom, choose by preference
171			pos.y = savePos.y-layerEl.offsetHeight; // move to top
172		var deltaTop = pos.y- window.pageYOffset;
173		if (deltaTop < 0) //Didn't fit above
174			pos.y = savePos.y+savePos.height; // move to bottom
175		
176		//Final check for any clipping in Y dimension
177		var deltaBottom = (pos.y+layerEl.offsetHeight- window.pageYOffset) - clientHeight;
178		if (deltaBottom > 0) pos.y = requestedPos.y - (reqAbove?deltaTop:deltaBottom);	//No fit top or bottom, choose by preference
179
180		if (preferredPos) {
181			pos.x = preferredPos.x; //Already calculated/optimized in prior call to tryPosition()
182			//preferredPos may be improve-able for this axis, so try to line up x-a
182xis edges, if possible
183			if (preferredPos.x > savePos.x) pos.x = savePos.x; //Left edge
184			if (preferredPos.x+layerEl.offsetWidth < savePos.x+savePos.width) pos.x = savePos.x+savePos.width-layerEl.offsetWidth; //Right edge
185		} else {
186			//If it's clipped in the alternate axis, just scoot it over
187			if (pos.x+layerEl.offsetWidth- window.pageXOffset > clientWidth)
188				pos.x = clientWidth - layerEl.offsetWidth;
189			if (pos.x- window.pageXOffset < 0)
190				pos.x = window.pageXOffset;
191		}	
192		
193		return deltaBottom <= 0; //Return false if no fit on either
194	}	
195		
196	function LeftOrRightCorrections(reqLeft) {
197		//Check clearance on the right
198		if (pos.x+layerEl.offsetWidth- window.pageXOffset > clientWidth) //Doesn't fit on the right
199			pos.x = savePos.x-layerEl.offsetWidth; // move to left
200		var deltaLeft = pos.x- window.pageXOffset;
201		if (deltaLeft < 0) //Didn't fit on the left side
202			pos.x = savePos.x+savePos.width; // move to right
203
204		//Final check for any clipping in X dimension
205		var deltaRight = (pos.x+layerEl.offsetWidth- window.pageXOffset) - clientWidth;
206		if (deltaRight > 0) pos.x = requestedPos.x - (reqLeft?deltaLeft:deltaRight); //No fit left or right
207			
208		if (preferredPos) {
209			pos.y = preferredPos.y; //Already calculated/optimized in prior call to tryPosition()
210			//preferredPos may be improve-able for this axis, so try to line up y-axis edges, if possible
211			if (preferredPos.y > savePos.y) pos.y = savePos.y; //Top edge
212			if (preferredPos.y+layerEl.offsetHeight < savePos.y+savePos.height) pos.y = savePos.y+savePos.height-layerEl.offsetHeight; //Bottom edge
213		} else {
214			//If it's clipped in the alternate axis, just scoot it over
215			if (pos.y+layerEl.offsetHeight- window.pageYOffset > clientHeight)
216				pos.y = clientHeight - layerEl.offsetHeight;
217			if (pos.y- window.pageYOffset < 0)
218				pos.y = window.pageYOffset;
219		}
220	
221		return deltaRight <= 0; //Return false if no fit on either
222	}
223	
224	if (position == 'center') {
225			pos.x = pos.x + (pos.width-layerEl.offsetWidth)/2;
226			pos.y = pos.y + (pos.height-layerEl.offsetHeight)/2;
227	} else {
228		function tryPosition(position) {
229			switch (position) {
230				case 'top': 
231					pos.y = pos.y-layerEl.offsetHeight-2;
232					requestedPos = Object.assign({}, pos);
233					return BottomOrTopCorrections(true);
234				case 'bottom': 
235					pos.y = pos.y+pos.height+1;
236					requestedPos = Object.assign({}, pos);
237					return BottomOrTopCorrections(false);
238				case 'left': 
239					pos.x = pos.x-layerEl.offsetWidth-3;
240					requestedPos = Object.assign({}, pos);
241					return LeftOrRightCorrections(true);
242				case 'right': 
243					pos.x = pos.x+pos.width+3;
244					requestedPos = Object.assign({}, pos);
245					return LeftOrRightCorrections(false);
246				default: return false;
247			}
248		}
249		var success = tryPosition(position);
250		if (!success) { //Try for fit in the alternate axis
251			preferredPos = Object.assign({}, pos); //If alt-axis fails then we will use this
252			pos = Object.assign({}, savePos); //Restore to original
253			if (!tryPosition(position=='top'||position=='bottom'?'right':'bottom')) pos = preferredPos; //Try alt w/ preference for right/bottom, else use prior
254		}	
255	}
256	
257	layerEl.style.display = saveDisp;
258	layerEl.style.visibility = saveVis;
259	
260	//ShowRect(pos.x,pos.y,layerEl.offsetWidth,layerEl.offsetHeight);
261	
262	return {'left': pos.x, 'top': pos.y, 'x': pos.x, 'y': pos.y}
263}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.