From e64d831c40d89f18e4d5e339aaee190568cfdc35 Mon Sep 17 00:00:00 2001 From: yflory Date: Fri, 26 Jun 2020 14:02:24 +0200 Subject: [PATCH] Remove requirements for unsafe-inline and unsafe-eval in pad --- www/pad/comment.js | 4 +- www/pad/csp.js | 301 +++++++++++++++++++++++++ www/pad/inner.js | 155 +------------ www/pad/mathjax/config/TeX-AMS_HTML.js | 2 + 4 files changed, 315 insertions(+), 147 deletions(-) create mode 100644 www/pad/csp.js diff --git a/www/pad/comment.js b/www/pad/comment.js index 1a059a50e..b5598137b 100644 --- a/www/pad/comment.js +++ b/www/pad/comment.js @@ -44,8 +44,8 @@ path = path || editor.elementPath(); sel = sel || editor.getSelection(); var applicable = removeStyle.checkApplicable(path, editor); - var el = editor.getSelectedHtml().$; - var hasComments = el && el.querySelectorAll('comment').length; + var el = editor.getSelectedHtml(); + var hasComments = el && el.$ && el.$.querySelectorAll('comment').length; var isComment = removeStyle.checkActive(path, editor); var empty = !sel.getSelectedText(); return applicable && !empty && !hasComments && !isComment; diff --git a/www/pad/csp.js b/www/pad/csp.js new file mode 100644 index 000000000..5d6072348 --- /dev/null +++ b/www/pad/csp.js @@ -0,0 +1,301 @@ +define(['jquery'], function ($) { + var CKEDITOR = window.CKEDITOR; + + + // Buttons + var $a = $('.cke_toolbox_main').find('.cke_button, .cke_combo_button'); + $a.each(function (i, el) { + var attr = $(el).attr('onclick'); + var reg = /CKEDITOR.tools.callFunction\(([0-9]+),this\);return false;/; + var f = attr.match(reg)[1]; + $(el).click(function () { + CKEDITOR.tools.callFunction(Number(f), el); + }); + }); + + + // Dropdown menus + + var frameTpl = CKEDITOR.getTemplate('panel-frame'); + var panelTpl = CKEDITOR.getTemplate('panel'); + var frameDocTpl = CKEDITOR.addTemplate( 'panel-frame-inner-csp', '' + + '' + + '{css}' + + '' + + '<\/html>' ); + CKEDITOR.ui.panel.prototype.render = function( editor, output ) { + var data = { + editorId: editor.id, + id: this.id, + langCode: editor.langCode, + dir: editor.lang.dir, + cls: this.className, + frame: '', + env: CKEDITOR.env.cssClass, + 'z-index': editor.config.baseFloatZIndex + 1 + }; + + this.getHolderElement = function() { + var holder = this._.holder; + + if ( !holder ) { + if ( this.isFramed ) { + var iframe = this.document.getById( this.id + '_frame' ), + parentDiv = iframe.getParent(), + doc = iframe.getFrameDocument(); + + // Make it scrollable on iOS. (https://dev.ckeditor.com/ticket/8308) + if (CKEDITOR.env.iOS) { + parentDiv.setStyles( { + 'overflow': 'scroll', + '-webkit-overflow-scrolling': 'touch' + } ); + } + + var onLoad = CKEDITOR.tools.addFunction( CKEDITOR.tools.bind( function() { + this.isLoaded = true; + if ( this.onLoad ) { + this.onLoad(); + } + }, this ) ); + + doc.write( frameDocTpl.output( CKEDITOR.tools.extend( { + css: CKEDITOR.tools.buildStyleHtml( this.css ) + }, data ) ) ); + + var that = this; + $(iframe.$).on('load', function () { + that.isLoaded = true; + if (that.onLoad) { + that.onLoad(); + } + }).contents().find('body').on('click', '.cke_button, a.cke_colormore, a.cke_colorbox, .cke_colorauto, .cke_combo_button, .cke_panel_listItem a', function (e) { + var attr = $(e.currentTarget).attr('onclick'); + var reg = /CKEDITOR.tools.callFunction\(([0-9]+),'([A-Za-z0-9 ]+)'(,'([A-Za-z0-9 ]+)')?\);/; + var match = attr.match(reg); + var f = match[1]; + var el = match[2]; + CKEDITOR.tools.callFunction(Number(f), el, match[4]); + }); + + // Register the CKEDITOR global. + var win = doc.getWindow(); + win.$.CKEDITOR = CKEDITOR; + + // Arrow keys for scrolling is only preventable with 'keypress' event in Opera (https://dev.ckeditor.com/ticket/4534). + doc.on( 'keydown', function( evt ) { + var keystroke = evt.data.getKeystroke(), + dir = this.document.getById( this.id ).getAttribute( 'dir' ); + + // Arrow left and right should use native behaviour inside input element + if ( evt.data.getTarget().getName() === 'input' && ( keystroke === 37 || keystroke === 39 ) ) { + return; + } + // Delegate key processing to block. + if ( this._.onKeyDown && this._.onKeyDown( keystroke ) === false ) { + if ( !( evt.data.getTarget().getName() === 'input' && keystroke === 32 ) ) { + // Don't prevent space when is pressed on a input filed. + evt.data.preventDefault(); + } + return; + } + + // ESC/ARROW-LEFT(ltr) OR ARROW-RIGHT(rtl) + if ( keystroke === 27 || keystroke === ( dir === 'rtl' ? 39 : 37 ) ) { + if ( this.onEscape && this.onEscape( keystroke ) === false ) { + evt.data.preventDefault(); + } + } + }, this ); + + holder = doc.getBody(); + holder.unselectable(); + if (CKEDITOR.env.air) { CKEDITOR.tools.callFunction( onLoad ); } + } else { + holder = this.document.getById( this.id ); + } + + this._.holder = holder; + } + + return holder; + }; + + if ( this.isFramed ) { + // With IE, the custom domain has to be taken care at first, + // for other browers, the 'src' attribute should be left empty to + // trigger iframe's 'load' event. + var src = + CKEDITOR.env.air ? 'javascript:void(0)' : // jshint ignore:line + ( CKEDITOR.env.ie && !CKEDITOR.env.edge ) ? 'javascript:void(function(){' + encodeURIComponent( // jshint ignore:line + 'document.open();' + + // In IE, the document domain must be set any time we call document.open(). + '(' + CKEDITOR.tools.fixDomain + ')();' + + 'document.close();' + ) + '}())' : + ''; + + data.frame = frameTpl.output( { + id: this.id + '_frame', + src: src + } ); + } + + var html = panelTpl.output( data ); + + if ( output ) { output.push( html ); } + + return html; + }; + + + + + + + // Mathjax + + if ( !( CKEDITOR.env.ie && CKEDITOR.env.version === 8 ) ) { + CKEDITOR.plugins.mathjax.frameWrapper = function( iFrame, editor ) { + + var update = function () {}; // Placeholder + var buffer, preview, value, newValue, + doc = iFrame.getFrameDocument(), + + // Is MathJax loaded and ready to work. + isInit = false, + + // Is MathJax parsing Tex. + isRunning = false, + + // Function called when MathJax is loaded. + loadedHandler = CKEDITOR.tools.addFunction( function() { + preview = doc.getById( 'preview' ); + buffer = doc.getById( 'buffer' ); + isInit = true; + + if ( newValue ) { update(); } + + // Private! For test usage only. + CKEDITOR.fire( 'mathJaxLoaded', iFrame ); + } ), + + // Function called when MathJax finish his job. + updateDoneHandler = CKEDITOR.tools.addFunction( function() { + CKEDITOR.plugins.mathjax.copyStyles( iFrame, preview ); + + preview.setHtml( buffer.getHtml() ); + + editor.fire( 'lockSnapshot' ); + + iFrame.setStyles( { + height: 0, + width: 0 + } ); + + // Set iFrame dimensions. + var height = Math.max( doc.$.body.offsetHeight, doc.$.documentElement.offsetHeight ), + width = Math.max( preview.$.offsetWidth, doc.$.body.scrollWidth ); + + iFrame.setStyles( { + height: height + 'px', + width: width + 'px' + } ); + + editor.fire( 'unlockSnapshot' ); + + // Private! For test usage only. + CKEDITOR.fire( 'mathJaxUpdateDone', iFrame ); + + // If value changed in the meantime update it again. + if ( value !== newValue ) { + update(); + } else { + isRunning = false; + } + } ); + + // Run MathJax parsing Tex. + update = function () { + isRunning = true; + + value = newValue; + + editor.fire( 'lockSnapshot' ); + + buffer.setHtml( value ); + + // Set loading indicator. + preview.setHtml( ' + editor.lang.mathjax.loading + ' ); + + iFrame.setStyles( { + height: '16px', + width: '16px', + display: 'inline', + 'vertical-align': 'middle' + } ); + + editor.fire( 'unlockSnapshot' ); + + // Run MathJax. + doc.getWindow().$.update( value ); + }; + + + var load = function () { + doc = iFrame.getFrameDocument(); + + if ( doc.getById( 'preview' ) ) { return; } + + // Because of IE9 bug in a src attribute can not be javascript + // when you undo (https://dev.ckeditor.com/ticket/10930). If you have iFrame with javascript in src + // and call insertBefore on such element then IE9 will see crash. + if ( CKEDITOR.env.ie ) { iFrame.removeAttribute( 'src' ); } + + doc.write( '' + + '' + + '' + + '' + + // Load MathJax lib. + '' + + '' + + '' + + '' + + + // Render everything here and after that copy it to the preview. + '' + + '' + + '' ); + iFrame.$.contentWindow.mathjax_loaded = loadedHandler; + iFrame.$.contentWindow.mathjax_done = updateDoneHandler; + }; + + iFrame.on( 'load', load ); + load(); + + + return { + /** + * Sets the TeX value to be displayed in the `iframe` element inside + * the editor. This function will activate the MathJax + * library which interprets TeX expressions and converts them into + * their representation that is displayed in the editor. + * + * @param {String} value TeX string. + */ + setValue: function( value ) { + newValue = CKEDITOR.tools.htmlEncode( value ); + + if ( isInit && !isRunning ) { + update(); + } + } + }; + }; + } + + + + +}); diff --git a/www/pad/inner.js b/www/pad/inner.js index 73450a172..1ca6edd78 100644 --- a/www/pad/inner.js +++ b/www/pad/inner.js @@ -15,6 +15,14 @@ require(['/api/config'], function(ApiConfig) { } return resource; }; + + window.MathJax = { + "HTML-CSS": { + }, + TeX: { + } + }; + require(['/bower_components/ckeditor/ckeditor.js']); }); define([ @@ -1023,152 +1031,9 @@ define([ $ckeToolbar.find('.cke_button__image_icon').parent().hide(); }).nThen(waitFor()); + }).nThen(function(waitFor) { + require(['/pad/csp.js'], waitFor()); }).nThen(function( /*waitFor*/ ) { - var $a = $('.cke_toolbox_main').find('.cke_button, .cke_combo_button'); - $a.each(function (i, el) { - var attr = $(el).attr('onclick'); - var reg = /CKEDITOR.tools.callFunction\(([0-9]+),this\);return false;/; - var f = attr.match(reg)[1]; - $(el).click(function () { - CKEDITOR.tools.callFunction(Number(f), el); - }); - }); - - - - - - - - - - - - var frameTpl = CKEDITOR.getTemplate('panel-frame'); - var panelTpl = CKEDITOR.getTemplate('panel'); - var frameDocTpl = CKEDITOR.addTemplate( 'panel-frame-inner-csp', '' + - '' + - '{css}' + - '' + - '<\/html>' ); - CKEDITOR.ui.panel.prototype.render = function( editor, output ) { - var data = { - editorId: editor.id, - id: this.id, - langCode: editor.langCode, - dir: editor.lang.dir, - cls: this.className, - frame: '', - env: CKEDITOR.env.cssClass, - 'z-index': editor.config.baseFloatZIndex + 1 - }; -console.log(this); - - this.getHolderElement = function() { - var holder = this._.holder; - - if ( !holder ) { - if ( this.isFramed ) { - var iframe = this.document.getById( this.id + '_frame' ), - parentDiv = iframe.getParent(), - doc = iframe.getFrameDocument(); - - // Make it scrollable on iOS. (https://dev.ckeditor.com/ticket/8308) - CKEDITOR.env.iOS && parentDiv.setStyles( { - 'overflow': 'scroll', - '-webkit-overflow-scrolling': 'touch' - } ); - - var onLoad = CKEDITOR.tools.addFunction( CKEDITOR.tools.bind( function() { - this.isLoaded = true; - if ( this.onLoad ) - this.onLoad(); - }, this ) ); - - doc.write( frameDocTpl.output( CKEDITOR.tools.extend( { - css: CKEDITOR.tools.buildStyleHtml( this.css ) - }, data ) ) ); - - var that = this; - iframe.$.onload = function () { - console.error(that.onLoad); - that.isLoaded = true; - if ( that.onLoad ) - that.onLoad(); - }; - - // Register the CKEDITOR global. - var win = doc.getWindow(); - win.$.CKEDITOR = CKEDITOR; - - // Arrow keys for scrolling is only preventable with 'keypress' event in Opera (https://dev.ckeditor.com/ticket/4534). - doc.on( 'keydown', function( evt ) { - var keystroke = evt.data.getKeystroke(), - dir = this.document.getById( this.id ).getAttribute( 'dir' ); - - // Arrow left and right should use native behaviour inside input element - if ( evt.data.getTarget().getName() === 'input' && ( keystroke === 37 || keystroke === 39 ) ) { - return; - } - // Delegate key processing to block. - if ( this._.onKeyDown && this._.onKeyDown( keystroke ) === false ) { - if ( !( evt.data.getTarget().getName() === 'input' && keystroke === 32 ) ) { - // Don't prevent space when is pressed on a input filed. - evt.data.preventDefault(); - } - return; - } - - // ESC/ARROW-LEFT(ltr) OR ARROW-RIGHT(rtl) - if ( keystroke == 27 || keystroke == ( dir == 'rtl' ? 39 : 37 ) ) { - if ( this.onEscape && this.onEscape( keystroke ) === false ) - evt.data.preventDefault(); - } - }, this ); - - holder = doc.getBody(); - holder.unselectable(); - CKEDITOR.env.air && CKEDITOR.tools.callFunction( onLoad ); - } else { - holder = this.document.getById( this.id ); - } - - this._.holder = holder; - } - - return holder; - }; - - if ( this.isFramed ) { - // With IE, the custom domain has to be taken care at first, - // for other browers, the 'src' attribute should be left empty to - // trigger iframe's 'load' event. - var src = - CKEDITOR.env.air ? 'javascript:void(0)' : // jshint ignore:line - ( CKEDITOR.env.ie && !CKEDITOR.env.edge ) ? 'javascript:void(function(){' + encodeURIComponent( // jshint ignore:line - 'document.open();' + - // In IE, the document domain must be set any time we call document.open(). - '(' + CKEDITOR.tools.fixDomain + ')();' + - 'document.close();' - ) + '}())' : - ''; - - data.frame = frameTpl.output( { - id: this.id + '_frame', - src: src - } ); - } - - var html = panelTpl.output( data ); - - if ( output ) - output.push( html ); - - return html; - }; - - diff --git a/www/pad/mathjax/config/TeX-AMS_HTML.js b/www/pad/mathjax/config/TeX-AMS_HTML.js index 14cd40cd2..27d25a5d9 100644 --- a/www/pad/mathjax/config/TeX-AMS_HTML.js +++ b/www/pad/mathjax/config/TeX-AMS_HTML.js @@ -33,6 +33,8 @@ MathJax.Ajax.Preloading( "[MathJax]/extensions/a11y/accessibility-menu.js" ); +MathJax.Hub.Config( {showMathMenu: false,messageStyle: "none"} );function getCKE() {if ( typeof window.parent.CKEDITOR == 'object' ) {return window.parent.CKEDITOR;} else {return window.parent.parent.CKEDITOR;}}function update() {MathJax.Hub.Queue([ 'Typeset', MathJax.Hub, this.buffer ],function() {getCKE().tools.callFunction( window.mathjax_done );});}MathJax.Hub.Queue( function() {getCKE().tools.callFunction(window.mathjax_loaded);} ); + MathJax.Hub.Config({ extensions: ['[a11y]/accessibility-menu.js'] });