更新
This commit is contained in:
parent
e97641ca99
commit
fc470d46ea
2
typecho/write/css/joe.write.min.css
vendored
2
typecho/write/css/joe.write.min.css
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
import { undo, redo } from '@codemirror/history';
|
||||
export default class JoeAction {
|
||||
constructor() {
|
||||
$('body').append(`
|
||||
constructor() {
|
||||
$('body').append(`
|
||||
<div class="cm-modal">
|
||||
<div class="cm-modal__wrapper">
|
||||
<div class="cm-modal__wrapper-header">
|
||||
@ -16,186 +16,186 @@ export default class JoeAction {
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
$('.cm-modal__wrapper-footer--cancle, .cm-modal__wrapper-header--close').on('click', () => $('.cm-modal').removeClass('active'));
|
||||
$('.cm-modal__wrapper-footer--confirm').on('click', () => {
|
||||
this.options.confirm();
|
||||
$('.cm-modal').removeClass('active');
|
||||
});
|
||||
}
|
||||
_openModal(options = {}) {
|
||||
const _options = {
|
||||
title: '提示',
|
||||
innerHtml: '内容',
|
||||
hasFooter: true,
|
||||
confirm: () => {},
|
||||
handler: () => {}
|
||||
};
|
||||
this.options = Object.assign(_options, options);
|
||||
$('.cm-modal__wrapper-header--text').html(this.options.title);
|
||||
$('.cm-modal__wrapper-bodyer').html(this.options.innerHtml);
|
||||
this.options.hasFooter ? $('.cm-modal__wrapper-footer').show() : $('.cm-modal__wrapper-footer').hide();
|
||||
$('.cm-modal').addClass('active');
|
||||
this.options.handler();
|
||||
}
|
||||
_getLineCh(cm) {
|
||||
const head = cm.state.selection.main.head;
|
||||
const line = cm.state.doc.lineAt(head);
|
||||
return head - line.from;
|
||||
}
|
||||
_replaceSelection(cm, str) {
|
||||
cm.dispatch(cm.state.replaceSelection(str));
|
||||
}
|
||||
_setCursor(cm, pos) {
|
||||
cm.dispatch({ selection: { anchor: pos } });
|
||||
}
|
||||
_getSelection(cm) {
|
||||
return cm.state.sliceDoc(cm.state.selection.main.from, cm.state.selection.main.to);
|
||||
}
|
||||
_insetAmboText(cm, str) {
|
||||
const cursor = cm.state.selection.main.head;
|
||||
const selection = this._getSelection(cm);
|
||||
this._replaceSelection(cm, ` ${str + selection + str} `);
|
||||
if (selection === '') this._setCursor(cm, cursor + str.length + 1);
|
||||
cm.focus();
|
||||
}
|
||||
_createTableLists(cm, url, activeTab = '', modalTitle) {
|
||||
$.ajax({
|
||||
url,
|
||||
dataType: 'json',
|
||||
success: res => {
|
||||
let tabbarStr = '';
|
||||
let listsStr = '';
|
||||
for (let key in res) {
|
||||
const arr = res[key].split(' ');
|
||||
tabbarStr += `<div class="tabbar-item ${key === activeTab ? 'active' : ''}" data-show="${key}">${key}</div>`;
|
||||
listsStr += `<div class="lists ${key === activeTab ? 'active' : ''}" data-show="${key}">${arr.map(item => `<div class="lists-item" data-text="${item}">${item}</div>`).join(' ')}</div>`;
|
||||
}
|
||||
this._openModal({
|
||||
title: modalTitle,
|
||||
hasFooter: false,
|
||||
innerHtml: `<div class="tabbar">${tabbarStr}</div>${listsStr}`,
|
||||
handler: () => {
|
||||
$('.cm-modal__wrapper-bodyer .tabbar-item').on('click', function () {
|
||||
const activeTab = $(this);
|
||||
const show = activeTab.attr('data-show');
|
||||
const tabbar = $('.cm-modal__wrapper-bodyer .tabbar');
|
||||
activeTab.addClass('active').siblings().removeClass('active');
|
||||
tabbar.stop().animate({
|
||||
scrollLeft: activeTab[0].offsetLeft - tabbar[0].offsetWidth / 2 + activeTab[0].offsetWidth / 2 - 15
|
||||
});
|
||||
$('.cm-modal__wrapper-bodyer .lists').removeClass('active');
|
||||
$(".cm-modal__wrapper-bodyer .lists[data-show='" + show + "']").addClass('active');
|
||||
});
|
||||
const _this = this;
|
||||
$('.cm-modal__wrapper-bodyer .lists-item').on('click', function () {
|
||||
const text = $(this).attr('data-text');
|
||||
_this._replaceSelection(cm, ` ${text} `);
|
||||
$('.cm-modal').removeClass('active');
|
||||
cm.focus();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
handleFullScreen(el) {
|
||||
el.toggleClass('active');
|
||||
$('body').toggleClass('fullscreen');
|
||||
$('.cm-container').toggleClass('fullscreen');
|
||||
$('.cm-preview').width(0);
|
||||
}
|
||||
handlePublish() {
|
||||
$('#btn-submit').click();
|
||||
}
|
||||
handleUndo(cm) {
|
||||
undo(cm);
|
||||
cm.focus();
|
||||
}
|
||||
handleRedo(cm) {
|
||||
redo(cm);
|
||||
cm.focus();
|
||||
}
|
||||
handleIndent(cm) {
|
||||
this._replaceSelection(cm, ' ');
|
||||
cm.focus();
|
||||
}
|
||||
handleTime(cm) {
|
||||
const time = new Date();
|
||||
const _Year = time.getFullYear();
|
||||
const _Month = String(time.getMonth() + 1).padStart(2, 0);
|
||||
const _Date = String(time.getDate()).padStart(2, 0);
|
||||
const _Hours = String(time.getHours()).padStart(2, 0);
|
||||
const _Minutes = String(time.getMinutes()).padStart(2, 0);
|
||||
const _Seconds = String(time.getSeconds()).padStart(2, 0);
|
||||
const _Day = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'][time.getDay()];
|
||||
const _time = `${this._getLineCh(cm) ? '\n' : ''}${_Year}-${_Month}-${_Date} ${_Hours}:${_Minutes}:${_Seconds} ${_Day}\n`;
|
||||
this._replaceSelection(cm, _time);
|
||||
cm.focus();
|
||||
}
|
||||
handleHr(cm) {
|
||||
const str = `${this._getLineCh(cm) ? '\n' : ''}\n------------\n\n`;
|
||||
this._replaceSelection(cm, str);
|
||||
cm.focus();
|
||||
}
|
||||
handleClean(cm) {
|
||||
cm.dispatch({ changes: { from: 0, to: cm.state.doc.length, insert: '' } });
|
||||
cm.focus();
|
||||
}
|
||||
handleOrdered(cm) {
|
||||
const selection = this._getSelection(cm);
|
||||
if (selection === '') {
|
||||
const str = (this._getLineCh(cm) ? '\n\n' : '') + '1. ';
|
||||
this._replaceSelection(cm, str);
|
||||
} else {
|
||||
const selectionText = selection.split('\n');
|
||||
for (let i = 0, len = selectionText.length; i < len; i++) {
|
||||
selectionText[i] = selectionText[i] === '' ? '' : i + 1 + '. ' + selectionText[i];
|
||||
}
|
||||
const str = (this._getLineCh(cm) ? '\n' : '') + selectionText.join('\n');
|
||||
this._replaceSelection(cm, str);
|
||||
}
|
||||
cm.focus();
|
||||
}
|
||||
handleUnordered(cm) {
|
||||
const selection = this._getSelection(cm);
|
||||
if (selection === '') {
|
||||
const str = (this._getLineCh(cm) ? '\n' : '') + '- ';
|
||||
this._replaceSelection(cm, str);
|
||||
} else {
|
||||
const selectionText = selection.split('\n');
|
||||
for (let i = 0, len = selectionText.length; i < len; i++) {
|
||||
selectionText[i] = selectionText[i] === '' ? '' : '- ' + selectionText[i];
|
||||
}
|
||||
const str = (this._getLineCh(cm) ? '\n' : '') + selectionText.join('\n');
|
||||
this._replaceSelection(cm, str);
|
||||
}
|
||||
cm.focus();
|
||||
}
|
||||
handleQuote(cm) {
|
||||
const selection = this._getSelection(cm);
|
||||
if (selection === '') {
|
||||
this._replaceSelection(cm, `${this._getLineCh(cm) ? '\n' : ''}> `);
|
||||
} else {
|
||||
const selectionText = selection.split('\n');
|
||||
for (let i = 0, len = selectionText.length; i < len; i++) {
|
||||
selectionText[i] = selectionText[i] === '' ? '' : '> ' + selectionText[i];
|
||||
}
|
||||
const str = (this._getLineCh(cm) ? '\n' : '') + selectionText.join('\n');
|
||||
this._replaceSelection(cm, str);
|
||||
}
|
||||
cm.focus();
|
||||
}
|
||||
handleDownload(cm) {
|
||||
const title = $('#title').val() || '新文章';
|
||||
const aTag = document.createElement('a');
|
||||
let blob = new Blob([cm.state.doc.toString()]);
|
||||
aTag.download = title + '.md';
|
||||
aTag.href = URL.createObjectURL(blob);
|
||||
aTag.click();
|
||||
URL.revokeObjectURL(blob);
|
||||
}
|
||||
handleTitle(cm, tool) {
|
||||
const item = $(`
|
||||
$('.cm-modal__wrapper-footer--cancle, .cm-modal__wrapper-header--close').on('click', () => $('.cm-modal').removeClass('active'));
|
||||
$('.cm-modal__wrapper-footer--confirm').on('click', () => {
|
||||
this.options.confirm();
|
||||
$('.cm-modal').removeClass('active');
|
||||
});
|
||||
}
|
||||
_openModal(options = {}) {
|
||||
const _options = {
|
||||
title: '提示',
|
||||
innerHtml: '内容',
|
||||
hasFooter: true,
|
||||
confirm: () => {},
|
||||
handler: () => {}
|
||||
};
|
||||
this.options = Object.assign(_options, options);
|
||||
$('.cm-modal__wrapper-header--text').html(this.options.title);
|
||||
$('.cm-modal__wrapper-bodyer').html(this.options.innerHtml);
|
||||
this.options.hasFooter ? $('.cm-modal__wrapper-footer').show() : $('.cm-modal__wrapper-footer').hide();
|
||||
$('.cm-modal').addClass('active');
|
||||
this.options.handler();
|
||||
}
|
||||
_getLineCh(cm) {
|
||||
const head = cm.state.selection.main.head;
|
||||
const line = cm.state.doc.lineAt(head);
|
||||
return head - line.from;
|
||||
}
|
||||
_replaceSelection(cm, str) {
|
||||
cm.dispatch(cm.state.replaceSelection(str));
|
||||
}
|
||||
_setCursor(cm, pos) {
|
||||
cm.dispatch({ selection: { anchor: pos } });
|
||||
}
|
||||
_getSelection(cm) {
|
||||
return cm.state.sliceDoc(cm.state.selection.main.from, cm.state.selection.main.to);
|
||||
}
|
||||
_insetAmboText(cm, str) {
|
||||
const cursor = cm.state.selection.main.head;
|
||||
const selection = this._getSelection(cm);
|
||||
this._replaceSelection(cm, ` ${str + selection + str} `);
|
||||
if (selection === '') this._setCursor(cm, cursor + str.length + 1);
|
||||
cm.focus();
|
||||
}
|
||||
_createTableLists(cm, url, activeTab = '', modalTitle) {
|
||||
$.ajax({
|
||||
url,
|
||||
dataType: 'json',
|
||||
success: res => {
|
||||
let tabbarStr = '';
|
||||
let listsStr = '';
|
||||
for (let key in res) {
|
||||
const arr = res[key].split(' ');
|
||||
tabbarStr += `<div class="tabbar-item ${key === activeTab ? 'active' : ''}" data-show="${key}">${key}</div>`;
|
||||
listsStr += `<div class="lists ${key === activeTab ? 'active' : ''}" data-show="${key}">${arr.map(item => `<div class="lists-item" data-text="${item}">${item}</div>`).join(' ')}</div>`;
|
||||
}
|
||||
this._openModal({
|
||||
title: modalTitle,
|
||||
hasFooter: false,
|
||||
innerHtml: `<div class="tabbar">${tabbarStr}</div>${listsStr}`,
|
||||
handler: () => {
|
||||
$('.cm-modal__wrapper-bodyer .tabbar-item').on('click', function () {
|
||||
const activeTab = $(this);
|
||||
const show = activeTab.attr('data-show');
|
||||
const tabbar = $('.cm-modal__wrapper-bodyer .tabbar');
|
||||
activeTab.addClass('active').siblings().removeClass('active');
|
||||
tabbar.stop().animate({
|
||||
scrollLeft: activeTab[0].offsetLeft - tabbar[0].offsetWidth / 2 + activeTab[0].offsetWidth / 2 - 15
|
||||
});
|
||||
$('.cm-modal__wrapper-bodyer .lists').removeClass('active');
|
||||
$(".cm-modal__wrapper-bodyer .lists[data-show='" + show + "']").addClass('active');
|
||||
});
|
||||
const _this = this;
|
||||
$('.cm-modal__wrapper-bodyer .lists-item').on('click', function () {
|
||||
const text = $(this).attr('data-text');
|
||||
_this._replaceSelection(cm, ` ${text} `);
|
||||
$('.cm-modal').removeClass('active');
|
||||
cm.focus();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
handleFullScreen(el) {
|
||||
el.toggleClass('active');
|
||||
$('body').toggleClass('fullscreen');
|
||||
$('.cm-container').toggleClass('fullscreen');
|
||||
$('.cm-preview').width(0);
|
||||
}
|
||||
handlePublish() {
|
||||
$('#btn-submit').click();
|
||||
}
|
||||
handleUndo(cm) {
|
||||
undo(cm);
|
||||
cm.focus();
|
||||
}
|
||||
handleRedo(cm) {
|
||||
redo(cm);
|
||||
cm.focus();
|
||||
}
|
||||
handleIndent(cm) {
|
||||
this._replaceSelection(cm, ' ');
|
||||
cm.focus();
|
||||
}
|
||||
handleTime(cm) {
|
||||
const time = new Date();
|
||||
const _Year = time.getFullYear();
|
||||
const _Month = String(time.getMonth() + 1).padStart(2, 0);
|
||||
const _Date = String(time.getDate()).padStart(2, 0);
|
||||
const _Hours = String(time.getHours()).padStart(2, 0);
|
||||
const _Minutes = String(time.getMinutes()).padStart(2, 0);
|
||||
const _Seconds = String(time.getSeconds()).padStart(2, 0);
|
||||
const _Day = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'][time.getDay()];
|
||||
const _time = `${this._getLineCh(cm) ? '\n' : ''}${_Year}-${_Month}-${_Date} ${_Hours}:${_Minutes}:${_Seconds} ${_Day}\n`;
|
||||
this._replaceSelection(cm, _time);
|
||||
cm.focus();
|
||||
}
|
||||
handleHr(cm) {
|
||||
const str = `${this._getLineCh(cm) ? '\n' : ''}\n------------\n\n`;
|
||||
this._replaceSelection(cm, str);
|
||||
cm.focus();
|
||||
}
|
||||
handleClean(cm) {
|
||||
cm.dispatch({ changes: { from: 0, to: cm.state.doc.length, insert: '' } });
|
||||
cm.focus();
|
||||
}
|
||||
handleOrdered(cm) {
|
||||
const selection = this._getSelection(cm);
|
||||
if (selection === '') {
|
||||
const str = (this._getLineCh(cm) ? '\n\n' : '') + '1. ';
|
||||
this._replaceSelection(cm, str);
|
||||
} else {
|
||||
const selectionText = selection.split('\n');
|
||||
for (let i = 0, len = selectionText.length; i < len; i++) {
|
||||
selectionText[i] = selectionText[i] === '' ? '' : i + 1 + '. ' + selectionText[i];
|
||||
}
|
||||
const str = (this._getLineCh(cm) ? '\n' : '') + selectionText.join('\n');
|
||||
this._replaceSelection(cm, str);
|
||||
}
|
||||
cm.focus();
|
||||
}
|
||||
handleUnordered(cm) {
|
||||
const selection = this._getSelection(cm);
|
||||
if (selection === '') {
|
||||
const str = (this._getLineCh(cm) ? '\n' : '') + '- ';
|
||||
this._replaceSelection(cm, str);
|
||||
} else {
|
||||
const selectionText = selection.split('\n');
|
||||
for (let i = 0, len = selectionText.length; i < len; i++) {
|
||||
selectionText[i] = selectionText[i] === '' ? '' : '- ' + selectionText[i];
|
||||
}
|
||||
const str = (this._getLineCh(cm) ? '\n' : '') + selectionText.join('\n');
|
||||
this._replaceSelection(cm, str);
|
||||
}
|
||||
cm.focus();
|
||||
}
|
||||
handleQuote(cm) {
|
||||
const selection = this._getSelection(cm);
|
||||
if (selection === '') {
|
||||
this._replaceSelection(cm, `${this._getLineCh(cm) ? '\n' : ''}> `);
|
||||
} else {
|
||||
const selectionText = selection.split('\n');
|
||||
for (let i = 0, len = selectionText.length; i < len; i++) {
|
||||
selectionText[i] = selectionText[i] === '' ? '' : '> ' + selectionText[i];
|
||||
}
|
||||
const str = (this._getLineCh(cm) ? '\n' : '') + selectionText.join('\n');
|
||||
this._replaceSelection(cm, str);
|
||||
}
|
||||
cm.focus();
|
||||
}
|
||||
handleDownload(cm) {
|
||||
const title = $('#title').val() || '新文章';
|
||||
const aTag = document.createElement('a');
|
||||
let blob = new Blob([cm.state.doc.toString()]);
|
||||
aTag.download = title + '.md';
|
||||
aTag.href = URL.createObjectURL(blob);
|
||||
aTag.click();
|
||||
URL.revokeObjectURL(blob);
|
||||
}
|
||||
handleTitle(cm, tool) {
|
||||
const item = $(`
|
||||
<div class="cm-tools-item" title="${tool.title}">
|
||||
${tool.innerHTML}
|
||||
<div class="cm-tools__dropdown">
|
||||
@ -208,26 +208,26 @@ export default class JoeAction {
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
item.on('click', function (e) {
|
||||
e.stopPropagation();
|
||||
$(this).toggleClass('active');
|
||||
});
|
||||
const _this = this;
|
||||
item.on('click', '.cm-tools__dropdown-item', function (e) {
|
||||
e.stopPropagation();
|
||||
const text = $(this).attr('data-text');
|
||||
if (_this._getLineCh(cm)) _this._replaceSelection(cm, '\n\n' + text);
|
||||
else _this._replaceSelection(cm, text);
|
||||
item.removeClass('active');
|
||||
cm.focus();
|
||||
});
|
||||
$(document).on('click', () => item.removeClass('active'));
|
||||
$('.cm-tools').append(item);
|
||||
}
|
||||
handleLink(cm) {
|
||||
this._openModal({
|
||||
title: '插入链接',
|
||||
innerHtml: `
|
||||
item.on('click', function (e) {
|
||||
e.stopPropagation();
|
||||
$(this).toggleClass('active');
|
||||
});
|
||||
const _this = this;
|
||||
item.on('click', '.cm-tools__dropdown-item', function (e) {
|
||||
e.stopPropagation();
|
||||
const text = $(this).attr('data-text');
|
||||
if (_this._getLineCh(cm)) _this._replaceSelection(cm, '\n\n' + text);
|
||||
else _this._replaceSelection(cm, text);
|
||||
item.removeClass('active');
|
||||
cm.focus();
|
||||
});
|
||||
$(document).on('click', () => item.removeClass('active'));
|
||||
$('.cm-tools').append(item);
|
||||
}
|
||||
handleLink(cm) {
|
||||
this._openModal({
|
||||
title: '插入链接',
|
||||
innerHtml: `
|
||||
<div class="fitem">
|
||||
<label>链接标题</label>
|
||||
<input autocomplete="off" name="title" placeholder="请输入链接标题"/>
|
||||
@ -237,18 +237,18 @@ export default class JoeAction {
|
||||
<input autocomplete="off" name="url" placeholder="请输入链接地址"/>
|
||||
</div>
|
||||
`,
|
||||
confirm: () => {
|
||||
const title = $(".cm-modal input[name='title']").val() || 'Test';
|
||||
const url = $(".cm-modal input[name='url']").val() || 'http://';
|
||||
this._replaceSelection(cm, ` [${title}](${url}) `);
|
||||
cm.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
handleImage(cm) {
|
||||
this._openModal({
|
||||
title: '插入图片',
|
||||
innerHtml: `
|
||||
confirm: () => {
|
||||
const title = $(".cm-modal input[name='title']").val() || 'Test';
|
||||
const url = $(".cm-modal input[name='url']").val() || 'http://';
|
||||
this._replaceSelection(cm, ` [${title}](${url}) `);
|
||||
cm.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
handleImage(cm) {
|
||||
this._openModal({
|
||||
title: '插入图片',
|
||||
innerHtml: `
|
||||
<div class="fitem">
|
||||
<label>图片名称</label>
|
||||
<input autocomplete="off" name="title" placeholder="请输入图片名称"/>
|
||||
@ -258,18 +258,18 @@ export default class JoeAction {
|
||||
<input autocomplete="off" name="url" placeholder="请输入图片地址"/>
|
||||
</div>
|
||||
`,
|
||||
confirm: () => {
|
||||
const title = $(".cm-modal input[name='title']").val() || 'Test';
|
||||
const url = $(".cm-modal input[name='url']").val() || 'http://';
|
||||
this._replaceSelection(cm, ` ![${title}](${url}) `);
|
||||
cm.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
handleTable(cm) {
|
||||
this._openModal({
|
||||
title: '插入表格',
|
||||
innerHtml: `
|
||||
confirm: () => {
|
||||
const title = $(".cm-modal input[name='title']").val() || 'Test';
|
||||
const url = $(".cm-modal input[name='url']").val() || 'http://';
|
||||
this._replaceSelection(cm, ` ![${title}](${url}) `);
|
||||
cm.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
handleTable(cm) {
|
||||
this._openModal({
|
||||
title: '插入表格',
|
||||
innerHtml: `
|
||||
<div class="fitem">
|
||||
<label>表格行</label>
|
||||
<input style="width: 50px; flex: none; margin-right: 10px;" value="3" autocomplete="off" name="row"/>
|
||||
@ -277,33 +277,33 @@ export default class JoeAction {
|
||||
<input style="width: 50px; flex: none;" value="3" autocomplete="off" name="column"/>
|
||||
</div>
|
||||
`,
|
||||
confirm: () => {
|
||||
let row = $(".cm-modal input[name='row']").val();
|
||||
let column = $(".cm-modal input[name='column']").val();
|
||||
if (isNaN(row)) row = 3;
|
||||
if (isNaN(column)) column = 3;
|
||||
let rowStr = '';
|
||||
let rangeStr = '';
|
||||
let columnlStr = '';
|
||||
for (let i = 0; i < column; i++) {
|
||||
rowStr += '| 表头 ';
|
||||
rangeStr += '| :--: ';
|
||||
}
|
||||
for (let i = 0; i < row; i++) {
|
||||
for (let j = 0; j < column; j++) columnlStr += '| 表格 ';
|
||||
columnlStr += '|\n';
|
||||
}
|
||||
const htmlStr = `${rowStr}|\n${rangeStr}|\n${columnlStr}\n`;
|
||||
if (this._getLineCh(cm)) this._replaceSelection(cm, '\n\n' + htmlStr);
|
||||
else this._replaceSelection(cm, htmlStr);
|
||||
cm.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
handleCodeBlock(cm) {
|
||||
this._openModal({
|
||||
title: '插入代码块',
|
||||
innerHtml: `
|
||||
confirm: () => {
|
||||
let row = $(".cm-modal input[name='row']").val();
|
||||
let column = $(".cm-modal input[name='column']").val();
|
||||
if (isNaN(row)) row = 3;
|
||||
if (isNaN(column)) column = 3;
|
||||
let rowStr = '';
|
||||
let rangeStr = '';
|
||||
let columnlStr = '';
|
||||
for (let i = 0; i < column; i++) {
|
||||
rowStr += '| 表头 ';
|
||||
rangeStr += '| :--: ';
|
||||
}
|
||||
for (let i = 0; i < row; i++) {
|
||||
for (let j = 0; j < column; j++) columnlStr += '| 表格 ';
|
||||
columnlStr += '|\n';
|
||||
}
|
||||
const htmlStr = `${rowStr}|\n${rangeStr}|\n${columnlStr}\n`;
|
||||
if (this._getLineCh(cm)) this._replaceSelection(cm, '\n\n' + htmlStr);
|
||||
else this._replaceSelection(cm, htmlStr);
|
||||
cm.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
handleCodeBlock(cm) {
|
||||
this._openModal({
|
||||
title: '插入代码块',
|
||||
innerHtml: `
|
||||
<div class="fitem">
|
||||
<label>语言类型</label>
|
||||
<select name="type">
|
||||
@ -347,25 +347,30 @@ export default class JoeAction {
|
||||
</select>
|
||||
</div>
|
||||
`,
|
||||
confirm: () => {
|
||||
const type = $(".cm-modal select[name='type']").val() || 'html';
|
||||
const htmlStr = `\`\`\`${type}\ncode here...\n\`\`\``;
|
||||
if (this._getLineCh(cm)) this._replaceSelection(cm, '\n\n' + htmlStr);
|
||||
else this._replaceSelection(cm, htmlStr);
|
||||
cm.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
handleAbout() {
|
||||
this._openModal({
|
||||
title: '关于',
|
||||
innerHtml: `
|
||||
confirm: () => {
|
||||
const type = $(".cm-modal select[name='type']").val() || 'html';
|
||||
const htmlStr = `\`\`\`${type}\ncode here...\n\`\`\``;
|
||||
if (this._getLineCh(cm)) this._replaceSelection(cm, '\n\n' + htmlStr);
|
||||
else this._replaceSelection(cm, htmlStr);
|
||||
cm.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
handleAbout() {
|
||||
this._openModal({
|
||||
title: '关于',
|
||||
innerHtml: `
|
||||
<ul>
|
||||
<li>短代码功能正在开发中...</li>
|
||||
<li>仅支持网络图片粘贴上传(截图等)</li>
|
||||
<li>本编辑器仅供Joe主题使用,未经允许不得移植至其他主题!</li>
|
||||
</ul>
|
||||
`
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
handleTask(cm, type) {
|
||||
const str = type ? '{x}' : '{ }';
|
||||
this._replaceSelection(cm, ` ${str} `);
|
||||
cm.focus();
|
||||
}
|
||||
}
|
||||
|
10
typecho/write/js/_create.js
Normal file
10
typecho/write/js/_create.js
Normal file
@ -0,0 +1,10 @@
|
||||
const parser = new HyperDown();
|
||||
export default function createPreviewHtml(str) {
|
||||
str = parser.makeHtml(str);
|
||||
|
||||
str = str.replace(/{x}/g, '<input type="checkbox" class="task" checked disabled></input>')
|
||||
str = str.replace(/{ }/g, '<input type="checkbox" class="task" disabled></input>')
|
||||
|
||||
$('.cm-preview-content').html(str);
|
||||
$('.cm-preview-content pre code').each((i, el) => Prism.highlightElement(el));
|
||||
}
|
@ -84,6 +84,16 @@ export default [
|
||||
title: '符号表情',
|
||||
innerHTML: '<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="19" height="19"><path d="M512 56.889A455.111 455.111 0 0 0 56.889 512 455.111 455.111 0 0 0 512 967.111 455.111 455.111 0 0 0 967.111 512 455.111 455.111 0 0 0 512 56.889zm111.047 270.336A69.086 69.086 0 0 1 671.29 307.2c17.863 0 35.67 7.396 48.242 20.025 12.629 12.572 20.025 30.379 20.025 48.242 0 17.863-7.396 35.669-20.025 48.241-12.8 12.744-30.151 19.912-48.242 20.025a68.95 68.95 0 0 1-48.242-20.025 68.95 68.95 0 0 1-20.025-48.241c0-17.863 7.396-35.67 20.025-48.242zm-318.578 0a69.086 69.086 0 0 1 48.242-20.025c17.863 0 35.67 7.396 48.242 20.025 12.63 12.572 20.025 30.379 20.025 48.242 0 17.863-7.396 35.669-20.025 48.241-12.8 12.744-30.151 19.912-48.242 20.025a68.95 68.95 0 0 1-48.242-20.025 68.95 68.95 0 0 1-20.025-48.241c0-17.863 7.396-35.67 20.025-48.242zM786.375 566.67c-10.24 132.893-118.556 236.544-270.563 235.975-156.331 1.707-264.704-107.178-270.507-235.975a23.324 23.324 0 0 1-2.446-10.41c0-13.597 11.605-24.633 26.282-24.52h493.796c14.336 0 26.055 11.037 26.055 24.52a24.292 24.292 0 0 1-2.617 10.41z"/></svg>'
|
||||
},
|
||||
{
|
||||
type: 'task-no',
|
||||
title: '任务 - 未完成',
|
||||
innerHTML: '<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="20" height="20"><path d="M831.55 128.531c38.35 0 63.911 25.568 63.911 63.91v639.104c0 38.355-25.561 63.916-63.91 63.916H192.44c-38.34 0-63.908-25.56-63.908-63.916V192.442c0-38.343 25.567-63.91 63.908-63.91h639.11m0-63.91H192.44c-70.3 0-127.816 57.518-127.816 127.82v639.103c0 70.308 57.515 127.833 127.816 127.833h639.11c70.294 0 127.822-57.525 127.822-127.833V192.442c0-70.302-57.527-127.82-127.823-127.82zm0 0"/></svg>'
|
||||
},
|
||||
{
|
||||
type: 'task-yes',
|
||||
title: '任务 - 已完成',
|
||||
innerHTML: '<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="20" height="20"><path d="M831.551 64.623h-639.11c-70.3 0-127.816 57.517-127.816 127.819v639.103c0 70.308 57.515 127.833 127.816 127.833h639.11c70.294 0 127.822-57.525 127.822-127.833V192.442c0-70.302-57.527-127.82-127.822-127.82zM646.217 486.44c-108.652 159.779-204.52 345.115-204.52 345.115L192.443 550.351l63.916-70.303 153.385 146.994s76.695-127.822 178.95-236.469c102.261-108.652 223.689-198.127 223.689-198.127l19.17 63.916c0-.001-102.255 108.646-185.337 230.078z"/></svg>'
|
||||
},
|
||||
{
|
||||
type: 'code-block',
|
||||
title: '代码块',
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -7,36 +7,29 @@ import { history, historyKeymap } from '@codemirror/history';
|
||||
import { classHighlightStyle } from '@codemirror/highlight';
|
||||
import tools from './_tools';
|
||||
import JoeAction from './_actions';
|
||||
import createPreviewHtml from './_create';
|
||||
|
||||
class Joe extends JoeAction {
|
||||
constructor() {
|
||||
super();
|
||||
this.plugins = [history(), classHighlightStyle, bracketMatching(), closeBrackets()];
|
||||
this.parser = new HyperDown();
|
||||
this._isPasting = false;
|
||||
constructor() {
|
||||
super();
|
||||
this.plugins = [history(), classHighlightStyle, bracketMatching(), closeBrackets()];
|
||||
this._isPasting = false;
|
||||
this.init_ViewPort();
|
||||
this.init_Editor();
|
||||
this.init_Preview();
|
||||
this.init_Tools();
|
||||
this.init_Insert();
|
||||
}
|
||||
|
||||
this.init_ViewPort();
|
||||
this.init_Editor();
|
||||
this.init_Preview();
|
||||
this.init_Tools();
|
||||
this.init_Insert();
|
||||
}
|
||||
/* 已测 √ */
|
||||
init_ViewPort() {
|
||||
if ($('meta[name="viewport"]').length > 0) $('meta[name="viewport"]').attr('content', 'width=device-width, user-scalable=no, initial-scale=1.0, shrink-to-fit=no, viewport-fit=cover');
|
||||
else $('head').append('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, shrink-to-fit=no, viewport-fit=cover">');
|
||||
}
|
||||
|
||||
_createPreviewHtml(str) {
|
||||
str = this.parser.makeHtml(str);
|
||||
$('.cm-preview-content').html(str);
|
||||
$('.cm-preview-content pre code').each((i, el) => Prism.highlightElement(el));
|
||||
}
|
||||
|
||||
/* 已测 √ */
|
||||
init_ViewPort() {
|
||||
if ($('meta[name="viewport"]').length > 0) $('meta[name="viewport"]').attr('content', 'width=device-width, user-scalable=no, initial-scale=1.0, shrink-to-fit=no, viewport-fit=cover');
|
||||
else $('head').append('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, shrink-to-fit=no, viewport-fit=cover">');
|
||||
}
|
||||
|
||||
/* 已测 √ */
|
||||
init_Editor() {
|
||||
$('#text').before(`
|
||||
/* 已测 √ */
|
||||
init_Editor() {
|
||||
$('#text').before(`
|
||||
<div class="cm-container">
|
||||
<div class="cm-tools"></div>
|
||||
<div class="cm-mainer">
|
||||
@ -47,225 +40,231 @@ class Joe extends JoeAction {
|
||||
<div class="cm-progress-right"></div>
|
||||
</div>
|
||||
`);
|
||||
this._createPreviewHtml($('#text').val());
|
||||
const cm = new EditorView({
|
||||
state: EditorState.create({
|
||||
doc: $('#text').val(),
|
||||
extensions: [
|
||||
...this.plugins,
|
||||
keymap.of([defaultTabBinding, ...defaultKeymap, ...historyKeymap, ...closeBracketsKeymap]),
|
||||
EditorView.updateListener.of(update => {
|
||||
if (!update.docChanged) return;
|
||||
this._createPreviewHtml(update.state.doc.toString());
|
||||
}),
|
||||
EditorView.domEventHandlers({
|
||||
paste: e => {
|
||||
const clipboardData = e.clipboardData;
|
||||
if (!clipboardData || !clipboardData.items) return;
|
||||
const items = clipboardData.items;
|
||||
if (!items.length) return;
|
||||
let blob = null;
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
if (items[i].type.indexOf('image') !== -1) {
|
||||
e.preventDefault();
|
||||
blob = items[i].getAsFile();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!blob) return;
|
||||
let api = window.JoeConfig.uploadAPI;
|
||||
if (!api) return;
|
||||
const cid = $('input[name="cid"]').val();
|
||||
cid && (api = api + '&cid=' + cid);
|
||||
if (this._isPasting) return;
|
||||
this._isPasting = true;
|
||||
const fileName = Date.now().toString(36) + '.png';
|
||||
let formData = new FormData();
|
||||
formData.append('name', fileName);
|
||||
formData.append('file', blob, fileName);
|
||||
$.ajax({
|
||||
url: api,
|
||||
method: 'post',
|
||||
data: formData,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
dataType: 'json',
|
||||
xhr: () => {
|
||||
const xhr = $.ajaxSettings.xhr();
|
||||
if (!xhr.upload) return;
|
||||
xhr.upload.addEventListener(
|
||||
'progress',
|
||||
e => {
|
||||
let percent = (e.loaded / e.total) * 100;
|
||||
$('.cm-progress-left').width(percent / 2 + '%');
|
||||
$('.cm-progress-right').width(percent / 2 + '%');
|
||||
},
|
||||
false
|
||||
);
|
||||
return xhr;
|
||||
},
|
||||
success: res => {
|
||||
$('.cm-progress-left').width(0);
|
||||
$('.cm-progress-right').width(0);
|
||||
this._isPasting = false;
|
||||
const str = `${super._getLineCh(cm) ? '\n' : ''}![${res[1].title}](${res[0]})\n`;
|
||||
super._replaceSelection(cm, str);
|
||||
cm.focus();
|
||||
},
|
||||
error: () => {
|
||||
$('.cm-progress-left').width(0);
|
||||
$('.cm-progress-right').width(0);
|
||||
this._isPasting = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
],
|
||||
tabSize: 4
|
||||
})
|
||||
});
|
||||
$('.cm-mainer').prepend(cm.dom);
|
||||
$('#text')[0].form && $('#text')[0].form.addEventListener('submit', () => $('#text').val(cm.state.doc.toString()));
|
||||
this.cm = cm;
|
||||
}
|
||||
createPreviewHtml($('#text').val());
|
||||
const cm = new EditorView({
|
||||
state: EditorState.create({
|
||||
doc: $('#text').val(),
|
||||
extensions: [
|
||||
...this.plugins,
|
||||
keymap.of([defaultTabBinding, ...defaultKeymap, ...historyKeymap, ...closeBracketsKeymap]),
|
||||
EditorView.updateListener.of(update => {
|
||||
if (!update.docChanged) return;
|
||||
createPreviewHtml(update.state.doc.toString());
|
||||
}),
|
||||
EditorView.domEventHandlers({
|
||||
paste: e => {
|
||||
const clipboardData = e.clipboardData;
|
||||
if (!clipboardData || !clipboardData.items) return;
|
||||
const items = clipboardData.items;
|
||||
if (!items.length) return;
|
||||
let blob = null;
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
if (items[i].type.indexOf('image') !== -1) {
|
||||
e.preventDefault();
|
||||
blob = items[i].getAsFile();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!blob) return;
|
||||
let api = window.JoeConfig.uploadAPI;
|
||||
if (!api) return;
|
||||
const cid = $('input[name="cid"]').val();
|
||||
cid && (api = api + '&cid=' + cid);
|
||||
if (this._isPasting) return;
|
||||
this._isPasting = true;
|
||||
const fileName = Date.now().toString(36) + '.png';
|
||||
let formData = new FormData();
|
||||
formData.append('name', fileName);
|
||||
formData.append('file', blob, fileName);
|
||||
$.ajax({
|
||||
url: api,
|
||||
method: 'post',
|
||||
data: formData,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
dataType: 'json',
|
||||
xhr: () => {
|
||||
const xhr = $.ajaxSettings.xhr();
|
||||
if (!xhr.upload) return;
|
||||
xhr.upload.addEventListener(
|
||||
'progress',
|
||||
e => {
|
||||
let percent = (e.loaded / e.total) * 100;
|
||||
$('.cm-progress-left').width(percent / 2 + '%');
|
||||
$('.cm-progress-right').width(percent / 2 + '%');
|
||||
},
|
||||
false
|
||||
);
|
||||
return xhr;
|
||||
},
|
||||
success: res => {
|
||||
$('.cm-progress-left').width(0);
|
||||
$('.cm-progress-right').width(0);
|
||||
this._isPasting = false;
|
||||
const str = `${super._getLineCh(cm) ? '\n' : ''}![${res[1].title}](${res[0]})\n`;
|
||||
super._replaceSelection(cm, str);
|
||||
cm.focus();
|
||||
},
|
||||
error: () => {
|
||||
$('.cm-progress-left').width(0);
|
||||
$('.cm-progress-right').width(0);
|
||||
this._isPasting = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
],
|
||||
tabSize: 4
|
||||
})
|
||||
});
|
||||
$('.cm-mainer').prepend(cm.dom);
|
||||
$('#text')[0].form && $('#text')[0].form.addEventListener('submit', () => $('#text').val(cm.state.doc.toString()));
|
||||
this.cm = cm;
|
||||
}
|
||||
|
||||
/* 已测 √ */
|
||||
init_Preview() {
|
||||
const move = (nowClientX, nowWidth, clientX) => {
|
||||
let moveX = nowClientX - clientX;
|
||||
let moveWidth = nowWidth + moveX;
|
||||
if (moveWidth <= 0) moveWidth = 0;
|
||||
if (moveWidth >= $('.cm-mainer').outerWidth() - 16) moveWidth = $('.cm-mainer').outerWidth() - 16;
|
||||
$('.cm-preview').width(moveWidth);
|
||||
};
|
||||
$('.cm-resize').on({
|
||||
mousedown: e => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const nowWidth = $('.cm-preview').outerWidth();
|
||||
const nowClientX = e.clientX;
|
||||
document.onmousemove = _e => {
|
||||
if (window.requestAnimationFrame) requestAnimationFrame(() => move(nowClientX, nowWidth, _e.clientX));
|
||||
else move(nowClientX, nowWidth, _e.clientX);
|
||||
};
|
||||
document.onmouseup = () => {
|
||||
document.onmousemove = null;
|
||||
document.onmouseup = null;
|
||||
};
|
||||
return false;
|
||||
},
|
||||
touchstart: e => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const nowWidth = $('.cm-preview').outerWidth();
|
||||
const nowClientX = e.originalEvent.targetTouches[0].clientX;
|
||||
document.ontouchmove = _e => {
|
||||
if (window.requestAnimationFrame) requestAnimationFrame(() => move(nowClientX, nowWidth, _e.targetTouches[0].clientX));
|
||||
else move(nowClientX, nowWidth, _e.targetTouches[0].clientX);
|
||||
};
|
||||
document.ontouchend = () => {
|
||||
document.ontouchmove = null;
|
||||
document.ontouchend = null;
|
||||
};
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
/* 已测 √ */
|
||||
init_Preview() {
|
||||
const move = (nowClientX, nowWidth, clientX) => {
|
||||
let moveX = nowClientX - clientX;
|
||||
let moveWidth = nowWidth + moveX;
|
||||
if (moveWidth <= 0) moveWidth = 0;
|
||||
if (moveWidth >= $('.cm-mainer').outerWidth() - 16) moveWidth = $('.cm-mainer').outerWidth() - 16;
|
||||
$('.cm-preview').width(moveWidth);
|
||||
};
|
||||
$('.cm-resize').on({
|
||||
mousedown: e => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const nowWidth = $('.cm-preview').outerWidth();
|
||||
const nowClientX = e.clientX;
|
||||
document.onmousemove = _e => {
|
||||
if (window.requestAnimationFrame) requestAnimationFrame(() => move(nowClientX, nowWidth, _e.clientX));
|
||||
else move(nowClientX, nowWidth, _e.clientX);
|
||||
};
|
||||
document.onmouseup = () => {
|
||||
document.onmousemove = null;
|
||||
document.onmouseup = null;
|
||||
};
|
||||
return false;
|
||||
},
|
||||
touchstart: e => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const nowWidth = $('.cm-preview').outerWidth();
|
||||
const nowClientX = e.originalEvent.targetTouches[0].clientX;
|
||||
document.ontouchmove = _e => {
|
||||
if (window.requestAnimationFrame) requestAnimationFrame(() => move(nowClientX, nowWidth, _e.targetTouches[0].clientX));
|
||||
else move(nowClientX, nowWidth, _e.targetTouches[0].clientX);
|
||||
};
|
||||
document.ontouchend = () => {
|
||||
document.ontouchmove = null;
|
||||
document.ontouchend = null;
|
||||
};
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* 已测 √ */
|
||||
init_Tools() {
|
||||
tools.forEach(item => {
|
||||
if (item.type === 'title') {
|
||||
super.handleTitle(this.cm, item);
|
||||
} else {
|
||||
const el = $(`<div class="cm-tools-item" title="${item.title}">${item.innerHTML}</div>`);
|
||||
el.on('click', e => {
|
||||
e.preventDefault();
|
||||
switch (item.type) {
|
||||
case 'fullScreen':
|
||||
super.handleFullScreen(el);
|
||||
break;
|
||||
case 'publish':
|
||||
super.handlePublish();
|
||||
break;
|
||||
case 'undo':
|
||||
super.handleUndo(this.cm);
|
||||
break;
|
||||
case 'redo':
|
||||
super.handleRedo(this.cm);
|
||||
break;
|
||||
case 'time':
|
||||
super.handleTime(this.cm);
|
||||
break;
|
||||
case 'bold':
|
||||
super._insetAmboText(this.cm, '**');
|
||||
break;
|
||||
case 'italic':
|
||||
super._insetAmboText(this.cm, '*');
|
||||
break;
|
||||
case 'delete':
|
||||
super._insetAmboText(this.cm, '~~');
|
||||
break;
|
||||
case 'code-inline':
|
||||
super._insetAmboText(this.cm, '`');
|
||||
break;
|
||||
case 'indent':
|
||||
super.handleIndent(this.cm);
|
||||
break;
|
||||
case 'hr':
|
||||
super.handleHr(this.cm);
|
||||
break;
|
||||
case 'clean':
|
||||
super.handleClean(this.cm);
|
||||
break;
|
||||
case 'ordered-list':
|
||||
super.handleOrdered(this.cm);
|
||||
break;
|
||||
case 'unordered-list':
|
||||
super.handleUnordered(this.cm);
|
||||
break;
|
||||
case 'quote':
|
||||
super.handleQuote(this.cm);
|
||||
break;
|
||||
case 'download':
|
||||
super.handleDownload(this.cm);
|
||||
break;
|
||||
case 'link':
|
||||
super.handleLink(this.cm);
|
||||
break;
|
||||
case 'image':
|
||||
super.handleImage(this.cm);
|
||||
break;
|
||||
case 'table':
|
||||
super.handleTable(this.cm);
|
||||
break;
|
||||
case 'code-block':
|
||||
super.handleCodeBlock(this.cm);
|
||||
break;
|
||||
case 'about':
|
||||
super.handleAbout();
|
||||
break;
|
||||
case 'character':
|
||||
super._createTableLists(this.cm, JoeConfig.characterAPI, '星星符号', '字符大全');
|
||||
break;
|
||||
case 'emoji':
|
||||
super._createTableLists(this.cm, JoeConfig.emojiAPI, '表情', '符号表情(需数据库支持)');
|
||||
break;
|
||||
}
|
||||
});
|
||||
$('.cm-tools').append(el);
|
||||
}
|
||||
});
|
||||
}
|
||||
/* 已测 √ */
|
||||
init_Tools() {
|
||||
tools.forEach(item => {
|
||||
if (item.type === 'title') {
|
||||
super.handleTitle(this.cm, item);
|
||||
} else {
|
||||
const el = $(`<div class="cm-tools-item" title="${item.title}">${item.innerHTML}</div>`);
|
||||
el.on('click', e => {
|
||||
e.preventDefault();
|
||||
switch (item.type) {
|
||||
case 'fullScreen':
|
||||
super.handleFullScreen(el);
|
||||
break;
|
||||
case 'publish':
|
||||
super.handlePublish();
|
||||
break;
|
||||
case 'undo':
|
||||
super.handleUndo(this.cm);
|
||||
break;
|
||||
case 'redo':
|
||||
super.handleRedo(this.cm);
|
||||
break;
|
||||
case 'time':
|
||||
super.handleTime(this.cm);
|
||||
break;
|
||||
case 'bold':
|
||||
super._insetAmboText(this.cm, '**');
|
||||
break;
|
||||
case 'italic':
|
||||
super._insetAmboText(this.cm, '*');
|
||||
break;
|
||||
case 'delete':
|
||||
super._insetAmboText(this.cm, '~~');
|
||||
break;
|
||||
case 'code-inline':
|
||||
super._insetAmboText(this.cm, '`');
|
||||
break;
|
||||
case 'indent':
|
||||
super.handleIndent(this.cm);
|
||||
break;
|
||||
case 'hr':
|
||||
super.handleHr(this.cm);
|
||||
break;
|
||||
case 'clean':
|
||||
super.handleClean(this.cm);
|
||||
break;
|
||||
case 'ordered-list':
|
||||
super.handleOrdered(this.cm);
|
||||
break;
|
||||
case 'unordered-list':
|
||||
super.handleUnordered(this.cm);
|
||||
break;
|
||||
case 'quote':
|
||||
super.handleQuote(this.cm);
|
||||
break;
|
||||
case 'download':
|
||||
super.handleDownload(this.cm);
|
||||
break;
|
||||
case 'link':
|
||||
super.handleLink(this.cm);
|
||||
break;
|
||||
case 'image':
|
||||
super.handleImage(this.cm);
|
||||
break;
|
||||
case 'table':
|
||||
super.handleTable(this.cm);
|
||||
break;
|
||||
case 'code-block':
|
||||
super.handleCodeBlock(this.cm);
|
||||
break;
|
||||
case 'about':
|
||||
super.handleAbout();
|
||||
break;
|
||||
case 'character':
|
||||
super._createTableLists(this.cm, JoeConfig.characterAPI, '星星符号', '字符大全');
|
||||
break;
|
||||
case 'emoji':
|
||||
super._createTableLists(this.cm, JoeConfig.emojiAPI, '表情', '符号表情(需数据库支持)');
|
||||
break;
|
||||
case 'task-no':
|
||||
super.handleTask(this.cm, false);
|
||||
break;
|
||||
case 'task-yes':
|
||||
super.handleTask(this.cm, true);
|
||||
break;
|
||||
}
|
||||
});
|
||||
$('.cm-tools').append(el);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* 已测 √ */
|
||||
init_Insert() {
|
||||
Typecho.insertFileToEditor = (file, url, isImage) => {
|
||||
const str = `${super._getLineCh(this.cm) ? '\n' : ''}${isImage ? '!' : ''}[${file}](${url})\n`;
|
||||
super._replaceSelection(this.cm, str);
|
||||
this.cm.focus();
|
||||
};
|
||||
}
|
||||
/* 已测 √ */
|
||||
init_Insert() {
|
||||
Typecho.insertFileToEditor = (file, url, isImage) => {
|
||||
const str = `${super._getLineCh(this.cm) ? '\n' : ''}${isImage ? '!' : ''}[${file}](${url})\n`;
|
||||
super._replaceSelection(this.cm, str);
|
||||
this.cm.focus();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => new Joe());
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
||||
import { uglify } from 'rollup-plugin-uglify';
|
||||
export default {
|
||||
input: './js/joe.write.js',
|
||||
output: {
|
||||
file: './js/joe.write.chunk.js',
|
||||
format: 'iife'
|
||||
},
|
||||
plugins: [nodeResolve(), uglify()]
|
||||
input: './js/joe.write.js',
|
||||
output: {
|
||||
file: './js/joe.write.chunk.js',
|
||||
format: 'iife'
|
||||
},
|
||||
plugins: [nodeResolve(), uglify()]
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user