Add a markdown toolbar to help with the markdown syntax

pull/1/head
yflory 7 years ago
parent 9795ac32cb
commit b0f553e9ea

@ -23,5 +23,15 @@
} }
} }
.markdown_main() {
blockquote {
background: #e5e5e5;
padding: 10px;
border-left: 3px solid #999;
padding-right: 0;
p { margin: 0; }
blockquote { margin: 0; }
}
}
// todo ul, ol // todo ul, ol

@ -23,6 +23,33 @@
display: flex; display: flex;
} }
.toolbar_button {
height: @toolbar_line-height;
box-sizing: border-box;
padding: 3px 10px;
margin: 0;
transition: all 0.15s;
.tools_unselectable();
&.cp-toolbar-hidden {
display: none;
}
.cp-toolbar-drawer-element {
display: none;
}
// Bootstrap 4 colors (btn-secondary)
border: 1px solid transparent;
color: inherit;
font: @toolbar_button-font;
* {
color: inherit;
font: @toolbar_button-font;
}
background: transparent;
&:hover {
background-color: rgba(50,50,50,0.3);
}
}
.cp-toolbar-userlist-drawer { .cp-toolbar-userlist-drawer {
background-color: @colortheme_default-bg; background-color: @colortheme_default-bg;
font: @colortheme_app-font-size @colortheme_font; font: @colortheme_app-font-size @colortheme_font;
@ -143,6 +170,20 @@
} }
.addToolbarColors (@color, @bg-color, @barWidth: 600px) { .addToolbarColors (@color, @bg-color, @barWidth: 600px) {
.cp-markdown-toolbar {
height: @toolbar_line-height;
background-color: lighten(@bg-color, 20%);
button {
outline: 0;
color: @color;
.toolbar_button;
font: normal normal normal 14px/1 FontAwesome;
&:hover {
background-color: lighten(@bgcolor, 8%);
}
&.cp-markdown-help { float: right; }
}
}
.cp-toolbar-userlist-drawer { .cp-toolbar-userlist-drawer {
background-color: @bgcolor; background-color: @bgcolor;
color: @color; color: @color;
@ -282,7 +323,6 @@
.addToolbarColors(@color, @bgcolor); .addToolbarColors(@color, @bgcolor);
} }
.cp-toolbar { .cp-toolbar {
* { * {
outline-width: 0; outline-width: 0;
@ -328,28 +368,7 @@
} }
button { button {
transition: all 0.15s; .toolbar_button;
.tools_unselectable();
&.cp-toolbar-hidden {
display: none;
}
.cp-toolbar-drawer-element {
display: none;
}
// Bootstrap 4 colors (btn-secondary)
border: 1px solid transparent;
color: inherit;
font: @toolbar_button-font;
* {
color: inherit;
font: @toolbar_button-font;
}
}
.cp-toolbar-rightside button, .cp-toolbar-leftside button {
background: transparent;
&:hover {
background-color: rgba(50,50,50,0.3);
}
} }
.cp-toolbar-limit { .cp-toolbar-limit {
@ -373,13 +392,12 @@
white-space: normal; white-space: normal;
} }
button, select { /*button, select {
height: @toolbar_line-height; height: @toolbar_line-height;
box-sizing: border-box; box-sizing: border-box;
padding: 3px 10px; padding: 3px 10px;
margin: 0; margin: 0;
}*/
}
.cp-toolbar-rightside-button { .cp-toolbar-rightside-button {
float: right; float: right;

@ -559,6 +559,22 @@ define(function () {
// general warnings // general warnings
out.warn_notPinned = "Ce pad n'est stocké dans aucun CryptDrive. Il va expirer après 3 mois d'inactivité. <a href='/about.html#pinning'>En savoir plus...</a>"; out.warn_notPinned = "Ce pad n'est stocké dans aucun CryptDrive. Il va expirer après 3 mois d'inactivité. <a href='/about.html#pinning'>En savoir plus...</a>";
// markdown toolbar
out.mdToolbar_button = "Afficher ou cacher la barre d'outils Markdown";
out.mdToolbar_defaultText = "Votre texte ici";
out.mdToolbar_help = "Aide";
out.mdToolbar_tutorial = "https://blog.wax-o.com/2014/04/tutoriel-un-guide-pour-bien-commencer-avec-markdown/";
out.mdToolbar_bold = "Gras";
out.mdToolbar_italic = "Italique";
out.mdToolbar_strikethrough = "Barré";
out.mdToolbar_heading = "Titre";
out.mdToolbar_link = "Lien";
out.mdToolbar_quote = "Citation";
out.mdToolbar_nlist = "Liste ordonnée";
out.mdToolbar_list = "Liste à puces";
out.mdToolbar_check = "Liste de tâches";
out.mdToolbar_code = "Code";
// index.html // index.html
//about.html //about.html

@ -564,6 +564,22 @@ define(function () {
// general warnings // general warnings
out.warn_notPinned = "This pad is not in anyone's CryptDrive. It will expire after 3 months. <a href='/about.html#pinning'>Learn more...</a>"; out.warn_notPinned = "This pad is not in anyone's CryptDrive. It will expire after 3 months. <a href='/about.html#pinning'>Learn more...</a>";
// markdown toolbar
out.mdToolbar_button = "Show or hide the Markdown toolbar";
out.mdToolbar_defaultText = "Your text here";
out.mdToolbar_help = "Help";
out.mdToolbar_tutorial = "http://www.markdowntutorial.com/";
out.mdToolbar_bold = "Bold";
out.mdToolbar_italic = "Italic";
out.mdToolbar_strikethrough = "Strikethrough";
out.mdToolbar_heading = "Heading";
out.mdToolbar_link = "Link";
out.mdToolbar_quote = "Quote";
out.mdToolbar_nlist = "Ordered list";
out.mdToolbar_list = "Bullet list";
out.mdToolbar_check = "Task list";
out.mdToolbar_code = "Code";
// index.html // index.html

@ -6,5 +6,6 @@ define([], function () {
} }
var bounceTo = decodeURIComponent(window.location.hash.slice(1)); var bounceTo = decodeURIComponent(window.location.hash.slice(1));
if (!bounceTo) { return; } if (!bounceTo) { return; }
window.opener = null;
window.location.href = bounceTo; window.location.href = bounceTo;
}); });

@ -17,21 +17,27 @@
max-height: 100%; max-height: 100%;
min-height: auto; min-height: auto;
.CodeMirror { #cp-app-code-container {
display: inline-block; display: inline-flex;
flex-flow: column;
height: 100%; height: 100%;
min-height: 100%; min-height: 100%;
width: 50%; width: 50%;
min-width: 20%; min-width: 20%;
max-width: 80%; max-width: 80%;
resize: horizontal; resize: horizontal;
font-size: initial; overflow: hidden;
&.cp-app-code-fullpage {
max-width: 100%;
resize: none;
flex: 1;
}
} }
.CodeMirror.cp-app-code-fullpage { .CodeMirror {
//min-width: 100%;
max-width: 100%;
resize: none;
flex: 1; flex: 1;
font-size: initial;
width: 100%;
} }
.CodeMirror-focused .cm-matchhighlight { .CodeMirror-focused .cm-matchhighlight {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFklEQVQI12NgYGBgkKzc8x9CMDAwAAAmhwSbidEoSQAAAABJRU5ErkJggg==); background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFklEQVQI12NgYGBgkKzc8x9CMDAwAAAmhwSbidEoSQAAAABJRU5ErkJggg==);
@ -68,6 +74,7 @@
max-height:50vh; max-height:50vh;
} }
} }
.markdown_main();
} }
#cp-app-code-preview-content { #cp-app-code-preview-content {

@ -12,7 +12,9 @@
<body class="cp-app-code"> <body class="cp-app-code">
<div id="cme_toolbox" class="cp-toolbar-container"></div> <div id="cme_toolbox" class="cp-toolbar-container"></div>
<div id="cp-app-code-editor"> <div id="cp-app-code-editor">
<textarea id="editor1" name="editor1"></textarea> <div id="cp-app-code-container">
<textarea id="editor1" name="editor1"></textarea>
</div>
<div id="cp-app-code-preview"> <div id="cp-app-code-preview">
<div id="cp-app-code-preview-content"></div> <div id="cp-app-code-preview-content"></div>
</div> </div>

@ -67,10 +67,13 @@ define([
var $previewContainer = $('#cp-app-code-preview'); var $previewContainer = $('#cp-app-code-preview');
var $preview = $('#cp-app-code-preview-content'); var $preview = $('#cp-app-code-preview-content');
var $editorContainer = $('#cp-app-code-editor'); var $editorContainer = $('#cp-app-code-editor');
var $codeMirrorContainer = $('#cp-app-code-container');
var $codeMirror = $('.CodeMirror'); var $codeMirror = $('.CodeMirror');
var $previewButton = framework._.sfCommon.createButton(null, true); var markdownTb = framework._.sfCommon.createMarkdownToolbar(editor);
$codeMirrorContainer.prepend(markdownTb.toolbar);
var $previewButton = framework._.sfCommon.createButton(null, true);
var forceDrawPreview = function () { var forceDrawPreview = function () {
try { try {
DiffMd.apply(DiffMd.render(editor.getValue()), $preview); DiffMd.apply(DiffMd.render(editor.getValue()), $preview);
@ -101,20 +104,21 @@ define([
$previewContainer.toggle(); $previewContainer.toggle();
if ($previewContainer.is(':visible')) { if ($previewContainer.is(':visible')) {
forceDrawPreview(); forceDrawPreview();
$codeMirror.removeClass('cp-app-code-fullpage'); $codeMirrorContainer.removeClass('cp-app-code-fullpage');
$previewButton.addClass('cp-toolbar-button-active'); $previewButton.addClass('cp-toolbar-button-active');
framework._.sfCommon.setPadAttribute('previewMode', true, function (e) { framework._.sfCommon.setPadAttribute('previewMode', true, function (e) {
if (e) { return console.log(e); } if (e) { return console.log(e); }
}); });
} else { } else {
$codeMirror.addClass('cp-app-code-fullpage'); $codeMirrorContainer.addClass('cp-app-code-fullpage');
$previewButton.removeClass('cp-toolbar-button-active'); $previewButton.removeClass('cp-toolbar-button-active');
framework._.sfCommon.setPadAttribute('previewMode', false, function (e) { framework._.sfCommon.setPadAttribute('previewMode', false, function (e) {
if (e) { return console.log(e); } if (e) { return console.log(e); }
}); });
} }
}); });
framework._.toolbar.$rightside.append($previewButton);
framework._.toolbar.$rightside.append($previewButton).append(markdownTb.button);
$preview.click(function (e) { $preview.click(function (e) {
if (!e.target) { return; } if (!e.target) { return; }
@ -135,19 +139,20 @@ define([
if (data !== false) { if (data !== false) {
$previewContainer.show(); $previewContainer.show();
$previewButton.addClass('cp-toolbar-button-active'); $previewButton.addClass('cp-toolbar-button-active');
$codeMirror.removeClass('cp-app-code-fullpage'); $codeMirrorContainer.removeClass('cp-app-code-fullpage');
if (isPresentMode) { if (isPresentMode) {
$editorContainer.addClass('cp-app-code-present'); $editorContainer.addClass('cp-app-code-present');
} }
} }
}); });
return; markdownTb.setState(true);
} }
$editorContainer.removeClass('cp-app-code-present'); $editorContainer.removeClass('cp-app-code-present');
$previewButton.hide(); $previewButton.hide();
$previewContainer.hide(); $previewContainer.hide();
$previewButton.removeClass('active'); $previewButton.removeClass('active');
$codeMirror.addClass('cp-app-code-fullpage'); $codeMirrorContainer.addClass('cp-app-code-fullpage');
markdownTb.setState(true);
}; };
var isVisible = function () { var isVisible = function () {
@ -164,7 +169,7 @@ define([
splitter.css('top', $preview.scrollTop() + 'px'); splitter.css('top', $preview.scrollTop() + 'px');
}); });
var $target = $('.CodeMirror'); var $target = $codeMirrorContainer;
splitter.on('mousedown', function (e) { splitter.on('mousedown', function (e) {
e.preventDefault(); e.preventDefault();
@ -372,7 +377,7 @@ define([
SFCommon.create(waitFor(function (c) { common = c; })); SFCommon.create(waitFor(function (c) { common = c; }));
}).nThen(function () { }).nThen(function () {
CodeMirror = common.initCodeMirrorApp(null, CMeditor); CodeMirror = common.initCodeMirrorApp(null, CMeditor);
$('.CodeMirror').addClass('cp-app-code-fullpage'); $('#cp-app-code-container').addClass('cp-app-code-fullpage');
editor = CodeMirror.editor; editor = CodeMirror.editor;
}).nThen(waitFor()); }).nThen(waitFor());

@ -227,6 +227,27 @@ define([
.click(common.prepareFeedback(type)) .click(common.prepareFeedback(type))
.click(function () { UIElements.updateTags(common, null); }); .click(function () { UIElements.updateTags(common, null); });
break; break;
case 'toggle':
button = $('<button>', {
'class': 'fa fa-caret-down',
})
.click(common.prepareFeedback(type));
window.setTimeout(function () {
button.attr('title', data.title);
});
var updateIcon = function (isVisible) {
button.removeClass('fa-caret-down').removeClass('fa-caret-up');
if (!isVisible) { button.addClass('fa-caret-down'); }
else { button.addClass('fa-caret-up'); }
};
button.click(function () {
data.element.toggle();
var isVisible = data.element.is(':visible');
if (callback) { callback(isVisible); }
updateIcon(isVisible);
});
updateIcon(data.element.is(':visible'));
break;
default: default:
button = $('<button>', { button = $('<button>', {
'class': "fa fa-question", 'class': "fa fa-question",
@ -240,6 +261,157 @@ define([
return button; return button;
}; };
var createMdToolbar = function (editor) {
var $toolbar = $('<div>', {
'class': 'cp-markdown-toolbar'
});
var clean = function (str) {
return str.replace(/^(\n)+/, '').replace(/(\n)+$/, '');
};
var actions = {
'bold': {
expr: '**{0}**',
icon: 'fa-bold'
},
'italic': {
expr: '_{0}_',
icon: 'fa-italic'
},
'strikethrough': {
expr: '~~{0}~~',
icon: 'fa-strikethrough'
},
'heading': {
apply: function (str) {
return '\n'+clean(str).split('\n').map(function (line) {
return '# '+line;
}).join('\n')+'\n';
},
icon: 'fa-header'
},
'link': {
expr: '[{0}](http://)',
icon: 'fa-link'
},
'quote': {
apply: function (str) {
return '\n\n'+str.split('\n').map(function (line) {
return '> '+line;
}).join('\n')+'\n\n';
},
icon: 'fa-quote-right'
},
'nlist': {
apply: function (str) {
return '\n'+clean(str).split('\n').map(function (line) {
return '1. '+line;
}).join('\n')+'\n';
},
icon: 'fa-list-ol'
},
'list': {
apply: function (str) {
return '\n'+clean(str).split('\n').map(function (line) {
return '* '+line;
}).join('\n')+'\n';
},
icon: 'fa-list-ul'
},
'check': {
apply: function (str) {
return '\n' + clean(str).split('\n').map(function (line) {
return '* [ ] ' + line;
}).join('\n') + '\n';
},
icon: 'fa-check-square-o'
},
'code': {
apply: function (str) {
if (str.indexOf('\n') !== -1) {
return '\n```\n' + clean(str) + '\n```\n';
}
return '`' + str + '`';
},
icon: 'fa-code'
}
};
var onClick = function () {
var type = $(this).attr('data-type');
var texts = editor.getSelections();
var newTexts = texts.map(function (str) {
str = str || Messages.mdToolbar_defaultText;
if (actions[type].apply) {
return actions[type].apply(str);
}
return actions[type].expr.replace('{0}', str);
});
editor.replaceSelections(newTexts, 'around');
};
for (var k in actions) {
$('<button>', {
'data-type': k,
'class': 'fa ' + actions[k].icon,
title: Messages['mdToolbar_' + k] || k
}).click(onClick).appendTo($toolbar);
}
$('<button>', {
'class': 'fa fa-question cp-markdown-help',
title: Messages.mdToolbar_help
}).click(function () {
var href = Messages.mdToolbar_tutorial;
var bounceHref = window.location.origin + '/bounce/#' + encodeURIComponent(href);
window.open(bounceHref);
}).appendTo($toolbar);
return $toolbar;
};
UIElements.createMarkdownToolbar = function (common, editor) {
var $toolbar = createMdToolbar(editor);
var cfg = {
title: Messages.mdToolbar_button,
element: $toolbar
};
var onClick = function (visible) {
common.setAttribute(['general', 'markdown-help'], visible, function (e) {
if (e) { return void console.error(e); }
});
};
var $toolbarButton = common.createButton('toggle', true, cfg, onClick);
common.getAttribute(['general', 'markdown-help'], function (e, data) {
if (e) { return void console.error(e); }
if (data === true && $toolbarButton) {
$toolbarButton.click();
}
});
// setState provides the ability to disable the toolbar and the button in case we don't
// have the markdown editor available (in code we can switch mode, in poll we can publish)
var setState = function (state) {
if (!state) {
$toolbar.hide();
$toolbarButton.hide();
return;
}
common.getAttribute(['general', 'markdown-help'], function (e, data) {
if (e) { return void console.error(e); }
if (data === true && $toolbarButton) {
// Show the toolbar using the button to make sure the icon in the button is
// correct (caret-down / caret-up)
$toolbar.hide();
$toolbarButton.click();
return;
}
$toolbar.show();
$toolbarButton.click();
});
$toolbarButton.show();
};
return {
toolbar: $toolbar,
button: $toolbarButton,
setState: setState
};
};
// Avatars // Avatars
// Enable mediatags // Enable mediatags

@ -87,6 +87,7 @@ define([
funcs.createUsageBar = callWithCommon(UIElements.createUsageBar); funcs.createUsageBar = callWithCommon(UIElements.createUsageBar);
funcs.updateTags = callWithCommon(UIElements.updateTags); funcs.updateTags = callWithCommon(UIElements.updateTags);
funcs.createLanguageSelector = callWithCommon(UIElements.createLanguageSelector); funcs.createLanguageSelector = callWithCommon(UIElements.createLanguageSelector);
funcs.createMarkdownToolbar = callWithCommon(UIElements.createMarkdownToolbar);
// Thumb // Thumb
funcs.displayThumbnail = callWithCommon(Thumb.displayThumbnail); funcs.displayThumbnail = callWithCommon(Thumb.displayThumbnail);

@ -263,38 +263,20 @@ define([
var addToolbarHideBtn = function (framework, $bar) { var addToolbarHideBtn = function (framework, $bar) {
// Expand / collapse the toolbar // Expand / collapse the toolbar
var $collapse = framework._.sfCommon.createButton(null, true); var cfg = {
$collapse.removeClass('fa-question'); element: $bar.find('.cke_toolbox_main')
var updateIcon = function (isVisible) {
$collapse.removeClass('fa-caret-down').removeClass('fa-caret-up');
if (!isVisible) {
framework.feedback('HIDETOOLBAR_PAD');
$collapse.addClass('fa-caret-down');
}
else {
framework.feedback('SHOWTOOLBAR_PAD');
$collapse.addClass('fa-caret-up');
}
}; };
updateIcon(); var onClick = function (visible) {
$collapse.click(function () {
$(window).trigger('resize'); $(window).trigger('resize');
$('.cke_toolbox_main').toggle();
$(window).trigger('cryptpad-ck-toolbar'); $(window).trigger('cryptpad-ck-toolbar');
var isVisible = $bar.find('.cke_toolbox_main').is(':visible'); framework._.sfCommon.setAttribute(['pad', 'showToolbar'], visible);
framework._.sfCommon.setAttribute(['pad', 'showToolbar'], isVisible); };
updateIcon(isVisible);
});
framework._.sfCommon.getAttribute(['pad', 'showToolbar'], function (err, data) { framework._.sfCommon.getAttribute(['pad', 'showToolbar'], function (err, data) {
if (typeof(data) === "undefined" || data) { if (typeof(data) === "undefined" || data) { $('.cke_toolbox_main').show(); }
$('.cke_toolbox_main').show(); else { $('.cke_toolbox_main').hide(); }
updateIcon(true); var $collapse = framework._.sfCommon.createButton('toggle', true, cfg, onClick);
return; framework._.toolbar.$rightside.append($collapse);
}
$('.cke_toolbox_main').hide();
updateIcon(false);
}); });
framework._.toolbar.$rightside.append($collapse);
}; };
var displayMediaTags = function (framework, dom, mediaTagMap) { var displayMediaTags = function (framework, dom, mediaTagMap) {

Loading…
Cancel
Save