|
59 | 59 |
|
60 | 60 |
|
61 | 61 | <div id="gjs-wrapper">
|
62 |
| - <div id="gjs" style="height:0px; overflow:hidden"> |
63 |
| - {{#if resource.editorData.html}} |
64 |
| - <style>{{{resource.editorData.css}}}</style> |
65 |
| - {{{resource.editorData.html}}} |
66 |
| - {{else}} |
67 |
| - {{{resource.html}}} |
68 |
| - {{/if}} |
69 |
| - </div> |
| 62 | + <div id="gjs" style="height: 0px; overflow: hidden"></div> |
70 | 63 | </div>
|
71 | 64 |
|
72 | 65 |
|
|
136 | 129 | <script>
|
137 | 130 | $.ajaxSetup({ headers: { 'X-CSRF-TOKEN': '{{csrfToken}}' } });
|
138 | 131 |
|
139 |
| - var editor = grapesjs.init({ |
140 |
| - height: '100%', |
141 |
| - storageManager: { |
142 |
| - type: 'none' |
143 |
| - }, |
144 |
| - assetManager: { |
145 |
| - assets: [], |
146 |
| - upload: '/editorapi/upload?type={{type}}&id={{resource.id}}&editor={{resource.editorName}}', |
147 |
| - uploadText: 'Drop images here or click to upload', |
148 |
| - }, |
149 |
| - container : '#gjs', |
150 |
| - fromElement: true, |
151 |
| - plugins: ['gjs-preset-newsletter'], |
152 |
| - pluginsOpts: { |
153 |
| - 'gjs-preset-newsletter': { |
| 132 | + var resource = {{{stringifiedResource}}}; |
| 133 | +
|
| 134 | + var config = (function(mode) { |
| 135 | + var c = { |
| 136 | + clearOnRender: true, |
| 137 | + height: '100%', |
| 138 | + storageManager: { |
| 139 | + type: 'none' |
| 140 | + }, |
| 141 | + assetManager: { |
| 142 | + assets: [], |
| 143 | + upload: '/editorapi/upload?type={{type}}&id={{resource.id}}&editor={{editor.name}}', |
| 144 | + uploadText: 'Drop images here or click to upload', |
| 145 | + }, |
| 146 | + container : '#gjs', |
| 147 | + fromElement: false, |
| 148 | + plugins: [], |
| 149 | + pluginsOpts: {}, |
| 150 | + }; |
| 151 | +
|
| 152 | + if (mode === 'mjml') { |
| 153 | + var serializer = new XMLSerializer(); |
| 154 | + var doc = new DOMParser().parseFromString(resource.editorData.mjml, 'text/xml'); |
| 155 | +
|
| 156 | + // convert relative to absolute urls |
| 157 | + ['mj-wrapper', 'mj-section', 'mj-navbar', 'mj-hero', 'mj-image'].forEach(function(tagName) { |
| 158 | + var serviceUrl = window.location.protocol + '//' + window.location.host + '/'; |
| 159 | + var elements = doc.getElementsByTagName(tagName); |
| 160 | +
|
| 161 | + for (var i = 0; i < elements.length; i++) { |
| 162 | + var node = elements[i]; |
| 163 | + var attrName = tagName === 'mj-image' ? 'src' : 'background-url'; |
| 164 | + var url = node.getAttribute(attrName); |
| 165 | +
|
| 166 | + if (url && url.substring(0, 2) === './') { |
| 167 | + var absoluteUrl = serviceUrl + 'grapejs/templates/' + resource.editorData.template + '/' + url.substring(2); |
| 168 | + node.setAttribute(attrName, absoluteUrl); |
| 169 | + } |
| 170 | + } |
| 171 | + }); |
| 172 | +
|
| 173 | + var title = doc.getElementsByTagName('mj-title')[0]; |
| 174 | + if (title) { |
| 175 | + title.textContent = resource.name; |
| 176 | + } |
| 177 | +
|
| 178 | + var head = doc.getElementsByTagName('mj-head')[0]; |
| 179 | + var mjHead = head ? serializer.serializeToString(head) : '<mj-head></mj-head>'; |
| 180 | +
|
| 181 | + var container = doc.getElementsByTagName('mj-container')[0]; |
| 182 | + var mjContainer = container ? serializer.serializeToString(container) : '<mj-container></mj-container>'; |
| 183 | +
|
| 184 | + c.plugins.push('gjs-mjml', 'gjs-preset-mjml'); |
| 185 | + c.pluginsOpts['gjs-mjml'] = { |
| 186 | + preMjml: '<mjml>' + mjHead + '<mj-body>', |
| 187 | + postMjml: '</mj-body></mjml>', |
| 188 | + }; |
| 189 | + c.components = mjContainer; |
| 190 | + } |
| 191 | +
|
| 192 | + if (mode === 'html') { |
| 193 | + c.plugins.push('gjs-preset-newsletter'); |
| 194 | + c.pluginsOpts['gjs-preset-newsletter'] = { |
154 | 195 | modalLabelImport: 'Paste all your code here below and click import',
|
155 | 196 | modalLabelExport: 'Copy the code and use it wherever you want',
|
156 | 197 | codeViewerTheme: 'material',
|
|
163 | 204 | margin: 0,
|
164 | 205 | padding: 0,
|
165 | 206 | }
|
166 |
| - } |
| 207 | + }; |
| 208 | + c.components = resource.editorData.html || resource.html || ''; |
| 209 | + c.style = resource.editorData.css || ''; |
167 | 210 | }
|
168 |
| - }); |
169 | 211 |
|
170 |
| - $.getJSON('/editorapi/upload?type={{type}}&id={{resource.id}}&editor={{resource.editorName}}', function(data) { |
| 212 | + return c; |
| 213 | + })('{{editor.mode}}'); |
| 214 | +
|
| 215 | + var editor = grapesjs.init(config); |
| 216 | +
|
| 217 | + $.getJSON('/editorapi/upload?type={{type}}&id={{resource.id}}&editor={{editor.name}}', function(data) { |
171 | 218 | editor.AssetManager.add(data.files);
|
172 | 219 | });
|
173 | 220 |
|
174 |
| - function getPreparedHtml() { |
175 |
| - var imgs = []; |
176 |
| - $('.gjs-pn-buttons > .gjs-pn-btn.fa.fa-desktop').click(); |
177 |
| - $('.gjs-editor > .gjs-cv-canvas > iframe.gjs-frame') |
178 |
| - .contents() |
179 |
| - .find('img') |
180 |
| - .each(function() { |
181 |
| - var src = $(this).attr('src'); |
182 |
| - var s = src.match(/\/editorapi\/img\?src=([^&]*)/); |
183 |
| - var encodedSrc = (s && s[1]) || encodeURIComponent(src); |
184 |
| - var dynamicSrc = '/editorapi/img?src=' + encodedSrc + '&method=resize¶ms=' + $(this).width() + '%2C' + $(this).height(); |
185 |
| - imgs.push({ |
186 |
| - cls: $(this).attr('class').split(' ')[0], |
187 |
| - dynamicSrc: dynamicSrc, |
188 |
| - src: src, |
| 221 | + function getMjml() { |
| 222 | + var c = config.pluginsOpts['gjs-mjml']; |
| 223 | + return c.preMjml + editor.getHtml() + c.postMjml; |
| 224 | + } |
| 225 | +
|
| 226 | + function getPreparedHtml(callback) { |
| 227 | + var html; |
| 228 | +
|
| 229 | + switch ('{{editor.mode}}') { |
| 230 | + case 'html': |
| 231 | + html = editor.runCommand('gjs-get-inlined-html'); |
| 232 | + html = '<!doctype html><html><head><meta charset="utf-8"><title>{{resource.name}}</title></head><body>' + html + '</body></html>'; |
| 233 | + break; |
| 234 | + case 'mjml': |
| 235 | + var mjml = editor.runCommand('mjml-get-code'); |
| 236 | + mjml.errors.length && mjml.errors.forEach(function(err) { |
| 237 | + console.warn(err.formattedMessage); |
189 | 238 | });
|
190 |
| - }); |
191 |
| - var html = editor.runCommand('gjs-get-inlined-html'); |
192 |
| - imgs.forEach(function(img) { |
193 |
| - html = html.replace( |
194 |
| - '<img class="' + img.cls + '" src="' + img.src, |
195 |
| - '<img class="' + img.cls + '" src="' + img.dynamicSrc |
196 |
| - ); |
197 |
| - }); |
| 239 | + html = mjml.html; |
| 240 | + break; |
| 241 | + } |
| 242 | +
|
| 243 | + var frame = document.createElement('iframe'); |
| 244 | + frame.width = 2048; |
| 245 | + frame.height = 0; |
| 246 | + document.body.appendChild(frame); |
| 247 | + var frameDoc = frame.contentDocument || frame.contentWindow.document; |
198 | 248 |
|
199 |
| - html = '<!doctype html><html><head><meta charset="utf-8"><title>{{resource.name}}</title></head><body>' + html + '</body></html>'; |
| 249 | + frame.onload = function() { |
| 250 | + var imgs = frameDoc.querySelectorAll('img'); |
200 | 251 |
|
201 |
| - return html; |
| 252 | + for (var i = 0; i < imgs.length; i++) { |
| 253 | + var img = imgs[i]; |
| 254 | + var m = img.src.match(/\/editorapi\/img\?src=([^&]*)/); |
| 255 | + var encodedSrc = m && m[1] || encodeURIComponent(img.src); |
| 256 | + img.src = '/editorapi/img?src=' + encodedSrc + '&method=resize¶ms=' + img.clientWidth + '%2C' + img.clientHeight; |
| 257 | + } |
| 258 | +
|
| 259 | + html = '<!doctype html>' + frameDoc.documentElement.outerHTML; |
| 260 | + document.body.removeChild(frame); |
| 261 | + callback(html); |
| 262 | + }; |
| 263 | +
|
| 264 | + frameDoc.open(); |
| 265 | + frameDoc.write(html); |
| 266 | + frameDoc.close(); |
202 | 267 | }
|
203 | 268 |
|
| 269 | +
|
| 270 | + // Save Button |
| 271 | +
|
| 272 | + window.bridge = window.bridge || {}; |
| 273 | +
|
| 274 | + $('#mt-save').on('click', function() { |
| 275 | +
|
| 276 | + if ($(this).hasClass('busy')) { |
| 277 | + return; |
| 278 | + } |
| 279 | +
|
| 280 | + $(this).addClass('busy'); |
| 281 | +
|
| 282 | + getPreparedHtml(function(html) { |
| 283 | + var editorData = '{{editor.mode}}' === 'mjml' ? { |
| 284 | + template: resource.editorData.template, |
| 285 | + mjml: getMjml(), |
| 286 | + } : { |
| 287 | + template: resource.editorData.template, |
| 288 | + css: editor.getCss(), |
| 289 | + html: editor.getHtml(), |
| 290 | + style: editor.getStyle(), |
| 291 | + components: editor.getComponents(), |
| 292 | + }; |
| 293 | +
|
| 294 | + // TODO: Make templates and campaigns accept partial updates, i.e. don't require 'name' and 'list' |
| 295 | + var update = { |
| 296 | + id: resource.id, |
| 297 | + name: resource.name, |
| 298 | + {{#if resource.list}} list: resource.list, {{/if}} |
| 299 | + editorData: JSON.stringify(editorData), |
| 300 | + html: html, |
| 301 | + }; |
| 302 | +
|
| 303 | + $.post('/editorapi/update?type={{type}}&editor={{editor.name}}', update, null, 'html') |
| 304 | + .success(function() { |
| 305 | + window.bridge.lastSavedHtml = html; |
| 306 | + toastr.success('Sucessfully saved'); |
| 307 | + }) |
| 308 | + .fail(function(data) { |
| 309 | + toastr.error(data.responseText || 'An error occured while saving the document'); |
| 310 | + }) |
| 311 | + .always(function() { |
| 312 | + setTimeout(function() { |
| 313 | + $('#mt-save').removeClass('busy'); |
| 314 | + }, 200); // Don't save too fast |
| 315 | + }); |
| 316 | + }); |
| 317 | + }); |
| 318 | +
|
| 319 | +
|
| 320 | + // Close Button |
| 321 | +
|
| 322 | + $('#mt-close').on('click', function() { |
| 323 | + if (confirm('Unsaved changes will be lost. Close now?') === true) { |
| 324 | + window.bridge.exit |
| 325 | + ? window.bridge.exit() |
| 326 | + : window.location.href = '/{{type}}s/edit/{{resource.id}}?tab=template'; |
| 327 | + } |
| 328 | + }); |
| 329 | +
|
| 330 | +
|
| 331 | + // Commands |
| 332 | +
|
204 | 333 | var mdlClass = 'gjs-mdl-dialog-sm';
|
205 | 334 | var pnm = editor.Panels;
|
206 | 335 | var cmdm = editor.Commands;
|
207 |
| - var testContainer = document.getElementById("test-form"); |
208 |
| - var contentEl = testContainer.querySelector('input[name=html]'); |
209 | 336 | var md = editor.Modal;
|
210 | 337 |
|
| 338 | +
|
| 339 | + // Test email command |
| 340 | +
|
| 341 | + var testContainer = document.getElementById('test-form'); |
| 342 | + var testContentEl = testContainer.querySelector('input[name=html]'); |
| 343 | +
|
211 | 344 | cmdm.add('send-test', {
|
212 | 345 | run(editor, sender) {
|
213 |
| - sender.set('active', 0); |
214 |
| - var modalContent = md.getContentEl(); |
215 |
| - var mdlDialog = document.querySelector('.gjs-mdl-dialog'); |
216 |
| - // var cmdGetCode = cmdm.get('gjs-get-inlined-html'); |
217 |
| - // contentEl.value = cmdGetCode && cmdGetCode.run(editor); |
218 |
| - contentEl.value = getPreparedHtml(); |
219 |
| - mdlDialog.className += ' ' + mdlClass; |
220 |
| - testContainer.style.display = 'block'; |
221 |
| - md.setTitle('Test your Newsletter'); |
222 |
| - md.setContent(testContainer); |
223 |
| - md.open(); |
224 |
| - md.getModel().once('change:open', function() { |
225 |
| - mdlDialog.className = mdlDialog.className.replace(mdlClass, ''); |
226 |
| - //clean status |
227 |
| - }) |
| 346 | + // TODO: Show a spinner |
| 347 | + getPreparedHtml(function(html) { |
| 348 | + sender.set('active', 0); |
| 349 | + var modalContent = md.getContentEl(); |
| 350 | + var mdlDialog = document.querySelector('.gjs-mdl-dialog'); |
| 351 | + testContentEl.value = html; |
| 352 | + mdlDialog.className += ' ' + mdlClass; |
| 353 | + testContainer.style.display = 'block'; |
| 354 | + md.setTitle('Test your Newsletter'); |
| 355 | + md.setContent(testContainer); |
| 356 | + md.open(); |
| 357 | + md.getModel().once('change:open', function() { |
| 358 | + mdlDialog.className = mdlDialog.className.replace(mdlClass, ''); |
| 359 | + //clean status |
| 360 | + }); |
| 361 | + }); |
228 | 362 | }
|
229 | 363 | });
|
230 | 364 |
|
|
240 | 374 |
|
241 | 375 | var statusFormElC = document.querySelector('.form-status');
|
242 | 376 | var statusFormEl = document.querySelector('.form-status i');
|
| 377 | +
|
243 | 378 | var ajaxTest = ajaxable(testContainer, { headers: { 'X-CSRF-TOKEN': '{{csrfToken}}' } })
|
244 | 379 | .onStart(function() {
|
245 | 380 | statusFormEl.className = 'fa fa-refresh anim-spin';
|
|
260 | 395 | }
|
261 | 396 | });
|
262 | 397 |
|
263 |
| - // Add Merge Tag Reference command |
| 398 | + // Remember testemail address |
| 399 | +
|
| 400 | + var isValidEmail = function(email) { |
| 401 | + return /\S+@\S+\.\S+/.test(email); |
| 402 | + }; |
| 403 | +
|
| 404 | + if (isValidEmail(localStorage.getItem('testemail'))) { |
| 405 | + $('#test-form input[name=email]').val(localStorage.getItem('testemail')); |
| 406 | + } |
| 407 | +
|
| 408 | + $('#test-form').on('submit', function() { |
| 409 | + var email = $('#test-form input[name=email]').val(); |
| 410 | + isValidEmail(email) && localStorage.setItem('testemail', email); |
| 411 | + }); |
| 412 | +
|
| 413 | +
|
| 414 | + // Merge Tag Reference command |
| 415 | +
|
264 | 416 | var mergeTagReferenceContainer = document.getElementById('merge-tag-reference-container');
|
265 | 417 | cmdm.add('open-merge-tag-reference', {
|
266 | 418 | run(editor, sender) {
|
|
287 | 439 | },
|
288 | 440 | });
|
289 | 441 |
|
| 442 | +
|
290 | 443 | // Simple warn notifier
|
| 444 | +
|
291 | 445 | var origWarn = console.warn;
|
292 | 446 | toastr.options = {
|
293 | 447 | closeButton: true,
|
|
300 | 454 | origWarn(msg);
|
301 | 455 | };
|
302 | 456 |
|
| 457 | +
|
| 458 | + // Beautify tooltips |
| 459 | +
|
303 | 460 | $(document).ready(function() {
|
304 |
| - // Beautify tooltips |
305 | 461 | $('*[title]').each(function() {
|
306 | 462 | var el = $(this);
|
307 | 463 | var title = el.attr('title').trim();
|
|
310 | 466 | el.attr('title', '');
|
311 | 467 | }
|
312 | 468 | });
|
313 |
| -
|
314 |
| - // Remember testmail address |
315 |
| - var isValidEmail = function(email) { |
316 |
| - return /\S+@\S+\.\S+/.test(email); |
317 |
| - }; |
318 |
| - var email = localStorage.getItem('testemail'); |
319 |
| - isValidEmail(email) && $('#test-form input[name=email]').val(email); |
320 |
| -
|
321 |
| - $(document).on('submit', '#test-form', function() { |
322 |
| - var email = $('#test-form input[name=email]').val(); |
323 |
| - isValidEmail(email) && localStorage.setItem('testemail', email); |
324 |
| - }); |
325 |
| -
|
326 |
| -
|
327 |
| - // Save and Close Buttons |
328 |
| -
|
329 |
| - window.bridge = window.bridge || {}; |
330 |
| -
|
331 |
| - $('#mt-close').on('click', function() { |
332 |
| - if (confirm('Unsaved changes will be lost. Close now?') === true) { |
333 |
| - window.bridge.exit |
334 |
| - ? window.bridge.exit() |
335 |
| - : window.location.href = '/{{type}}s/edit/{{resource.id}}?tab=template'; |
336 |
| - } |
337 |
| - }); |
338 |
| -
|
339 |
| - $('#mt-save').on('click', function() { |
340 |
| - if ($(this).hasClass('busy')) { |
341 |
| - return; |
342 |
| - } |
343 |
| - $(this).addClass('busy'); |
344 |
| -
|
345 |
| - var html = getPreparedHtml(); |
346 |
| -
|
347 |
| - $.post('/editorapi/update?type={{type}}&editor={{resource.editorName}}', { |
348 |
| - id: {{resource.id}}, |
349 |
| - name: '{{resource.name}}', |
350 |
| - {{#if resource.list}} list: {{resource.list}}, {{/if}} |
351 |
| - html: html, |
352 |
| - editorData: JSON.stringify({ |
353 |
| - template: '{{resource.editorData.template}}', |
354 |
| - css: editor.getCss(), |
355 |
| - html: editor.getHtml(), |
356 |
| - style: editor.getStyle(), |
357 |
| - components: editor.getComponents(), |
358 |
| - }), |
359 |
| - }, null, 'html') |
360 |
| - .success(function() { |
361 |
| - window.bridge.lastSavedHtml = html; |
362 |
| - toastr.success('Sucessfully saved'); |
363 |
| - }) |
364 |
| - .fail(function(data) { |
365 |
| - toastr.error(data.responseText || 'An error occured while saving the document'); |
366 |
| - }) |
367 |
| - .always(function() { |
368 |
| - setTimeout(function() { |
369 |
| - $(this).removeClass('busy'); |
370 |
| - }.bind(this), 500); // Don't save too fast |
371 |
| - }.bind(this)); |
372 |
| - }); |
373 | 469 | });
|
| 470 | +
|
374 | 471 | </script>
|
0 commit comments