UNPKG

8.44 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.equalCoords = exports.doesFitWithin = exports.centerOfBoundsFromBounds = exports.centerOfBounds = exports.centerOfSize = exports.axes = exports.pickZone = exports.place = exports.calcRelPos = exports.validTypeValues = exports.types = exports.El = undefined;
7
8var _platform = require("./platform");
9
10var _utils = require("./utils");
11
12function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
13
14/* Axes System
15
16This allows us to at-will work in a different orientation
17without having to manually keep track of knowing if we should be using
18x or y positions. */
19
20var axes = {
21 row: {},
22 column: {}
23};
24
25axes.row.main = {
26 start: "x",
27 end: "x2",
28 size: "w"
29};
30axes.row.cross = {
31 start: "y",
32 end: "y2",
33 size: "h"
34};
35axes.column.main = axes.row.cross;
36axes.column.cross = axes.row.main;
37
38var types = [{ name: "side", values: ["start", "end"] }, { name: "standing", values: ["above", "right", "below", "left"] }, { name: "flow", values: ["column", "row"] }];
39
40var validTypeValues = types.reduce(function (xs, _ref) {
41 var values = _ref.values;
42 return xs.concat(values);
43}, []);
44
45var centerOfSize = function centerOfSize(flow, axis, size) {
46 return size[axes[flow][axis].size] / 2;
47};
48
49var centerOfBounds = function centerOfBounds(flow, axis, bounds) {
50 return bounds[axes[flow][axis].start] + bounds[axes[flow][axis].size] / 2;
51};
52
53var centerOfBoundsFromBounds = function centerOfBoundsFromBounds(flow, axis, boundsTo, boundsFrom) {
54 return centerOfBounds(flow, axis, boundsTo) - boundsFrom[axes[flow][axis].start];
55};
56
57var place = function place(flow, axis, align, bounds, size) {
58 var axisProps = axes[flow][axis];
59 return align === "center" ? centerOfBounds(flow, axis, bounds) - centerOfSize(flow, axis, size) : align === "end" ? bounds[axisProps.end] : align === "start"
60 /* DOM rendering unfolds leftward. Therefore if the slave is positioned before
61 the master then the slave`s position must in addition be pulled back
62 by its [the slave`s] own length. */
63 ? bounds[axisProps.start] - size[axisProps.size] : null;
64};
65
66/* Element Layout Queries */
67
68var El = {};
69
70El.calcBounds = function (el) {
71
72 if (el === _platform.window) {
73 return {
74 x: 0,
75 y: 0,
76 x2: el.innerWidth,
77 y2: el.innerHeight,
78 w: el.innerWidth,
79 h: el.innerHeight
80 };
81 }
82
83 var b = el.getBoundingClientRect();
84
85 return {
86 x: b.left,
87 y: b.top,
88 x2: b.right,
89 y2: b.bottom,
90 w: b.right - b.left,
91 h: b.bottom - b.top
92 };
93};
94
95El.calcSize = function (el) {
96 return el === _platform.window ? { w: el.innerWidth, h: el.innerHeight } : { w: el.offsetWidth, h: el.offsetHeight };
97};
98
99El.calcScrollSize = function (el) {
100 return el === _platform.window ? {
101 w: el.scrollX || el.pageXOffset,
102 h: el.scrollY || el.pageYOffset
103 } : { w: el.scrollLeft, h: el.scrollTop };
104};
105
106/* Misc Utilities */
107
108var getPreferenceType = function getPreferenceType(preference) {
109 return types.reduce(function (found, type) {
110 return found ? found : type.values.indexOf(preference) !== -1 ? type.name : null;
111 }, null);
112};
113
114/* Dimension Fit Checks */
115
116var fitWithinChecker = function fitWithinChecker(dimension) {
117 return function (domainSize, itemSize) {
118 return domainSize[dimension] >= itemSize[dimension];
119 };
120};
121
122var doesWidthFitWithin = fitWithinChecker("w");
123var doesHeightFitWithin = fitWithinChecker("h");
124
125var doesFitWithin = function doesFitWithin(domainSize, itemSize) {
126 return doesWidthFitWithin(domainSize, itemSize) && doesHeightFitWithin(domainSize, itemSize);
127};
128
129/* Errors */
130
131var createPreferenceError = function createPreferenceError(givenValue) {
132 return new Error("The given layout placement of \"" + givenValue + "\" is not a valid choice. Valid choices are: " + validTypeValues.join(" | ") + ".");
133};
134
135/* Algorithm for picking the best fitting zone for popover. The current technique will loop through all zones picking the last one that fits.
136In the case that none fit we should pick the least-not-fitting zone. */
137
138var pickZone = function pickZone(opts, frameBounds, targetBounds, size) {
139 var t = targetBounds;
140 var f = frameBounds;
141 var zones = [{ side: "start", standing: "above", flow: "column", order: -1, w: f.x2, h: t.y }, { side: "end", standing: "right", flow: "row", order: 1, w: f.x2 - t.x2, h: f.y2 }, { side: "end", standing: "below", flow: "column", order: 1, w: f.x2, h: f.y2 - t.y2 }, { side: "start", standing: "left", flow: "row", order: -1, w: t.x, h: f.y2 }];
142
143 /* Order the zones by the amount of popup that would be cut out if that zone is used.
144 The first one in the array is the one that cuts the least amount.
145 const area = size.w * size.h // Popup area is constant and it does not change the order
146 */
147 zones.forEach(function (z) {
148 // TODO Update to satisfy linter
149 // eslint-disable-next-line no-param-reassign
150 z.cutOff = /* area */-Math.max(0, Math.min(z.w, size.w)) * Math.max(0, Math.min(z.h, size.h));
151 });
152 zones.sort(function (a, b) {
153 return a.cutOff - b.cutOff;
154 });
155
156 var availZones = zones.filter(function (zone) {
157 return doesFitWithin(zone, size);
158 });
159
160 /* If a place is required pick it from the available zones if possible. */
161
162 if (opts.place) {
163 var type = getPreferenceType(opts.place);
164 if (!type) throw createPreferenceError(opts.place);
165 var finder = function finder(z) {
166 return z[type] === opts.place;
167 };
168 return (0, _utils.find)(finder, availZones) || (0, _utils.find)(finder, zones);
169 }
170
171 /* If the preferred side is part of the available zones, use that otherwise
172 pick the largest available zone. If there are no available zones, pick the
173 largest zone. */
174
175 if (opts.preferPlace) {
176 var preferenceType = getPreferenceType(opts.preferPlace);
177 if (!preferenceType) throw createPreferenceError(opts.preferPlace);
178
179 // Try to fit first in zone where the pop up fit completely
180 var preferredAvailZones = availZones.filter(function (zone) {
181 return zone[preferenceType] === opts.preferPlace;
182 });
183 if (preferredAvailZones.length) return preferredAvailZones[0];
184
185 // If there are not areas where the pop up fit completely, it uses the preferred ones
186 // in order from the one the fit better
187 var preferredZones = zones.filter(function (zone) {
188 return zone[preferenceType] === opts.preferPlace;
189 });
190 if (!availZones.length && preferredZones.length) return preferredZones[0];
191 }
192
193 // Return a zone that fit completely or the one that fit the best
194 return availZones.length ? availZones[0] : zones[0];
195};
196
197/* TODO Document this. */
198
199var calcRelPos = function calcRelPos(zone, masterBounds, slaveSize) {
200 var _ref2;
201
202 var _axes$zone$flow = axes[zone.flow],
203 main = _axes$zone$flow.main,
204 cross = _axes$zone$flow.cross;
205 /* TODO: The slave is hard-coded to align cross-center with master. */
206
207 var crossAlign = "center";
208 var mainStart = place(zone.flow, "main", zone.side, masterBounds, slaveSize);
209 var mainSize = slaveSize[main.size];
210 var crossStart = place(zone.flow, "cross", crossAlign, masterBounds, slaveSize);
211 var crossSize = slaveSize[cross.size];
212
213 return _ref2 = {}, _defineProperty(_ref2, main.start, mainStart), _defineProperty(_ref2, "mainLength", mainSize), _defineProperty(_ref2, main.end, mainStart + mainSize), _defineProperty(_ref2, cross.start, crossStart), _defineProperty(_ref2, "crossLength", crossSize), _defineProperty(_ref2, cross.end, crossStart + crossSize), _ref2;
214};
215
216exports.default = {
217 El: El,
218 types: types,
219 validTypeValues: validTypeValues,
220 calcRelPos: calcRelPos,
221 place: place,
222 pickZone: pickZone,
223 axes: axes,
224 centerOfSize: centerOfSize,
225 centerOfBounds: centerOfBounds,
226 centerOfBoundsFromBounds: centerOfBoundsFromBounds,
227 doesFitWithin: doesFitWithin,
228 equalCoords: _utils.equalRecords
229};
230exports.El = El;
231exports.types = types;
232exports.validTypeValues = validTypeValues;
233exports.calcRelPos = calcRelPos;
234exports.place = place;
235exports.pickZone = pickZone;
236exports.axes = axes;
237exports.centerOfSize = centerOfSize;
238exports.centerOfBounds = centerOfBounds;
239exports.centerOfBoundsFromBounds = centerOfBoundsFromBounds;
240exports.doesFitWithin = doesFitWithin;
241exports.equalCoords = _utils.equalRecords;
\No newline at end of file