8

Creando botones propios para Pulse Editor

21837Puntos

hace 7 años

Una de las características de Pulse Editor es que podemos configurar cuáles botones de todos los que nos provee el editor queremos usar. Pero no solo podemos usar esos botones, también podemos crear botones propios.

Si ya vieron como implementar Pulse Editor pueden luego crear botones propios. Vamos a ver cómo hacer esto.

Botón base

El editor nos provee de un editor base que podemos usar. Este es un simple wrapper de la etiqueta <button /> para colocar siempre ciertos atributos. Pueden acceder a este componente simplemente con un import.

import { Base } from 'pulse-editor/buttons`

Luego ya pueden hacer render y pasarle lo que quieran, al final del día es un botón, lo únicos props que deben pasar sí o sí son:

  • children => los componentes hijos, pueden ser lo que quieran.
  • name => el nombre del botón, en el componente <Bold /> este es bold, así que pueden darse una idea.
  • onClick => la función que se va a ejecutar cuando el usuario haga click sobre el botón.

El botón además define un className por defecto llamado PulseEditor-button (que pueden cambiar si pasan su propio className), define disabled como false (también sobre escribible) y fuerza que el type sea button. Porque por defecto las etiquetas <button /> son de tipo submit. Así evitamos que cualquier botón del editor envíe un posible formulario que envuelva al editor.

Creando el botón

Vamos a crear un botón para la aplicación de escritorio Pulse. Este botón va a encargarse de crear un nuevo archivo en el editor. Como Pulse usa Next.js no necesitamos importar React, pero como vamos a crear un componente de clase entonces sí vamos a importar Component.

import { Component } from'react';

Luego importamos el botón base como vimos antes y vamos a iniciar a crear nuestro componente.

import { Component } from'react'import { Base } from'pulse-editor/buttons'exportdefaultclassNewButtonextendsComponent{
	render = () => (
		<BaseonClick={this.handleClick}name='new'><spantitle='New file [CMD+N]'>
				New
			</span></Base>
	)
}

Con eso nuestro botón ya hace render de un botón normal de nuestro editor y definimos dos cosas extras sobre este: la primera es que tenemos que crear un handleClick y la segunda es que vamos a usar el atajo de teclado cmd+n en Mac o ctrl+n en Windows y Linux.

Definiendo el atajo de teclado

Vamos primero a definir nuestro atajo de teclado. Para eso necesitamos acceder a dos funciones desde el contexto de React a los cuales vamos a tener acceso siempre que nuestro botón se renderice dentro del componente <Editor />.

import { Component } from'react'import { Base } from'pulse-editor/buttons'import { func } from'prop-types'// importamos el prop-type func para definir funcionesexportdefaultclassNewButtonextendsComponent{
	static contextTypes = {
		setShortcut: func.isRequired, // esta función nos permite definir un shortcut
		removeShortcut: func.isRequired, // esta función nos permite quitar un shortcut
	}

	render = () => (
		<BaseonClick={this.handleClick}name='new'><spantitle='New file [CMD+N]'>
				New
			</span></Base>
	)
}

Con eso tenemos acceso a la función. Ahora vamos a usar estas funciones, la primera se usa en componentDidMount para agregar nuestro atajo de teclado y la segunda se usa en componentWillUnmount cuando el componente se vaya a desmontar.

import { Component } from'react'import { Base } from'pulse-editor/buttons'import { func } from'prop-types'import isMac from'pulse-editor/built/utils/is-mac'// importamos un util interno de pulse-editor para saber si estamos en MacexportdefaultclassNewButtonextendsComponent{
	static contextTypes = {
		setShortcut: func.isRequired,
		removeShortcut: func.isRequired,
	}

	componentDidMount() {
		this.context.setShortcut({
			ctrlKey: !isMac(), // si no estamos en Mac usamos la tecla control
			metaKey: isMac(), // si estamos en Mac usamos la tecla meta (command)
			altKey: false, // no vamos a usar la tecla alt
			shiftKey: false, // no vamos a usar la tecla shift
			keyName: 'n', // vamos a usar la tecla N (cmd+n o ctrl+n)
			updater: selected => selected, // nuestra función updater (más abajo vemos que es)
			handler: event => event.selection, // nuestro función handler (más abajo vemos que es)
		})
	}

	componentWillUnmount() {
		// eliminamos el atajo de teclado que usa la tecla N al desmontar el componentethis.context.removeShortcut({ keyName: 'n' })
	}

	render = () => (
		<BaseonClick={this.handleClick}name='new'><spantitle='New file [CMD+N]'>
				New
			</span></Base>
	)
}

Así configuramos atajos de teclados. Como vemos al momento de definir uno indicamos que atajo se va a usar, si vamos a usar las teclas ctrl, meta, alt y shift y otra tecla. Le tecla meta puede significar cmd (command) en Mac o win (windows) en teclados no-mac en Windows y Linux.

Luego definimos dos funciones, updater y handler. Esta es probablemente la parte más complicada. La función updater recibe los siguientes datos:

  • selected => el texto seleccionado por el usuario al momento de ejecutarse updater
  • value => el valor completo actual del editor
  • selection => un objeto que nos indica la posición de selected dentro de value

Esta función updater devuelve un nuevo string que sobreescribe selected dentro de value.

Por ejemplo si tenemos el texto hola como value y ol como selected entonces el objeto selection va a venir con { start: 1, end: 3 }. Si updater devuelve **ol** entonces el valor completo nuevo va a ser h**ol**a.

La función handler se ejecuta luego de aplicar updater y actualizar el contenido del editor. Esto nos permite modificar la posición del cursor del usuario (para cambiar el texto seleccionado) o hacer cualquier cosa, por ejemplo mandar eventos de analytics.

Esta función debe devolver un objeto similar a selection, con las propiedades start y end y recibe un objeto event con las siguientes propiedades.

  • value => el valor completo actualizado
  • field => el elemento del DOM del textarea
  • updated => el valor generado por la función updater
  • selected => el texto seleccionado original
  • selection => la posición del selected dentro del valor original
  • Todas las propiedades de un evento nativo del DOM

Luego de convertir ol a **ol** podemos decidir entre mantener seleccionado ol o **ol**, para el primero caso handler debe devolver { start: 3, end: 5 } y para el segundo { start: 1, end: 7 }.

Programando la funcionalidad

Vamos a programar la funcionalidad propia del botón, ya que hasta ahora el botón no hace nada de verdad.

import { Component } from'react'import { Base } from'pulse-editor/buttons'import { ipcRenderer } from'electron'// módulo para de Electron para comunicarse con el proceso principalimport { func } from'prop-types'import isMac from'pulse-editor/built/utils/is-mac'import Icon from'react-icons/lib/fa/file-o'// componente de ícono que renderiza un SVG directoexportdefaultclassNewButtonextendsComponent{
	static contextTypes = {
		setShortcut: func.isRequired,
		setFileName: func.isRequired, // función propia de la aplicación de escritorio Pulse para definir el nombre del archivo abierto actualmente
		removeShortcut: func.isRequired,
		writeValue: func.isRequired // función de Pulse Editor para sobreescribir el valor actual del editor
	}

	componentDidMount() {
		 // escuchamos el evento `new-file` que llega desde el proceso main
		ipcRenderer.on('new-file', this.createFile)
		this.context.setShortcut({
			ctrlKey: !isMac(),
			metaKey: isMac(),
			altKey: false,
			shiftKey: false,
			keyName: 'n',
			updater: selected => selected,
			handler: event => event.selection,
		})
	}

	componentWillUnmount() {
		// dejamos de escuchar el evento `new-file` que llega desde el proceso main
		ipcRenderer.removeListener('new-file', this.createFile)
		this.context.removeShortcut({ keyName: 'n' })
	}

	createFile = () => {
		// cuando creamos un nuevo archivo// limpiamos el nombre del archivo actual de la aplicación de escritoriothis.context.setFileName(undefined)
		// cambiamos el valor actual del editor a un string vacíothis.context.writeValue({ target: { value: '' } })
	}

	handleClick = () => this.createFile() // cuando se haga click ejecutamos la función `createFile`

	render = () => (
		<BaseonClick={this.handleClick}name='new'><spantitle='New file [CMD+N]'>
				New
			</span></Base>
	)
}

Ese es el botón completo, la funcionalidad principal del editor está definida en createFile, en la que limpiamos el nombre de archivo y el valor actual del editor. La razón de limpiar el nombre de archivo es porque en nuestra aplicación de escritorio si abrimos un archivo o guardamos uno mantenemos la ruta completa del archivo para poder volver a guardarlo en el mismo lugar. Y vaciamos el valor del editor para limpiarlo.

Luego tenemos una conexión con el proceso main de Electron para enterarnos cuando este nos pida crear un nuevo archivo.

Implementando nuestro botón

Con lo que hicimos ya tenemos nuestro botón programado. Ahora para usarlo es tan simple como renderizarlo dentro del componente <Editor />.

import { Component } from'react'import { Editor, ButtonBar, ButtonGroup, Field, Preview, EmojiBar } from'pulse-editor'import { Bold, Italic, Underline } from'pulse-editor/buttons'import Head from'next/head'// importamos nuestro botónimport New from'../components/buttons/new-button.js'exportdefault () => (
	<Editor>
		<Head>
			<link
				rel='stylesheet'
				href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css'
			/>
			<link
				rel='stylesheet'
				href='https://raw.githubusercontent.com/PlatziDev/pulse-editor/master/examples/full-usage/static/styles.css'
			/>
		</Head>
		<ButtonBar>
			<ButtonGroup>
				<Bold><i className="fa fa-bold" /></Bold>
				<Italic><i className="fa fa-italic" /></Italic>
				<Underline><i className="fa fa-underline" /></Underline>
			</ButtonGroup>
			<ButtonGroup>
				<New /> {/* renderizamos nuestro botón */}
			</ButtonGroup>
		</ButtonBar>
		<div className="PulseEditor-content">
			<Field>
			<Preview />
		</div>
		<EmojiBar />
	</Editor>
)

Como se ve, usar un botón personalizado es tan simple como cualquier otro botón, con eso pueden empezar a crear botones propios para cualquier funcionalidad extra que deseen incluir.

Palabras finales

Crear un botón puede parecer complicado pero en general depende de que tantas cosas queremos hacer con nuestro botón, un botón de bold es super simple, un botón como este que se conecta con Electron es claramente mucho más complejo y así y todo no es tanto código al final del día.

Sergio Daniel
Sergio Daniel
sergiodxa

21837Puntos

hace 7 años

Todas sus entradas
Escribe tu comentario
+ 2
Ordenar por:
1

Many, many thanks for sharing this post with us, and I really do hope that you will share more of your posts with us in the future, so please do not stop sharing, and I wish you the best of luck with your job… teknopediia

1

It is great to see that some people still put in an effort into managing their website. I’ll be sure to check back again real soon

1

Good job. Excellent article, and your website is quite user-friendly. Your website and post are fantastic. I own a fashion blog. This website contains examples of my work.

1
4Puntos

It’s really an amazing blog great to get the relatives information through your site for all the people, I appreciate your efforts. Thank you for sharing your knowledge and experience with me https://letslearnirish.com/

1
4Puntos

Wow! Such an amazing and helpful post this is. I really really love it. It’s so good and so awesome. I am just amazed. I hope that you continue to do your work like this in the future also. https://sydneyheadshot.net/

1

Many of his outfits are already popular and well-liked by the public. The Rupert Friend Blue Coat from Anatomy of a Scandal Rupert Friend Coat has gotten the most attention from the crowd. This coat has a comfortable inner viscose lining and is composed of a superior wool blend.

1

Thanks for sharing this great and informative content good work keep it up

1
3Puntos

brawl stars hack download
Gaming is fun and an activity that involves people from every walk of life. It works perfectly well in uniting people, even those living in different parts of the world through online gaming. Although not all games can be played online, you can still enjoy a perfect moment with your friends during your free time.

0

Do you have thoughts on changing Anchor Replacement to a pulse editor version? I have tried the code with my own installed operating system which is raspberry and it just doesn’t run. How else shall do this?