UNPKG

next-csrf

Version:

CSRF mitigation library for Next.js

141 lines (115 loc) 4.41 kB
// determine if an element is rendered // NOTE: that does not mean an element is visible in the viewport, see util/visible-area import findIndex from '../util/array-find-index'; import getParents from '../get/parents'; import contextToElement from '../util/context-to-element'; import getFrameElement from '../util/get-frame-element'; // https://www.w3.org/TR/html5/rendering.html#being-rendered // <area> is not rendered, but we *consider* it visible to simplfiy this function's usage var notRenderedElementsPattern = /^(area)$/; function computedStyle(element, property) { return window.getComputedStyle(element, null).getPropertyValue(property); } function notDisplayed(_path) { return _path.some(function (element) { // display:none is not visible (optimized away at layout) return computedStyle(element, 'display') === 'none'; }); } function notVisible(_path) { // https://github.com/jquery/jquery-ui/blob/master/ui/core.js#L109-L114 // NOTE: a nested element can reverse visibility:hidden|collapse by explicitly setting visibility:visible // NOTE: visibility can be ["", "visible", "hidden", "collapse"] var hidden = findIndex(_path, function (element) { var visibility = computedStyle(element, 'visibility'); return visibility === 'hidden' || visibility === 'collapse'; }); if (hidden === -1) { // there is no hidden element return false; } var visible = findIndex(_path, function (element) { return computedStyle(element, 'visibility') === 'visible'; }); if (visible === -1) { // there is no visible element (but a hidden element) return true; } if (hidden < visible) { // there is a hidden element and it's closer than the first visible element return true; } // there may be a hidden element, but the closest element is visible return false; } function collapsedParent(_path) { var offset = 1; if (_path[0].nodeName.toLowerCase() === 'summary') { offset = 2; } return _path.slice(offset).some(function (element) { // "content children" of a closed details element are not visible return element.nodeName.toLowerCase() === 'details' && element.open === false; }); } function isVisibleRules() { var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, context = _ref.context, _ref$except = _ref.except, except = _ref$except === undefined ? { notRendered: false, cssDisplay: false, cssVisibility: false, detailsElement: false, browsingContext: false } : _ref$except; var element = contextToElement({ label: 'is/visible', resolveDocument: true, context: context }); var nodeName = element.nodeName.toLowerCase(); if (!except.notRendered && notRenderedElementsPattern.test(nodeName)) { return true; } var _path = getParents({ context: element }); // in Internet Explorer <audio> has a default display: none, where others have display: inline // but IE allows focusing <audio style="display:none">, but not <div display:none><audio> // this is irrelevant to other browsers, as the controls attribute is required to make <audio> focusable var isAudioWithoutControls = nodeName === 'audio' && !element.hasAttribute('controls'); if (!except.cssDisplay && notDisplayed(isAudioWithoutControls ? _path.slice(1) : _path)) { return false; } if (!except.cssVisibility && notVisible(_path)) { return false; } if (!except.detailsElement && collapsedParent(_path)) { return false; } if (!except.browsingContext) { // elements within a browsing context are affected by the // browsing context host element's visibility and tabindex var frameElement = getFrameElement(element); var _isVisible = isVisibleRules.except(except); if (frameElement && !_isVisible(frameElement)) { return false; } } return true; } // bind exceptions to an iterator callback isVisibleRules.except = function () { var except = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var isVisible = function isVisible(context) { return isVisibleRules({ context: context, except: except }); }; isVisible.rules = isVisibleRules; return isVisible; }; // provide isVisible(context) as default iterator callback var isVisible = isVisibleRules.except({}); export default isVisible; //# sourceMappingURL=visible.js.map