iframe.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  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' && location.origin !== parentLocation.origin) {
  16. hasDifferentOriginAncestorFlag = true;
  17. return null;
  18. }
  19. }
  20. catch (e) {
  21. hasDifferentOriginAncestorFlag = true;
  22. return null;
  23. }
  24. return w.parent;
  25. }
  26. export class IframeUtils {
  27. /**
  28. * Returns a chain of embedded windows with the same origin (which can be accessed programmatically).
  29. * 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.
  30. * To distinguish if at one point the current execution environment is running inside a window with a different origin, see hasDifferentOriginAncestor()
  31. */
  32. static getSameOriginWindowChain() {
  33. if (!sameOriginWindowChainCache) {
  34. sameOriginWindowChainCache = [];
  35. let w = window;
  36. let parent;
  37. do {
  38. parent = getParentWindowIfSameOrigin(w);
  39. if (parent) {
  40. sameOriginWindowChainCache.push({
  41. window: w,
  42. iframeElement: w.frameElement || null
  43. });
  44. }
  45. else {
  46. sameOriginWindowChainCache.push({
  47. window: w,
  48. iframeElement: null
  49. });
  50. }
  51. w = parent;
  52. } while (w);
  53. }
  54. return sameOriginWindowChainCache.slice(0);
  55. }
  56. /**
  57. * 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.
  58. * Returns false if the current execution environment is not running inside an iframe or if the entire chain of iframes have the same origin.
  59. */
  60. static hasDifferentOriginAncestor() {
  61. if (!sameOriginWindowChainCache) {
  62. this.getSameOriginWindowChain();
  63. }
  64. return hasDifferentOriginAncestorFlag;
  65. }
  66. /**
  67. * Returns the position of `childWindow` relative to `ancestorWindow`
  68. */
  69. static getPositionOfChildWindowRelativeToAncestorWindow(childWindow, ancestorWindow) {
  70. if (!ancestorWindow || childWindow === ancestorWindow) {
  71. return {
  72. top: 0,
  73. left: 0
  74. };
  75. }
  76. let top = 0, left = 0;
  77. let windowChain = this.getSameOriginWindowChain();
  78. for (const windowChainEl of windowChain) {
  79. top += windowChainEl.window.scrollY;
  80. left += windowChainEl.window.scrollX;
  81. if (windowChainEl.window === ancestorWindow) {
  82. break;
  83. }
  84. if (!windowChainEl.iframeElement) {
  85. break;
  86. }
  87. let boundingRect = windowChainEl.iframeElement.getBoundingClientRect();
  88. top += boundingRect.top;
  89. left += boundingRect.left;
  90. }
  91. return {
  92. top: top,
  93. left: left
  94. };
  95. }
  96. }