Add a markdown toolbar to help with the markdown syntax

This commit is contained in:
yflory
2017-11-27 12:17:35 +01:00
parent 9795ac32cb
commit b0f553e9ea
11 changed files with 300 additions and 70 deletions

View File

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

View File

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

View File

@@ -12,7 +12,9 @@
<body class="cp-app-code">
<div id="cme_toolbox" class="cp-toolbar-container"></div>
<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-content"></div>
</div>

View File

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

View File

@@ -227,6 +227,27 @@ define([
.click(common.prepareFeedback(type))
.click(function () { UIElements.updateTags(common, null); });
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:
button = $('<button>', {
'class': "fa fa-question",
@@ -240,6 +261,157 @@ define([
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
// Enable mediatags

View File

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

View File

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