Introduce MarkdownEditor base code
This commit is contained in:
parent
3f58cd70fc
commit
d2da170864
|
|
@ -131,6 +131,10 @@ class ServiceProvider extends ModuleServiceProvider
|
||||||
'label' => 'Rich editor',
|
'label' => 'Rich editor',
|
||||||
'code' => 'richeditor'
|
'code' => 'richeditor'
|
||||||
]);
|
]);
|
||||||
|
$manager->registerFormWidget('Backend\FormWidgets\MarkdownEditor', [
|
||||||
|
'label' => 'Markdown editor',
|
||||||
|
'code' => 'markdown'
|
||||||
|
]);
|
||||||
$manager->registerFormWidget('Backend\FormWidgets\FileUpload', [
|
$manager->registerFormWidget('Backend\FormWidgets\FileUpload', [
|
||||||
'label' => 'File uploader',
|
'label' => 'File uploader',
|
||||||
'code' => 'fileupload'
|
'code' => 'fileupload'
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
<?php namespace Backend\FormWidgets;
|
||||||
|
|
||||||
|
use Backend\Models\EditorPreferences;
|
||||||
|
use Backend\Classes\FormWidgetBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Code Editor
|
||||||
|
* Renders a code editor field.
|
||||||
|
*
|
||||||
|
* @package october\backend
|
||||||
|
* @author Alexey Bobkov, Samuel Georges
|
||||||
|
*/
|
||||||
|
class MarkdownEditor extends FormWidgetBase
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Configurable properties
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// Object properties
|
||||||
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
protected $defaultAlias = 'markdown';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->fillFromConfig([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
$this->prepareVars();
|
||||||
|
return $this->makePartial('markdowneditor');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepares the widget data
|
||||||
|
*/
|
||||||
|
public function prepareVars()
|
||||||
|
{
|
||||||
|
$this->vars['stretch'] = $this->formField->stretch;
|
||||||
|
$this->vars['size'] = $this->formField->size;
|
||||||
|
$this->vars['name'] = $this->formField->getName();
|
||||||
|
$this->vars['value'] = $this->getLoadValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function loadAssets()
|
||||||
|
{
|
||||||
|
$this->addCss('css/markdowneditor.css', 'core');
|
||||||
|
$this->addJs('js/markdowneditor.js', 'core');
|
||||||
|
$this->addJs('/modules/backend/formwidgets/codeeditor/assets/js/build-min.js', 'core');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,234 @@
|
||||||
|
+function ($) { "use strict";
|
||||||
|
var Base = $.oc.foundation.base,
|
||||||
|
BaseProto = Base.prototype
|
||||||
|
|
||||||
|
var MarkdownEditor = function (element, options) {
|
||||||
|
this.$el = $(element)
|
||||||
|
this.options = options || {}
|
||||||
|
this.$textarea = $('textarea:first', this.$el)
|
||||||
|
this.$toolbar = $('.editor-toolbar:first', this.$el)
|
||||||
|
this.$write = $('.editor-write:first', this.$el)
|
||||||
|
this.$preview = $('.editor-preview:first', this.$el)
|
||||||
|
this.$code = null
|
||||||
|
this.editor = null
|
||||||
|
this.$form = null
|
||||||
|
|
||||||
|
$.oc.foundation.controlUtils.markDisposable(element)
|
||||||
|
Base.call(this)
|
||||||
|
this.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkdownEditor.prototype = Object.create(BaseProto)
|
||||||
|
MarkdownEditor.prototype.constructor = MarkdownEditor
|
||||||
|
|
||||||
|
MarkdownEditor.prototype.init = function() {
|
||||||
|
this.$el.one('dispose-control', this.proxy(this.dispose))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Control must have an identifier
|
||||||
|
*/
|
||||||
|
if (!this.$el.attr('id')) {
|
||||||
|
this.$el.attr('id', 'element-' + Math.random().toString(36).substring(7))
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create code container
|
||||||
|
*/
|
||||||
|
this.$code = $('<div />')
|
||||||
|
.addClass('editor-code')
|
||||||
|
.attr('id', this.$el.attr('id') + '-code')
|
||||||
|
.css({
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
left: 0
|
||||||
|
})
|
||||||
|
.appendTo(this.$write)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize ACE editor
|
||||||
|
*/
|
||||||
|
var editor = this.editor = ace.edit(this.$code.attr('id')),
|
||||||
|
options = this.options,
|
||||||
|
$form = this.$el.closest('form');
|
||||||
|
|
||||||
|
editor.getSession().setMode({ path: 'ace/mode/markdown' })
|
||||||
|
editor.setHighlightActiveLine(false)
|
||||||
|
editor.renderer.setShowGutter(false)
|
||||||
|
editor.renderer.setShowPrintMargin(false)
|
||||||
|
editor.getSession().setUseWrapMode(true)
|
||||||
|
editor.setFontSize(14)
|
||||||
|
editor.on('blur', this.proxy(this.onBlur))
|
||||||
|
editor.on('focus', this.proxy(this.onFocus))
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkdownEditor.prototype.dispose = function() {
|
||||||
|
this.$el.off('dispose-control', this.proxy(this.dispose))
|
||||||
|
this.$el.removeData('oc.markdownEditor')
|
||||||
|
|
||||||
|
this.$el = null
|
||||||
|
|
||||||
|
// In some cases options could contain callbacks,
|
||||||
|
// so it's better to clean them up too.
|
||||||
|
this.options = null
|
||||||
|
|
||||||
|
BaseProto.dispose.call(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkdownEditor.prototype.onResize = function() {
|
||||||
|
this.editor.resize()
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkdownEditor.prototype.onBlur = function() {
|
||||||
|
this.$el.removeClass('editor-focus')
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkdownEditor.prototype.onFocus = function() {
|
||||||
|
this.$el.addClass('editor-focus')
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkdownEditor.DEFAULTS = {
|
||||||
|
buttons: ['formatting', 'bold', 'italic', 'unorderedlist', 'orderedlist', 'link', 'horizontalrule'],
|
||||||
|
viewMode: 'tab'
|
||||||
|
}
|
||||||
|
|
||||||
|
// PLUGIN DEFINITION
|
||||||
|
// ============================
|
||||||
|
|
||||||
|
var old = $.fn.markdownEditor
|
||||||
|
|
||||||
|
$.fn.markdownEditor = function (option) {
|
||||||
|
var args = arguments;
|
||||||
|
|
||||||
|
return this.each(function () {
|
||||||
|
var $this = $(this)
|
||||||
|
var data = $this.data('oc.markdownEditor')
|
||||||
|
var options = $.extend({}, MarkdownEditor.DEFAULTS, $this.data(), typeof option == 'object' && option)
|
||||||
|
if (!data) $this.data('oc.markdownEditor', (data = new MarkdownEditor(this, options)))
|
||||||
|
if (typeof option == 'string') data[option].apply(data, args)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.markdownEditor.Constructor = MarkdownEditor
|
||||||
|
|
||||||
|
$.fn.markdownEditor.noConflict = function () {
|
||||||
|
$.fn.markdownEditor = old
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).render(function (){
|
||||||
|
$('[data-control="markdowneditor"]').markdownEditor()
|
||||||
|
})
|
||||||
|
|
||||||
|
// BUTTON DEFINITIONS
|
||||||
|
// =================
|
||||||
|
|
||||||
|
if ($.oc === undefined)
|
||||||
|
$.oc = {}
|
||||||
|
|
||||||
|
$.oc.markdownEditorButtons = {
|
||||||
|
|
||||||
|
formatting: {
|
||||||
|
label: 'markdowneditor.formatting',
|
||||||
|
icon: 'formatting',
|
||||||
|
dropdown: {
|
||||||
|
quote: {
|
||||||
|
label: 'markdowneditor.quote',
|
||||||
|
cssClass: 'oc-button oc-icon-quote-right',
|
||||||
|
action: 'list.toggle',
|
||||||
|
template: '> $1'
|
||||||
|
},
|
||||||
|
code: {
|
||||||
|
label: 'markdowneditor.code',
|
||||||
|
cssClass: 'oc-button oc-icon-code',
|
||||||
|
action: 'block.format',
|
||||||
|
template: '```$1```'
|
||||||
|
},
|
||||||
|
header1: {
|
||||||
|
label: 'markdowneditor.header1',
|
||||||
|
cssClass: 'oc-button oc-icon-header',
|
||||||
|
action: 'block.format',
|
||||||
|
template: '# $1'
|
||||||
|
},
|
||||||
|
header2: {
|
||||||
|
label: 'markdowneditor.header2',
|
||||||
|
cssClass: 'oc-button oc-icon-header',
|
||||||
|
action: 'block.format',
|
||||||
|
template: '## $1'
|
||||||
|
},
|
||||||
|
header3: {
|
||||||
|
label: 'markdowneditor.header3',
|
||||||
|
cssClass: 'oc-button oc-icon-header',
|
||||||
|
action: 'block.format',
|
||||||
|
template: '### $1'
|
||||||
|
},
|
||||||
|
header4: {
|
||||||
|
label: 'markdowneditor.header4',
|
||||||
|
cssClass: 'oc-button oc-icon-header',
|
||||||
|
action: 'block.format',
|
||||||
|
template: '#### $1'
|
||||||
|
},
|
||||||
|
header5: {
|
||||||
|
label: 'markdowneditor.header5',
|
||||||
|
cssClass: 'oc-button oc-icon-header',
|
||||||
|
action: 'block.format',
|
||||||
|
template: '##### $1'
|
||||||
|
},
|
||||||
|
header6: {
|
||||||
|
label: 'markdowneditor.header6',
|
||||||
|
cssClass: 'oc-button oc-icon-header',
|
||||||
|
action: 'block.format',
|
||||||
|
template: '###### $1'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
bold: {
|
||||||
|
label: 'markdowneditor.bold',
|
||||||
|
icon: 'bold',
|
||||||
|
action: 'inline.format',
|
||||||
|
template: '**$1**'
|
||||||
|
},
|
||||||
|
italic: {
|
||||||
|
label: 'markdowneditor.italic',
|
||||||
|
icon: 'italic',
|
||||||
|
action: 'inline.format',
|
||||||
|
template: '*$1*'
|
||||||
|
},
|
||||||
|
unorderedlist: {
|
||||||
|
label: 'markdowneditor.unorderedlist',
|
||||||
|
icon: 'unorderedlist',
|
||||||
|
action: 'list.toggle',
|
||||||
|
template: '* $1'
|
||||||
|
},
|
||||||
|
orderedlist: {
|
||||||
|
label: 'markdowneditor.orderedlist',
|
||||||
|
icon: 'orderedlist',
|
||||||
|
action: 'list.toggle',
|
||||||
|
template: '1. $1'
|
||||||
|
},
|
||||||
|
link: {
|
||||||
|
label: 'markdowneditor.link',
|
||||||
|
icon: 'link',
|
||||||
|
action: 'inline.format',
|
||||||
|
template: '[$1](http://)'
|
||||||
|
},
|
||||||
|
horizontalrule: {
|
||||||
|
label: 'markdowneditor.horizontalrule',
|
||||||
|
icon: 'horizontalrule',
|
||||||
|
action: 'line.insert',
|
||||||
|
template: '---'
|
||||||
|
},
|
||||||
|
fullscreen: {
|
||||||
|
label: 'markdowneditor.fullscreen',
|
||||||
|
icon: 'fullscreen',
|
||||||
|
action: 'fullscreen.toggle'
|
||||||
|
},
|
||||||
|
preview: {
|
||||||
|
label: 'markdowneditor.preview',
|
||||||
|
cssClass: 'oc-button oc-icon-eye',
|
||||||
|
action: 'preview.toggle'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}(window.jQuery);
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,101 @@
|
||||||
|
|
||||||
|
<?php if ($this->previewMode): ?>
|
||||||
|
<div class="form-control"><?= e($value) ?></div>
|
||||||
|
<?php else: ?>
|
||||||
|
<div
|
||||||
|
id="<?= $this->getId() ?>"
|
||||||
|
class="field-markdowneditor size-<?= $size ?> <?= $stretch?'layout-relative':'' ?>"
|
||||||
|
data-control="markdowneditor"
|
||||||
|
>
|
||||||
|
|
||||||
|
<div class="layout control-toolbar edita-toolbar">
|
||||||
|
<div class="layout-cell toolbar-item">
|
||||||
|
<div data-control="toolbar">
|
||||||
|
<div class="dropdown">
|
||||||
|
<a href="#" data-toggle="dropdown" class="btn tb-icon tb-formatting"></a>
|
||||||
|
<ul class="dropdown-menu" data-dropdown-title="Formatting">
|
||||||
|
<li><a href="#" rel="quote" tabindex="-1" class="oc-icon-quote-right">Quote</a></li>
|
||||||
|
<li><a href="#" rel="code" tabindex="-1" class="oc-icon-code">Code</a></li>
|
||||||
|
<li><a href="#" rel="header1" tabindex="-1" class="oc-icon-header">Header 1</a></li>
|
||||||
|
<li><a href="#" rel="header2" tabindex="-1" class="oc-icon-header">Header 2</a></li>
|
||||||
|
<li><a href="#" rel="header3" tabindex="-1" class="oc-icon-header">Header 3</a></li>
|
||||||
|
<li><a href="#" rel="header4" tabindex="-1" class="oc-icon-header">Header 4</a></li>
|
||||||
|
<li><a href="#" rel="header5" tabindex="-1" class="oc-icon-header">Header 5</a></li>
|
||||||
|
<li><a href="#" rel="header6" tabindex="-1" class="oc-icon-header">Header 6</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn tb-icon tb-bold"></button>
|
||||||
|
<button type="button" class="btn tb-icon tb-italic"></button>
|
||||||
|
|
||||||
|
<button type="button" class="btn tb-icon tb-unorderedlist"></button>
|
||||||
|
<button type="button" class="btn tb-icon tb-orderedlist"></button>
|
||||||
|
|
||||||
|
<button type="button" class="btn tb-icon tb-link"></button>
|
||||||
|
<button type="button" class="btn tb-icon tb-horizontalrule"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layout-cell toolbar-item width-fix">
|
||||||
|
<button type="button" class="btn oc-icon-eye"></button>
|
||||||
|
<button type="button" class="btn oc-icon-expand"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<div class="layout-cell toolbar-item width-fix">
|
||||||
|
<input placeholder="search..." type="text" name="" value="" class="form-control icon search growable" autocomplete="off"/>
|
||||||
|
</div>
|
||||||
|
<div class="layout control-toolbar edita-toolbar">
|
||||||
|
<div class="layout-cell toolbar-item">
|
||||||
|
<div data-control="toolbar">
|
||||||
|
<div class="btn-group">
|
||||||
|
<button type="button" class="btn btn-primary oc-icon-plus">Create post</button>
|
||||||
|
<button type="button" class="btn btn-primary oc-icon-copy">Copy</button>
|
||||||
|
<button type="button" class="btn btn-primary oc-icon-trash">Delete</button>
|
||||||
|
|
||||||
|
<button type="button" class="btn btn-primary oc-icon-magic">Publish</button>
|
||||||
|
<button type="button" class="btn btn-primary oc-icon-off">Unpublish</button>
|
||||||
|
|
||||||
|
<button type="button" class="btn btn-primary oc-icon-time">Timer</button>
|
||||||
|
<button type="button" class="btn btn-primary oc-icon-mail-reply-all">Send by email</button>
|
||||||
|
<button type="button" class="btn btn-primary oc-icon-hdd">Archive</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="editor-toolbar">
|
||||||
|
<li class="dropdown">
|
||||||
|
<a href="#" data-toggle="dropdown" class="md-icon md-formatting" rel="formatting" tabindex="-1"></a>
|
||||||
|
<ul class="dropdown-menu" data-dropdown-title="Formatting">
|
||||||
|
<li><a href="#" rel="quote" tabindex="-1" class="oc-icon-quote-right">Quote</a></li>
|
||||||
|
<li><a href="#" rel="code" tabindex="-1" class="oc-icon-code">Code</a></li>
|
||||||
|
<li><a href="#" rel="header1" tabindex="-1" class="oc-icon-header">Header 1</a></li>
|
||||||
|
<li><a href="#" rel="header2" tabindex="-1" class="oc-icon-header">Header 2</a></li>
|
||||||
|
<li><a href="#" rel="header3" tabindex="-1" class="oc-icon-header">Header 3</a></li>
|
||||||
|
<li><a href="#" rel="header4" tabindex="-1" class="oc-icon-header">Header 4</a></li>
|
||||||
|
<li><a href="#" rel="header5" tabindex="-1" class="oc-icon-header">Header 5</a></li>
|
||||||
|
<li><a href="#" rel="header6" tabindex="-1" class="oc-icon-header">Header 6</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="#" class="md-icon md-bold" rel="bold" tabindex="-1"></a></li>
|
||||||
|
<li><a href="#" class="md-icon md-italic" rel="italic" tabindex="-1"></a></li>
|
||||||
|
<li><a href="#" class="md-icon md-unorderedlist" rel="unorderedlist" tabindex="-1"></a></li>
|
||||||
|
<li><a href="#" class="md-icon md-orderedlist" rel="orderedlist" tabindex="-1"></a></li>
|
||||||
|
<li><a href="#" class="md-icon md-link" rel="link" tabindex="-1"></a></li>
|
||||||
|
<li><a href="#" class="md-icon md-horizontalrule" rel="horizontalrule" tabindex="-1"></a></li>
|
||||||
|
<li class="editor-btn-right"><a href="#" class="md-icon md-fullscreen editor-btn-fullscreen" rel="fullscreen" tabindex="-1"></a></li>
|
||||||
|
<li class="editor-btn-right"><a href="#" class="oc-button oc-icon-eye editor-btn-preview" rel="preview" tabindex="-1"></a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<div class="editor-write">
|
||||||
|
<textarea name="<?= $name ?>" id="<?= $this->getId('textarea') ?>"><?= e($value) ?></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="editor-preview">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<?php endif ?>
|
||||||
Loading…
Reference in New Issue