This PR makes frontend load EasyMDE/CodeMirror dynamically, and removes `RequireEasyMDE`.tags/v1.16.0-rc1
@@ -254,7 +254,6 @@ func FileHistory(ctx *context.Context) { | |||
func Diff(ctx *context.Context) { | |||
ctx.Data["PageIsDiff"] = true | |||
ctx.Data["RequireHighlightJS"] = true | |||
ctx.Data["RequireEasyMDE"] = true | |||
ctx.Data["RequireTribute"] = true | |||
userName := ctx.Repo.Owner.Name |
@@ -764,7 +764,6 @@ func CompareDiff(ctx *context.Context) { | |||
ctx.Data["IsRepoToolbarCommits"] = true | |||
ctx.Data["IsDiffCompare"] = true | |||
ctx.Data["RequireTribute"] = true | |||
ctx.Data["RequireEasyMDE"] = true | |||
setTemplateIfExists(ctx, pullRequestTemplateKey, nil, pullRequestTemplateCandidates) | |||
ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled | |||
upload.AddUploadContext(ctx, "comment") |
@@ -69,7 +69,6 @@ func editFile(ctx *context.Context, isNewFile bool) { | |||
ctx.Data["PageIsEdit"] = true | |||
ctx.Data["IsNewFile"] = isNewFile | |||
ctx.Data["RequireHighlightJS"] = true | |||
ctx.Data["RequireEasyMDE"] = true | |||
canCommit := renderCommitRights(ctx) | |||
treePath := cleanUploadFileName(ctx.Repo.TreePath) | |||
@@ -200,7 +199,6 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b | |||
ctx.Data["PageHasPosted"] = true | |||
ctx.Data["IsNewFile"] = isNewFile | |||
ctx.Data["RequireHighlightJS"] = true | |||
ctx.Data["RequireEasyMDE"] = true | |||
ctx.Data["TreePath"] = form.TreePath | |||
ctx.Data["TreeNames"] = treeNames | |||
ctx.Data["TreePaths"] = treePaths | |||
@@ -544,7 +542,6 @@ func DeleteFilePost(ctx *context.Context) { | |||
func UploadFile(ctx *context.Context) { | |||
ctx.Data["PageIsUpload"] = true | |||
ctx.Data["RequireTribute"] = true | |||
ctx.Data["RequireEasyMDE"] = true | |||
upload.AddUploadContext(ctx, "repo") | |||
canCommit := renderCommitRights(ctx) | |||
treePath := cleanUploadFileName(ctx.Repo.TreePath) | |||
@@ -580,7 +577,6 @@ func UploadFilePost(ctx *context.Context) { | |||
form := web.GetForm(ctx).(*forms.UploadRepoFileForm) | |||
ctx.Data["PageIsUpload"] = true | |||
ctx.Data["RequireTribute"] = true | |||
ctx.Data["RequireEasyMDE"] = true | |||
upload.AddUploadContext(ctx, "repo") | |||
canCommit := renderCommitRights(ctx) | |||
@@ -789,7 +789,6 @@ func NewIssue(ctx *context.Context) { | |||
ctx.Data["PageIsIssueList"] = true | |||
ctx.Data["NewIssueChooseTemplate"] = len(ctx.IssueTemplatesFromDefaultBranch()) > 0 | |||
ctx.Data["RequireHighlightJS"] = true | |||
ctx.Data["RequireEasyMDE"] = true | |||
ctx.Data["RequireTribute"] = true | |||
ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes | |||
title := ctx.FormString("title") | |||
@@ -962,7 +961,6 @@ func NewIssuePost(ctx *context.Context) { | |||
ctx.Data["PageIsIssueList"] = true | |||
ctx.Data["NewIssueChooseTemplate"] = len(ctx.IssueTemplatesFromDefaultBranch()) > 0 | |||
ctx.Data["RequireHighlightJS"] = true | |||
ctx.Data["RequireEasyMDE"] = true | |||
ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes | |||
ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled | |||
upload.AddUploadContext(ctx, "comment") | |||
@@ -1147,7 +1145,6 @@ func ViewIssue(ctx *context.Context) { | |||
ctx.Data["RequireHighlightJS"] = true | |||
ctx.Data["RequireTribute"] = true | |||
ctx.Data["RequireEasyMDE"] = true | |||
ctx.Data["IsProjectsEnabled"] = ctx.Repo.CanRead(unit.TypeProjects) | |||
ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled | |||
upload.AddUploadContext(ctx, "comment") |
@@ -738,7 +738,6 @@ func ViewPullFiles(ctx *context.Context) { | |||
setCompareContext(ctx, baseCommit, commit, ctx.Repo.Owner.Name, ctx.Repo.Repository.Name) | |||
ctx.Data["RequireHighlightJS"] = true | |||
ctx.Data["RequireEasyMDE"] = true | |||
ctx.Data["RequireTribute"] = true | |||
if ctx.Data["Assignees"], err = models.GetRepoAssignees(ctx.Repo.Repository); err != nil { | |||
ctx.ServerError("GetAssignees", err) | |||
@@ -1098,7 +1097,6 @@ func CompareAndPullRequestPost(ctx *context.Context) { | |||
ctx.Data["IsDiffCompare"] = true | |||
ctx.Data["IsRepoToolbarCommits"] = true | |||
ctx.Data["RequireTribute"] = true | |||
ctx.Data["RequireEasyMDE"] = true | |||
ctx.Data["RequireHighlightJS"] = true | |||
ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes | |||
ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled |
@@ -262,7 +262,6 @@ func LatestRelease(ctx *context.Context) { | |||
func NewRelease(ctx *context.Context) { | |||
ctx.Data["Title"] = ctx.Tr("repo.release.new_release") | |||
ctx.Data["PageIsReleaseList"] = true | |||
ctx.Data["RequireEasyMDE"] = true | |||
ctx.Data["RequireTribute"] = true | |||
ctx.Data["tag_target"] = ctx.Repo.Repository.DefaultBranch | |||
if tagName := ctx.FormString("tag"); len(tagName) > 0 { | |||
@@ -296,7 +295,6 @@ func NewReleasePost(ctx *context.Context) { | |||
form := web.GetForm(ctx).(*forms.NewReleaseForm) | |||
ctx.Data["Title"] = ctx.Tr("repo.release.new_release") | |||
ctx.Data["PageIsReleaseList"] = true | |||
ctx.Data["RequireEasyMDE"] = true | |||
ctx.Data["RequireTribute"] = true | |||
if ctx.HasError() { | |||
@@ -415,7 +413,6 @@ func EditRelease(ctx *context.Context) { | |||
ctx.Data["Title"] = ctx.Tr("repo.release.edit_release") | |||
ctx.Data["PageIsReleaseList"] = true | |||
ctx.Data["PageIsEditRelease"] = true | |||
ctx.Data["RequireEasyMDE"] = true | |||
ctx.Data["RequireTribute"] = true | |||
ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled | |||
upload.AddUploadContext(ctx, "release") | |||
@@ -454,7 +451,6 @@ func EditReleasePost(ctx *context.Context) { | |||
ctx.Data["Title"] = ctx.Tr("repo.release.edit_release") | |||
ctx.Data["PageIsReleaseList"] = true | |||
ctx.Data["PageIsEditRelease"] = true | |||
ctx.Data["RequireEasyMDE"] = true | |||
ctx.Data["RequireTribute"] = true | |||
tagName := ctx.Params("*") |
@@ -622,7 +622,6 @@ func WikiRaw(ctx *context.Context) { | |||
func NewWiki(ctx *context.Context) { | |||
ctx.Data["Title"] = ctx.Tr("repo.wiki.new_page") | |||
ctx.Data["PageIsWiki"] = true | |||
ctx.Data["RequireEasyMDE"] = true | |||
if !ctx.Repo.Repository.HasWiki() { | |||
ctx.Data["title"] = "Home" | |||
@@ -639,7 +638,6 @@ func NewWikiPost(ctx *context.Context) { | |||
form := web.GetForm(ctx).(*forms.NewWikiForm) | |||
ctx.Data["Title"] = ctx.Tr("repo.wiki.new_page") | |||
ctx.Data["PageIsWiki"] = true | |||
ctx.Data["RequireEasyMDE"] = true | |||
if ctx.HasError() { | |||
ctx.HTML(http.StatusOK, tplWikiNew) | |||
@@ -677,7 +675,6 @@ func NewWikiPost(ctx *context.Context) { | |||
func EditWiki(ctx *context.Context) { | |||
ctx.Data["PageIsWiki"] = true | |||
ctx.Data["PageIsWikiEdit"] = true | |||
ctx.Data["RequireEasyMDE"] = true | |||
if !ctx.Repo.Repository.HasWiki() { | |||
ctx.Redirect(ctx.Repo.RepoLink + "/wiki") | |||
@@ -697,7 +694,6 @@ func EditWikiPost(ctx *context.Context) { | |||
form := web.GetForm(ctx).(*forms.NewWikiForm) | |||
ctx.Data["Title"] = ctx.Tr("repo.wiki.new_page") | |||
ctx.Data["PageIsWiki"] = true | |||
ctx.Data["RequireEasyMDE"] = true | |||
if ctx.HasError() { | |||
ctx.HTML(http.StatusOK, tplWikiNew) |
@@ -12,14 +12,6 @@ | |||
{{template "custom/body_outer_post" .}} | |||
{{template "base/footer_content" .}} | |||
{{if .RequireEasyMDE}} | |||
<script src="{{AssetUrlPrefix}}/js/easymde.js?v={{MD5 AppVer}}"></script> | |||
<script src="{{AssetUrlPrefix}}/vendor/plugins/codemirror/addon/mode/loadmode.js"></script> | |||
<script src="{{AssetUrlPrefix}}/vendor/plugins/codemirror/mode/meta.js"></script> | |||
<script> | |||
CodeMirror.modeURL = '{{AssetUrlPrefix}}/vendor/plugins/codemirror/mode/%N/%N.js'; | |||
</script> | |||
{{end}} | |||
<!-- Third-party libraries --> | |||
{{if .RequireU2F}} |
@@ -59,9 +59,6 @@ | |||
</script> | |||
<link rel="icon" href="{{AssetUrlPrefix}}/img/logo.svg" type="image/svg+xml"> | |||
<link rel="alternate icon" href="{{AssetUrlPrefix}}/img/favicon.png" type="image/png"> | |||
{{if .RequireEasyMDE}} | |||
<link rel="stylesheet" href="{{AssetUrlPrefix}}/css/easymde.css?v={{MD5 AppVer}}"> | |||
{{end}} | |||
<link rel="stylesheet" href="{{AssetUrlPrefix}}/css/index.css?v={{MD5 AppVer}}"> | |||
<noscript> | |||
<style> |
@@ -1,7 +0,0 @@ | |||
import EasyMDE from 'easymde'; | |||
import CodeMirror from 'codemirror/lib/codemirror.js'; | |||
window.EasyMDE = EasyMDE; | |||
window.CodeMirror = CodeMirror; | |||
@@ -1,11 +1,58 @@ | |||
import attachTribute from '../tribute.js'; | |||
const {appSubUrl} = window.config; | |||
function loadScript(url) { | |||
return new Promise((resolve, reject) => { | |||
const script = document.createElement('script'); | |||
script.async = true; | |||
script.addEventListener('load', () => { | |||
resolve(); | |||
}); | |||
script.addEventListener('error', (e) => { | |||
reject(e.error); | |||
}); | |||
script.src = url; | |||
document.body.appendChild(script); | |||
}); | |||
} | |||
/** | |||
* @returns {EasyMDE} | |||
*/ | |||
export async function importEasyMDE() { | |||
// for CodeMirror: the plugins should be loaded dynamically | |||
// https://github.com/codemirror/CodeMirror/issues/5484 | |||
// https://github.com/codemirror/CodeMirror/issues/4838 | |||
const [{default: EasyMDE}, {default: CodeMirror}] = await Promise.all([ | |||
import(/* webpackChunkName: "easymde" */'easymde'), | |||
import(/* webpackChunkName: "codemirror" */'codemirror'), | |||
import(/* webpackChunkName: "easymde" */'easymde/dist/easymde.min.css'), | |||
]); | |||
// CodeMirror plugins must be loaded by a "Plain browser env" | |||
window.CodeMirror = CodeMirror; | |||
await Promise.all([ | |||
loadScript(`${appSubUrl}/assets/vendor/plugins/codemirror/addon/mode/loadmode.js`), | |||
loadScript(`${appSubUrl}/assets/vendor/plugins/codemirror/mode/meta.js`), | |||
]); | |||
// the loadmode.js/meta.js would set the modeURL/modeInfo properties, so we check it to make sure our loading works | |||
if (!CodeMirror.modeURL || !CodeMirror.modeInfo) { | |||
throw new Error('failed to load plugins for CodeMirror'); | |||
} | |||
CodeMirror.modeURL = `${appSubUrl}/assets/vendor/plugins/codemirror/mode/%N/%N.js`; | |||
return EasyMDE; | |||
} | |||
/** | |||
* create an EasyMDE editor for comment | |||
* @param textarea jQuery or HTMLElement | |||
* @returns {null|EasyMDE} | |||
*/ | |||
export function createCommentEasyMDE(textarea) { | |||
export async function createCommentEasyMDE(textarea) { | |||
if (textarea instanceof jQuery) { | |||
textarea = textarea[0]; | |||
} | |||
@@ -13,12 +60,13 @@ export function createCommentEasyMDE(textarea) { | |||
return null; | |||
} | |||
const easyMDE = new window.EasyMDE({ | |||
const EasyMDE = await importEasyMDE(); | |||
const easyMDE = new EasyMDE({ | |||
autoDownloadFontAwesome: false, | |||
element: textarea, | |||
forceSync: true, | |||
renderingConfig: { | |||
singleLineBreaks: false | |||
singleLineBreaks: false, | |||
}, | |||
indentWithTabs: false, | |||
tabSize: 4, | |||
@@ -56,7 +104,7 @@ export function createCommentEasyMDE(textarea) { | |||
className: 'fa fa-file', | |||
title: 'Revert to simple textarea', | |||
}, | |||
] | |||
], | |||
}); | |||
const inputField = easyMDE.codemirror.getInputField(); | |||
inputField.classList.add('js-quick-submit'); | |||
@@ -64,7 +112,7 @@ export function createCommentEasyMDE(textarea) { | |||
Enter: () => { | |||
const tributeContainer = document.querySelector('.tribute-container'); | |||
if (!tributeContainer || tributeContainer.style.display === 'none') { | |||
return CodeMirror.Pass; | |||
return window.CodeMirror.Pass; | |||
} | |||
}, | |||
Backspace: (cm) => { | |||
@@ -72,7 +120,7 @@ export function createCommentEasyMDE(textarea) { | |||
cm.getInputField().trigger('input'); | |||
} | |||
cm.execCommand('delCharBefore'); | |||
} | |||
}, | |||
}); | |||
attachTribute(inputField, {mentions: true, emoji: true}); | |||
attachEasyMDEToElements(easyMDE); |
@@ -1,6 +1,6 @@ | |||
import {initCompReactionSelector} from './comp/ReactionSelector.js'; | |||
import {initRepoIssueContentHistory} from './repo-issue-content.js'; | |||
import {validateTextareaNonEmpty} from './comp/CommentEasyMDE.js'; | |||
import {validateTextareaNonEmpty} from './comp/EasyMDE.js'; | |||
const {csrfToken} = window.config; | |||
export function initRepoDiffReviewButton() { |
@@ -1,6 +1,6 @@ | |||
import {htmlEscape} from 'escape-goat'; | |||
import attachTribute from './tribute.js'; | |||
import {createCommentEasyMDE, getAttachedEasyMDE} from './comp/CommentEasyMDE.js'; | |||
import {createCommentEasyMDE, getAttachedEasyMDE} from './comp/EasyMDE.js'; | |||
import {initCompImagePaste} from './comp/ImagePaste.js'; | |||
import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js'; | |||
@@ -439,16 +439,17 @@ export function initRepoPullRequestReview() { | |||
$(`#show-outdated-${id}`).removeClass('hide'); | |||
}); | |||
$(document).on('click', 'button.comment-form-reply', function (e) { | |||
$(document).on('click', 'button.comment-form-reply', async function (e) { | |||
e.preventDefault(); | |||
$(this).hide(); | |||
const form = $(this).closest('.comment-code-cloud').find('.comment-form'); | |||
form.removeClass('hide'); | |||
const $textarea = form.find('textarea'); | |||
let easyMDE = getAttachedEasyMDE($textarea); | |||
if (!easyMDE) { | |||
attachTribute($textarea.get(), {mentions: true, emoji: true}); | |||
easyMDE = createCommentEasyMDE($textarea); | |||
await attachTribute($textarea.get(), {mentions: true, emoji: true}); | |||
easyMDE = await createCommentEasyMDE($textarea); | |||
} | |||
$textarea.focus(); | |||
easyMDE.codemirror.focus(); | |||
@@ -515,8 +516,8 @@ export function initRepoPullRequestReview() { | |||
td.find("input[name='side']").val(side === 'left' ? 'previous' : 'proposed'); | |||
td.find("input[name='path']").val(path); | |||
const $textarea = commentCloud.find('textarea'); | |||
attachTribute($textarea.get(), {mentions: true, emoji: true}); | |||
const easyMDE = createCommentEasyMDE($textarea); | |||
await attachTribute($textarea.get(), {mentions: true, emoji: true}); | |||
const easyMDE = await createCommentEasyMDE($textarea); | |||
$textarea.focus(); | |||
easyMDE.codemirror.focus(); | |||
} |
@@ -1,4 +1,4 @@ | |||
import {createCommentEasyMDE, getAttachedEasyMDE} from './comp/CommentEasyMDE.js'; | |||
import {createCommentEasyMDE, getAttachedEasyMDE} from './comp/EasyMDE.js'; | |||
import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js'; | |||
import {initCompImagePaste, initEasyMDEImagePaste} from './comp/ImagePaste.js'; | |||
import { | |||
@@ -256,6 +256,7 @@ export function initRepoCommentForm() { | |||
async function onEditContent(event) { | |||
event.preventDefault(); | |||
$(this).closest('.dropdown').find('.menu').toggle('visible'); | |||
const $segment = $(this).closest('.header').next(); | |||
const $editContentZone = $segment.find('.edit-content-zone'); | |||
@@ -341,7 +342,7 @@ async function onEditContent(event) { | |||
$tabMenu.find('.preview.item').attr('data-tab', $editContentZone.data('preview')); | |||
$editContentForm.find('.write').attr('data-tab', $editContentZone.data('write')); | |||
$editContentForm.find('.preview').attr('data-tab', $editContentZone.data('preview')); | |||
easyMDE = createCommentEasyMDE($textarea); | |||
easyMDE = await createCommentEasyMDE($textarea); | |||
initCompMarkupContentPreviewTab($editContentForm); | |||
if ($dropzone.length === 1) { |
@@ -1,7 +1,7 @@ | |||
import attachTribute from './tribute.js'; | |||
import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js'; | |||
import {initEasyMDEImagePaste} from './comp/ImagePaste.js'; | |||
import {createCommentEasyMDE} from './comp/CommentEasyMDE.js'; | |||
import {createCommentEasyMDE} from './comp/EasyMDE.js'; | |||
export function initRepoRelease() { | |||
$(document).on('click', '.remove-rel-attach', function() { | |||
@@ -19,11 +19,13 @@ export function initRepoReleaseEditor() { | |||
return false; | |||
} | |||
const $textarea = $editor.find('textarea'); | |||
attachTribute($textarea.get(), {mentions: false, emoji: true}); | |||
const $files = $editor.parent().find('.files'); | |||
const easyMDE = createCommentEasyMDE($textarea); | |||
initCompMarkupContentPreviewTab($editor); | |||
const dropzone = $editor.parent().find('.dropzone')[0]; | |||
initEasyMDEImagePaste(easyMDE, dropzone, $files); | |||
(async () => { | |||
const $textarea = $editor.find('textarea'); | |||
await attachTribute($textarea.get(), {mentions: false, emoji: true}); | |||
const $files = $editor.parent().find('.files'); | |||
const easyMDE = await createCommentEasyMDE($textarea); | |||
initCompMarkupContentPreviewTab($editor); | |||
const dropzone = $editor.parent().find('.dropzone')[0]; | |||
initEasyMDEImagePaste(easyMDE, dropzone, $files); | |||
})(); | |||
} |
@@ -1,186 +1,191 @@ | |||
import {initMarkupContent} from '../markup/content.js'; | |||
import {attachEasyMDEToElements, validateTextareaNonEmpty} from './comp/CommentEasyMDE.js'; | |||
import {attachEasyMDEToElements, importEasyMDE, validateTextareaNonEmpty} from './comp/EasyMDE.js'; | |||
import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js'; | |||
const {csrfToken} = window.config; | |||
export function initRepoWikiForm() { | |||
async function initRepoWikiFormEditor() { | |||
const $editArea = $('.repository.wiki textarea#edit_area'); | |||
if (!$editArea.length) return; | |||
let sideBySideChanges = 0; | |||
let sideBySideTimeout = null; | |||
let hasEasyMDE = true; | |||
if ($editArea.length > 0) { | |||
const $form = $('.repository.wiki.new .ui.form'); | |||
const easyMDE = new window.EasyMDE({ | |||
autoDownloadFontAwesome: false, | |||
element: $editArea[0], | |||
forceSync: true, | |||
previewRender(plainText, preview) { // Async method | |||
// FIXME: still send render request when return back to edit mode | |||
const render = function () { | |||
sideBySideChanges = 0; | |||
const $form = $('.repository.wiki.new .ui.form'); | |||
const EasyMDE = await importEasyMDE(); | |||
const easyMDE = new EasyMDE({ | |||
autoDownloadFontAwesome: false, | |||
element: $editArea[0], | |||
forceSync: true, | |||
previewRender(plainText, preview) { // Async method | |||
// FIXME: still send render request when return back to edit mode | |||
const render = function () { | |||
sideBySideChanges = 0; | |||
if (sideBySideTimeout !== null) { | |||
clearTimeout(sideBySideTimeout); | |||
sideBySideTimeout = null; | |||
} | |||
$.post($editArea.data('url'), { | |||
_csrf: csrfToken, | |||
mode: 'gfm', | |||
context: $editArea.data('context'), | |||
text: plainText, | |||
wiki: true | |||
}, (data) => { | |||
preview.innerHTML = `<div class="markup ui segment">${data}</div>`; | |||
initMarkupContent(); | |||
}); | |||
}; | |||
setTimeout(() => { | |||
if (!easyMDE.isSideBySideActive()) { | |||
render(); | |||
} else { | |||
// delay preview by keystroke counting | |||
sideBySideChanges++; | |||
if (sideBySideChanges > 10) { | |||
render(); | |||
} | |||
// or delay preview by timeout | |||
if (sideBySideTimeout !== null) { | |||
clearTimeout(sideBySideTimeout); | |||
sideBySideTimeout = null; | |||
} | |||
$.post($editArea.data('url'), { | |||
_csrf: csrfToken, | |||
mode: 'gfm', | |||
context: $editArea.data('context'), | |||
text: plainText, | |||
wiki: true | |||
}, (data) => { | |||
preview.innerHTML = `<div class="markup ui segment">${data}</div>`; | |||
initMarkupContent(); | |||
}); | |||
}; | |||
setTimeout(() => { | |||
if (!easyMDE.isSideBySideActive()) { | |||
render(); | |||
} else { | |||
// delay preview by keystroke counting | |||
sideBySideChanges++; | |||
if (sideBySideChanges > 10) { | |||
render(); | |||
} | |||
// or delay preview by timeout | |||
if (sideBySideTimeout !== null) { | |||
clearTimeout(sideBySideTimeout); | |||
sideBySideTimeout = null; | |||
} | |||
sideBySideTimeout = setTimeout(render, 600); | |||
} | |||
}, 0); | |||
if (!easyMDE.isSideBySideActive()) { | |||
return 'Loading...'; | |||
sideBySideTimeout = setTimeout(render, 600); | |||
} | |||
return preview.innerHTML; | |||
}, | |||
renderingConfig: { | |||
singleLineBreaks: false | |||
}, 0); | |||
if (!easyMDE.isSideBySideActive()) { | |||
return 'Loading...'; | |||
} | |||
return preview.innerHTML; | |||
}, | |||
renderingConfig: { | |||
singleLineBreaks: false | |||
}, | |||
indentWithTabs: false, | |||
tabSize: 4, | |||
spellChecker: false, | |||
toolbar: ['bold', 'italic', 'strikethrough', '|', | |||
'heading-1', 'heading-2', 'heading-3', 'heading-bigger', 'heading-smaller', '|', | |||
{ | |||
name: 'code-inline', | |||
action(e) { | |||
const cm = e.codemirror; | |||
const selection = cm.getSelection(); | |||
cm.replaceSelection(`\`${selection}\``); | |||
if (!selection) { | |||
const cursorPos = cm.getCursor(); | |||
cm.setCursor(cursorPos.line, cursorPos.ch - 1); | |||
} | |||
cm.focus(); | |||
}, | |||
className: 'fa fa-angle-right', | |||
title: 'Add Inline Code', | |||
}, 'code', 'quote', '|', { | |||
name: 'checkbox-empty', | |||
action(e) { | |||
const cm = e.codemirror; | |||
cm.replaceSelection(`\n- [ ] ${cm.getSelection()}`); | |||
cm.focus(); | |||
}, | |||
className: 'fa fa-square-o', | |||
title: 'Add Checkbox (empty)', | |||
}, | |||
indentWithTabs: false, | |||
tabSize: 4, | |||
spellChecker: false, | |||
toolbar: ['bold', 'italic', 'strikethrough', '|', | |||
'heading-1', 'heading-2', 'heading-3', 'heading-bigger', 'heading-smaller', '|', | |||
{ | |||
name: 'code-inline', | |||
action(e) { | |||
const cm = e.codemirror; | |||
const selection = cm.getSelection(); | |||
cm.replaceSelection(`\`${selection}\``); | |||
if (!selection) { | |||
const cursorPos = cm.getCursor(); | |||
cm.setCursor(cursorPos.line, cursorPos.ch - 1); | |||
} | |||
cm.focus(); | |||
}, | |||
className: 'fa fa-angle-right', | |||
title: 'Add Inline Code', | |||
}, 'code', 'quote', '|', { | |||
name: 'checkbox-empty', | |||
action(e) { | |||
const cm = e.codemirror; | |||
cm.replaceSelection(`\n- [ ] ${cm.getSelection()}`); | |||
cm.focus(); | |||
}, | |||
className: 'fa fa-square-o', | |||
title: 'Add Checkbox (empty)', | |||
{ | |||
name: 'checkbox-checked', | |||
action(e) { | |||
const cm = e.codemirror; | |||
cm.replaceSelection(`\n- [x] ${cm.getSelection()}`); | |||
cm.focus(); | |||
}, | |||
{ | |||
name: 'checkbox-checked', | |||
action(e) { | |||
const cm = e.codemirror; | |||
cm.replaceSelection(`\n- [x] ${cm.getSelection()}`); | |||
cm.focus(); | |||
}, | |||
className: 'fa fa-check-square-o', | |||
title: 'Add Checkbox (checked)', | |||
}, '|', | |||
'unordered-list', 'ordered-list', '|', | |||
'link', 'image', 'table', 'horizontal-rule', '|', | |||
'clean-block', 'preview', 'fullscreen', 'side-by-side', '|', | |||
{ | |||
name: 'revert-to-textarea', | |||
action(e) { | |||
e.toTextArea(); | |||
hasEasyMDE = false; | |||
const $root = $form.find('.field.content'); | |||
const loading = $root.data('loading'); | |||
$root.append(`<div class="ui bottom tab markup" data-tab="preview">${loading}</div>`); | |||
initCompMarkupContentPreviewTab($form); | |||
}, | |||
className: 'fa fa-file', | |||
title: 'Revert to simple textarea', | |||
className: 'fa fa-check-square-o', | |||
title: 'Add Checkbox (checked)', | |||
}, '|', | |||
'unordered-list', 'ordered-list', '|', | |||
'link', 'image', 'table', 'horizontal-rule', '|', | |||
'clean-block', 'preview', 'fullscreen', 'side-by-side', '|', | |||
{ | |||
name: 'revert-to-textarea', | |||
action(e) { | |||
e.toTextArea(); | |||
hasEasyMDE = false; | |||
const $root = $form.find('.field.content'); | |||
const loading = $root.data('loading'); | |||
$root.append(`<div class="ui bottom tab markup" data-tab="preview">${loading}</div>`); | |||
initCompMarkupContentPreviewTab($form); | |||
}, | |||
] | |||
}); | |||
className: 'fa fa-file', | |||
title: 'Revert to simple textarea', | |||
}, | |||
] | |||
}); | |||
attachEasyMDEToElements(easyMDE); | |||
attachEasyMDEToElements(easyMDE); | |||
const $mdeInputField = $(easyMDE.codemirror.getInputField()); | |||
$mdeInputField.addClass('js-quick-submit'); | |||
const $mdeInputField = $(easyMDE.codemirror.getInputField()); | |||
$mdeInputField.addClass('js-quick-submit'); | |||
$form.on('submit', () => { | |||
if (!validateTextareaNonEmpty($editArea)) { | |||
return false; | |||
} | |||
}); | |||
$form.on('submit', () => { | |||
if (!validateTextareaNonEmpty($editArea)) { | |||
setTimeout(() => { | |||
const $bEdit = $('.repository.wiki.new .previewtabs a[data-tab="write"]'); | |||
const $bPrev = $('.repository.wiki.new .previewtabs a[data-tab="preview"]'); | |||
const $toolbar = $('.editor-toolbar'); | |||
const $bPreview = $('.editor-toolbar button.preview'); | |||
const $bSideBySide = $('.editor-toolbar a.fa-columns'); | |||
$bEdit.on('click', (e) => { | |||
if (!hasEasyMDE) { | |||
return false; | |||
} | |||
}); | |||
e.stopImmediatePropagation(); | |||
if ($toolbar.hasClass('disabled-for-preview')) { | |||
$bPreview.trigger('click'); | |||
} | |||
setTimeout(() => { | |||
const $bEdit = $('.repository.wiki.new .previewtabs a[data-tab="write"]'); | |||
const $bPrev = $('.repository.wiki.new .previewtabs a[data-tab="preview"]'); | |||
const $toolbar = $('.editor-toolbar'); | |||
const $bPreview = $('.editor-toolbar button.preview'); | |||
const $bSideBySide = $('.editor-toolbar a.fa-columns'); | |||
$bEdit.on('click', (e) => { | |||
if (!hasEasyMDE) { | |||
return false; | |||
} | |||
e.stopImmediatePropagation(); | |||
return false; | |||
}); | |||
$bPrev.on('click', (e) => { | |||
if (!hasEasyMDE) { | |||
return false; | |||
} | |||
e.stopImmediatePropagation(); | |||
if (!$toolbar.hasClass('disabled-for-preview')) { | |||
$bPreview.trigger('click'); | |||
} | |||
return false; | |||
}); | |||
$bPreview.on('click', () => { | |||
setTimeout(() => { | |||
if ($toolbar.hasClass('disabled-for-preview')) { | |||
$bPreview.trigger('click'); | |||
if ($bEdit.hasClass('active')) { | |||
$bEdit.removeClass('active'); | |||
} | |||
if (!$bPrev.hasClass('active')) { | |||
$bPrev.addClass('active'); | |||
} | |||
} else { | |||
if (!$bEdit.hasClass('active')) { | |||
$bEdit.addClass('active'); | |||
} | |||
if ($bPrev.hasClass('active')) { | |||
$bPrev.removeClass('active'); | |||
} | |||
} | |||
}, 0); | |||
return false; | |||
}); | |||
$bPrev.on('click', (e) => { | |||
if (!hasEasyMDE) { | |||
return false; | |||
} | |||
e.stopImmediatePropagation(); | |||
if (!$toolbar.hasClass('disabled-for-preview')) { | |||
$bPreview.trigger('click'); | |||
} | |||
return false; | |||
}); | |||
$bPreview.on('click', () => { | |||
setTimeout(() => { | |||
if ($toolbar.hasClass('disabled-for-preview')) { | |||
if ($bEdit.hasClass('active')) { | |||
$bEdit.removeClass('active'); | |||
} | |||
if (!$bPrev.hasClass('active')) { | |||
$bPrev.addClass('active'); | |||
} | |||
} else { | |||
if (!$bEdit.hasClass('active')) { | |||
$bEdit.addClass('active'); | |||
} | |||
if ($bPrev.hasClass('active')) { | |||
$bPrev.removeClass('active'); | |||
} | |||
} | |||
}, 0); | |||
return false; | |||
}); | |||
$bSideBySide.on('click', () => { | |||
sideBySideChanges = 10; | |||
}); | |||
}, 0); | |||
} | |||
return false; | |||
}); | |||
$bSideBySide.on('click', () => { | |||
sideBySideChanges = 10; | |||
}); | |||
}, 0); | |||
} | |||
export function initRepoWikiForm() { | |||
initRepoWikiFormEditor(); | |||
} |
@@ -60,10 +60,6 @@ export default { | |||
'eventsource.sharedworker': [ | |||
resolve(__dirname, 'web_src/js/features/eventsource.sharedworker.js'), | |||
], | |||
'easymde': [ | |||
resolve(__dirname, 'web_src/js/easymde.js'), | |||
resolve(__dirname, 'node_modules/easymde/dist/easymde.min.css'), | |||
], | |||
...themes, | |||
}, | |||
devtool: false, |