Implemented Preview button and states abstraction for toolbar

This commit is contained in:
Djamil Legato
2016-03-01 19:00:29 -08:00
parent 234484f14d
commit aa73b82832
9 changed files with 225 additions and 101 deletions

View File

@@ -750,7 +750,7 @@ class AdminController
$html = $page->content();
$this->admin->json_response = ['status' => 'success', 'message' => $html];
$this->admin->json_response = ['status' => 'success', 'preview' => $html];
} catch (\Exception $e) {
$this->admin->json_response = ['status' => 'error', 'message' => $e->getMessage()];

View File

@@ -110,10 +110,16 @@ export class Toolbar {
static templates() {
return {
navigation: `
<div class="grav-editor-toolbar"></div>
<div class="grav-editor-toolbar">
<div class="grav-editor-actions"></div>
<div class="grav-editor-modes"></div>
</div>
`,
states: `
<div class="grav-editor-states"></div>
<div class="grav-editor-states">
<div class="grav-editor-info"></div>
<div class="grav-editor-modes"></div>
</div>
`
};
}
@@ -135,14 +141,35 @@ export class Toolbar {
}
renderButtons() {
this.ui.navigation.empty().append('<ul />');
this.ui.navigation.find('.grav-editor-actions').empty().append('<ul />');
Buttons.navigation.forEach((button) => {
Object.keys(button).forEach((key) => {
let obj = button[key];
let element = $(`<li class="grav-editor-button-${key}"><a title="${obj.title}">${obj.label}</a></li>`);
this.ui.navigation.find('ul').append(element);
this.ui.navigation.find('.grav-editor-actions ul').append(element);
obj.action && obj.action.call(obj.action, this.codemirror, element, this.editor);
obj.action && obj.action.call(obj.action, {
codemirror: this.codemirror,
button: element,
textarea: this.editor,
ui: this.ui
});
});
});
this.ui.navigation.find('.grav-editor-modes').empty().append('<ul />');
Buttons.states.forEach((button) => {
Object.keys(button).forEach((key) => {
let obj = button[key];
let element = $(`<li class="grav-editor-button-${key}"><a title="${obj.title}">${obj.label}</a></li>`);
this.ui.navigation.find('.grav-editor-modes ul').append(element);
obj.action && obj.action.call(obj.action, {
codemirror: this.codemirror,
button: element,
textarea: this.editor,
ui: this.ui
});
});
});
}

View File

@@ -1,4 +1,6 @@
import $ from 'jquery';
import { config } from 'grav-config';
import request from '../../../utils/request';
let replacer = ({ name, replace, codemirror, button, mode = 'replaceSelections', runner }) => {
button.on(`click.editor.${name}`, () => {
@@ -71,7 +73,7 @@ export default {
identifier: 'bold',
title: 'Bold',
label: '<i class="fa fa-fw fa-bold"></i>',
action(codemirror, button, textarea) {
action({ codemirror, button, textarea }) {
replacer({ name: 'bold', replace: '**$1$cur**', codemirror, button });
}
}
@@ -80,7 +82,7 @@ export default {
identifier: 'italic',
title: 'Italic',
label: '<i class="fa fa-fw fa-italic"></i>',
action(codemirror, button, textarea) {
action({ codemirror, button, textarea }) {
replacer({ name: 'italic', replace: '_$1$cur_', codemirror, button });
}
}
@@ -89,7 +91,7 @@ export default {
identifier: 'strike',
title: 'Strikethrough',
label: '<i class="fa fa-fw fa-strikethrough"></i>',
action(codemirror, button, textarea) {
action({ codemirror, button, textarea }) {
replacer({ name: 'strike', replace: '~~$1$cur~~', codemirror, button });
}
}
@@ -98,7 +100,7 @@ export default {
identifier: 'link',
title: 'Link',
label: '<i class="fa fa-fw fa-link"></i>',
action(codemirror, button, textarea) {
action({ codemirror, button, textarea }) {
replacer({ name: 'link', replace: '[$1](http://$cur)', codemirror, button });
}
}
@@ -107,7 +109,7 @@ export default {
identifier: 'image',
title: 'Image',
label: '<i class="fa fa-fw fa-picture-o"></i>',
action(codemirror, button, textarea) {
action({ codemirror, button, textarea }) {
replacer({ name: 'image', replace: '![$1](http://$cur)', codemirror, button });
}
}
@@ -116,7 +118,7 @@ export default {
identifier: 'blockquote',
title: 'Blockquote',
label: '<i class="fa fa-fw fa-quote-right"></i>',
action(codemirror, button, textarea) {
action({ codemirror, button, textarea }) {
replacer({ name: 'blockquote', replace: '> $1', codemirror, button, mode: 'replaceLine' });
}
}
@@ -125,7 +127,7 @@ export default {
identifier: 'listUl',
title: 'Unordered List',
label: '<i class="fa fa-fw fa-list-ul"></i>',
action(codemirror, button, textarea) {
action({ codemirror, button, textarea }) {
replacer({ name: 'listUl', replace: '* $1', codemirror, button, mode: 'replaceLine' });
}
}
@@ -134,7 +136,7 @@ export default {
identifier: 'listOl',
title: 'Ordered List',
label: '<i class="fa fa-fw fa-list-ol"></i>',
action(codemirror, button, textarea) {
action({ codemirror, button, textarea }) {
replacer({
name: 'listOl',
replace: '. $1',
@@ -152,47 +154,109 @@ export default {
});
}
}
}, {
fullscreen: {
identifier: 'fullscreen',
title: 'Fullscreen',
label: '<i class="fa fa-fw fa-expand"></i>',
action(codemirror, button, textarea) {
button.on('click.editor.fullscreen', () => {
let container = textarea.closest('.grav-editor');
let wrapper = codemirror.getWrapperElement();
if (!container.hasClass('grav-editor-fullscreen')) {
textarea.data('fullScreenRestore', {
scrollTop: window.pageYOffset,
scrollLeft: window.pageXOffset,
width: wrapper.style.width,
height: wrapper.style.height
});
wrapper.style.width = '';
wrapper.style.height = textarea.parent('.grav-editor-content').height() + 'px';
global.document.documentElement.style.overflow = 'hidden';
} else {
global.document.documentElement.style.overflow = '';
let state = textarea.data('fullScreenRestore');
wrapper.style.width = state.width;
wrapper.style.height = state.height;
window.scrollTo(state.scrollLeft, state.scrollTop);
}
container.toggleClass('grav-editor-fullscreen');
setTimeout(() => {
codemirror.refresh();
// this.preview.parent().css('height', this.code.height());
$(window).trigger('resize');
}, 5);
});
}
}
}
],
states: [{}]
states: [{
code: {
identifier: 'editor',
title: 'Editor',
label: '<i class="fa fa-fw fa-code"></i>',
action({ codemirror, button, textarea, ui }) {
if (textarea.data('grav-editor-mode') === 'editor') {
button.addClass('editor-active');
}
button.on('click.states.editor', () => {
button.siblings().removeClass('editor-active');
button.addClass('editor-active');
textarea.data('grav-editor-mode', 'editor');
let previewContainer = textarea.data('grav-editor-preview-container');
let content = textarea.parent('.grav-editor-content');
content.css('display', 'block');
ui.navigation.find('.grav-editor-actions').css('display', 'block');
if (previewContainer.length) {
previewContainer.css('display', 'none');
}
});
}
}
}, {
preview: {
identifier: 'preview',
title: 'Preview',
label: '<i class="fa fa-fw fa-eye"></i>',
action({ codemirror, button, textarea, ui }) {
if (textarea.data('grav-editor-mode') === 'preview') {
button.addClass('editor-active');
}
button.on('click.states.preview', () => {
let previewContainer = textarea.data('grav-editor-preview-container');
let content = textarea.parent('.grav-editor-content');
button.siblings().removeClass('editor-active');
button.addClass('editor-active');
textarea.data('grav-editor-mode', 'preview');
if (!previewContainer) {
previewContainer = $('<div class="grav-editor-preview" />');
content.after(previewContainer);
textarea.data('grav-editor-preview-container', previewContainer);
}
previewContainer.css({ height: content.height(), display: 'block' });
content.css('display', 'none');
ui.navigation.find('.grav-editor-actions').css('display', 'none');
let url = `${textarea.data('grav-urlpreview')}/task${config.param_sep}processmarkdown`;
let params = textarea.closest('form').serializeArray();
let body = {};
params.map((obj) => { body[obj.name] = obj.value; });
request(url, {
method: 'post',
body: params
}, (response) => previewContainer.html(response.preview));
});
}
}
}, {
fullscreen: {
identifier: 'fullscreen',
title: 'Fullscreen',
label: '<i class="fa fa-fw fa-expand"></i>',
action({ codemirror, button, textarea }) {
button.on('click.editor.fullscreen', () => {
let container = textarea.closest('.grav-editor');
let wrapper = codemirror.getWrapperElement();
if (!container.hasClass('grav-editor-fullscreen')) {
textarea.data('fullScreenRestore', {
scrollTop: window.pageYOffset,
scrollLeft: window.pageXOffset,
width: wrapper.style.width,
height: wrapper.style.height
});
wrapper.style.width = '';
wrapper.style.height = textarea.parent('.grav-editor-content').height() + 'px';
global.document.documentElement.style.overflow = 'hidden';
} else {
global.document.documentElement.style.overflow = '';
let state = textarea.data('fullScreenRestore');
wrapper.style.width = state.width;
wrapper.style.height = state.height;
window.scrollTo(state.scrollLeft, state.scrollTop);
}
container.toggleClass('grav-editor-fullscreen');
setTimeout(() => {
codemirror.refresh();
// this.preview.parent().css('height', this.code.height());
$(window).trigger('resize');
}, 5);
});
}
}
}]
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -30,6 +30,22 @@
}
}
.grav-editor-toolbar {
@include align-items(stretch);
@include display(flex);
@include flex-direction(row);
.grav-editor-actions {
@include flex(80% 0 0);
}
.grav-editor-modes {
@include flex(1);
ul {
float: right;
}
}
}
.grav-editor-toolbar {
@include clearfix;
border: 1px solid $form-border;
@@ -48,15 +64,6 @@
}
display: inline-block;
}
.editor-active a {
background: white;
cursor: auto;
border-left: 1px solid $form-border;
border-right: 1px solid $form-border;
&:hover {
background: $white;
}
}
a {
display: inline-block;
@@ -75,22 +82,48 @@
&:hover, &:focus {
background: lighten($content-bg, 2%);
color: darken($content-fg, 10%);
border-top: 1px solid darken($content-bg, 20%);
border-bottom: 1px solid darken($content-bg, 20%);
border-top: 1px solid $form-border;
border-bottom: 1px solid $form-border;
}
}
.editor-active {
a {
background: white;
cursor: auto;
border-top: 1px solid $form-border;
border-left: 1px solid $form-border;
border-right: 1px solid $form-border;
&:hover {
background: $white;
border-top: 0;
border-bottom: 1px solid $white;
}
}
&:last-child a, &:last-child a:hover {
border-right: 1px solid transparent;
}
}
}
}
.grav-editor-actions {
&.left {
float: left;
.grav-editor-toolbar .grav-editor-modes {
li {
&:first-child a {
border-top-left-radius: 0;
}
&:last-child a {
border-top-right-radius: 4px;
}
}
&.right {
float: right;
a {
&:hover {
/*border: 1px solid transparent;
border-bottom: 1px solid darken($content-bg, 20%);*/
}
}
}
@@ -101,8 +134,7 @@
}
}
.grav-editor-content {
.grav-editor-content, .grav-editor-preview {
@include clearfix;
cursor: text;
border: 1px solid $form-border;
@@ -123,7 +155,7 @@
padding: 20px;
overflow-y: scroll;
position: relative;
background: #fbfbfb;
background: #fff;
border-bottom-right-radius: $form-border-radius;
}

View File

@@ -13,6 +13,7 @@
<div class="grav-editor-content">
<textarea
data-grav-editor="{{ {'codemirror': codemirrorOptions} | json_encode|e('html_attr') }}"
data-grav-editor-mode="editor"
name="{{ (scope ~ field.name)|fieldName }}"
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
{% if field.showPreview %}data-grav-preview-enabled="true"{% endif %}