Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<Version>9.0.4</Version>
<Version>9.0.5</Version>
</PropertyGroup>

<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ public partial class Editor
[Parameter]
public bool ShowSubmit { get; set; } = true;

/// <summary>
/// 获得/设置 Editor 组件内上传文件时回调此方法
/// </summary>
[Parameter]
public Func<EditorUploadFile, Task>? OnFileUpload { get; set; }

private bool _lastShowSubmit = true;

private string? ShowSubmitString => ShowSubmit ? "true" : null;
Expand All @@ -83,7 +89,7 @@ public partial class Editor
public string? Language { get; set; }

/// <summary>
/// 获得/设置 语言扩展脚本路径 默认 null 如加载德语可设置为
/// 获得/设置 语言扩展脚本路径 默认 null 如加载德语可设置为
/// </summary>
[Parameter]
public string? LanguageUrl { get; set; }
Expand Down Expand Up @@ -186,7 +192,7 @@ protected override async Task InvokeInitAsync()
methodClickPluginItem = nameof(ClickPluginItem);
}

await InvokeVoidAsync("init", Id, Interop, methodGetPluginAttributes, methodClickPluginItem, Height, Value ?? "", Language, LanguageUrl);
await InvokeVoidAsync("init", Id, Interop, methodGetPluginAttributes, methodClickPluginItem, Height, Value ?? "", Language, LanguageUrl, OnFileUpload is not null);
}

/// <summary>
Expand Down Expand Up @@ -256,6 +262,24 @@ public async Task<string> ClickPluginItem(string pluginItemName)
return ret;
}

/// <summary>
/// 文件上传回调
/// </summary>
/// <param name="name"></param>
/// <param name="contentType"></param>
/// <param name="size"></param>
/// <param name="stream"></param>
[JSInvokable]
public async Task ImageUpload(string name, string contentType, long size, IJSStreamReference stream)
{
var data = await stream.OpenReadStreamAsync(size);
var file = new EditorUploadFile(name, contentType, size, data);
if (OnFileUpload != null)
{
await OnFileUpload(file);
}
}

/// <summary>
/// 执行 editor 的方法
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ if (window.BootstrapBlazor === void 0) {
window.BootstrapBlazor = {};
}

export async function init(id, invoker, methodGetPluginAttrs, methodClickPluginItem, height, value, lang, langUrl) {
export async function init(id, invoker, methodGetPluginAttrs, methodClickPluginItem, height, value, lang, langUrl, hasUpload) {
const el = document.getElementById(id)
if (el === null) {
return
Expand Down Expand Up @@ -46,6 +46,26 @@ export async function init(id, invoker, methodGetPluginAttrs, methodClickPluginI
const showSubmit = el.getAttribute("data-bb-submit") === "true"
option.toolbar = toolbar;
reloadCallbacks(id, option);
if (hasUpload) {
option.callbacks.onImageUpload = async files => {
editor.files = files
for (let i = 0; i < files.length; i++) {
const file = files[i];
const image = createImage(file);
editor.$editor.summernote('insertNode', image);

const buffer = await file.arrayBuffer();
const stream = DotNet.createJSStreamReference(buffer);
await editor.invoker.invokeMethodAsync('ImageUpload',
file.name,
file.type || 'application/octet-stream',
file.size,
stream
)
}
}
}

if (!showSubmit) {
const externalOnChange = option.callbacks.onChange;
option.callbacks.onChange = function (contents) {
Expand Down Expand Up @@ -125,7 +145,7 @@ export async function init(id, invoker, methodGetPluginAttrs, methodClickPluginI
}

const reloadCallbacks = (id, option) => {
const events = ['Blur', 'BlurCodeview', 'Change', 'ChangeCodeview', 'DialogShown', 'Enter', 'Focus', 'ImageLinkInsert', 'ImageUploadError', 'Init', 'Keydown', 'Keyup', 'Mousedown', 'Mouseup', 'Paste', 'Scroll'];
const events = ['Blur', 'BlurCodeview', 'Change', 'ChangeCodeview', 'DialogShown', 'Enter', 'Focus', 'ImageUpload', 'ImageLinkInsert', 'ImageUploadError', 'Init', 'Keydown', 'Keyup', 'Mousedown', 'Mouseup', 'Paste', 'Scroll'];

events.forEach(event => {
option.callbacks[`on${event}`] = function () {
Expand Down Expand Up @@ -200,6 +220,12 @@ export function dispose(id) {
}
}

const createImage = file => {
const element = document.createElement('img');
element.src = URL.createObjectURL(file);
return element;
}

const offEvent = eventEl => {
if (eventEl) {
EventHandler.off(eventEl, 'click')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/

namespace BootstrapBlazor.Components;

/// <summary>
/// Editor 上传文件信息类
/// </summary>
public class EditorUploadFile(string fileName, string contentType, long fileSize, Stream stream)
{
/// <summary>
/// 获得/设置 文件名
/// </summary>
public string FileName => fileName;

/// <summary>
/// 获得/设置 文件大小
/// </summary>
public long FileSize => fileSize;

/// <summary>
/// 获得/设置 文件类型
/// </summary>
public string ContentType => contentType;

/// <summary>
/// 获得/设置 上传的文件流
/// </summary>
public Stream Stream => stream;

/// <summary>
/// 获得/设置 错误信息
/// </summary>
public Exception? Error { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/

namespace BootstrapBlazor.Components;

/// <summary>
/// EditorUploadFile 扩展方法类
/// </summary>
public static class EditorUploadFileExtensions
{
/// <summary>
/// 保存到文件方法
/// </summary>
/// <param name="upload"></param>
/// <param name="fileName"></param>
/// <param name="bufferSize"></param>
/// <param name="token"></param>
/// <returns></returns>
public static async Task<bool> SaveToFileAsync(this EditorUploadFile upload, string fileName, int bufferSize = 64 * 1024, CancellationToken token = default)
{
var ret = false;

// 文件保护,如果文件存在则先删除
if (File.Exists(fileName))
{
try
{
File.Delete(fileName);
}
catch (Exception ex)
{
upload.Error = ex;
return ret;
}
}

var folder = Path.GetDirectoryName(fileName);
if (!string.IsNullOrEmpty(folder) && !Directory.Exists(folder))
{
Directory.CreateDirectory(folder);
}

using var uploadFile = File.OpenWrite(fileName);
try
{
// 打开文件流
var buffer = new byte[bufferSize];
int bytesRead = 0;

// 开始读取文件
while ((bytesRead = await upload.Stream.ReadAsync(buffer, token)) > 0)
{
await uploadFile.WriteAsync(buffer.AsMemory(0, bytesRead), token);
}
ret = true;
}
catch (Exception ex)
{
upload.Error = ex;
}

return ret;
}
}