-
Notifications
You must be signed in to change notification settings - Fork 4
/
seamless.js
151 lines (122 loc) · 3.96 KB
/
seamless.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
;(function(win, doc) {
"use strict";
/**
* Work around for lack of seamless support in pretty much every browser.
*/
/**
* List of domains that are allowed to read data in postMessage.
*/
var allowed_domains = ['*'];
/**
* Will be used to store length of allowed_domains so it doesn't need to be
* checked every time allowed_domains is looped over.
*/
var allowed_domains_length = allowed_domains.length;
/**
* By default, the targetOrigin of window.postMessage is * meaning all
* domains. In some cases you will want to restrict this to help prevent
* XSS and other unscrupulus uses.
*/
var target_origin = '*';
/**
* Will contain mapping of frame src => element
*/
var frames = {};
/**
* Stores passed options (keyword arguments) to local variables.
*/
var setOptions = function(options) {
if (options.allowed_domains) {
allowed_domains = options.allowed_domains;
allowed_domains_length = allowed_domains.length;
}
if (options.target_origin) {
target_origin = options.target_origin;
}
};
/**
* Convenience function to determine if the origin is in the list of
* allowed domains.
*/
var checkDomain = function(origin) {
var i;
for (i = 0; i < allowed_domains_length; i++) {
if (allowed_domains[i] === origin || allowed_domains[i] === '*') {
return true;
}
}
return false;
};
/**
* Send message containing the height of the document to the parent frame.
*/
var sendHeight = function() {
win.parent.postMessage(JSON.stringify({
height: doc.body.scrollHeight,
href: win.location.href
}), target_origin);
};
/**
* Listener to respond to postMessage containing a request for information
* about a frame document's height.
*/
var heightListener = function(evt) {
if (!checkDomain(evt.origin)) {
return;
}
var data = JSON.parse(evt.data);
if (data.request && data.request === 'height') {
sendHeight();
}
};
var setFrameHeight = function(evt) {
if (!checkDomain(evt.origin)) {
return;
}
var data = JSON.parse(evt.data), frame;
if (data.height && data.href) {
frame = frames[data.href];
if (frame) {
frame.style.height = parseInt(data.height, 10 || 0) + 'px';
}
}
};
/**
* Function to call to enable an framed page to communicate it's height to
* it's parent frame.
*
* options arguments:
* - allowed_domains: list of domains from which to accept messages
* - target_origin: targetOrigin value for window.postMessage
*/
var frame = function(options) {
setOptions(options);
win.onmessage = heightListener;
win.onload = sendHeight;
};
/**
* Function to call to enable parent frame to respond check child frame
* heights.
*
* option arguments:
* - allowed_domains: list of domains from which to accept messages
* - target_origin: targetOrigin value for window.postMessage
*/
var parent = function(options) {
setOptions(options);
var elements = doc.querySelectorAll('iframe[seamless]'),
len = elements.length, i;
for (i = 0; i < len; i++) {
frames[elements[i].src] = elements[i];
}
window.addEventListener('message', setFrameHeight);
};
var seamless = {'frame': frame, 'parent': parent};
if (typeof define === 'function' && define.amd) {
define([], function () { return seamless; });
} else if (typeof module !== 'undefined' && module !== null) {
module.exports = seamless;
} else {
window.seamless = seamless;
}
})(window, document);