Skip to content
Merged
Show file tree
Hide file tree
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.example.gutenbergkit

import android.app.AlertDialog
import android.content.Context
import android.content.Intent
import android.content.pm.ApplicationInfo
Expand Down Expand Up @@ -311,6 +312,22 @@ fun EditorScreen(
}
}
})
setAutocompleterTriggeredListener(object : GutenbergView.AutocompleterTriggeredListener {
override fun onAutocompleterTriggered(type: String) {
val suggestions = when (type) {
"at-symbol" -> arrayOf("alice", "bob", "charlie")
"plus-symbol" -> arrayOf("photoblog", "traveldiaries", "dailydev")
else -> return
}
AlertDialog.Builder(context)
.setTitle("Select a suggestion")
.setItems(suggestions) { _, which ->
appendTextAtCursor(suggestions[which] + " ")
}
.setNegativeButton("Cancel", null)
.show()
}
})
// Demo app has no persistence layer, so return null.
// In a real app, return the persisted title and content from autosave.
setLatestContentProvider(object : GutenbergView.LatestContentProvider {
Expand Down
19 changes: 18 additions & 1 deletion ios/Demo-iOS/Sources/Views/EditorView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,24 @@ private struct _EditorView: UIViewControllerRepresentable {
}

func editor(_ viewController: EditorViewController, didTriggerAutocompleter type: String) {
// No-op for demo
let suggestions: [String]
switch type {
case "at-symbol":
suggestions = ["alice", "bob", "charlie"]
case "plus-symbol":
suggestions = ["photoblog", "traveldiaries", "dailydev"]
default:
return
}

let alert = UIAlertController(title: "Select a suggestion", message: nil, preferredStyle: .actionSheet)
for suggestion in suggestions {
alert.addAction(UIAlertAction(title: suggestion, style: .default) { _ in
viewController.appendTextAtCursor(suggestion + " ")
})
}
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
viewController.present(alert, animated: true)
}

func editor(_ viewController: EditorViewController, didOpenModalDialog dialogType: String) {
Expand Down
43 changes: 43 additions & 0 deletions src/components/editor/test/use-host-bridge.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,49 @@ describe( 'useHostBridge', () => {
} );
} );

it( 'appendTextAtCursor preserves existing content when block attribute is a RichTextData object', () => {
const existingContent = 'Existing block content @';
const richTextData = {
toString: () => existingContent,
valueOf: () => existingContent,
toHTMLString: () => existingContent,
};

mockGetSelectedBlockClientId.mockReturnValue( 'block-1' );
mockGetBlock.mockReturnValue( {
name: 'core/paragraph',
clientId: 'block-1',
attributes: { content: richTextData },
} );
getBlockType.mockReturnValue( {
attributes: { content: { type: 'string' } },
} );
mockGetSelectionStart.mockReturnValue( {
clientId: 'block-1',
attributeKey: 'content',
offset: existingContent.length,
} );
mockGetSelectionEnd.mockReturnValue( {
clientId: 'block-1',
attributeKey: 'content',
offset: existingContent.length,
} );

renderHook( () =>
useHostBridge( defaultPost, editorRef, markBridgeReady )
);

window.editor.appendTextAtCursor( 'username ' );

// The block should contain the original content plus the
// appended text — not just the appended text alone.
expect( mockUpdateBlock ).toHaveBeenCalledWith( 'block-1', {
attributes: expect.objectContaining( {
content: 'Existing block content @username ',
} ),
} );
} );

it( 'appendTextAtCursor returns false when no block is selected', () => {
mockGetSelectedBlockClientId.mockReturnValue( null );

Expand Down
4 changes: 1 addition & 3 deletions src/components/editor/use-host-bridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,7 @@ export function useHostBridge( post, editorRef, markBridgeReady ) {
return false;
}

const blockContent = normalizeAttribute(
block.attributes?.content
);
const blockContent = block.attributes?.content || '';
const currentValue = create( { html: blockContent } );
const selectionStart = getSelectionStart();
const selectionEnd = getSelectionEnd();
Expand Down
Loading