Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit089be62

Browse files
committed
FEATURE: inline event editor for the rich editor
1 parentc0e9e4b commit089be62

File tree

11 files changed

+1217
-72
lines changed

11 files changed

+1217
-72
lines changed
Lines changed: 69 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,72 @@
1+
importComponentfrom"@glimmer/component";
12
import {on }from"@ember/modifier";
2-
importautosizefrom"autosize";
3-
import {modifierasmodifierFn}from"ember-modifier";
3+
import{action }from"@ember/object";
4+
import {modifier }from"ember-modifier";
45
importautoFocusfrom"discourse/modifiers/auto-focus";
56

6-
constresize=modifierFn((element)=> {
7-
autosize(element);
8-
return ()=>autosize.destroy(element);
9-
});
10-
11-
constExpandingTextArea= <template>
12-
<textarea
13-
{{autoFocus}}
14-
{{resize}}
15-
{{! deprecated args: }}
16-
autocorrect={{@autocorrect}}
17-
class={{@class}}
18-
maxlength={{@maxlength}}
19-
name={{@name}}
20-
rows={{@rows}}
21-
value={{@value}}
22-
{{(if@input(modifieron"input"@input))}}
23-
...attributes
24-
></textarea>
25-
</template>;
26-
27-
exportdefaultExpandingTextArea;
7+
exportdefaultclassExpandingTextAreaextendsComponent {
8+
setTextarea=modifier((element)=> {
9+
this.#textarea= element;
10+
11+
constplaceholderObserver=newMutationObserver((mutations)=> {
12+
mutations.forEach((mutation)=> {
13+
if (
14+
mutation.type==="attributes"&&
15+
mutation.attributeName==="placeholder"
16+
) {
17+
this.autoResize();
18+
}
19+
});
20+
});
21+
22+
placeholderObserver.observe(element, {
23+
attributes:true,
24+
attributeFilter: ["placeholder"],
25+
});
26+
27+
// we shoulda void this... but without setTimeout, it doesn't resize when toggling modes
28+
setTimeout(()=>this.autoResize(),100);
29+
30+
return ()=> {
31+
placeholderObserver.disconnect();
32+
this.#textarea=null;
33+
};
34+
});
35+
36+
#textarea;
37+
38+
@action
39+
autoResize() {
40+
this.#textarea.style.height="auto";
41+
this.#textarea.style.height=this.#textarea.scrollHeight+"px";
42+
43+
// Get the max-height value from CSS (30vh)
44+
constmaxHeight=parseInt(getComputedStyle(this.#textarea).maxHeight,10);
45+
46+
// Only enable scrolling if content exceeds max-height
47+
if (this.#textarea.scrollHeight> maxHeight) {
48+
this.#textarea.style.overflowY="auto";
49+
}else {
50+
this.#textarea.style.overflowY="hidden";
51+
}
52+
}
53+
54+
<template>
55+
<textarea
56+
{{this.setTextarea}}
57+
{{(if@autoFocusautoFocus)}}
58+
{{! deprecated args: }}
59+
autocorrect={{@autocorrect}}
60+
class={{@class}}
61+
maxlength={{@maxlength}}
62+
name={{@name}}
63+
rows={{@rows}}
64+
value={{@value}}
65+
{{(if@input(modifieron"input"@input))}}
66+
{{on"input"this.autoResize}}
67+
{{on"focus"this.autoResize}}
68+
{{on"blur"this.autoResize}}
69+
...attributes
70+
></textarea>
71+
</template>
72+
}

‎frontend/discourse/app/lib/composer/rich-editor-extensions.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@
9090
* Markdown-it token parse definition
9191
*@property {RichPlugin | Array<RichPlugin>} [plugins]
9292
* ProseMirror plugins
93-
*@property {Record<string, import('prosemirror-view').NodeViewConstructor>} [nodeViews]
94-
* ProseMirror node views
93+
*@property {Record<string, import('prosemirror-view').NodeViewConstructor | { component: any, name?: string }>} [nodeViews]
94+
* ProseMirror node views. Can be a NodeViewConstructor or an object with { component, name } for automatic Glimmer component wrapping
9595
*@property {RichKeymap} [keymap]
9696
* Additional keymap definitions
9797
*@property {(params: PluginParams) => Record<string, import('prosemirror-state').Command>} [commands]

‎frontend/discourse/app/static/prosemirror/core/plugin.js‎

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import{Plugin}from"prosemirror-state";
2+
importGlimmerNodeViewfrom"../lib/glimmer-node-view";
23

34
/*
4-
There are3 ways to define a node view:
5+
There are4 ways to define a node view:
56
67
Setting a node view class directly (e.g. code-block)
78
`nodeViews: { nodeName: NodeViewClass }`
@@ -11,13 +12,31 @@ import { Plugin } from "prosemirror-state";
1112
1213
Setting a node view instance as returned by a function, when plugin params are needed (e.g. image)
1314
`nodeViews: { nodeName: (pluginParams) => (...args) => nodeViewInstance }`
15+
16+
Setting a Glimmer component with auto-wrapping (new)
17+
`nodeViews: { nodeName: { component: GlimmerComponent, name: "nodeName" }}`
1418
*/
1519
exportfunctionextractNodeViews(extensions,pluginParams){
1620
/**@type {Record<string, import('prosemirror-view').NodeViewConstructor>} */
1721
constallNodeViews={};
1822
for(const{ nodeViews}ofextensions){
1923
if(nodeViews){
2024
for(let[name,nodeView]ofObject.entries(nodeViews)){
25+
// Check if nodeView is a Glimmer component descriptor
26+
if(nodeView&&typeofnodeView==="object"&&nodeView.component){
27+
allNodeViews[name]=(node,view,getPos)=>{
28+
returnnewGlimmerNodeView({
29+
node,
30+
view,
31+
getPos,
32+
getContext:pluginParams.getContext,
33+
component:nodeView.component,
34+
name:nodeView.name||name,
35+
});
36+
};
37+
continue;
38+
}
39+
2140
// node view can be a function, to which we pass pluginParams
2241
if(!nodeView.toString().startsWith("class")){
2342
nodeView=nodeView(pluginParams);

‎plugins/discourse-calendar/assets/javascripts/discourse/components/discourse-post-event/more-menu.gjs‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,48 @@ export default class DiscoursePostEventMoreMenu extends Component {
190190
this.modal.show(PostEventBuilder, {
191191
model: {
192192
event:this.args.event,
193+
onDelete:async (event)=> {
194+
constpost=awaitthis.store.find("post",event.id);
195+
constraw=post.raw;
196+
197+
consteventRegex=newRegExp(
198+
`\\[event\\s(.*?)\\]\\n\\[\\/event\\]`,
199+
"m"
200+
);
201+
constnewRaw=raw.replace(eventRegex,"");
202+
203+
constprops= {
204+
raw: newRaw,
205+
edit_reason:"Destroy event",
206+
};
207+
208+
constcooked=awaitcook(newRaw);
209+
props.cooked=cooked.string;
210+
211+
returnawaitpost.save(props);
212+
},
213+
onUpdate:async (startsAt,endsAt,event,siteSettings)=> {
214+
constpost=awaitthis.store.find("post",event.id);
215+
constraw=post.raw;
216+
consteventParams=buildParams(
217+
startsAt,
218+
endsAt,
219+
event,
220+
siteSettings
221+
);
222+
constnewRaw=replaceRaw(eventParams, raw);
223+
if (newRaw) {
224+
constprops= {
225+
raw: newRaw,
226+
edit_reason:i18n("discourse_post_event.edit_reason"),
227+
};
228+
229+
constcooked=awaitcook(newRaw);
230+
props.cooked=cooked.string;
231+
232+
returnawaitpost.save(props);
233+
}
234+
},
193235
},
194236
});
195237
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp