Skip to content

Commit

Permalink
Merge pull request #197 from gaelj/fix-uploads
Browse files Browse the repository at this point in the history
Fix uploads issue #196
  • Loading branch information
gaelj authored Nov 13, 2024
2 parents c081cab + 84ff1e8 commit 9cabfe1
Show file tree
Hide file tree
Showing 16 changed files with 63 additions and 30 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 0.8.13 - 2024-11-13

### ✨ Introduce new features

- Add new parameter `InsertDroppedFileContents`. If true, text files will have their content extracted and inserted in the editor. If false, all file types dropped into the editor will be passed to the upload callback. In case of multiple mixed-type files, they will all be uploaded

## 0.8.12 - 2024-11-06

### ⚡️ Improve performance
Expand Down
2 changes: 1 addition & 1 deletion CodeMirror6/CodeMirror6.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<AssemblyName>GaelJ.BlazorCodeMirror6</AssemblyName>
<IsPackable>true</IsPackable>
<PackageId>GaelJ.BlazorCodeMirror6</PackageId>
<Version>0.8.12</Version>
<Version>0.8.13</Version>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
Expand Down
1 change: 1 addition & 0 deletions CodeMirror6/CodeMirror6Wrapper.razor
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
TabSize="@TabSize"
Theme="@Theme"
UploadBrowserFile="@UploadBrowserFile"
InsertDroppedFileContents="@InsertDroppedFileContents"
EmbedUploadsAsDataUrls="@EmbedUploadsAsDataUrls"
MergeViewConfiguration="@MergeViewConfiguration"
FileNameOrExtension="@FileNameOrExtension"
Expand Down
4 changes: 4 additions & 0 deletions CodeMirror6/CodeMirror6Wrapper.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ public partial class CodeMirror6Wrapper : ComponentBase
/// </summary>
[Parameter] public Func<IBrowserFile, Task<string>>? UploadBrowserFile { get; set; }
/// <summary>
/// Whether to upload dropped files, or let CodeMirror handle them, which means their contents will be inserted in the document if possible
/// </summary>
[Parameter] public bool InsertDroppedFileContents { get; set; }
/// <summary>
/// Whether to embed uploads as data URLs instead of using the custom callback. Warning: this can cause performance issues, especially in Blazor Server apps.
/// </summary>
[Parameter] public bool EmbedUploadsAsDataUrls { get; set; }
Expand Down
9 changes: 9 additions & 0 deletions CodeMirror6/CodeMirror6WrapperInternal.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ public partial class CodeMirror6WrapperInternal : ComponentBase, IAsyncDisposabl
/// </summary>
[Parameter] public Func<IBrowserFile, Task<string>>? UploadBrowserFile { get; set; }
/// <summary>
/// Whether to upload dropped files, or let CodeMirror handle them, which means their contents will be inserted in the document if possible
/// </summary>
[Parameter] public bool InsertDroppedFileContents { get; set; }
/// <summary>
/// Whether to embed uploads as data URLs instead of using the custom callback. Warning: this can cause performance issues, especially in Blazor Server apps.
/// </summary>
[Parameter] public bool EmbedUploadsAsDataUrls { get; set; }
Expand Down Expand Up @@ -301,6 +305,7 @@ public async Task InitializeAsync(bool initializeJsInterop)
LocalStorageKey,
FullScreen,
UploadBrowserFile is not null || EmbedUploadsAsDataUrls,
InsertDroppedFileContents,
MaxDocumentLength,
LineNumbers,
HighlightActiveLineGutter,
Expand Down Expand Up @@ -465,6 +470,10 @@ protected override async Task OnParametersSetAsync()
Config.SupportFileUpload = UploadBrowserFile is not null || EmbedUploadsAsDataUrls;
updated = true;
}
if (Config.InsertDroppedFileContents != InsertDroppedFileContents) {
Config.InsertDroppedFileContents = InsertDroppedFileContents;
updated = true;
}
if (Config.EmbedUploadsAsDataUrls != EmbedUploadsAsDataUrls) {
Config.EmbedUploadsAsDataUrls = EmbedUploadsAsDataUrls;
updated = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
using GaelJ.BlazorCodeMirror6.Models;

namespace GaelJ.BlazorCodeMirror6.Converters;

Expand Down
7 changes: 7 additions & 0 deletions CodeMirror6/Models/CodeMirrorConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ namespace GaelJ.BlazorCodeMirror6.Models;
/// <param name="localStorageKey"></param>
/// <param name="fullScreen"></param>
/// <param name="supportFileUpload"></param>
/// <param name="insertDroppedFileContents"></param>
/// <param name="maxDocumentLength"></param>
/// <param name="lineNumbers"></param>
/// <param name="highlightActiveLineGutter"></param>
Expand Down Expand Up @@ -59,6 +60,7 @@ public class CodeMirrorConfiguration(
string? localStorageKey,
bool fullScreen,
bool supportFileUpload,
bool insertDroppedFileContents,
int? maxDocumentLength,
bool lineNumbers,
bool highlightActiveLineGutter,
Expand Down Expand Up @@ -172,6 +174,11 @@ public class CodeMirrorConfiguration(
/// </summary>
[JsonPropertyName("supportFileUpload")] public bool SupportFileUpload { get; internal set; } = supportFileUpload;

/// <summary>
/// Whether to upload dropped files, or let CodeMirror handle them, which means their contents will be inserted in the document if possible
/// </summary>
[JsonPropertyName("insertDroppedFileContents")] public bool InsertDroppedFileContents { get; internal set; } = insertDroppedFileContents;

/// <summary>
/// The maximum length of the document
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions CodeMirror6/NodeLib/src/CmConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export class CmConfiguration {
public localStorageKey: string
public fullScreen: boolean
public supportFileUpload: boolean
public insertDroppedFileContents: boolean
public embedUploadsAsDataUrls: boolean
public maxDocumentLength: number | null
public lineNumbers: boolean
Expand Down
34 changes: 23 additions & 11 deletions CodeMirror6/NodeLib/src/CmFileUpload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,14 @@ export function getFileUploadExtensions(id: string, setup: CmSetup)
overlay.style.display = 'flex'
},
drop(event, view) {
if (!CMInstances[id].config.supportFileUpload || !isFileDragEvent(event)) return
if (!isFileDragEvent(event)) return
consoleLog(id, "drop")
const transfer = event.dataTransfer
if (transfer?.files) {
const fileList = event.dataTransfer?.files
if (fileList) {
for (let i = 0; i < fileList.length; i++) {
consoleLog(id, fileList[i].name, fileList[i].type)
}
overlay.style.display = 'none'
event.preventDefault()
event.stopPropagation()
const { clientX, clientY } = event
const pos = view.posAtCoords({ x: clientX, y: clientY })
if (pos !== null) {
Expand All @@ -82,7 +83,7 @@ export function getFileUploadExtensions(id: string, setup: CmSetup)
selection: newSelection
});
}
uploadFiles(id, transfer.files, view)
processAddedFiles(id, fileList, view, event)
depth = 0
}
}
Expand All @@ -98,39 +99,50 @@ async function uploadFileWithDotnet(id: string, file: File): Promise<string> {
return await CMInstances[id].dotNetHelper.invokeMethodAsync('UploadFileFromJS', byteArray, file.name, file.type, lastModifiedDate)
}

async function encodeFileAsDataUrl(file: File): Promise<string> {
async function encodeFileAsDataUrl(id: string, file: File): Promise<string> {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = function (e) {
resolve(e.target.result as string)
}
reader.onerror = function (e) {
consoleLog(id, "Error encoding file as data URL:", e)
reject(e)
}
reader.readAsDataURL(file)
})
}

export async function processAddedFiles(id: string, fileList: FileList, view: EditorView, event: DragEvent | ClipboardEvent) {
const hasOtherFileType = Array.from(fileList).some(f => f.type && !f.type.startsWith("text/"))
if (!CMInstances[id].config.insertDroppedFileContents || hasOtherFileType) {
event.preventDefault()
event.stopPropagation()
uploadFiles(id, fileList, view)
}
}

export async function uploadFiles(id: string, files: FileList, view: EditorView) {
if (!CMInstances[id].config.supportFileUpload) return
const fileUrls = []
const embedUploadsAsDataUrls = CMInstances[id].config.embedUploadsAsDataUrls
for (let i = 0; i < files.length; i++) {
const file = files[i]
const fileUrl = embedUploadsAsDataUrls
? await encodeFileAsDataUrl(file)
? await encodeFileAsDataUrl(id, file)
: await uploadFileWithDotnet(id, file)
fileUrls.push(fileUrl)
consoleLog(id, "Uploaded file:", fileUrl)
const fileName = files[0].name
var imageChar = file.type.indexOf("image/") === 0 ? "!" : ""
var imageLink = `\n${imageChar}[${fileName}](${fileUrl})\n`
var mdLink = `\n${imageChar}[${fileName}](${fileUrl})\n`
const ranges = view.state.selection.ranges;
const lastRange = ranges[ranges.length - 1];

view.dispatch(
{
changes: { from: view.state.selection.main.from, insert: imageLink },
selection: { anchor: lastRange.from + imageLink.length, head: lastRange.from + imageLink.length }
changes: { from: view.state.selection.main.from, insert: mdLink },
selection: { anchor: lastRange.from + mdLink.length, head: lastRange.from + mdLink.length }
},
{
scrollIntoView: true
Expand Down
6 changes: 4 additions & 2 deletions CodeMirror6/NodeLib/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,14 +176,15 @@ export async function initCodeMirror(
const pasteHandler = EditorView.domEventHandlers({
paste(event: ClipboardEvent, view: EditorView) {
const transfer = event.clipboardData
const fileList = transfer?.files

consoleLog(id, "Pasting", transfer.files, transfer.types, transfer.items)
for (let i = 0; i < transfer.items.length; i++) {
const item = transfer.items[i]
consoleLog(id, "Item", item.kind, item.type)
}
if (CMInstances[id].config.supportFileUpload && transfer?.files && transfer.files.length > 0 && !transfer.types.includes('text/plain')) {
uploadFiles(id, transfer.files, view)
if (fileList && fileList.length > 0 && !transfer.types.includes('text/plain')) {
uploadFiles(id, fileList, view)
event.preventDefault()
}
else if (paste(view))
Expand Down Expand Up @@ -400,6 +401,7 @@ export async function setConfiguration(id: string, newConfig: CmConfiguration) {
if (oldConfig.localStorageKey !== newConfig.localStorageKey) setLocalStorageKey(id, newConfig.localStorageKey)
if (oldConfig.fullScreen !== newConfig.fullScreen) view.focus()
if (oldConfig.supportFileUpload !== newConfig.supportFileUpload) {}
if (oldConfig.insertDroppedFileContents !== newConfig.insertDroppedFileContents) {}
if (oldConfig.maxDocumentLength !== newConfig.maxDocumentLength) {}
if (oldConfig.lineNumbers !== newConfig.lineNumbers) effects.push(CMInstances[id].lineNumbersCompartment.reconfigure(newConfig.lineNumbers ? lineNumbers() : []))
if (oldConfig.highlightActiveLineGutter !== newConfig.highlightActiveLineGutter) effects.push(CMInstances[id].highlightActiveLineGutterCompartment.reconfigure(newConfig.highlightActiveLineGutter ? highlightActiveLineGutter() : []))
Expand Down
2 changes: 1 addition & 1 deletion Examples.BlazorServer/Examples.BlazorServer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<ImplicitUsings>enable</ImplicitUsings>
<Version>0.8.12</Version>
<Version>0.8.13</Version>
</PropertyGroup>
<ItemGroup>
<SupportedPlatform Include="browser" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable>
<Version>0.8.12</Version>
<Version>0.8.13</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Sentry.AspNetCore" Version="4.12.0" />
Expand Down
2 changes: 1 addition & 1 deletion Examples.BlazorWasm/Examples.BlazorWasm.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable>
<Version>0.8.12</Version>
<Version>0.8.13</Version>
</PropertyGroup>
<ItemGroup>
<SupportedPlatform Include="browser-wasm" />
Expand Down
1 change: 1 addition & 0 deletions Examples.Common/Example.razor
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@
HighlightSelectionMatches = true,
ScrollToEnd = true,
BindMode = DocumentBindMode.OnDelayedInput,
DebugLogs = true,
};
private UnifiedMergeConfig? PreviousMergeViewConfiguration;
private UnifiedMergeConfig? MergeViewConfiguration;
Expand Down
2 changes: 1 addition & 1 deletion Examples.Common/Examples.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<Version>0.8.12</Version>
<Version>0.8.13</Version>
</PropertyGroup>
<ItemGroup>
<SupportedPlatform Include="browser" />
Expand Down
13 changes: 2 additions & 11 deletions NEW_CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
### ⚡️ Improve performance
### ✨ Introduce new features

- Add attribute `data-permanent` to container div

### 📝 Add or update documentation

- Add FAQ about blazor server interactive
- Include JS source maps in release

### 🙈 Add or update a .gitignore file

- git ignore map files
- Add new parameter `InsertDroppedFileContents`. If true, text files will have their content extracted and inserted in the editor. If false, all file types dropped into the editor will be passed to the upload callback. In case of multiple mixed-type files, they will all be uploaded

0 comments on commit 9cabfe1

Please sign in to comment.