Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix (?) CodeEditorLink #31

Merged
merged 1 commit into from
Dec 28, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 23 additions & 30 deletions src/yew/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
};
use std::{cell::RefCell, rc::Rc};
use web_sys::HtmlElement;
use yew::{html, html::Scope, Callback, Classes, Component, Context, Html, NodeRef, Properties};
use yew::{html, Callback, Classes, Component, Context, Html, NodeRef, Properties};

#[derive(Clone, Debug, PartialEq, Properties)]
pub struct CodeEditorProps<OPT: std::cmp::PartialEq + Clone + Into<IStandaloneEditorConstructionOptions> = IStandaloneEditorConstructionOptions> {
Expand All @@ -25,14 +25,13 @@ pub struct CodeEditorProps<OPT: std::cmp::PartialEq + Clone + Into<IStandaloneEd
pub classes: Classes,
}

type ModelCell = Rc<RefCell<Option<CodeEditorModel>>>;

/// CodeEditor component.
///
/// Use the `link` prop to pass down a [`CodeEditorLink`] which can be used to
/// access the [`CodeEditor`](CodeEditorModel).
#[derive(Debug)]
pub struct CodeEditor {
node_ref: NodeRef,
editor: Option<CodeEditorModel>,
editor: ModelCell,
}
impl CodeEditor {
fn emit_editor_created(&self, ctx: &Context<Self>) {
Expand All @@ -44,8 +43,7 @@ impl CodeEditor {
// reuse the link we were given or create a new one
let link = link
.clone()
.unwrap_or_else(|| CodeEditorLink::new_connected(ctx.link().clone()));

.unwrap_or_else(|| CodeEditorLink::new_connected(self.editor.clone()));
on_editor_created.emit(link);
}
}
Expand All @@ -54,13 +52,13 @@ impl Component for CodeEditor {
type Properties = CodeEditorProps;

fn create(ctx: &Context<Self>) -> Self {
let editor = ModelCell::default();
if let Some(editor_link) = &ctx.props().link {
editor_link.connect(ctx.link().clone());
editor_link.connect(editor.clone());
}

Self {
node_ref: NodeRef::default(),
editor: None,
editor,
}
}

Expand All @@ -78,7 +76,7 @@ impl Component for CodeEditor {
if link != &old_props.link {
// make sure to connect the new link to this component
if let Some(link) = &link {
link.connect(ctx.link().clone());
link.connect(self.editor.clone());
}
}
// changing options requires re-create
Expand All @@ -87,7 +85,7 @@ impl Component for CodeEditor {
}
// change the attached model
if model != &old_props.model {
if let Some(editor) = &self.editor {
if let Some(editor) = &mut *self.editor.borrow_mut() {
match model {
Some(model) => editor.set_model(model),
None => {
Expand All @@ -100,7 +98,7 @@ impl Component for CodeEditor {
if should_render {
// if we're gonna re-create the editor we need to clean up the old one first so
// as not to cause issues
self.editor = None;
self.editor.replace(None);
}

should_render
Expand All @@ -113,7 +111,7 @@ impl Component for CodeEditor {
let props = ctx.props();

debug_assert!(
editor.is_none(),
editor.borrow().is_none(),
"previous editor must be disposed before re-creating"
);

Expand All @@ -138,41 +136,36 @@ impl Component for CodeEditor {
editor.set_model(model)
}

self.editor = Some(editor);
self.editor.replace(Some(editor));
self.emit_editor_created(ctx);
}
}

/// Link to control a [`CodeEditor`].
#[derive(Clone, Debug, Default)]
pub struct CodeEditorLink(Rc<RefCell<Option<Scope<CodeEditor>>>>);
impl CodeEditorLink {
fn new_connected(link: Scope<CodeEditor>) -> Self {
Self(Rc::new(RefCell::new(Some(link))))
}
pub struct CodeEditorLink(RefCell<ModelCell>);

fn connect(&self, link: Scope<CodeEditor>) {
self.0.borrow_mut().replace(link);
impl CodeEditorLink {
pub fn new() -> Self {
Self(RefCell::default())
}

fn with_link<T>(&self, f: impl FnOnce(&Scope<CodeEditor>) -> T) -> Option<T> {
(*self.0.borrow()).as_ref().map(f)
fn new_connected(model_cell: ModelCell) -> Self {
Self(RefCell::new(model_cell))
}

fn with_component<T>(&self, f: impl FnOnce(&CodeEditor) -> T) -> Option<T> {
self.with_link(|link| link.get_component().as_deref().map(f))
.flatten()
fn connect(&self, model_cell: ModelCell) {
self.0.replace(model_cell);
}

/// Get access to the underlying [`CodeEditor`].
/// The return value is `None` if the link isn't connected.
pub fn with_editor<T>(&self, f: impl FnOnce(&CodeEditorModel) -> T) -> Option<T> {
self.with_component(|comp| comp.editor.as_ref().map(f))
.flatten()
self.0.borrow().borrow().as_ref().map(f)
}
}
impl PartialEq for CodeEditorLink {
fn eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.0, &other.0)
Rc::ptr_eq(&self.0.borrow(), &other.0.borrow())
}
}