@instructure/canvas-rce
Version:
A component wrapping Canvas's usage of Tinymce
324 lines (322 loc) • 17.6 kB
JavaScript
/*
* Copyright (C) 2021 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
function elemsToTinyStringConfig(list) {
return Object.entries(list).map(pair => {
const [tag, attrs] = pair;
if (attrs.length === 0) {
return tag;
} else {
const attrStr = attrs.map(attr => {
if (typeof attr === 'string') {
return attr;
} else if (typeof attr === 'object') {
return Object.entries(attr).map(([key, value]) => `${key}=${value}`);
}
}).join('|');
return `${tag}[${attrStr}]`;
}
}).join();
}
const defaultTinymceConfig = {
// ============================================================================
// Values in this section have acceptable defaults which you may want
// to override (though you really should provide content_css)
// ============================================================================
auto_focus: false,
// any values provided (in an array) will be merged into the standard then sorted
// you provide the translations
block_formats: undefined,
// replace to provide your own
body_class: 'default-theme',
// urls to branding css go here
content_css: [],
// these are up to you
directionality: 'ltr',
height: undefined,
// '400px' is s the standard height
language: 'en',
// any menubar entries here will be appended to the standard menubar
menubar: undefined,
// any menus here will be merged into the standard menubar menus
menu: undefined,
// any toolbar data here will be merged into the standard toolbars
toolbar: undefined,
// plugins included here will be added to the standard set
plugins: undefined,
// ==================================================================================
// values below this line define standard behavior and probably shouldn't be changed
// but will be used if you do
// ==================================================================================
branding: false,
browser_spellcheck: true,
content_style: '',
convert_urls: false,
// fonts specified here need to either be web-safe or self-hosted and loaded in app/stylesheets/bundles/fonts.scss
font_formats: "Lato Extended=Lato Extended,Helvetica Neue,Helvetica,Arial,sans-serif; Balsamiq Sans=Balsamiq Sans,Lato Extended,Helvetica Neue,Helvetica,Arial,sans-serif; Architect's Daughter=Architects Daughter,Lato Extended,Helvetica Neue,Helvetica,Arial,sans-serif; Arial=arial,helvetica,sans-serif; Arial Black=arial black,avant garde; Courier New=courier new,courier; Georgia=georgia,palatino; Tahoma=tahoma,arial,helvetica,sans-serif; Times New Roman=times new roman,times; Trebuchet MS=trebuchet ms,geneva; Verdana=verdana,geneva",
language_load: false,
language_url: 'none',
toolbar_mode: 'floating',
toolbar_ticky: true,
mobile: {
theme: 'silver'
},
preview_styles: 'font-family font-size font-weight font-style text-decoration text-transform border border-radius outline text-shadow',
remove_script_host: true,
resize: true,
// will get set from textareaId
// selector: '#textarea2',
skin: false,
statusbar: false,
// part of unifying tinymce and canvas_sanitize's element whitelist
// copied from
// https://www.tiny.cloud/docs-3x/reference/configuration/Configuration3x@valid_elements/#defaultruleset
// then edited.
//
// this list needs to be kept in sync with the list in gems/canvas_sanitize/lib/canvas_sanitize/canvas_sanitize.rb
valid_elements: elemsToTinyStringConfig({
'@': ['id', 'class', 'style', 'title', 'dir<ltr?rtl', 'lang', 'xml::lang', 'role'],
'a': ['rel', 'rev', 'charset', 'hreflang', 'tabindex', 'accesskey', 'type', 'name', 'href', 'target', 'title', 'class', 'data-old-link'],
'strong/b': [],
'em/i': [],
'strike/s': [],
'u': [],
'#p': [],
'-ol': ['type', 'compact'],
'-ul': ['type', 'compact'],
'-li': [],
'br': [],
'img': ['longdesc', 'usemap', 'src', 'border', 'alt', 'title', 'hspace', 'vspace', 'width', 'height', 'align', 'role', 'data-old-link'],
'-sub': [],
'-sup': [],
'-blockquote': ['cite'],
'-table': [{
'border': '0'
}, 'cellspacing', 'cellpadding', 'width', 'frame', 'rules', 'height', 'align', 'summary', 'bgcolor', 'background', 'bordercolor'],
'-tr': ['rowspan', 'width', 'height', 'align', 'valign', 'bgcolor', 'background', 'bordercolor'],
'tbody': [],
'thead': [],
'tfoot': [],
'#td': ['colspan', 'rowspan', 'width', 'height', 'align', 'valign', 'bgcolor', 'background', 'bordercolor', 'scope'],
'#th': ['colspan', 'rowspan', 'width', 'height', 'align', 'valign', 'scope'],
'caption': [],
'-div': [],
'-span': [],
'-code': [],
'-pre': [],
'address': [],
'-h1': [],
'-h2': [],
'-h3': [],
'-h4': [],
'-h5': [],
'-h6': [],
'hr': ['size', 'noshade'],
'-font': ['face', 'size', 'color'],
'dd': [],
'dl': [],
'dt': [],
'cite': [],
'abbr': [],
'acronym': [],
'del': ['datetime', 'cite'],
'ins': ['datetime', 'cite'],
'object': ['classid', 'width', 'height', 'codebase', '*'],
'param': ['name', 'value', '_value'],
'embed': ['type', 'width', 'height', 'src', '*'],
'map': ['name'],
'area': ['shape', 'coords', 'href', 'alt', 'target'],
'bdo': [],
'col': ['align', 'char', 'charoff', 'span', 'valign', 'width'],
'colgroup': ['align', 'char', 'charoff', 'span', 'valign', 'width'],
'dfn': [],
'kbd': [],
'q': ['cite'],
'samp': [],
'small': [],
'tt': [],
'var': [],
'big': [],
'figure': [],
'figcaption': [],
'source': ['media', 'width', 'height', 'sizes', 'src', 'srcset', 'type', 'data-old-link'],
'track': [],
'mark': [],
'article': [],
'aside': [],
'details': [],
'footer': [],
'header': [],
'nav': [],
'section': [],
'summary': [],
'time': []
}),
extended_valid_elements: elemsToTinyStringConfig({
'@': ['id', 'accesskey', 'class', 'dir', 'lang', 'style', 'tabindex', 'title', 'contenteditable', 'contextmenu', 'draggable', 'dropzone', 'hidden', 'longdesc', 'spellcheck', 'translate', 'align', 'role', 'aria-labelledby', 'aria-atomic', 'aria-busy', 'aria-controls', 'aria-describedby', 'aria-description', 'aria-disabled', 'aria-dropeffect', 'aria-flowto', 'aria-grabbed', 'aria-haspopup', 'aria-hidden', 'aria-invalid', 'aria-label', 'aria-labelledby', 'aria-live', 'aria-owns', 'aria-relevant', 'aria-autocomplete', 'aria-checked', 'aria-disabled', 'aria-expanded', 'aria-haspopup', 'aria-hidden', 'aria-invalid', 'aria-label', 'aria-level', 'aria-multiline', 'aria-multiselectable', 'aria-orientation', 'aria-pressed', 'aria-readonly', 'aria-required', 'aria-selected', 'aria-sort', 'aria-valuemax', 'aria-valuemin', 'aria-valuenow', 'aria-valuetext'],
'iframe': ['id', 'data-media-type', 'title', 'src', 'width', 'height', 'name', 'align', 'style', 'class', 'sandbox', 'loading', 'allowfullscreen', 'webkitallowfullscreen', 'mozallowfullscreen', 'allow', 'data-old-link'],
'i': ['iclass'],
'a': ['hidden', 'href', 'target', 'rel', 'media', 'hreflang', 'type', 'charset', 'name', 'rev', 'shape', 'coords', 'download', 'alt'],
'#p': [],
'li': ['value'],
'-ol': ['reversed', 'start', 'type', 'compact'],
'pre': ['width'],
'table': ['border', 'summary', 'width', 'frame', 'rules', 'cellspacing', 'cellpadding', 'bgcolor'],
'tbody': ['char', 'charoff', 'valign'],
'td': ['colspan', 'rowspan', 'headers', 'abbr', 'axis', 'scope', 'align', 'char', 'charoff', 'valign', 'nowrap', 'bgcolor', 'width', 'height'],
'tfoot': ['char', 'charoff', 'valign'],
'th': ['colspan', 'rowspan', 'headers', 'scope', 'abbr', 'axis', 'align', 'char', 'charoff', 'valign', 'nowrap', 'bgcolor', 'width', 'height'],
'thead': ['char', 'charoff', 'valign'],
'tr': ['char', 'charoff', 'valign', 'bgcolor'],
'-ul': ['compact'],
'video': ['name', 'src', 'allowfullscreen', 'muted', 'poster', 'width', 'height', 'controls', 'playsinline'],
'audio': ['name', 'src', 'muted', 'controls'],
'annotation': ['href', 'xref', 'definitionURL', 'encoding', 'cd', 'name', 'src'],
'annotation-xml': ['href', 'xref', 'definitionURL', 'encoding', 'cd', 'name', 'src'],
'maction': ['href', 'xref', 'mathcolor', 'mathbackground', 'actiontype', 'selection'],
'maligngroup': ['href', 'xref', 'mathcolor', 'mathbackground', 'groupalign'],
'malignmark': ['href', 'xref', 'mathcolor', 'mathbackground', 'edge'],
'math': ['xmlns', 'href', 'xref', 'display', 'maxwidth', 'overflow', 'altimg', 'altimg-width', 'altimg-height', 'altimg-valign', 'alttext', 'cdgroup', 'mathcolor', 'mathbackground', 'scriptlevel', 'displaystyle', 'scriptsizemultiplier', 'scriptminsize', 'infixlinebreakstyle', 'decimalpoint', 'mathvariant', 'mathsize', 'width', 'height', 'valign', 'form', 'fence', 'separator', 'lspace', 'rspace', 'stretchy', 'symmetric', 'maxsize', 'minsize', 'largeop', 'movablelimits', 'accent', 'linebreak', 'lineleading', 'linebreakstyle', 'linebreakmultchar', 'indentalign', 'indentshift', 'indenttarget', 'indentalignfirst', 'indentshiftfirst', 'indentalignlast', 'indentshiftlast', 'depth', 'lquote', 'rquote', 'linethickness', 'munalign', 'denomalign', 'bevelled', 'voffset', 'open', 'close', 'separators', 'notation', 'subscriptshift', 'superscriptshift', 'accentunder', 'align', 'rowalign', 'columnalign', 'groupalign', 'alignmentscope', 'columnwidth', 'rowspacing', 'columnspacing', 'rowlines', 'columnlines', 'frame', 'framespacing', 'equalrows', 'equalcolumns', 'side', 'minlabelspacing', 'rowspan', 'columnspan', 'edge', 'stackalign', 'charalign', 'charspacing', 'longdivstyle', 'position', 'shift', 'location', 'crossout', 'length', 'leftoverhang', 'rightoverhang', 'mslinethickness', 'selection'],
'menclose': ['href', 'xref', 'mathcolor', 'mathbackground', 'notation'],
'merror': ['href', 'xref', 'mathcolor', 'mathbackground'],
'mfenced': ['href', 'xref', 'mathcolor', 'mathbackground', 'open', 'close', 'separators'],
'mfrac': ['href', 'xref', 'mathcolor', 'mathbackground', 'linethickness', 'munalign', 'denomalign', 'bevelled'],
'mglyph': ['href', 'xref', 'mathcolor', 'mathbackground', 'src', 'alt', 'width', 'height', 'valign'],
'mi': ['href', 'xref', 'mathcolor', 'mathbackground', 'mathvariant', 'mathsize'],
'mlabeledtr': ['href', 'xref', 'mathcolor', 'mathbackground'],
'mlongdiv': ['href', 'xref', 'mathcolor', 'mathbackground', 'longdivstyle', 'align', 'stackalign', 'charalign', 'charspacing'],
'mmultiscripts': ['href', 'xref', 'mathcolor', 'mathbackground', 'subscriptshift', 'superscriptshift'],
'mn': ['href', 'xref', 'mathcolor', 'mathbackground', 'mathvariant', 'mathsize'],
'mo': ['href', 'xref', 'mathcolor', 'mathbackground', 'mathvariant', 'mathsize', 'form', 'fence', 'separator', 'lspace', 'rspace', 'stretchy', 'symmetric', 'maxsize', 'minsize', 'largeop', 'movablelimits', 'accent', 'linebreak', 'lineleading', 'linebreakstyle', 'linebreakmultchar', 'indentalign', 'indentshift', 'indenttarget', 'indentalignfirst', 'indentshiftfirst', 'indentalignlast', 'indentshiftlast'],
'mover': ['href', 'xref', 'mathcolor', 'mathbackground', 'accent', 'align'],
'mpadded': ['href', 'xref', 'mathcolor', 'mathbackground', 'height', 'depth', 'width', 'lspace', 'voffset'],
'mphantom': ['href', 'xref', 'mathcolor', 'mathbackground'],
'mprescripts': ['href', 'xref', 'mathcolor', 'mathbackground'],
'mroot': ['href', 'xref', 'mathcolor', 'mathbackground'],
'mrow': ['href', 'xref', 'mathcolor', 'mathbackground'],
'ms': ['href', 'xref', 'mathcolor', 'mathbackground', 'mathvariant', 'mathsize', 'lquote', 'rquote'],
'mscarries': ['href', 'xref', 'mathcolor', 'mathbackground', 'position', 'location', 'crossout', 'scriptsizemultiplier'],
'mscarry': ['href', 'xref', 'mathcolor', 'mathbackground', 'location', 'crossout'],
'msgroup': ['href', 'xref', 'mathcolor', 'mathbackground', 'position', 'shift'],
'msline': ['href', 'xref', 'mathcolor', 'mathbackground', 'position', 'length', 'leftoverhang', 'rightoverhang', 'mslinethickness'],
'mspace': ['href', 'xref', 'mathcolor', 'mathbackground', 'mathvariant', 'mathsize'],
'msqrt': ['href', 'xref', 'mathcolor', 'mathbackground'],
'msrow': ['href', 'xref', 'mathcolor', 'mathbackground', 'position'],
'mstack': ['href', 'xref', 'mathcolor', 'mathbackground', 'align', 'stackalign', 'charalign', 'charspacing'],
'mstyle': ['href', 'xref', 'mathcolor', 'mathbackground', 'scriptlevel', 'displaystyle', 'scriptsizemultiplier', 'scriptminsize', 'infixlinebreakstyle', 'decimalpoint', 'mathvariant', 'mathsize', 'width', 'height', 'valign', 'form', 'fence', 'separator', 'lspace', 'rspace', 'stretchy', 'symmetric', 'maxsize', 'minsize', 'largeop', 'movablelimits', 'accent', 'linebreak', 'lineleading', 'linebreakstyle', 'linebreakmultchar', 'indentalign', 'indentshift', 'indenttarget', 'indentalignfirst', 'indentshiftfirst', 'indentalignlast', 'indentshiftlast', 'depth', 'lquote', 'rquote', 'linethickness', 'munalign', 'denomalign', 'bevelled', 'voffset', 'open', 'close', 'separators', 'notation', 'subscriptshift', 'superscriptshift', 'accentunder', 'align', 'rowalign', 'columnalign', 'groupalign', 'alignmentscope', 'columnwidth', 'rowspacing', 'columnspacing', 'rowlines', 'columnlines', 'frame', 'framespacing', 'equalrows', 'equalcolumns', 'side', 'minlabelspacing', 'rowspan', 'columnspan', 'edge', 'stackalign', 'charalign', 'charspacing', 'longdivstyle', 'position', 'shift', 'location', 'crossout', 'length', 'leftoverhang', 'rightoverhang', 'mslinethickness', 'selection'],
'msub': ['href', 'xref', 'mathcolor', 'mathbackground', 'subscriptshift'],
'msubsup': ['href', 'xref', 'mathcolor', 'mathbackground', 'subscriptshift', 'superscriptshift'],
'msup': ['href', 'xref', 'mathcolor', 'mathbackground', 'superscriptshift'],
'mtable': ['href', 'xref', 'mathcolor', 'mathbackground', 'align', 'rowalign', 'columnalign', 'groupalign', 'alignmentscope', 'columnwidth', 'width', 'rowspacing', 'columnspacing', 'rowlines', 'columnlines', 'frame', 'framespacing', 'equalrows', 'equalcolumns', 'displaystyle', 'side', 'minlabelspacing'],
'mtd': ['href', 'xref', 'mathcolor', 'mathbackground', 'rowspan', 'columnspan', 'rowalign', 'columnalign', 'groupalign'],
'mtext': ['href', 'xref', 'mathcolor', 'mathbackground', 'mathvariant', 'mathsize', 'width', 'height', 'depth', 'linebreak'],
'mtr': ['href', 'xref', 'mathcolor', 'mathbackground', 'rowalign', 'columnalign', 'groupalign'],
'munder': ['href', 'xref', 'mathcolor', 'mathbackground', 'accentunder', 'align'],
'munderover': ['href', 'xref', 'mathcolor', 'mathbackground', 'accent', 'accentunder', 'align'],
'none': ['href', 'xref', 'mathcolor', 'mathbackground'],
'semantics': ['href', 'xref', 'definitionURL', 'encoding'],
'picture': [],
'ruby': [],
'rp': [],
'rt': [],
'g': ['*'],
'circle': ['*']
}),
non_empty_elements: 'td th iframe video audio object script a i area base basefont br col frame hr img input isindex link meta param embed source wbr track ruby',
// tiny's external link create/edit dialog config
target_list: false,
// don't show the target list when creating/editing links
link_title: false,
// don't show the title input when creating/editing links
default_link_target: '_blank',
// Remove the ability to add h1 tags (since there will already be an h1 on the page)
// but preserve the default Formats menu config otherwise
style_formats: [{
title: 'Headings',
items: [{
title: 'Heading 2',
format: 'h2'
}, {
title: 'Heading 3',
format: 'h3'
}, {
title: 'Heading 4',
format: 'h4'
}, {
title: 'Heading 5',
format: 'h5'
}, {
title: 'Heading 6',
format: 'h6'
}]
}, {
title: 'Inline',
items: [{
title: 'Bold',
format: 'bold'
}, {
title: 'Italic',
format: 'italic'
}, {
title: 'Underline',
format: 'underline'
}, {
title: 'Strikethrough',
format: 'strikethrough'
}, {
title: 'Superscript',
format: 'superscript'
}, {
title: 'Subscript',
format: 'subscript'
}, {
title: 'Code',
format: 'code'
}]
}, {
title: 'Blocks',
items: [{
title: 'Paragraph',
format: 'p'
}, {
title: 'Blockquote',
format: 'blockquote'
}, {
title: 'Div',
format: 'div'
}, {
title: 'Pre',
format: 'pre'
}]
}, {
title: 'Align',
items: [{
title: 'Left',
format: 'alignleft'
}, {
title: 'Center',
format: 'aligncenter'
}, {
title: 'Right',
format: 'alignright'
}, {
title: 'Justify',
format: 'alignjustify'
}]
}]
};
export default defaultTinymceConfig;