]>
git.immae.eu Git - perso/Immae/Projets/packagist/piedsjaloux-ckeditor-component.git/blob - sources/core/htmlparser/filter.js
72767b5943e84a3fa2770014c566e80ab353d48f
2 * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
10 * Filter is a configurable tool for transforming and filtering {@link CKEDITOR.htmlParser.node nodes}.
11 * It is mainly used during data processing phase which is done not on real DOM nodes,
12 * but on their simplified form represented by {@link CKEDITOR.htmlParser.node} class and its subclasses.
14 * var filter = new CKEDITOR.htmlParser.filter( {
15 * text: function( value ) {
16 * return '@' + value + '@';
19 * p: function( element ) {
20 * element.attributes.foo = '1';
25 * var fragment = CKEDITOR.htmlParser.fragment.fromHtml( '<p>Foo<b>bar!</b></p>' ),
26 * writer = new CKEDITOR.htmlParser.basicWriter();
27 * filter.applyTo( fragment );
28 * fragment.writeHtml( writer );
29 * writer.getHtml(); // '<p foo="1">@Foo@<b>@bar!@</b></p>'
33 CKEDITOR
.htmlParser
.filter
= CKEDITOR
.tools
.createClass( {
35 * @constructor Creates a filter class instance.
36 * @param {CKEDITOR.htmlParser.filterRulesDefinition} [rules]
38 $: function( rules
) {
40 * ID of filter instance, which is used to mark elements
41 * to which this filter has been already applied.
43 * @property {Number} id
46 this.id
= CKEDITOR
.tools
.getNextNumber();
49 * Rules for element names.
51 * @property {CKEDITOR.htmlParser.filterRulesGroup}
54 this.elementNameRules
= new filterRulesGroup();
57 * Rules for attribute names.
59 * @property {CKEDITOR.htmlParser.filterRulesGroup}
62 this.attributeNameRules
= new filterRulesGroup();
65 * Hash of elementName => {@link CKEDITOR.htmlParser.filterRulesGroup rules for elements}.
69 this.elementsRules
= {};
72 * Hash of attributeName => {@link CKEDITOR.htmlParser.filterRulesGroup rules for attributes}.
76 this.attributesRules
= {};
79 * Rules for text nodes.
81 * @property {CKEDITOR.htmlParser.filterRulesGroup}
84 this.textRules
= new filterRulesGroup();
87 * Rules for comment nodes.
89 * @property {CKEDITOR.htmlParser.filterRulesGroup}
92 this.commentRules
= new filterRulesGroup();
95 * Rules for a root node.
97 * @property {CKEDITOR.htmlParser.filterRulesGroup}
100 this.rootRules
= new filterRulesGroup();
103 this.addRules( rules
, 10 );
108 * Add rules to this filter.
110 * @param {CKEDITOR.htmlParser.filterRulesDefinition} rules Object containing filter rules.
111 * @param {Object/Number} [options] Object containing rules' options or a priority
112 * (for a backward compatibility with CKEditor versions up to 4.2.x).
113 * @param {Number} [options.priority=10] The priority of a rule.
114 * @param {Boolean} [options.applyToAll=false] Whether to apply rule to non-editable
115 * elements and their descendants too.
117 addRules: function( rules
, options
) {
120 // Backward compatibility.
121 if ( typeof options
== 'number' )
123 // New version - try reading from options.
124 else if ( options
&& ( 'priority' in options
) )
125 priority
= options
.priority
;
128 if ( typeof priority
!= 'number' )
130 if ( typeof options
!= 'object' )
133 // Add the elementNames.
134 if ( rules
.elementNames
)
135 this.elementNameRules
.addMany( rules
.elementNames
, priority
, options
);
137 // Add the attributeNames.
138 if ( rules
.attributeNames
)
139 this.attributeNameRules
.addMany( rules
.attributeNames
, priority
, options
);
142 if ( rules
.elements
)
143 addNamedRules( this.elementsRules
, rules
.elements
, priority
, options
);
145 // Add the attributes.
146 if ( rules
.attributes
)
147 addNamedRules( this.attributesRules
, rules
.attributes
, priority
, options
);
151 this.textRules
.add( rules
.text
, priority
, options
);
155 this.commentRules
.add( rules
.comment
, priority
, options
);
157 // Add root node rules.
159 this.rootRules
.add( rules
.root
, priority
, options
);
163 * Apply this filter to given node.
165 * @param {CKEDITOR.htmlParser.node} node The node to be filtered.
167 applyTo: function( node
) {
171 onElementName: function( context
, name
) {
172 return this.elementNameRules
.execOnName( context
, name
);
175 onAttributeName: function( context
, name
) {
176 return this.attributeNameRules
.execOnName( context
, name
);
179 onText: function( context
, text
, node
) {
180 return this.textRules
.exec( context
, text
, node
);
183 onComment: function( context
, commentText
, comment
) {
184 return this.commentRules
.exec( context
, commentText
, comment
);
187 onRoot: function( context
, element
) {
188 return this.rootRules
.exec( context
, element
);
191 onElement: function( context
, element
) {
192 // We must apply filters set to the specific element name as
193 // well as those set to the generic ^/$ name. So, add both to an
194 // array and process them in a small loop.
195 var rulesGroups
= [ this.elementsRules
[ '^' ], this.elementsRules
[ element
.name
], this.elementsRules
.$ ],
198 for ( var i
= 0; i
< 3; i
++ ) {
199 rulesGroup
= rulesGroups
[ i
];
201 ret
= rulesGroup
.exec( context
, element
, this );
206 if ( ret
&& ret
!= element
)
207 return this.onNode( context
, ret
);
209 // The non-root element has been dismissed by one of the filters.
210 if ( element
.parent
&& !element
.name
)
218 onNode: function( context
, node
) {
219 var type
= node
.type
;
221 return type
== CKEDITOR
.NODE_ELEMENT
? this.onElement( context
, node
) :
222 type
== CKEDITOR
.NODE_TEXT
? new CKEDITOR
.htmlParser
.text( this.onText( context
, node
.value
) ) :
223 type
== CKEDITOR
.NODE_COMMENT
? new CKEDITOR
.htmlParser
.comment( this.onComment( context
, node
.value
) ) : null;
226 onAttribute: function( context
, element
, name
, value
) {
227 var rulesGroup
= this.attributesRules
[ name
];
230 return rulesGroup
.exec( context
, value
, element
, this );
237 * Class grouping filter rules for one subject (like element or attribute names).
239 * @class CKEDITOR.htmlParser.filterRulesGroup
241 function filterRulesGroup() {
243 * Array of objects containing rule, priority and options.
245 * @property {Object[]}
251 CKEDITOR
.htmlParser
.filterRulesGroup
= filterRulesGroup
;
253 filterRulesGroup
.prototype = {
255 * Adds specified rule to this group.
257 * @param {Function/Array} rule Function for function based rule or [ pattern, replacement ] array for
258 * rule applicable to names.
259 * @param {Number} priority
262 add: function( rule
, priority
, options
) {
263 this.rules
.splice( this.findIndex( priority
), 0, {
271 * Adds specified rules to this group.
273 * @param {Array} rules Array of rules - see {@link #add}.
274 * @param {Number} priority
277 addMany: function( rules
, priority
, options
) {
278 var args
= [ this.findIndex( priority
), 0 ];
280 for ( var i
= 0, len
= rules
.length
; i
< len
; i
++ ) {
288 this.rules
.splice
.apply( this.rules
, args
);
292 * Finds an index at which rule with given priority should be inserted.
294 * @param {Number} priority
295 * @returns {Number} Index.
297 findIndex: function( priority
) {
298 var rules
= this.rules
,
302 // Search from the end, because usually rules will be added with default priority, so
303 // we will be able to stop loop quickly.
304 while ( i
>= 0 && priority
< rules
[ i
].priority
)
311 * Executes this rules group on given value. Applicable only if function based rules were added.
313 * All arguments passed to this function will be forwarded to rules' functions.
315 * @param {CKEDITOR.htmlParser.node/CKEDITOR.htmlParser.fragment/String} currentValue The value to be filtered.
316 * @returns {CKEDITOR.htmlParser.node/CKEDITOR.htmlParser.fragment/String} Filtered value.
318 exec: function( context
, currentValue
) {
319 var isNode
= currentValue
instanceof CKEDITOR
.htmlParser
.node
|| currentValue
instanceof CKEDITOR
.htmlParser
.fragment
,
320 // Splice '1' to remove context, which we don't want to pass to filter rules.
321 args
= Array
.prototype.slice
.call( arguments
, 1 ),
324 orgType
, orgName
, ret
, i
, rule
;
326 for ( i
= 0; i
< len
; i
++ ) {
327 // Backup the node info before filtering.
329 orgType
= currentValue
.type
;
330 orgName
= currentValue
.name
;
334 if ( isRuleApplicable( context
, rule
) ) {
335 ret
= rule
.value
.apply( null, args
);
340 // We're filtering node (element/fragment).
341 // No further filtering if it's not anymore fitable for the subsequent filters.
342 if ( isNode
&& ret
&& ( ret
.name
!= orgName
|| ret
.type
!= orgType
) )
345 // Update currentValue and corresponding argument in args array.
346 // Updated values will be used in next for-loop step.
348 args
[ 0 ] = currentValue
= ret
;
350 // ret == undefined will continue loop as nothing has happened.
358 * Executes this rules group on name. Applicable only if filter rules for names were added.
360 * @param {String} currentName The name to be filtered.
361 * @returns {String} Filtered name.
363 execOnName: function( context
, currentName
) {
369 for ( ; currentName
&& i
< len
; i
++ ) {
371 if ( isRuleApplicable( context
, rule
) )
372 currentName
= currentName
.replace( rule
.value
[ 0 ], rule
.value
[ 1 ] );
379 function addNamedRules( rulesGroups
, newRules
, priority
, options
) {
380 var ruleName
, rulesGroup
;
382 for ( ruleName
in newRules
) {
383 rulesGroup
= rulesGroups
[ ruleName
];
386 rulesGroup
= rulesGroups
[ ruleName
] = new filterRulesGroup();
388 rulesGroup
.add( newRules
[ ruleName
], priority
, options
);
392 function isRuleApplicable( context
, rule
) {
393 if ( context
.nonEditable
&& !rule
.options
.applyToAll
)
396 if ( context
.nestedEditable
&& rule
.options
.excludeNestedEditable
)
405 * @class CKEDITOR.htmlParser.filterRulesDefinition