iframe.js 3.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. let hasDifferentOriginAncestorFlag = false;
  6. let sameOriginWindowChainCache = null;
  7. function getParentWindowIfSameOrigin(w) {
  8. if (!w.parent || w.parent === w) {
  9. return null;
  10. }
  11. // Cannot really tell if we have access to the parent window unless we try to access something in it
  12. try {
  13. let location = w.location;
  14. let parentLocation = w.parent.location;
  15. if (location.origin !== 'null' && parentLocation.origin !== 'null') {
  16. if (location.protocol !== parentLocation.protocol || location.hostname !== parentLocation.hostname || location.port !== parentLocation.port) {
  17. hasDifferentOriginAncestorFlag = true;
  18. return null;
  19. }
  20. }
  21. }
  22. catch (e) {
  23. hasDifferentOriginAncestorFlag = true;
  24. return null;
  25. }
  26. return w.parent;
  27. }
  28. export class IframeUtils {
  29. /**
  30. * Returns a chain of embedded windows with the same origin (which can be accessed programmatically).
  31. * Having a chain of length 1 might mean that the current execution environment is running outside of an iframe or inside an iframe embedded in a window with a different origin.
  32. * To distinguish if at one point the current execution environment is running inside a window with a different origin, see hasDifferentOriginAncestor()
  33. */
  34. static getSameOriginWindowChain() {
  35. if (!sameOriginWindowChainCache) {
  36. sameOriginWindowChainCache = [];
  37. let w = window;
  38. let parent;
  39. do {
  40. parent = getParentWindowIfSameOrigin(w);
  41. if (parent) {
  42. sameOriginWindowChainCache.push({
  43. window: w,
  44. iframeElement: w.frameElement || null
  45. });
  46. }
  47. else {
  48. sameOriginWindowChainCache.push({
  49. window: w,
  50. iframeElement: null
  51. });
  52. }
  53. w = parent;
  54. } while (w);
  55. }
  56. return sameOriginWindowChainCache.slice(0);
  57. }
  58. /**
  59. * Returns true if the current execution environment is chained in a list of iframes which at one point ends in a window with a different origin.
  60. * Returns false if the current execution environment is not running inside an iframe or if the entire chain of iframes have the same origin.
  61. */
  62. static hasDifferentOriginAncestor() {
  63. if (!sameOriginWindowChainCache) {
  64. this.getSameOriginWindowChain();
  65. }
  66. return hasDifferentOriginAncestorFlag;
  67. }
  68. /**
  69. * Returns the position of `childWindow` relative to `ancestorWindow`
  70. */
  71. static getPositionOfChildWindowRelativeToAncestorWindow(childWindow, ancestorWindow) {
  72. if (!ancestorWindow || childWindow === ancestorWindow) {
  73. return {
  74. top: 0,
  75. left: 0
  76. };
  77. }
  78. let top = 0, left = 0;
  79. let windowChain = this.getSameOriginWindowChain();
  80. for (const windowChainEl of windowChain) {
  81. top += windowChainEl.window.scrollY;
  82. left += windowChainEl.window.scrollX;
  83. if (windowChainEl.window === ancestorWindow) {
  84. break;
  85. }
  86. if (!windowChainEl.iframeElement) {
  87. break;
  88. }
  89. let boundingRect = windowChainEl.iframeElement.getBoundingClientRect();
  90. top += boundingRect.top;
  91. left += boundingRect.left;
  92. }
  93. return {
  94. top: top,
  95. left: left
  96. };
  97. }
  98. }