1 | import rasterizeHTML from 'rasterizehtml';
|
2 |
|
3 | function shadeColor(color, percent) {
|
4 | let f = parseInt(color.slice(1),16)
|
5 | , t = percent < 0 ? 0 : 255
|
6 | , p = percent < 0 ? percent * -1 : percent
|
7 | ;
|
8 | let R = f >> 16
|
9 | , G = f >> 8 & 0x00FF
|
10 | , B = f & 0x0000FF
|
11 | ;
|
12 | return '#' + (
|
13 | 0x1000000 + (Math.round((t-R) * p) + R) * 0x10000 +
|
14 | (Math.round((t - G) * p) + G) * 0x100 +
|
15 | (Math.round((t - B) * p) + B)
|
16 | ).toString(16).slice(1);
|
17 | }
|
18 |
|
19 | function collectElements(article, selectors) {
|
20 | let q = '';
|
21 | [
|
22 | ['heading', 'h1,h2,h3,h4,h5,h6']
|
23 | , ['paragraph', 'p']
|
24 |
|
25 | , ['material', 'ul,ol,pre,table,blockquote']
|
26 | ].forEach(function(d) {
|
27 | let key = d[0];
|
28 | q += ',' + (selectors[key] || d[1]);
|
29 | });
|
30 | return article.querySelectorAll(q.slice(1));
|
31 | }
|
32 |
|
33 | function fetchResultData(
|
34 | endpointURL, csrfToken, resolveCallback, rejectCallback) {
|
35 | let credentials = {csrfToken};
|
36 | if (!credentials.csrfToken) {
|
37 | credentials.csrfToken = '';
|
38 | }
|
39 | let getJSON = (url) => {
|
40 | let emptyData = {'p': []};
|
41 | return new Promise((resolve, reject) => {
|
42 | let xhr = new XMLHttpRequest();
|
43 | xhr.open('GET', url, true);
|
44 | xhr.setRequestHeader('Accept', 'application/json');
|
45 | xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
46 | if (credentials.csrfToken !== '') {
|
47 | xhr.setRequestHeader('X-CSRF-Token', credentials.csrfToken);
|
48 | }
|
49 | xhr.responseType = 'text';
|
50 | xhr.onerror = () => {
|
51 | let status = xhr.status;
|
52 | reject(emptyData);
|
53 | };
|
54 | xhr.onload = () => {
|
55 | let status = xhr.status
|
56 | , response = xhr.response
|
57 | ;
|
58 | if (status === 200) {
|
59 | response = response.replace(/^\]\)\}while\(1\);<\/x>/, '');
|
60 | resolve(JSON.parse(response));
|
61 | } else {
|
62 | console.error('[ERROR] GET status: ', status);
|
63 | reject(emptyData);
|
64 | }
|
65 | };
|
66 | xhr.send();
|
67 | });
|
68 | };
|
69 | return getJSON(endpointURL).then((data) => {
|
70 | return resolveCallback(data);
|
71 | }, (data) => {
|
72 | return rejectCallback(data);
|
73 | });
|
74 | }
|
75 |
|
76 | function buildHTML(data, elements) {
|
77 | let html = '<html><head>';
|
78 | html += `
|
79 | <style>
|
80 | body {
|
81 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
82 | font-size: 1.66em;
|
83 | }
|
84 | </style>
|
85 | `;
|
86 |
|
87 |
|
88 |
|
89 |
|
90 | html += '</head><body>';
|
91 |
|
92 | let colors0 = [
|
93 | '#2d96db'
|
94 | , '#4aa8a6'
|
95 | , '#64b977'
|
96 | , '#99c95d'
|
97 | , '#c5d062'
|
98 | , '#f6d866'
|
99 | , '#fab252'
|
100 | , '#fd8e3e'
|
101 | , '#fe6f43'
|
102 | , '#fd515b'
|
103 | , '#fb1b2a'
|
104 | ];
|
105 |
|
106 | let colors1 = [
|
107 | '#9e0142'
|
108 | , '#d0384d'
|
109 | , '#ee6445'
|
110 | , '#fa9c58'
|
111 | , '#fdcd7b'
|
112 | , '#fef0a7'
|
113 | , '#f3faad'
|
114 | , '#d0ec9c'
|
115 | , '#98d5a4'
|
116 | , '#5cb7a9'
|
117 | , '#3582ba'
|
118 | , '#5e4fa2'
|
119 | ]
|
120 |
|
121 | let colors = colors0
|
122 | , pIndex = 0
|
123 | ;
|
124 | html += Array.from(elements).map((e) => {
|
125 | let n = document.importNode(e, true);
|
126 | if (n.nodeName !== 'IMG') {
|
127 | if (n.nodeName === 'P' && 'p' in data) {
|
128 |
|
129 | let v = data['p'][String(pIndex)];
|
130 | if (v !== undefined) {
|
131 | let color = '#ffffff';
|
132 | try {
|
133 | let i = Math.round(parseFloat(v) * 10);
|
134 | color = shadeColor(colors[i], 0.55);
|
135 | } catch(_e) {
|
136 | console.error(e);
|
137 | }
|
138 | n.style.background = color;
|
139 | n.style.backgroundColor = 'rgba(' + color + ', 0.9)';
|
140 | }
|
141 | pIndex += 1;
|
142 | }
|
143 | }
|
144 | return n.outerHTML;
|
145 | }).join('');
|
146 | html += '</body></html>';
|
147 | return html;
|
148 | }
|
149 |
|
150 | function makeCanvas(width, height) {
|
151 | let container = document.getElementById('scrolliris_canvas_container')
|
152 | , canvas = document.createElement('canvas')
|
153 | ;
|
154 | canvas.setAttribute('id', 'scrolliris_canvas');
|
155 | canvas.setAttribute('width', width* 0.5);
|
156 | canvas.setAttribute('height', height * 0.5);
|
157 | container.appendChild(canvas);
|
158 | return canvas;
|
159 | }
|
160 |
|
161 | function drawCanvas(canvas, html, width, height, margin) {
|
162 | let dragging = false
|
163 | , lastY
|
164 | , marginTop = 0
|
165 | , event = {}
|
166 | ;
|
167 |
|
168 | canvas.addEventListener('mousedown', (e) => {
|
169 | let evt = e || event;
|
170 | canvas.style.cursor = 'grabbing';
|
171 | dragging = true;
|
172 | lastY = evt.clientY;
|
173 | e.preventDefault();
|
174 | }, false);
|
175 |
|
176 | canvas.addEventListener('mouseup', (e) => {
|
177 | canvas.style.cursor = 'grab';
|
178 | dragging = false;
|
179 | }, false);
|
180 |
|
181 | rasterizeHTML.drawHTML(html, canvas, {
|
182 | zoom: 0.5
|
183 | , width: width
|
184 | , height: height
|
185 | });
|
186 |
|
187 | window.addEventListener('mousemove', (e) => {
|
188 | let evt = e || event;
|
189 | if (dragging) {
|
190 | let delta = evt.clientY - lastY;
|
191 | lastY = evt.clientY;
|
192 | marginTop += delta;
|
193 | if (marginTop > 0) {
|
194 | marginTop = 0;
|
195 | } else if (marginTop < margin) {
|
196 | marginTop = margin;
|
197 | }
|
198 | canvas.style.marginTop = marginTop + 'px';
|
199 | }
|
200 | e.preventDefault();
|
201 | }, false);
|
202 |
|
203 | window.addEventListener('mouseout', (e) => {
|
204 | canvas.style.cursor = 'grab';
|
205 | dragging = false;
|
206 | }, false);
|
207 | }
|
208 |
|
209 | ((doc, ctx) => {
|
210 | let config = {}
|
211 | , settings = {}
|
212 | , options = {}
|
213 | ;
|
214 |
|
215 | if (ctx.hasOwnProperty('config') && typeof ctx.config === 'object') {
|
216 | config = ctx['config'];
|
217 |
|
218 | }
|
219 | if (ctx.hasOwnProperty('settings') && typeof ctx.options === 'object') {
|
220 | settings = ctx['settings'];
|
221 | if (!settings.endpointURL) {
|
222 | console.error('endpointURL is required');
|
223 | return false;
|
224 | }
|
225 | }
|
226 | if (ctx.hasOwnProperty('options') && typeof ctx.options === 'object') {
|
227 | options = ctx['options'];
|
228 | }
|
229 |
|
230 | let selectors = (options.selectors || {});
|
231 | let article = doc.querySelector(selectors.article || 'body article');
|
232 |
|
233 |
|
234 | let elements = collectElements(article, selectors)
|
235 | ;
|
236 |
|
237 |
|
238 |
|
239 | let elm = doc.documentElement;
|
240 | let docWidth = Math.max(
|
241 | doc.body.scrollWidth, article.scrollWidth, elm.scrollWidth) / 0.5;
|
242 | let docHeight = Math.max(
|
243 | doc.body.scrollHeight, article.scrollHeight, elm.scrollHeight) / 0.5;
|
244 |
|
245 | let draw = (data) => {
|
246 | let html = buildHTML(data, elements)
|
247 | , canvas = makeCanvas(docWidth, docHeight)
|
248 | ;
|
249 |
|
250 | let canvasHeight = 325
|
251 | , headerHeight = 22
|
252 | , footerHeiht = 22
|
253 | , frameMargin = 9
|
254 | , scale = 0.5
|
255 | ;
|
256 | let margin = -1 * ((docHeight * scale) / canvasHeight * 100) +
|
257 | (headerHeight + footerHeiht + frameMargin)
|
258 | ;
|
259 | drawCanvas(canvas, html, docWidth, docHeight, margin);
|
260 | };
|
261 |
|
262 | fetchResultData(settings.endpointURL, settings.csrfToken, (data) => {
|
263 |
|
264 | draw(data);
|
265 | }, (data) => {
|
266 |
|
267 | draw(data);
|
268 | });
|
269 | })(
|
270 | window.parent.document,
|
271 | (window.ScrollirisReadabilityReflector || {}).Context
|
272 | );
|