Commit c33846a6 authored by Gaurav Kapoor's avatar Gaurav Kapoor Committed by Gaurav Kapoor
Browse files

Issue #3251961 by gaurav.kapoor: Port to CKEditor 5

parent 9af91a22
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -2,6 +2,6 @@
 * @module tweetable-text
 */

export { default as TweetableText } from "./tweetabletext";
export { default as TweetableTextEditing } from "./tweetabletextediting";
export { default as TweetableTextUI } from "./tweetabletextui";
export { default as TweetableText } from './tweetabletext';
export { default as TweetableTextEditing } from './tweetabletextediting';
export { default as TweetableTextUI } from './tweetabletextui';
+4 −4
Original line number Diff line number Diff line
@@ -2,10 +2,10 @@
 * @module tweetable-text
 */

import Plugin from "@ckeditor/ckeditor5-core/src/plugin";
import { Plugin } from 'ckeditor5/src/core';

import TweetableTextEditing from "./tweetabletextediting";
import TweetableTextUI from "./tweetabletextui";
import TweetableTextEditing from './tweetabletextediting';
import TweetableTextUI from './tweetabletextui';

/**
 * The tweetable text plugin.
@@ -29,6 +29,6 @@ export default class TweetableText extends Plugin {
     * @inheritDoc
     */
	static get pluginName() {
		return "TweetableText";
		return 'TweetableText';
	}
}
+27 −10
Original line number Diff line number Diff line
@@ -2,26 +2,43 @@
 * @module tweetable-text
 */

import Command from "@ckeditor/ckeditor5-core/src/command";
import { Command } from 'ckeditor5/src/core';

/**
 * The insert tweetable text command.
 *
 * The command is registered by the {@link module:tweetable-text/tweetabletextediting~TweetableTextEditing} as `'tweetableText'`.
 *
 * To insert tweetable text at the current selection, execute the command, specify the display text and tweetable text value:
 *
 *		editor.execute( 'tweetableText', 'My display text', 'My tweeted text' );
 *
 * @extends module:core/command~Command
 */

export default class TweetableTextCommand extends Command {
	execute({ value }) {
	/**
	 * Executes the command, which:
	 *
	 * * inserts tweetable text and puts the selection around it.
	 *
	 * @fires execute
	 * @param {String} displayText The display text.
	 * @param {String} tweetableTextVal The text which will be tweeted.
	 */
	execute( displayText, tweetableTextVal ) {
		const editor = this.editor;
		const selection = editor.model.document.selection;

		editor.model.change(writer => {
			// Create a <placeholder> elment with the "name" attribute (and all the selection attributes)...
			const tweetableText = writer.createElement("tweetableText", {
			const tweetableText = writer.createElement('tweetableText', {
				...Object.fromEntries(selection.getAttributes()),
				displayText: value.displayText,
				tweetableTextVal: value.tweetableTextVal
				displayText: displayText,
				tweetableTextVal: tweetableTextVal
			});

			// ... and insert it into the document.
			editor.model.insertContent( tweetableText );

			// Put the selection on the inserted element.
			writer.setSelection(tweetableText, "on");
			writer.setSelection( tweetableText, 'on' );
		});
	}
}
+47 −44
Original line number Diff line number Diff line
@@ -2,100 +2,103 @@
 * @module tweetable-text
 */

import Plugin from "@ckeditor/ckeditor5-core/src/plugin";
import { Plugin } from 'ckeditor5/src/core';

import TweetableTextCommand from "./tweetabletextcommand";
import { toWidget, viewToModelPositionOutsideModelElement } from "@ckeditor/ckeditor5-widget/src/utils";
import Widget from "@ckeditor/ckeditor5-widget/src/widget";
import TweetableTextCommand from './tweetabletextcommand';
import { toWidget, viewToModelPositionOutsideModelElement } from 'ckeditor5/src/widget';
import { Widget } from 'ckeditor5/src/widget';

/**
 * The tweetable text editing feature.
 *
 * @extends module:core/plugin~Plugin
 */
export default class TweetableTextEditing extends Plugin {
	/**
	 * @inheritDoc
	 */
	static get requires() {
		return [ Widget ];
	}

	/**
	 * @inheritDoc
	 */
	init() {
		this._defineSchema();
		this._defineConverters();
		this.editor.commands.add("tweetableText", new TweetableTextCommand(this.editor));
		this.editor.commands.add('tweetableText', new TweetableTextCommand(this.editor));
		this.editor.editing.mapper.on(
			"viewToModelPosition",
			viewToModelPositionOutsideModelElement(this.editor.model, viewElement => viewElement.hasClass("tweetableText"))
			'viewToModelPosition',
			viewToModelPositionOutsideModelElement(this.editor.model, viewElement => viewElement.hasClass('tweetableText'))
		);
	}

	/**
	 * Defines schema for the plugin.
	 */
	_defineSchema() {
		const schema = this.editor.model.schema;

		schema.register("tweetableText", {
			// Allow wherever text is allowed:
			allowWhere: "$text",

			// The placeholder will act as an inline node:
		schema.register('tweetableText', {
			allowWhere: '$text',
			isInline: true,

			// The inline widget is self-contained so it cannot be split by the caret and can be selected:
			isObject: true,

			// The inline widget can have the same attributes as text (for example linkHref, bold).
			allowAttributesOf: "$text",

			// The placeholder can have many types, like date, name, surname, etc:
			allowAttributes: ["displayText", "tweetableTextVal"]
			allowAttributesOf: '$text',
			allowAttributes: [ 'displayText', 'tweetableTextVal' ]
		});
	}

	_defineConverters() {                                                      // ADDED
	/**
	 * Defines converters for the plugin.
	 */
	_defineConverters() {
		const conversion = this.editor.conversion;

		conversion.for("upcast").elementToElement({
		conversion.for('upcast').elementToElement({
			view: {
				name: "span",
				classes: ["tweetableText"]
				name: 'span',
				classes: [ 'tweetableText' ]
			},
			model: (viewElement, { writer: modelWriter }) => {
				// Extract the "name" from "{name}".
				const displayText = viewElement.getChild(0).data.slice(1, -1);
				const tweetableTextVal = viewElement.getChild(0).data.slice(1, -1);

				return modelWriter.createElement("tweetableText", { displayText, tweetableTextVal });
				return modelWriter.createElement('tweetableText', { displayText, tweetableTextVal });
			}
		});

		conversion.for("editingDowncast").elementToElement({
			model: "tweetableText",
		conversion.for('editingDowncast').elementToElement({
			model: 'tweetableText',
			view: (modelItem, { writer: viewWriter }) => {
				const widgetElement = createTweetableTextView(modelItem, viewWriter);

				// Enable widget handling on a placeholder element inside the editing view.
				return toWidget(widgetElement, viewWriter);
			}
		});

		conversion.for("dataDowncast").elementToElement({
			model: "tweetableText",
		conversion.for('dataDowncast').elementToElement({
			model: 'tweetableText',
			view: (modelItem, { writer: viewWriter }) => createTweetableTextView(modelItem, viewWriter)
		});

		// Helper method for both downcast converters.
		function createTweetableTextView(modelItem, viewWriter) {
			const displayText = modelItem.getAttribute("displayText");
			const tweetableTextVal = modelItem.getAttribute("tweetableTextVal");
			const displayText = modelItem.getAttribute('displayText');
			const tweetableTextVal = modelItem.getAttribute('tweetableTextVal');

			const tweetableTextView = viewWriter.createContainerElement("span", {
				class: "tweetableText"
			const tweetableTextView = viewWriter.createContainerElement('span', {
				class: 'tweetableText'
			}, {
				isAllowedInsideAttributeElement: true
			});

			// Insert the placeholder name (as a text).
			const innerText = viewWriter.createText("{" + displayText + tweetableTextVal + "}");
			viewWriter.insert(viewWriter.createPositionAt(tweetableTextView, 0), innerText);

			// const linkText = 'Gaurav';
			// const linkUrl = 'https://twitter.com/test';
			// Logic to convert input into a tweetable text.
			const twitterBaseUrl = 'http://twitter.com/intent/tweet?';
			const encodedValue = encodeURI( tweetableTextVal );
			const linkUrl = twitterBaseUrl + 'text=' + encodedValue;

			// const insertPosition = editor.model.document.selection.getFirstPosition();
			// writer.insertText(linkText, { linkHref: linkUrl }, insertPosition);
			const innerText = viewWriter.createText(displayText, { linkHref: linkUrl });
			viewWriter.insert(viewWriter.createPositionAt(tweetableTextView, 0), innerText);

			return tweetableTextView;
		}
+37 −24
Original line number Diff line number Diff line
@@ -2,21 +2,28 @@
 * @module tweetable-text
 */

import Plugin from "@ckeditor/ckeditor5-core/src/plugin";
import { createDropdown } from "@ckeditor/ckeditor5-ui/src/dropdown/utils";
import TweetableTextFormView from "./ui/tweetabletextformview";
import tweetableTextIcon from "../theme/icons/tweetableText.svg";

import { Plugin } from 'ckeditor5/src/core';
import { createDropdown } from 'ckeditor5/src/ui';
import TweetableTextFormView from './ui/tweetabletextformview';
import tweetableTextIcon from '../theme/icons/tweetableText.svg';

/**
 * The tweetable text UI plugin.
 *
 * @extends module:core/plugin~Plugin
 */
export default class TweetableTextUI extends Plugin {
    /**
     * @inheritDoc
     */
	init() {
		const editor = this.editor;

		editor.ui.componentFactory.add("tweetableText", locale => {
		editor.ui.componentFactory.add('tweetableText', locale => {
			const dropdownView = createDropdown(locale);

			const tweetableTextForm = new TweetableTextFormView(getFormValidators(editor.t), editor.locale);
			const command = editor.commands.get("tweetableText");
			const command = editor.commands.get('tweetableText');

			this._setUpDropdown(dropdownView, tweetableTextForm, command, editor);
			this._setUpForm(dropdownView, tweetableTextForm, command);
@@ -25,38 +32,38 @@ export default class TweetableTextUI extends Plugin {
		});
	}

    /**
     * Setup dropdown for the plugin.
     */
	_setUpDropdown(dropdown, form, command) {
		const editor = this.editor;
		const button = dropdown.buttonView;

		dropdown.bind("isEnabled").to(command);
		dropdown.bind('isEnabled').to(command);
		dropdown.panelView.children.add(form);

		button.set({
			label: "Tweetable Text",
			label: 'Tweetable Text',
			icon: tweetableTextIcon,
			tooltip: true
		});

		button.on("open", () => {
		button.on('open', () => {
			editor.editing.view.focus();
			form.disableCssTransitions();
			console.log(command);
			form.displayText = command.value.displayText || "";
			form.tweetableTextVal = command.value.tweetableTextVal || "";
			// form.urlInputView.fieldView.select();
			form.focus();
			form.enableCssTransitions();
		}, { priority: "low" });
		}, { priority: 'low' });

		dropdown.on("submit", () => {
		dropdown.on('submit', () => {
			if (form.isValid()) {
				editor.execute("tweetableText", form.displayText, form.tweetableTextVal);
				editor.execute('tweetableText', form.displayText, form.tweetableTextVal);
				closeUI();
			}
		});

		dropdown.on("change:isOpen", () => form.resetFormStatus());
		dropdown.on("cancel", () => closeUI());
		dropdown.on('change:isOpen', () => form.resetFormStatus());
		dropdown.on('cancel', () => closeUI());

		function closeUI() {
			editor.editing.view.focus();
@@ -64,25 +71,31 @@ export default class TweetableTextUI extends Plugin {
		}
	}

    /**
     * Setup form for the plugin inputs.
     */
	_setUpForm(dropdown, form, command) {
		form.delegate("submit", "cancel").to(dropdown);
		form.displayTextInputView.bind("value").to(command, "value");
		form.delegate('submit', 'cancel').to(dropdown);
		form.displayTextInputView.bind('value').to(command, 'value');

		// Form elements should be read-only when corresponding commands are disabled.
		form.displayTextInputView.bind("isReadOnly").to(command, "isEnabled", value => !value);
		form.displayTextInputView.bind('isReadOnly').to(command, 'isEnabled', value => !value);
	}
}

/**
 * Provide validators for the plugin form.
 */
function getFormValidators(t) {
	return [
		form => {
			if (!form.displayText.length) {
				return t("The display text must not be empty.");
				return t('The display text must not be empty.');
			}
		},
		form => {
			if (!form.tweetableTextVal.length) {
				return t("The tweetable text must not be empty.");
				return t('The tweetable text must not be empty.');
			}
		}
	];
Loading