Skip to content

Commit

Permalink
feat: TinyMCE plugin insert iframe (openedx#427)
Browse files Browse the repository at this point in the history
  • Loading branch information
johnvente authored Feb 16, 2024
1 parent f33a3b5 commit 90d5ac4
Show file tree
Hide file tree
Showing 5 changed files with 618 additions and 1 deletion.
2 changes: 2 additions & 0 deletions src/editors/data/constants/tinyMCE.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export const buttons = StrictDict({
undo: 'undo',
underline: 'underline',
a11ycheck: 'a11ycheck',
embediframe: 'embediframe',
});

export const plugins = listKeyStore([
Expand All @@ -69,6 +70,7 @@ export const plugins = listKeyStore([
'quickbars',
'a11ychecker',
'powerpaste',
'embediframe',
]);

export const textToSpeechIcon = '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M3.5 22C3.08333 22 2.72917 21.8542 2.4375 21.5625C2.14583 21.2708 2 20.9167 2 20.5V3.5C2 3.08333 2.14583 2.72917 2.4375 2.4375C2.72917 2.14583 3.08333 2 3.5 2H13L11.5 3.5H3.5V20.5H15.5V17H17V20.5C17 20.9167 16.8542 21.2708 16.5625 21.5625C16.2708 21.8542 15.9167 22 15.5 22H3.5ZM6 17.75V16.25H13V17.75H6ZM6 14.75V13.25H11V14.75H6ZM15.5 15L11.5 11H8V6H11.5L15.5 2V15ZM17 12.7V4.05C17.9333 4.4 18.6667 5.01667 19.2 5.9C19.7333 6.78333 20 7.65 20 8.5C20 9.35 19.7083 10.1917 19.125 11.025C18.5417 11.8583 17.8333 12.4167 17 12.7ZM17 16.25V14.7C18.1667 14.2833 19.2083 13.5333 20.125 12.45C21.0417 11.3667 21.5 10.05 21.5 8.5C21.5 6.95 21.0417 5.63333 20.125 4.55C19.2083 3.46667 18.1667 2.71667 17 2.3V0.75C18.7 1.2 20.125 2.1375 21.275 3.5625C22.425 4.9875 23 6.63333 23 8.5C23 10.3667 22.425 12.0125 21.275 13.4375C20.125 14.8625 18.7 15.8 17 16.25Z" fill="black"/></svg>';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
function tinyMCEEmbedIframePlugin(editor) {
function openInsertIframeModal() {
const defaultConfig = {
title: 'Insert iframe',
body: {
type: 'tabpanel',
tabs: [
{
title: 'General',
items: [
{
type: 'input',
name: 'source',
label: 'Source URL',
multiline: false,
autofocus: true,
required: true,
},
{
type: 'selectbox',
name: 'sizeType',
label: 'Size',
items: [
{ text: 'Inline Value', value: 'inline' },
{ text: 'Big embed', value: 'big' },
{ text: 'Small embed', value: 'small' },
],
},

{
type: 'sizeinput',
name: 'size',
label: 'Dimensions',
},
],
},
{
title: 'Advanced',
items: [
{
type: 'input',
name: 'name',
label: 'Name',
value: '',
},
{
type: 'input',
name: 'title',
label: 'Title',
value: '',
},
{
type: 'input',
name: 'longDescriptionURL',
label: 'Long description URL',
value: '',
},
{
type: 'checkbox',
name: 'border',
label: 'Show iframe border',
text: 'Border',
checked: false,
},
{
type: 'checkbox',
name: 'scrollbar',
label: 'Enable scrollbar',
text: 'Scrollbar',
checked: false,
},
],
},
],
},
buttons: [
{
type: 'cancel',
name: 'cancel',
text: 'Cancel',
},
{
type: 'submit',
name: 'save',
text: 'Save',
primary: true,
},
],
onChange(api, field) {
const { name } = field;
const data = api.getData();
const { sizeType, ...fields } = data;
const isSizeTypeFiled = name === 'sizeType';
const hasCustomSize = sizeType === 'inline';

if (!hasCustomSize && isSizeTypeFiled) {
const {
body: {
tabs: [generalTab],
},
} = defaultConfig;

generalTab.items = generalTab.items.filter(
(item) => item.type !== 'sizeinput',
);

defaultConfig.initialData = { ...fields, sizeType };
api.redial(defaultConfig);
}

if (hasCustomSize && isSizeTypeFiled) {
const {
body: {
tabs: [generalTab],
},
} = defaultConfig;

const hasSizeInput = generalTab.items.some((item) => item.name === 'size');

if (!hasSizeInput) {
generalTab.items = [
...generalTab.items,
{
type: 'sizeinput',
name: 'size',
label: 'Dimensions',
},
];
}

defaultConfig.initialData = { ...fields, sizeType };
api.redial(defaultConfig);
}
},
onSubmit(api) {
const data = api.getData();
const sizeTypes = {
small: {
height: '100px',
width: '100px',
},
big: {
height: '800px',
width: '800px',
},
};
if (data.source) {
const {
size, sizeType, name, title, longDescriptionURL, border, scrollbar,
} = data;
const { width, height } = sizeTypes[sizeType] || { width: size.width, height: size.height };

const pxRegex = /^\d+px$/;
const widthFormat = pxRegex.test(width) ? width : '300px';
const heightFormat = pxRegex.test(height) ? height : '300px';
const hasScroll = scrollbar ? 'yes' : 'no';

let iframeCode = `<iframe src="${data.source}" width="${widthFormat}" height="${heightFormat}" scrolling="${hasScroll}"`;

if (name) {
iframeCode += ` name="${name}"`;
}

if (title) {
iframeCode += ` title="${title}"`;
}

if (longDescriptionURL) {
iframeCode += ` longdesc="${longDescriptionURL}"`;
}

if (!border) {
iframeCode += 'frameborder="0"';
}

iframeCode += '></iframe>';

iframeCode = `<div class="tiny-pageembed" style="width: ${widthFormat}; height: ${heightFormat}">`
+ `${iframeCode}`
+ '</div>';

editor.insertContent(iframeCode);
}

api.close();
},
};

editor.windowManager.open(defaultConfig);
}

// Register the button
editor.ui.registry.addButton('embediframe', {
text: 'Embed iframe',
onAction: openInsertIframeModal,
});
}

((tinymce) => {
if (tinymce) {
tinymce.PluginManager.add('embediframe', tinyMCEEmbedIframePlugin);
}
})(window.tinymce);

export default tinyMCEEmbedIframePlugin;
Loading

0 comments on commit 90d5ac4

Please sign in to comment.