Listen for click or doubleclick of the widget - ckeditor

Is there a possibility to listen click or doubleclick event on the widget? I have followed the tutorial of creating the inline widget plugin and now I would like to listen for the click or doubleclick event on the widget from the following demo. https://ckeditor.com/docs/ckeditor5/latest/framework/guides/tutorials/implementing-an-inline-widget.html#demo

if you want to listen to click event in the editor, you should use ClickObserver. However, it's not enabled by default, so you should add it.
The code for listening on click on the placeholder element will look like this:
import ClickObserver from '#ckeditor/ckeditor5-engine/src/view/observer/clickobserver';
const view = editor.editing.view;
const viewDocument = view.document;
view.addObserver( ClickObserver );
editor.listenTo( viewDocument, 'click', ( evt, data ) => {
const modelElement = editor.editing.mapper.toModelElement( data.target);
if ( modelElement.name == 'placeholder' ) {
console.log( 'Placeholder has been clicked.' );
}
} );
double click is not enabled by default, but you can create a custom click observer. You just need to extend a generic DomEventObserver class by a native DOM dblclick event.
Here's the code for that:
import DomEventObserver from '#ckeditor/ckeditor5-engine/src/view/observer/domeventobserver';
class DoubleClickObserver extends DomEventObserver {
constructor( view ) {
super( view );
this.domEventType = 'dblclick';
}
onDomEvent( domEvent ) {
this.fire( domEvent.type, domEvent );
}
}
And then use it in the editor:
const view = editor.editing.view;
const viewDocument = view.document;
view.addObserver( DoubleClickObserver );
editor.listenTo( viewDocument, 'dblclick', () => {
console.log( 'Double click fired.' );
} );
Hope this helps you!

Related

Stack react-bootstrap accordian as horizontal

We have requirement where we have some category group which needs to be rendered as accordian and it should look like following;
On expansion, it needs to expand itself and show body. We created separate component which will accept array of string and few helper functions but all of this accordian rendered as vertical on parent component
import { ListGroup, ListGroupItem } from "react-bootstrap";
import { generateUniqueComponentKey } from "../../utils/Helper";
const RenderButtonGroup = ({btnGroups, handleFilterGroupClick, selectedFilterGroup}) => {
console.log('selectedFilterGroup ', selectedFilterGroup)
const renderBtgGroup = () => {
if (btnGroups){
let btnItems = btnGroups && btnGroups.map(item => {
let myKey = generateUniqueComponentKey();
return (
<>
<ListGroupItem
eventKey={myKey}
key={myKey}
variant="warning"
onClick={handleFilterGroupClick}
active={selectedFilterGroup[0] === item ? true : false}
>{item}</ListGroupItem>
</>
)
})
return(
<ListGroup>{btnItems}</ListGroup>
)
}
}
return (
<div className="d-flex">
{renderBtgGroup()}
</div>
)
}
export default RenderButtonGroup;
Not CSS expert so don't know how to achieve this. Thanks in advance
Use the Grid component with 3 columns: https://react-bootstrap.github.io/layout/grid/

How can I disable the right click event or how can I hide the context menu on the Autodesk Forge Viewer

How can ı disable right click event on autodesk forge viewer. I want to hide the context menu.Does anyone have an idea about this?
if you just want to disable context menu, just set null to setContextMenu method.
viewer.setContextMenu(null);
if you would like to show context menu again, you just preserve context and set it.
// you need to get current context menu before calling setsetContextMenu(null)
var contextMenu = viewer.contextmenu;
viewer.setContextMenu(null);
....
//set preserved contextMenu inf you want to show it again.
viewer.setContextMenu(contextMenu);
If you want to hide context menu use this:
viewer.contextMenu.hide();
If you want to remove context menu items, and add your own context menu use this:
You can remove default Autodesk Forge Viewer Context menu by this.viewer.unregisterContextMenuCallback('Autodesk.Dasher.ContextMenuExtension');
And you can create on your own by
this.viewer.registerContextMenuCallback('Autodesk.Dasher.ContextMenuExtension',
(menu, status) => {}
REFERENCE : HOW TO ADD CUSTOM CONTEXT IN FORGE VIEWER.
Here is sample class for removing and adding your own custom context menu in Forge Viewer:
export default class ContextMenuExtension extends Autodesk.Viewing.Extension {
constructor(viewer: Autodesk.Viewing.Private.GuiViewer3D, options: any) {
super(viewer, options);
}
load(): boolean {
console.log('ContextMenuExtension loaded');
let self = this;
this.viewer.registerContextMenuCallback(
'Autodesk.Dasher.ContextMenuExtension',
(menu, status) => {
// Remove all existing menu items
while (menu.length > 0) {
menu.pop();
}
// Add our new item if an object is selected
if (status.hasSelected) {
menu.push({
title: 'Send to HoloLens',
target: function(): void {
let messageSpecs = {
'msgTitleKey': 'Sent to HoloLens',
'messageKey': 'Sent to HoloLens',
'messageDefaultValue': 'This object has been sent to HoloLens for viewing.',
};
Autodesk.Viewing.Private.HudMessage.displayMessage(
self.viewer.container, messageSpecs
);
setTimeout(
() => {
Autodesk.Viewing.Private.HudMessage.dismiss();
}, 10000
);
},
});
}
}
);
return true;
}
unload(): boolean {
console.log('ContextMenuExtension unloaded');
this.viewer.unregisterContextMenuCallback('Autodesk.Dasher.ContextMenuExtension');
return true;
}
}

AsyncStorage - error (React Native)

I have a problem with persisting user's data in a react-native application I am currently working on with my team. We have an app with a list of events and when you click on an event, it opens up the event details page and shows a menu to choose yes/no/maybe (attendance menu) which the user can toggle to select whether or not they are attending the event. Our code looks like this:
import React from 'react';
import { AsyncStorage, Text, View, StyleSheet, Picker } from 'react-native';
export class PickerMenu extends React.Component {
state = { choice: '' }
componentDidMount = () => AsyncStorage.getItem('choice').then((value) => this.setState({ 'choice': value }))
setName = (value) => {
AsyncStorage.setItem('choice', value);
this.setState({ 'choice': value });
}
render() {
return (
<View>
<Picker selectedValue = {this.state.choice} onValueChange = {this.setName} itemStyle = {styles.item}>
<Picker.Item label = "Yes" value = "yes" />
<Picker.Item label = "Maybe" value = "maybe" />
<Picker.Item label = "No" value = "no" />
</Picker>
</View>
);
}
}
We are running the build on Xcode. We want the user's choice to still be present after the page has been refreshed or the app has closed - this works HOWEVER,the choice that the user has selected, stays the same for every event. E.g. if they select 'Maybe' for event 1, the selection 'maybe' is highlighted for every other event in our app.
We had an idea of grabbing unique event IDs and implementing this into the AsyncStorage function but we are unsure of how to do this.
Any help will be great and much appreciated - thank-you!
In this case you need to use the async/await to store at the async storage
like this:
setName = async (value) => {
await AsyncStorage.setItem('choice', value);
this.setState({ 'choice': value });
}
Hope i have helped!
Some useful links for you:
https://facebook.github.io/react-native/docs/asyncstorage.html

Complex navigation in React Native using react-navigation and Redux

I have the following navigation structure in my React Native app:
StackNavigator configured with 3 routes:
Splash screen (React Component)
StackNavigator for my login flow
DrawerNavigator for my core app screens.
The DrawerNavigator has some dynamic multiple routes, but also one static route which is another StackNavigator.
Everything seems to be working as expected:
The store is being updated accordingly.
Navigation between screen works.
Go back between screen works when configured within each component, with the following command:
this.props.navigation.goBack();
My question is - is there a way for me to handle back button on Android globally? Currently when I click on the back button, nothing happens (due to the fact I'm using Redux). Should I handle the back button in each component or is there a way of doing it using Redux?
A bit late, but there is a way to handle this with redux. In your index.js file where you create your store you can make export a class and add a componentWillMount call to handle dispatching a call to your redux actions. Just remember to import the actions you need above.
const store = configureStore();
export default class Index extends Component {
componentWillMount = () => {
BackHandler.addEventListener('hardwareBackPress', () => {
const { nav: { routes } } = store.getState();
const currentRouteName = routes[routes.length-1].routeName;
if (currentRouteName === 'EditCoupleProfile') {
store.dispatch(editCoupleActions.navigateBack())
} else if ( currentRouteName === 'EditInterests' ) {
store.dispatch(interestsActions.navigateBack())
} else {
store.dispatch(popFromStack());
}
return true;
})
};
componentWillUnmount = () => {
BackHandler.removeEventListener('hardwareBackPress');
};
render() {
return (
<Provider store={store}>
<AppWithNavigation />
</Provider>
);
}
}

How to get data from CKEditor 5 instance

I know that for CKEditor 4, you can get the textarea data like this:
var content = CKEDITOR.instances['comment'].getData();
How is this done for CKEditor 5?
You can find the answer in the Basic API guide.
Basically, in CKEditor 5 there's no single global editors repository (like the old CKEDITOR.instances global variable). This means that you need to keep the reference to the editor that you created and use that reference once you'll want to retrieve the data:
ClassicEditor
.create( document.querySelector( '#editor' ) )
.then( editor => {
editor.getData(); // -> '<p>Foo!</p>'
} )
.catch( error => {
console.error( error );
} );
If you need to retrieve the data on some other occasions (who would read it just after initializing the editor, right? ;)), then save the reference to the editor in some shared object of your application's state or some variable in the scope:
let theEditor;
ClassicEditor
.create( document.querySelector( '#editor' ) )
.then( editor => {
theEditor = editor; // Save for later use.
} )
.catch( error => {
console.error( error );
} );
function getDataFromTheEditor() {
return theEditor.getData();
}
See this JSFiddle: https://jsfiddle.net/2h2rq5u2/
EDIT: If you need to manage more than one editor instance, see CKEDITOR 5 get editor instances.
Declare a global variable and then use editor.getData(). Something like this:
var editor;
ClassicEditor
.create(document.querySelector('#editor'))
.then(editor => {
editor=editor;
})
.catch(error => {
console.error(error);
});
Then, in your event handler, this should work:
editor.getData();
I ran into what felt like a unique situation where I was loading multiple instances of CKeditor5 on a page but I also had features to dynamically add/remove/rearrange text areas that had editors applied to them.
Creating an array that contained all the instances was manageable but also a bit more complicated to keep track of when adding/removing/rearrange editor instances.
I instead decided to obtain the innerHTML of the editor instances by selecting all .ck-editor__editable classes and iterating over them to check the content.
document.querySelector("button[type='submit']").addEventListener('click', (event) => {
event.preventDefault();
const domEditableElements = document.querySelectorAll('.ck-editor__editable');
for (let i = 0; i < domEditableElements.length; ++i) {
let elementData = domEditableElements[i].innerHTML
if (elementData === '<p><br data-cke-filler="true"></p>') {
console.log(`Field ${i} is empty`);
}
}
});
Console logging indicated that ck-editor stored <p><br data-cke-filler="true"></p> in blank fields.

Resources