From ef290df3af545b2e0ca28fc1773dc0399b555f72 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Tue, 24 May 2016 05:33:32 +1000 Subject: [PATCH] Custom CSS classes for styling elements Define allowed tags, allowed empty, do not wrap, remove tags Refs #2005 --- modules/backend/formwidgets/RichEditor.php | 12 ++ .../richeditor/assets/css/richeditor.css | 96 +++++----- .../richeditor/assets/js/build-min.js | 15 +- .../richeditor/assets/js/richeditor.js | 70 ++++++- .../richeditor/assets/less/_base_styles.less | 175 ++++++++++++++++++ .../richeditor/assets/less/richeditor.less | 7 +- .../richeditor/partials/_richeditor.htm | 11 +- modules/backend/layouts/_custom_styles.htm | 6 + modules/backend/models/EditorSetting.php | 138 +++++++++++--- 9 files changed, 443 insertions(+), 87 deletions(-) create mode 100644 modules/backend/formwidgets/richeditor/assets/less/_base_styles.less diff --git a/modules/backend/formwidgets/RichEditor.php b/modules/backend/formwidgets/RichEditor.php index 116aeecd6..7045976b7 100644 --- a/modules/backend/formwidgets/RichEditor.php +++ b/modules/backend/formwidgets/RichEditor.php @@ -5,6 +5,7 @@ use File; use Event; use Request; use Backend\Classes\FormWidgetBase; +use Backend\Models\EditorSetting; /** * Rich Editor @@ -71,6 +72,17 @@ class RichEditor extends FormWidgetBase $this->vars['name'] = $this->formField->getName(); $this->vars['value'] = $this->getLoadValue(); $this->vars['toolbarButtons'] = $this->evalToolbarButtons(); + + $this->vars['allowEmptyTags'] = EditorSetting::getConfigured('html_allow_empty_tags'); + $this->vars['allowTags'] = EditorSetting::getConfigured('html_allow_tags'); + $this->vars['noWrapTags'] = EditorSetting::getConfigured('html_no_wrap_tags'); + $this->vars['removeTags'] = EditorSetting::getConfigured('html_remove_tags'); + + $this->vars['imageStyles'] = EditorSetting::getConfiguredStyles('html_style_image'); + $this->vars['linkStyles'] = EditorSetting::getConfiguredStyles('html_style_link'); + $this->vars['paragraphStyles'] = EditorSetting::getConfiguredStyles('html_style_paragraph'); + $this->vars['tableStyles'] = EditorSetting::getConfiguredStyles('html_style_table'); + $this->vars['tableCellStyles'] = EditorSetting::getConfiguredStyles('html_style_table_cell'); } /** diff --git a/modules/backend/formwidgets/richeditor/assets/css/richeditor.css b/modules/backend/formwidgets/richeditor/assets/css/richeditor.css index 59cb684f6..23f9a7c1a 100755 --- a/modules/backend/formwidgets/richeditor/assets/css/richeditor.css +++ b/modules/backend/formwidgets/richeditor/assets/css/richeditor.css @@ -149,60 +149,6 @@ iframe.fr-iframe{width:100%;border:none;position:relative;display:block;z-index: .fr-sticky-on.fr-sticky-ios{position:absolute;left:0;right:0;width:auto !important} .fr-sticky-dummy{display:none} .fr-sticky-on + .fr-sticky-dummy,.fr-sticky-box > .fr-sticky-dummy{display:block} -.fr-view strong{font-weight:700} -.fr-view table{border:none;border-collapse:collapse;empty-cells:show;max-width:100%} -.fr-view table.fr-dashed-borders td,.fr-view table.fr-dashed-borders th{border-style:dashed} -.fr-view table.fr-alternate-rows tbody tr:nth-child(2n){background:#f5f5f5} -.fr-view table td,.fr-view table th{border:1px solid #dddddd} -.fr-view table td:empty,.fr-view table th:empty{height:20px} -.fr-view table td.fr-highlighted,.fr-view table th.fr-highlighted{border:1px double red} -.fr-view table td.fr-thick,.fr-view table th.fr-thick{border-width:2px} -.fr-view table th{background:#e6e6e6} -.fr-view hr{clear:both;user-select:none;-o-user-select:none;-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-ms-user-select:none;page-break-after:always} -.fr-view .fr-file{position:relative} -.fr-view .fr-file::after{position:relative;content:"\1F4CE";font-weight:normal} -.fr-view pre{white-space:pre-wrap;word-wrap:break-word} -.fr-view blockquote{border-left:solid 2px #5e35b1;margin-left:0;padding-left:5px;color:#5e35b1} -.fr-view blockquote blockquote{border-color:#00bcd4;color:#00bcd4} -.fr-view blockquote blockquote blockquote{border-color:#43a047;color:#43a047} -.fr-view span.fr-emoticon{font-weight:normal;font-family:"Apple Color Emoji","Segoe UI Emoji","NotoColorEmoji","Segoe UI Symbol","Android Emoji","EmojiSymbols";display:inline;line-height:0} -.fr-view span.fr-emoticon.fr-emoticon-img{background-repeat:no-repeat !important;font-size:inherit;height:1em;width:1em;min-height:20px;min-width:20px;display:inline-block;margin:-0.1em 0.1em 0.1em;line-height:1;vertical-align:middle} -.fr-view .fr-text-gray{color:#AAA !important} -.fr-view .fr-text-bordered{border-top:solid 1px #222;border-bottom:solid 1px #222;padding:10px 0} -.fr-view .fr-text-spaced{letter-spacing:1px} -.fr-view .fr-text-uppercase{text-transform:uppercase} -.fr-view img{position:relative;max-width:100%} -.fr-view img.fr-dib{margin:5px auto;display:block;float:none;vertical-align:top} -.fr-view img.fr-dib.fr-fil{margin-left:0} -.fr-view img.fr-dib.fr-fir{margin-right:0} -.fr-view img.fr-dii{display:inline-block;float:none;vertical-align:bottom;margin-left:5px;margin-right:5px;max-width:calc(90%)} -.fr-view img.fr-dii.fr-fil{float:left;margin:5px 5px 5px 0;max-width:calc(95%)} -.fr-view img.fr-dii.fr-fir{float:right;margin:5px 0 5px 5px;max-width:calc(95%)} -.fr-view img.fr-rounded{border-radius:100%;-moz-border-radius:100%;-webkit-border-radius:100%;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box} -.fr-view img.fr-bordered{border:solid 10px #CCC;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box} -.fr-view .fr-video{text-align:center;position:relative} -.fr-view .fr-video > *{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;max-width:100%;border:none} -.fr-view .fr-video.fr-dvb{display:block;clear:both} -.fr-view .fr-video.fr-dvb.fr-fvl{text-align:left} -.fr-view .fr-video.fr-dvb.fr-fvr{text-align:right} -.fr-view .fr-video.fr-dvi{display:inline-block} -.fr-view .fr-video.fr-dvi.fr-fvl{float:left} -.fr-view .fr-video.fr-dvi.fr-fvr{float:right} -.fr-view a.fr-strong{font-weight:700} -.fr-view a.fr-green{color:green} -.fr-view button.fr-rounded,.fr-view input.fr-rounded,.fr-view textarea.fr-rounded{border-radius:10px;-moz-border-radius:10px;-webkit-border-radius:10px;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box} -.fr-view button.fr-large,.fr-view input.fr-large,.fr-view textarea.fr-large{font-size:24px} - a.fr-view.fr-strong{font-weight:700} -a.fr-view.fr-green{color:green} - img.fr-view{position:relative;max-width:100%} -img.fr-view.fr-dib{margin:5px auto;display:block;float:none;vertical-align:top} -img.fr-view.fr-dib.fr-fil{margin-left:0} -img.fr-view.fr-dib.fr-fir{margin-right:0} -img.fr-view.fr-dii{display:inline-block;float:none;vertical-align:bottom;margin-left:5px;margin-right:5px;max-width:calc(90%)} -img.fr-view.fr-dii.fr-fil{float:left;margin:5px 5px 5px 0;max-width:calc(95%)} -img.fr-view.fr-dii.fr-fir{float:right;margin:5px 0 5px 5px;max-width:calc(95%)} -img.fr-view.fr-rounded{border-radius:100%;-moz-border-radius:100%;-webkit-border-radius:100%;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box} -img.fr-view.fr-bordered{border:solid 10px #CCC;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box} body.fr-fullscreen{overflow:hidden;height:100%;width:100%;position:fixed} .fr-box.fr-fullscreen{margin:0 !important;position:fixed;top:0;left:0;bottom:0;right:0;z-index:9990 !important;width:auto !important} .fr-box.fr-fullscreen .fr-toolbar.fr-top{top:0 !important} @@ -363,6 +309,48 @@ to{left:100%} .fr-drag-helper{background:#1e88e5;height:2px;margin-top:-1px;filter:alpha(opacity=20);-webkit-opacity:0.2;-moz-opacity:0.2;opacity:0.2;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";position:absolute;z-index:9999;display:none} .fr-drag-helper.fr-visible{display:block} .fr-dragging{filter:alpha(opacity=40);-webkit-opacity:0.4;-moz-opacity:0.4;opacity:0.4;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"} +.fr-view strong{font-weight:700} +.fr-view table{border:none;border-collapse:collapse;empty-cells:show;max-width:100%} +.fr-view table td,.fr-view table th{border:1px solid #dddddd} +.fr-view table td:empty,.fr-view table th:empty{height:20px} +.fr-view table th{background:#e6e6e6} +.fr-view hr{clear:both;user-select:none;-o-user-select:none;-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-ms-user-select:none;page-break-after:always} +.fr-view .fr-file{position:relative} +.fr-view .fr-file::after{position:relative;content:"\1F4CE";font-weight:normal} +.fr-view pre{white-space:pre-wrap;word-wrap:break-word} +.fr-view blockquote{border-left:solid 2px #5e35b1;margin-left:0;padding-left:5px;color:#5e35b1} +.fr-view blockquote blockquote{border-color:#00bcd4;color:#00bcd4} +.fr-view blockquote blockquote blockquote{border-color:#43a047;color:#43a047} +.fr-view span.fr-emoticon{font-weight:normal;font-family:"Apple Color Emoji","Segoe UI Emoji","NotoColorEmoji","Segoe UI Symbol","Android Emoji","EmojiSymbols";display:inline;line-height:0} +.fr-view span.fr-emoticon.fr-emoticon-img{background-repeat:no-repeat !important;font-size:inherit;height:1em;width:1em;min-height:20px;min-width:20px;display:inline-block;margin:-0.1em 0.1em 0.1em;line-height:1;vertical-align:middle} +.fr-view img{position:relative;max-width:100%} +.fr-view img.fr-dib{margin:5px auto;display:block;float:none;vertical-align:top} +.fr-view img.fr-dib.fr-fil{margin-left:0} +.fr-view img.fr-dib.fr-fir{margin-right:0} +.fr-view img.fr-dii{display:inline-block;float:none;vertical-align:bottom;margin-left:5px;margin-right:5px;max-width:calc(90%)} +.fr-view img.fr-dii.fr-fil{float:left;margin:5px 5px 5px 0;max-width:calc(95%)} +.fr-view img.fr-dii.fr-fir{float:right;margin:5px 0 5px 5px;max-width:calc(95%)} +.fr-view .fr-video{text-align:center;position:relative} +.fr-view .fr-video > *{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;max-width:100%;border:none} +.fr-view .fr-video.fr-dvb{display:block;clear:both} +.fr-view .fr-video.fr-dvb.fr-fvl{text-align:left} +.fr-view .fr-video.fr-dvb.fr-fvr{text-align:right} +.fr-view .fr-video.fr-dvi{display:inline-block} +.fr-view .fr-video.fr-dvi.fr-fvl{float:left} +.fr-view .fr-video.fr-dvi.fr-fvr{float:right} +.fr-view{ } +.fr-view .oc-text-gray{color:#AAA !important} +.fr-view .oc-text-bordered{border-top:solid 1px #222;border-bottom:solid 1px #222;padding:10px 0} +.fr-view .oc-text-spaced{letter-spacing:1px} +.fr-view .oc-text-uppercase{text-transform:uppercase} +.fr-view a.oc-link-strong{font-weight:700} +.fr-view a.oc-link-green{color:green} +.fr-view table.oc-dashed-borders td,.fr-view table.oc-dashed-borders th{border-style:dashed} +.fr-view table.oc-alternate-rows tbody tr:nth-child(2n){background:#f5f5f5} +.fr-view table td.oc-cell-highlighted,.fr-view table th.oc-cell-highlighted{border:1px double red} +.fr-view table td.oc-cell-thick-border,.fr-view table th.oc-cell-thick-border{border-width:2px} +.fr-view img.oc-img-rounded{border-radius:100%;background-clip:padding-box} +.fr-view img.oc-img-bordered{border:solid 10px #CCC;box-sizing:content-box} body .fr-box.fr-basic.fr-top .fr-wrapper,body .fr-box.fr-basic.fr-bottom .fr-wrapper{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none} body .fr-box .ace_editor{display:none} body .fr-box .ace_editor{position:absolute;top:0;bottom:0;left:0;right:0;margin:0} diff --git a/modules/backend/formwidgets/richeditor/assets/js/build-min.js b/modules/backend/formwidgets/richeditor/assets/js/build-min.js index 953344440..bf18a7bad 100755 --- a/modules/backend/formwidgets/richeditor/assets/js/build-min.js +++ b/modules/backend/formwidgets/richeditor/assets/js/build-min.js @@ -464,18 +464,25 @@ Base.call(this) this.init()} RichEditor.prototype=Object.create(BaseProto) RichEditor.prototype.constructor=RichEditor -RichEditor.DEFAULTS={linksHandler:null,stylesheet:null,fullpage:false,editorLang:'en',toolbarButtons:null} +RichEditor.DEFAULTS={linksHandler:null,stylesheet:null,fullpage:false,editorLang:'en',toolbarButtons:null,allowEmptyTags:null,allowTags:null,noWrapTags:null,removeTags:null,imageStyles:null,linkStyles:null,paragraphStyles:null,tableStyles:null,tableCellStyles:null} RichEditor.prototype.init=function(){var self=this;this.$el.one('dispose-control',this.proxy(this.dispose)) if(!this.$textarea.attr('id')){this.$textarea.attr('id','element-'+Math.random().toString(36).substring(7))} this.initFroala()} -RichEditor.prototype.initFroala=function(){var froalaOptions={editorClass:'control-richeditor',language:this.options.editorLang} +RichEditor.prototype.initFroala=function(){var froalaOptions={editorClass:'control-richeditor',language:this.options.editorLang,fullPage:this.options.fullpage} if(this.options.toolbarButtons){froalaOptions.toolbarButtons=this.options.toolbarButtons.split(',')} else{froalaOptions.toolbarButtons=['paragraphFormat','paragraphStyle','quote','bold','italic','align','formatOL','formatUL','insertTable','insertLink','insertImage','insertVideo','insertAudio','insertFile','insertHR','fullscreen','html']} +froalaOptions.imageStyles=this.options.imageStyles?this.options.imageStyles:{'oc-img-rounded':'Rounded','oc-img-bordered':'Bordered'} +froalaOptions.linkStyles=this.options.linkStyles?this.options.linkStyles:{'oc-link-green':'Green','oc-link-strong':'Thick'} +froalaOptions.paragraphStyles=this.options.paragraphStyles?this.options.paragraphStyles:{'oc-text-gray':'Gray','oc-text-bordered':'Bordered','oc-text-spaced':'Spaced','oc-text-uppercase':'Uppercase'} +froalaOptions.tableStyles=this.options.tableStyles?this.options.tableStyles:{'oc-dashed-borders':'Dashed Borders','oc-alternate-rows':'Alternate Rows'} +froalaOptions.tableCellStyles=this.options.tableCellStyles?this.options.tableCellStyles:{'oc-cell-highlighted':'Highlighted','oc-cell-thick-border':'Thick'} froalaOptions.toolbarButtonsMD=froalaOptions.toolbarButtons froalaOptions.toolbarButtonsSM=froalaOptions.toolbarButtons froalaOptions.toolbarButtonsXS=froalaOptions.toolbarButtons -froalaOptions.htmlAllowedEmptyTags=['figure','textarea','a','iframe','object','video','style','script'] -froalaOptions.htmlDoNotWrapTags=['figure','script','style'] +if(this.options.htmlAllowedEmptyTags){froalaOptions.allowEmptyTags=this.options.htmlAllowedEmptyTags.split(/[\s,]+/)} +if(this.options.allowTags){froalaOptions.htmlAllowedTags=this.options.allowTags.split(/[\s,]+/)} +froalaOptions.htmlDoNotWrapTags=this.options.noWrapTags?this.options.noWrapTags.split(/[\s,]+/):['figure','script','style'] +if(this.options.removeTags){froalaOptions.htmlRemoveTags=this.options.removeTags.split(/[\s,]+/)} froalaOptions.lineBreakerTags=['figure','table','hr','iframe','form','dl'] froalaOptions.shortcutsEnabled=['show','bold','italic','underline','indent','outdent','undo','redo'] froalaOptions.linkInsertButtons=['linkBack','|'] diff --git a/modules/backend/formwidgets/richeditor/assets/js/richeditor.js b/modules/backend/formwidgets/richeditor/assets/js/richeditor.js index 19b8c8559..58a4dd54e 100755 --- a/modules/backend/formwidgets/richeditor/assets/js/richeditor.js +++ b/modules/backend/formwidgets/richeditor/assets/js/richeditor.js @@ -39,7 +39,16 @@ stylesheet: null, fullpage: false, editorLang: 'en', - toolbarButtons: null + toolbarButtons: null, + allowEmptyTags: null, + allowTags: null, + noWrapTags: null, + removeTags: null, + imageStyles: null, + linkStyles: null, + paragraphStyles: null, + tableStyles: null, + tableCellStyles: null } RichEditor.prototype.init = function() { @@ -63,7 +72,8 @@ RichEditor.prototype.initFroala = function() { var froalaOptions = { editorClass: 'control-richeditor', - language: this.options.editorLang + language: this.options.editorLang, + fullPage: this.options.fullpage } if (this.options.toolbarButtons) { @@ -91,11 +101,63 @@ ] } + froalaOptions.imageStyles = this.options.imageStyles + ? this.options.imageStyles + : { + 'oc-img-rounded': 'Rounded', + 'oc-img-bordered': 'Bordered' + } + + froalaOptions.linkStyles = this.options.linkStyles + ? this.options.linkStyles + : { + 'oc-link-green': 'Green', + 'oc-link-strong': 'Thick' + } + + froalaOptions.paragraphStyles = this.options.paragraphStyles + ? this.options.paragraphStyles + : { + 'oc-text-gray': 'Gray', + 'oc-text-bordered': 'Bordered', + 'oc-text-spaced': 'Spaced', + 'oc-text-uppercase': 'Uppercase' + } + + froalaOptions.tableStyles = this.options.tableStyles + ? this.options.tableStyles + : { + 'oc-dashed-borders': 'Dashed Borders', + 'oc-alternate-rows': 'Alternate Rows' + } + + froalaOptions.tableCellStyles = this.options.tableCellStyles + ? this.options.tableCellStyles + : { + 'oc-cell-highlighted': 'Highlighted', + 'oc-cell-thick-border': 'Thick' + } + froalaOptions.toolbarButtonsMD = froalaOptions.toolbarButtons froalaOptions.toolbarButtonsSM = froalaOptions.toolbarButtons froalaOptions.toolbarButtonsXS = froalaOptions.toolbarButtons - froalaOptions.htmlAllowedEmptyTags = ['figure', 'textarea', 'a', 'iframe', 'object', 'video', 'style', 'script'] - froalaOptions.htmlDoNotWrapTags = ['figure', 'script', 'style'] + + if (this.options.htmlAllowedEmptyTags) { + froalaOptions.allowEmptyTags = this.options.htmlAllowedEmptyTags.split(/[\s,]+/) + } + + if (this.options.allowTags) { + froalaOptions.htmlAllowedTags = this.options.allowTags.split(/[\s,]+/) + } + + froalaOptions.htmlDoNotWrapTags = this.options.noWrapTags + ? this.options.noWrapTags.split(/[\s,]+/) + : ['figure', 'script', 'style'] + + if (this.options.removeTags) { + froalaOptions.htmlRemoveTags = this.options.removeTags.split(/[\s,]+/) + } + froalaOptions.lineBreakerTags = ['figure', 'table', 'hr', 'iframe', 'form', 'dl'] froalaOptions.shortcutsEnabled = ['show', 'bold', 'italic', 'underline', 'indent', 'outdent', 'undo', 'redo'] froalaOptions.linkInsertButtons = ['linkBack', '|'] diff --git a/modules/backend/formwidgets/richeditor/assets/less/_base_styles.less b/modules/backend/formwidgets/richeditor/assets/less/_base_styles.less new file mode 100644 index 000000000..ff3acc743 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/less/_base_styles.less @@ -0,0 +1,175 @@ +// Vars +@image-margin: 5px; +@table-border: 1px solid #DDD; +@blockquote-level1-color: #5E35B1; +@blockquote-level2-color: #00BCD4; +@blockquote-level3-color: #43A047; +@editor-text: #000; + +.image-style() { + img { + position: relative; + max-width: 100%; + + &.fr-dib { + margin: @image-margin auto; + display: block; + float: none; + vertical-align: top; + + &.fr-fil { + margin-left: 0; + } + + &.fr-fir { + margin-right: 0; + } + } + + &.fr-dii { + display: inline-block; + float: none; + vertical-align: bottom; + margin-left: @image-margin; + margin-right: @image-margin; + max-width: calc(100% - (2 * @image-margin)); + + &.fr-fil { + float: left; + margin: @image-margin @image-margin @image-margin 0; + max-width: calc(100% - @image-margin); + } + + &.fr-fir { + float: right; + margin: @image-margin 0 @image-margin @image-margin; + max-width: calc(100% - @image-margin); + } + } + } +} + +.video-style() { + .fr-video { + text-align: center; + position: relative; + + > * { + .box-sizing(content-box); + max-width: 100%; + border: none; + } + + &.fr-dvb { + display: block; + clear: both; + + &.fr-fvl { + text-align: left; + } + + &.fr-fvr { + text-align: right; + } + } + + &.fr-dvi { + display: inline-block; + + &.fr-fvl { + float: left; + } + + &.fr-fvr { + float: right; + } + } + } +} + +.fr-view { + strong { + font-weight: 700; + } + + table { + border: none; + border-collapse: collapse; + empty-cells: show; + max-width: 100%; + + td, th { + border: @table-border; + + &:empty { + height: 20px; + } + } + + th { + background: mix(white, @editor-text, 90%);; + } + } + + hr { + clear: both; + .user-select(none); + page-break-after: always; + } + + .fr-file { + position: relative; + + &::after { + position: relative; + content: "\1F4CE"; + font-weight: normal; + } + } + + pre { + white-space: pre-wrap; + word-wrap: break-word; + } + + blockquote { + border-left: solid 2px @blockquote-level1-color; + margin-left: 0; + padding-left: 5px; + color: @blockquote-level1-color; + + blockquote { + border-color: @blockquote-level2-color; + color: @blockquote-level2-color; + + blockquote { + border-color: @blockquote-level3-color; + color: @blockquote-level3-color; + } + } + } + + span.fr-emoticon { + font-weight: normal; + font-family: "Apple Color Emoji","Segoe UI Emoji","NotoColorEmoji","Segoe UI Symbol","Android Emoji","EmojiSymbols"; + display: inline; + line-height: 0; + + &.fr-emoticon-img { + background-repeat: no-repeat !important; + font-size: inherit; + height: 1em; + width: 1em; + min-height: 20px; + min-width: 20px; + display: inline-block; + margin: -.1em .1em .1em; + line-height: 1; + vertical-align: middle; + } + } + + .image-style(); + + .video-style(); +} diff --git a/modules/backend/formwidgets/richeditor/assets/less/richeditor.less b/modules/backend/formwidgets/richeditor/assets/less/richeditor.less index 743482b48..5fce8ccaf 100755 --- a/modules/backend/formwidgets/richeditor/assets/less/richeditor.less +++ b/modules/backend/formwidgets/richeditor/assets/less/richeditor.less @@ -11,7 +11,6 @@ @color-richeditor-toolbar-btn-color-hover: #ffffff; @import "../vendor/froala_drm/less/froala.less"; -@import "../vendor/froala_drm/less/style.less"; // Buttons @import "../vendor/froala_drm/less/plugins/fullscreen.less"; @@ -27,6 +26,12 @@ @import "../vendor/froala_drm/less/plugins/line_breaker.less"; @import "../vendor/froala_drm/less/plugins/draggable.less"; +// Base styles +@import "_base_styles.less"; + +.fr-view { + @import "../../../../models/editorsetting/default_styles.less"; +} // Modifications @import "_froala.less"; diff --git a/modules/backend/formwidgets/richeditor/partials/_richeditor.htm b/modules/backend/formwidgets/richeditor/partials/_richeditor.htm index 2aea55f83..4c73c7697 100755 --- a/modules/backend/formwidgets/richeditor/partials/_richeditor.htm +++ b/modules/backend/formwidgets/richeditor/partials/_richeditor.htm @@ -5,9 +5,18 @@
data-editor-lang="" data-fullpage="true" + data-editor-lang="" data-toolbar-buttons="" + data-allow-empty-tags="" + data-allow-tags="" + data-no-wrap-tags="" + data-remove-tags="" + data-image-styles="" + data-link-styles="" + data-paragraph-styles="" + data-table-styles="" + data-table-cell-styles="" data-links-handler="getEventHandler('onGetPageLinks') ?>" placeholder="placeholder)) ?>" data-control="richeditor"> diff --git a/modules/backend/layouts/_custom_styles.htm b/modules/backend/layouts/_custom_styles.htm index c0ad6169a..5a20fcd94 100644 --- a/modules/backend/layouts/_custom_styles.htm +++ b/modules/backend/layouts/_custom_styles.htm @@ -1,8 +1,14 @@ + + + diff --git a/modules/backend/models/EditorSetting.php b/modules/backend/models/EditorSetting.php index a17267102..c32fe8196 100644 --- a/modules/backend/models/EditorSetting.php +++ b/modules/backend/models/EditorSetting.php @@ -1,7 +1,9 @@ 'Rounded', + 'oc-img-bordered' => 'Bordered', + ]; + + protected $defaultHtmlStyleLink = [ + 'oc-link-green' => 'Green', + 'oc-link-strong' => 'Strong', + ]; + + protected $defaultHtmlStyleParagraph = [ 'oc-text-bordered' => 'Bordered', 'oc-text-gray' => 'Gray', 'oc-text-spaced' => 'Spaced', 'oc-text-uppercase' => 'Uppercase', ]; - protected $defaultTableStyles = [ + protected $defaultHtmlStyleTable = [ 'oc-table-dashed-borders' => 'Dashed Borders', 'oc-table-alternate-rows' => 'Alternate Rows', ]; - protected $defaultTableCellStyles = [ + protected $defaultHtmlStyleTableCell = [ 'oc-cell-highlighted' => 'Highlighted', 'oc-cell-thick-border' => 'Thick Border', ]; - protected $defaultImageStyles = [ - 'oc-img-rounded' => 'Rounded', - 'oc-img-bordered' => 'Bordered', - ]; - - protected $defaultLinkStyles = [ - 'oc-link-green' => 'Green', - 'oc-link-strong' => 'Strong', - ]; - /** * Validation rules */ @@ -55,24 +67,104 @@ class EditorSetting extends Model public function initSettingsData() { - $this->html_allow_empty_tags = 'figure, textarea, a, iframe, object, video, style, script'; - $this->html_allow_tags = 'a, abbr, address, area, article, aside, audio, b, base, bdi, bdo, blockquote, br, button, canvas, caption, cite, code, col, colgroup, datalist, dd, del, details, dfn, dialog, div, dl, dt, em, embed, fieldset, figcaption, figure, footer, form, h1, h2, h3, h4, h5, h6, header, hgroup, hr, i, iframe, img, input, ins, kbd, keygen, label, legend, li, link, main, map, mark, menu, menuitem, meter, nav, noscript, object, ol, optgroup, option, output, p, param, pre, progress, queue, rp, rt, ruby, s, samp, script, style, section, select, small, source, span, strike, strong, sub, summary, sup, table, tbody, td, textarea, tfoot, th, thead, time, title, tr, track, u, ul, var, video, wbr'; - $this->html_no_wrap_tags = 'figure, script, style'; - $this->html_remove_tags = 'script,style'; - + $this->html_allow_empty_tags = $this->defaultHtmlAllowEmptyTags; + $this->html_allow_tags = $this->defaultHtmlAllowTags; + $this->html_no_wrap_tags = $this->defaultHtmlNoWrapTags; + $this->html_remove_tags = $this->defaultHtmlRemoveTags; $this->html_custom_styles = File::get(base_path().'/modules/backend/models/editorsetting/default_styles.less'); - $this->html_style_paragraph = $this->makeStylesForTable($this->defaultParagraphStyles); - $this->html_style_table = $this->makeStylesForTable($this->defaultTableStyles); - $this->html_style_table_cell = $this->makeStylesForTable($this->defaultTableCellStyles); - $this->html_style_image = $this->makeStylesForTable($this->defaultImageStyles); - $this->html_style_link = $this->makeStylesForTable($this->defaultLinkStyles); + $this->html_style_image = $this->makeStylesForTable($this->defaultHtmlStyleImage); + $this->html_style_link = $this->makeStylesForTable($this->defaultHtmlStyleLink); + $this->html_style_paragraph = $this->makeStylesForTable($this->defaultHtmlStyleParagraph); + $this->html_style_table = $this->makeStylesForTable($this->defaultHtmlStyleTable); + $this->html_style_table_cell = $this->makeStylesForTable($this->defaultHtmlStyleTableCell); + } + + public function afterSave() + { + Cache::forget(self::CACHE_KEY); } protected function makeStylesForTable($arr) { $count = 0; + return array_build($arr, function($key, $value) use (&$count) { return [$count++, ['class_label' => $value, 'class_name' => $key]]; }); } + + /** + * Same as getConfigured but uses special style structure. + * @return mixed + */ + public static function getConfiguredStyles($key, $default = null) + { + $instance = static::instance(); + + $value = $instance->get($key); + + $defaultValue = $instance->getDefaultValue($key); + + if (is_array($value)) { + $value = array_build($value, function($key, $value) { + return [array_get($value, 'class_name'), array_get($value, 'class_label')]; + }); + } + + return $value != $defaultValue ? $value : $default; + } + + /** + * Returns the value only if it differs from the default value. + * @return mixed + */ + public static function getConfigured($key, $default = null) + { + $instance = static::instance(); + + $value = $instance->get($key); + + $defaultValue = $instance->getDefaultValue($key); + + return $value != $defaultValue ? $value : $default; + } + + public function getDefaultValue($attribute) + { + $property = 'default'.studly_case($attribute); + + return $this->$property; + } + + public static function renderCss() + { + if (Cache::has(self::CACHE_KEY)) { + return Cache::get(self::CACHE_KEY); + } + + try { + $customCss = self::compileCss(); + Cache::forever(self::CACHE_KEY, $customCss); + } + catch (Exception $ex) { + $customCss = '/* ' . $ex->getMessage() . ' */'; + } + + return $customCss; + } + + public static function compileCss() + { + $parser = new Less_Parser(['compress' => true]); + + $customStyles = '.fr-view {'; + $customStyles .= self::get('html_custom_styles'); + $customStyles .= '}'; + + $parser->parse($customStyles); + + $css = $parser->getCss(); + + return $css; + } }