Skip to content

Commit 5e8d1aa

Browse files
committed
Refactor MarkdownEditor to use structured link data
Updated the MarkdownEditor component and its Blade view to handle link and media insertions using structured data objects instead of plain markdown strings. This enables more flexible handling of attributes and supports toggling selected text as links. The PHP methods now return arrays with url, title, tag, and attributes, and the JavaScript logic formats these into markdown as needed.
1 parent b65f0f7 commit 5e8d1aa

File tree

2 files changed

+96
-31
lines changed

2 files changed

+96
-31
lines changed

resources/views/filament/forms/components/markdown-editor.blade.php

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -137,15 +137,69 @@
137137
138138
var cm = editor.codemirror;
139139
140-
const urls = $event.detail.data || '';
140+
// Convert data to array if it's not already
141+
const dataArray = Array.isArray($event.detail.data) ? $event.detail.data : [$event.detail.data || ''];
142+
const pickerName = $event.detail.name;
141143
142-
var startPoint = cm.getCursor('start')
143-
var endPoint = cm.getCursor('end')
144-
cm.replaceRange(
145-
urls,
146-
startPoint,
147-
endPoint,
148-
);
144+
var startPoint = cm.getCursor('start');
145+
var endPoint = cm.getCursor('end');
146+
var selectedText = cm.getSelection();
147+
148+
// Helper function to format attributes string
149+
const formatAttributes = (attributes) => {
150+
if (!attributes || typeof attributes !== 'string' || attributes.trim() === '') {
151+
return '';
152+
}
153+
154+
return `{${attributes}}`;
155+
};
156+
157+
// Helper function to convert item object to markdown
158+
const itemToMarkdown = (item) => {
159+
if (typeof item === 'string') {
160+
return item; // Fallback for old format
161+
}
162+
163+
const { url, title, tag, attributes } = item;
164+
let markdown = '';
165+
166+
if (tag === 'img') {
167+
markdown = `![${title}](${url})`;
168+
} else {
169+
markdown = `[${title}](${url})`;
170+
}
171+
172+
// Add attributes using helper function
173+
markdown += formatAttributes(attributes);
174+
175+
return markdown;
176+
};
177+
178+
if (pickerName === 'contentPicker' && selectedText && dataArray.length > 0) {
179+
// For contentPicker with selected text, toggle as link
180+
const item = dataArray[0];
181+
const { url, attributes } = item;
182+
183+
let linkMarkdown = `[${selectedText}](${url})`;
184+
185+
// Add attributes using helper function
186+
linkMarkdown += formatAttributes(attributes);
187+
188+
cm.replaceRange(
189+
linkMarkdown,
190+
startPoint,
191+
endPoint,
192+
);
193+
} else {
194+
// Default behavior: insert the content
195+
const markdownItems = dataArray.map(itemToMarkdown);
196+
197+
cm.replaceRange(
198+
markdownItems.join(' '),
199+
startPoint,
200+
endPoint,
201+
);
202+
}
149203
}"
150204
{{ $getExtraAlpineAttributeBag() }}
151205
>

src/Filament/Forms/Components/MarkdownEditor.php

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public function getContentPickerAction()
7474

7575
$livewire->dispatch(
7676
'append-custom-links-to-markdown-editor',
77+
name: 'contentPicker',
7778
awaitSchemaComponent: $key,
7879
livewireId: $livewire->getId(),
7980
key: $key,
@@ -115,6 +116,7 @@ public function getMediaPickerAction()
115116

116117
$livewire->dispatch(
117118
'append-custom-links-to-markdown-editor',
119+
name: 'mediaPicker',
118120
awaitSchemaComponent: $key,
119121
livewireId: $livewire->getId(),
120122
key: $key,
@@ -138,7 +140,7 @@ public function formatMediaPickerState($state)
138140
->filter(fn ($record) => $record instanceof MediaAsset)
139141
->sortBy(fn (Model $record) => array_search($record->getKey(), $state))
140142
->map(fn (Model | MediaAsset $record) => $this->mutateMediaPickerState($record))
141-
->implode(' ');
143+
->toArray();
142144
}
143145

144146
public function formatContentPickerState($state)
@@ -155,7 +157,7 @@ public function formatContentPickerState($state)
155157
->filter(fn ($record) => $record instanceof Content)
156158
->sortBy(fn (Model $record) => array_search($record->getKey(), $state))
157159
->map(fn (Model | Content $record) => $this->mutateContentPickerState($record))
158-
->implode("\r\n");
160+
->toArray();
159161
}
160162

161163
protected function mutateMediaPickerState(Model | MediaAsset $mediaAsset)
@@ -165,19 +167,21 @@ protected function mutateMediaPickerState(Model | MediaAsset $mediaAsset)
165167
$mediaUrl = $mediaAsset->getUrl(isAbsolute: false);
166168
$title = $media?->title ?? $mediaAsset->title;
167169

168-
if ($mediaAsset->isImage()) {
169-
$template = '![%s](%s)';
170-
} else {
171-
$template = '[%s](%s)';
172-
}
173-
$template .= '{data-cmsmediaasset-id="%s"}';
174-
175-
return sprintf(
176-
$template,
177-
htmlspecialchars($title),
178-
htmlspecialchars($mediaUrl),
179-
htmlspecialchars($mediaAsset->getKey()),
180-
);
170+
$attributes = [
171+
'data-cmsmediaasset-id' => $mediaAsset->getKey(),
172+
];
173+
174+
// Convert attributes array to string
175+
$attributesString = collect($attributes)
176+
->map(fn($value, $key) => "{$key}=\"{$value}\"")
177+
->join(' ');
178+
179+
return [
180+
'url' => $mediaUrl,
181+
'title' => $title,
182+
'tag' => $mediaAsset->isImage() ? 'img' : 'a',
183+
'attributes' => $attributesString,
184+
];
181185
}
182186

183187
protected function mutateContentPickerState(Model | Content $content)
@@ -212,14 +216,21 @@ protected function mutateContentPickerState(Model | Content $content)
212216
->prepend('/')
213217
->toString();
214218

215-
$template = '[%s](%s){data-content-id="%s" data-content-slug="%s"}';
219+
$attributes = [
220+
'data-content-id' => $content->getKey(),
221+
'data-content-slug' => $content->slug,
222+
];
223+
224+
// Convert attributes array to string
225+
$attributesString = collect($attributes)
226+
->map(fn($value, $key) => "{$key}=\"{$value}\"")
227+
->join(' ');
216228

217-
return sprintf(
218-
$template,
219-
htmlspecialchars($content->title),
220-
htmlspecialchars($relativeUrl),
221-
htmlspecialchars($content->getKey()),
222-
htmlspecialchars($content->slug),
223-
);
229+
return [
230+
'url' => $relativeUrl,
231+
'title' => $content->title,
232+
'tag' => 'a',
233+
'attributes' => $attributesString,
234+
];
224235
}
225236
}

0 commit comments

Comments
 (0)