Skip to content

Commit 928e740

Browse files
Merge branch 'MAGETWO-50522-schema' of github.com:magento-vanilla/magento2ce into PR
2 parents 7f3a3ce + e8eea71 commit 928e740

File tree

2 files changed

+244
-10
lines changed

2 files changed

+244
-10
lines changed
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
/**
2+
* Copyright © 2016 Magento. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
6+
define([
7+
'underscore'
8+
], function (_) {
9+
'use strict';
10+
11+
/* eslint-disable max-len */
12+
13+
var schema = {
14+
blockContent: [
15+
'address', 'article', 'aside', 'blockquote', 'details', 'dialog', 'div', 'dl', 'fieldset',
16+
'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr',
17+
'menu', 'nav', 'ol', 'p', 'pre', 'section', 'table', 'ul'
18+
],
19+
phrasingContent: [
20+
'#comment', '#text', 'a', 'abbr', 'audio', 'b', 'bdi', 'bdo', 'br', 'button', 'canvas',
21+
'cite','code', 'command', 'datalist', 'del', 'dfn', 'em', 'embed', 'i', 'iframe', 'img',
22+
'input', 'ins', 'kbd', 'keygen', 'label', 'map', 'mark', 'meter', 'noscript', 'object',
23+
'output', 'picture', 'progress', 'q', 'ruby', 's', 'samp', 'script', 'select', 'small',
24+
'span', 'strong', 'sub', 'sup', 'textarea', 'time', 'u', 'var', 'video', 'wbr'
25+
],
26+
blockElements: [
27+
'address', 'article', 'aside', 'blockquote', 'caption', 'center', 'datalist', 'dd', 'dir', 'div',
28+
'dl', 'dt', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
29+
'header', 'hgroup', 'hr', 'isindex', 'li', 'menu', 'nav', 'noscript', 'ol', 'optgroup', 'option',
30+
'p', 'pre', 'section', 'select', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr', 'ul'
31+
],
32+
boolAttrs: [
33+
'autoplay', 'checked', 'compact', 'controls', 'declare', 'defer', 'disabled', 'ismap', 'loop',
34+
'multiple', 'nohref', 'noresize', 'noshade', 'nowrap', 'readonly', 'selected'
35+
],
36+
shortEnded: [
37+
'area', 'base', 'basefont', 'br', 'col', 'embed', 'frame', 'hr', 'img', 'input', 'isindex',
38+
'link', 'meta', 'param', 'source', 'track', 'wbr'
39+
],
40+
whiteSpace: [
41+
'audio', 'iframe', 'noscript', 'object', 'pre', 'script', 'style', 'textarea', 'video'
42+
],
43+
selfClosing: [
44+
'colgroup', 'dd', 'dt', 'li', 'option', 'p', 'td', 'tfoot', 'th', 'thead', 'tr'
45+
]
46+
};
47+
48+
schema.flowContent = schema.blockContent.concat(schema.phrasingContent, ['style']);
49+
schema.nonEmpty = ['td', 'th', 'iframe', 'video', 'audio', 'object', 'script'].concat(schema.shortEnded);
50+
51+
_.extend(schema, (function (phrasingContent, flowContent) {
52+
var validElements = [],
53+
validChildren = [],
54+
compiled = {},
55+
globalAttrs,
56+
rawData;
57+
58+
globalAttrs = [
59+
'id', 'dir', 'lang', 'class', 'style', 'title', 'hidden', 'onclick', 'onkeyup',
60+
'tabindex', 'dropzone', 'accesskey', 'draggable', 'translate', 'onmouseup',
61+
'onkeydown', 'spellcheck', 'ondblclick', 'onmouseout', 'onkeypress', 'contextmenu',
62+
'onmousedown', 'onmouseover', 'onmousemove', 'contenteditable'
63+
];
64+
65+
rawData = [
66+
['html', 'manifest', 'head body'],
67+
['head', '', 'base command link meta noscript script style title'],
68+
['title hr noscript br'],
69+
['base', 'href target'],
70+
['link', 'href rel media hreflang type sizes hreflang'],
71+
['meta', 'name http-equiv content charset'],
72+
['style', 'media type scoped'],
73+
['script', 'src async defer type charset'],
74+
['body', 'onafterprint onbeforeprint onbeforeunload onblur onerror onfocus ' +
75+
'onhashchange onload onmessage onoffline ononline onpagehide onpageshow ' +
76+
'onpopstate onresize onscroll onstorage onunload background bgcolor text link vlink alink', flowContent
77+
],
78+
['caption', '', _.without(flowContent, 'table')],
79+
['address dt dd div', '', flowContent],
80+
['h1 h2 h3 h4 h5 h6 pre p abbr code var samp kbd sub sup i b u bdo span legend em strong small s cite dfn', '', phrasingContent],
81+
['blockquote', 'cite', flowContent],
82+
['ol', 'reversed start type', 'li'],
83+
['ul', 'type compact', 'li'],
84+
['li', 'value type', flowContent],
85+
['dl', '', 'dt dd'],
86+
['a', 'href target rel media hreflang type charset name rev shape coords download', phrasingContent],
87+
['q', 'cite', phrasingContent],
88+
['ins del', 'cite datetime', flowContent],
89+
['img', 'src sizes srcset alt usemap ismap width height name longdesc align border hspace vspace'],
90+
['iframe', 'src name width height longdesc frameborder marginwidth marginheight scrolling align sandbox seamless allowfullscreen', flowContent],
91+
['embed', 'src type width height'],
92+
['object', 'data type typemustmatch name usemap form width height declare classid code codebase codetype archive standby align border hspace vspace', flowContent.concat(['param'])],
93+
['param', 'name value valuetype type'],
94+
['map', 'name', flowContent.concat(['area'])],
95+
['area', 'alt coords shape href target rel media hreflang type nohref'],
96+
['table', 'border summary width frame rules cellspacing cellpadding align bgcolor', 'caption colgroup thead tfoot tbody tr col'],
97+
['colgroup', 'span width align char charoff valign', 'col'],
98+
['col', 'span'],
99+
['tbody thead tfoot', 'align char charoff valign', 'tr'],
100+
['tr', 'align char charoff valign bgcolor', 'td th'],
101+
['td', 'colspan rowspan headers abbr axis scope align char charoff valign nowrap bgcolor width height', flowContent],
102+
['th', 'colspan rowspan headers scope abbr axis align char charoff valign nowrap bgcolor width height accept', flowContent],
103+
['form', 'accept-charset action autocomplete enctype method name novalidate target onsubmit onreset', flowContent],
104+
['fieldset', 'disabled form name', flowContent.concat(['legend'])],
105+
['label', 'form for', phrasingContent],
106+
['input', 'accept alt autocomplete checked dirname disabled form formaction formenctype formmethod formnovalidate ' +
107+
'formtarget height list max maxlength min multiple name pattern readonly required size src step type value width usemap align'
108+
],
109+
['button', 'disabled form formaction formenctype formmethod formnovalidate formtarget name type value', phrasingContent],
110+
['select', 'disabled form multiple name required size onfocus onblur onchange', 'option optgroup'],
111+
['optgroup', 'disabled label', 'option'],
112+
['option', 'disabled label selected value'],
113+
['textarea', 'cols dirname disabled form maxlength name readonly required rows wrap'],
114+
['menu', 'type label', flowContent.concat(['li'])],
115+
['noscript', '', flowContent],
116+
['wbr'],
117+
['ruby', '', phrasingContent.concat(['rt', 'rp'])],
118+
['figcaption', '', flowContent],
119+
['mark rt rp summary bdi', '', phrasingContent],
120+
['canvas', 'width height', flowContent],
121+
['video', 'src crossorigin poster preload autoplay mediagroup loop muted controls width height buffered', flowContent.concat(['track', 'source'])],
122+
['audio', 'src crossorigin preload autoplay mediagroup loop muted controls buffered volume', flowContent.concat(['track', 'source'])],
123+
['picture', '', 'img source'],
124+
['source', 'src srcset type media sizes'],
125+
['track', 'kind src srclang label default'],
126+
['datalist', '', phrasingContent.concat(['option'])],
127+
['article section nav aside header footer', '', flowContent],
128+
['hgroup', '', 'h1 h2 h3 h4 h5 h6'],
129+
['figure', '', flowContent.concat(['figcaption'])],
130+
['time', 'datetime', phrasingContent],
131+
['dialog', 'open', flowContent],
132+
['command', 'type label icon disabled checked radiogroup command'],
133+
['output', 'for form name', phrasingContent],
134+
['progress', 'value max', phrasingContent],
135+
['meter', 'value min max low high optimum', phrasingContent],
136+
['details', 'open', flowContent.concat(['summary'])],
137+
['keygen', 'autofocus challenge disabled form keytype name'],
138+
['script', 'language xml:space'],
139+
['style', 'xml:space'],
140+
['embed', 'align name hspace vspace'],
141+
['br', 'clear'],
142+
['applet', 'codebase archive code object alt name width height align hspace vspace'],
143+
['font basefont', 'size color face'],
144+
['h1 h2 h3 h4 h5 h6 div p legend caption', 'align'],
145+
['ol dl menu dir', 'compact'],
146+
['pre', 'width xml:space'],
147+
['hr', 'align noshade size width'],
148+
['isindex', 'prompt'],
149+
['col', 'width align char charoff valign'],
150+
['input button select textarea', 'autofocus'],
151+
['input textarea', 'placeholder onselect onchange onfocus onblur'],
152+
['link script img', 'crossorigin']
153+
];
154+
155+
rawData.forEach(function (data) {
156+
var nodes = data[0].split(' '),
157+
attributes = data[1] || [],
158+
children = data[2] || [],
159+
ni = nodes.length,
160+
nodeName,
161+
schemaData;
162+
163+
if (typeof attributes === 'string') {
164+
attributes = attributes.split(' ');
165+
}
166+
167+
if (typeof children === 'string') {
168+
children = children.split(' ');
169+
}
170+
171+
while (ni--) {
172+
nodeName = nodes[ni];
173+
schemaData = compiled[nodeName] || {};
174+
175+
compiled[nodeName] = {
176+
attributes: _.union(schemaData.attributes, globalAttrs, attributes),
177+
children: _.union(schemaData.children, children)
178+
};
179+
}
180+
});
181+
182+
['a', 'dfn', 'form', 'meter', 'progress'].forEach(function (nodeName) {
183+
var node = compiled[nodeName];
184+
185+
node.children = _.without(node.children, nodeName);
186+
});
187+
188+
_.each(compiled, function (node, nodeName) {
189+
var attributes = node.attributes.join('|'),
190+
children = node.children.join('|');
191+
192+
validElements.push(nodeName + '[' + attributes + ']');
193+
validChildren.push(nodeName + '[' + children + ']');
194+
});
195+
196+
return {
197+
nodes: compiled,
198+
validElements: validElements,
199+
validChildren: validChildren
200+
};
201+
})(schema.phrasingContent, schema.flowContent));
202+
203+
return schema;
204+
});

lib/web/mage/adminhtml/wysiwyg/tiny_mce/setup.js

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ define([
66
'jquery',
77
'underscore',
88
'tinymce',
9+
'mage/adminhtml/wysiwyg/tiny_mce/html5-schema',
910
'mage/translate',
1011
'prototype',
1112
'mage/adminhtml/events',
1213
'mage/adminhtml/browser'
13-
], function(jQuery, _, tinyMCE) {
14+
], function(jQuery, _, tinyMCE, html5Schema) {
1415

1516
tinyMceWysiwygSetup = Class.create();
1617

@@ -25,6 +26,7 @@ define([
2526

2627
this.id = htmlId;
2728
this.config = config;
29+
this.schema = config.schema || html5Schema;
2830

2931
_.bindAll(this, 'beforeSetContent', 'saveContent', 'onChangeContent', 'openFileBrowser', 'updateTextArea');
3032

@@ -55,7 +57,8 @@ define([
5557
},
5658

5759
getSettings: function(mode) {
58-
var plugins = 'inlinepopups,safari,pagebreak,style,layer,table,advhr,advimage,emotions,iespell,media,searchreplace,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras';
60+
var plugins = 'inlinepopups,safari,pagebreak,style,layer,table,advhr,advimage,emotions,iespell,media,searchreplace,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras',
61+
self = this;
5962

6063
if (this.config.widget_plugin_src) {
6164
plugins = 'magentowidget,' + plugins;
@@ -86,9 +89,8 @@ define([
8689
theme_advanced_toolbar_location: 'top',
8790
theme_advanced_toolbar_align: 'left',
8891
theme_advanced_statusbar_location: 'bottom',
89-
extended_valid_elements: 'style,input[placeholder|accept|alt|checked|disabled|maxlength|name|readonly|size|src|type|value]',
90-
valid_children: '+body[style]',
91-
custom_elements: 'style',
92+
valid_elements: this.schema.validElements.join(','),
93+
valid_children: this.schema.validChildren.join(','),
9294
theme_advanced_resizing: true,
9395
theme_advanced_resize_horizontal: false,
9496
convert_urls: false,
@@ -99,6 +101,8 @@ define([
99101
magentoPluginsOptions: magentoPluginsOptions,
100102
doctype: '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
101103
setup: function(ed){
104+
ed.onInit.add(self.onEditorInit.bind(self));
105+
102106
ed.onSubmit.add(function(ed, e) {
103107
varienGlobalEvents.fireEvent('tinymceSubmit', e);
104108
});
@@ -162,6 +166,28 @@ define([
162166
return settings;
163167
},
164168

169+
applySchema: function (editor) {
170+
var schema = editor.schema,
171+
schemaData = this.schema,
172+
makeMap = tinyMCE.makeMap;
173+
174+
jQuery.extend(true, {
175+
nonEmpty: schema.getNonEmptyElements(),
176+
boolAttrs: schema.getBoolAttrs(),
177+
whiteSpace: schema.getWhiteSpaceElements(),
178+
shortEnded: schema.getShortEndedElements(),
179+
selfClosing: schema.getSelfClosingElements(),
180+
blockElements: schema.getBlockElements()
181+
}, {
182+
nonEmpty: makeMap(schemaData.nonEmpty),
183+
boolAttrs: makeMap(schemaData.boolAttrs),
184+
whiteSpace: makeMap(schemaData.whiteSpace),
185+
shortEnded: makeMap(schemaData.shortEnded),
186+
selfClosing: makeMap(schemaData.selfClosing),
187+
blockElements: makeMap(schemaData.blockElements)
188+
});
189+
},
190+
165191
openFileBrowser: function(o) {
166192
var typeTitle,
167193
storeId = this.config.store_id !== null ? this.config.store_id : 0,
@@ -215,21 +241,21 @@ define([
215241
this.closePopups();
216242

217243
this.setup(mode);
218-
244+
219245
tinyMCE.execCommand('mceAddControl', false, this.id);
220-
246+
221247
this.getPluginButtons().each(function(e) {
222248
e.hide();
223249
});
224-
250+
225251
return this;
226252
},
227253

228254
turnOff: function() {
229255
this.closePopups();
230-
256+
231257
tinyMCE.execCommand('mceRemoveControl', false, this.id);
232-
258+
233259
this.getPluginButtons().each(function(e) {
234260
e.show();
235261
});
@@ -255,6 +281,10 @@ define([
255281
}
256282
},
257283

284+
onEditorInit: function (editor) {
285+
this.applySchema(editor);
286+
},
287+
258288
onFormValidation: function() {
259289
if (tinyMCE.get(this.id)) {
260290
$(this.id).value = tinyMCE.get(this.id).getContent();

0 commit comments

Comments
 (0)