Skip to content

Commit

Permalink
Merge branch 't/10202b' into major
Browse files Browse the repository at this point in the history
  • Loading branch information
Reinmar committed Mar 12, 2014
2 parents e9e018d + eaf9c31 commit 6563276
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ CKEditor 4 Changelog

New Features:

* [#10202](http://dev.ckeditor.com/ticket/10202): Introduced wildcards support in the [Allowed Content Rules](http://docs.ckeditor.com/#!/guide/dev_allowed_content_rules) format.
* [#11532](http://dev.ckeditor.com/ticket/11532): Introduced the [`editor.addContentsCss()`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-addContentsCss) method that can be used for adding custom CSS files.
* [#11536](http://dev.ckeditor.com/ticket/11536): Added the [`CKEDITOR.tools.htmlDecode`](http://docs.ckeditor.com/#!/api/CKEDITOR.tools-method-htmlDecode) method for decoding HTML entities.
* [#11377](http://dev.ckeditor.com/ticket/11377): Unify internal representation of empty anchors using fake objects.
Expand Down
88 changes: 75 additions & 13 deletions core/filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -1044,13 +1044,21 @@
if ( rule.nothingRequired )
return true;

var i, reqs, existing;
var i, req, reqs, existing;

if ( ( reqs = rule.requiredClasses ) ) {
existing = element.classes;
for ( i = 0; i < reqs.length; ++i ) {
if ( CKEDITOR.tools.indexOf( existing, reqs[ i ] ) == -1 )
return false;
req = reqs[ i ];
if ( typeof req == 'string' ) {
if ( CKEDITOR.tools.indexOf( existing, req ) == -1 )
return false;
}
// This means regexp.
else {
if ( !CKEDITOR.tools.checkIfAnyArrayItemMatches( existing, req ) )
return false;
}
}
}

Expand All @@ -1063,9 +1071,17 @@
if ( !required )
return true;

for ( var i = 0; i < required.length; ++i ) {
if ( !( required[ i ] in existing ) )
return false;
for ( var i = 0, req; i < required.length; ++i ) {
req = required[ i ];
if ( typeof req == 'string' ) {
if ( !( req in existing ) )
return false;
}
// This means regexp.
else {
if ( !CKEDITOR.tools.checkIfAnyObjectPropertyMatches( existing, req ) )
return false;
}
}

return true;
Expand Down Expand Up @@ -1133,6 +1149,23 @@
return obj;
}

// Extract properties names from the object
// and replace those containing wildcards with regexps.
// Note: there's a room for performance improvement. Array of mixed types
// breaks JIT-compiler optiomization what may invalidate compilation of pretty a lot of code.
//
// @returns An array of strings and regexps.
function optimizeRequiredProperties( requiredProperties ) {
var arr = [];
for ( var propertyName in requiredProperties ) {
if ( propertyName.indexOf( '*' ) > -1 )
arr.push( new RegExp( '^' + propertyName.replace( /\*/g, '.*' ) + '$' ) );
else
arr.push( propertyName );
}
return arr;
}

var validators = { styles: 1, attributes: 1, classes: 1 },
validatorsRequired = {
styles: 'requiredStyles',
Expand All @@ -1143,16 +1176,23 @@
// Optimize a rule by replacing validators with functions
// and rewriting requiredXXX validators to arrays.
function optimizeRule( rule ) {
var i;
for ( i in validators )
rule[ i ] = validatorFunction( rule[ i ] );
var validatorName,
requiredProperties,
i;

for ( validatorName in validators )
rule[ validatorName ] = validatorFunction( rule[ validatorName ] );

var nothingRequired = true;
for ( i in validatorsRequired ) {
i = validatorsRequired[ i ];
rule[ i ] = CKEDITOR.tools.objectKeys( rule[ i ] );
if ( rule[ i ] )
validatorName = validatorsRequired[ i ];
requiredProperties = optimizeRequiredProperties( rule[ validatorName ] );
// Don't set anything if there are no required properties. This will allow to
// save some memory by GCing all empty arrays (requiredProperties).
if ( requiredProperties.length ) {
rule[ validatorName ] = requiredProperties;
nothingRequired = false;
}
}

rule.nothingRequired = nothingRequired;
Expand Down Expand Up @@ -1253,6 +1293,23 @@
element.classes = element.attributes[ 'class' ] ? element.attributes[ 'class' ].split( /\s+/ ) : [];
}

// Returns a regexp object which can be used to test if a property
// matches one of wildcard validators.
function regexifyPropertiesWithWildcards( validators ) {
var patterns = [],
i;

for ( i in validators ) {
if ( i.indexOf( '*' ) > -1 )
patterns.push( i.replace( /\*/g, '.*' ) );
}

if ( patterns.length )
return new RegExp( '^(?:' + patterns.join( '|' ) + ')$' );
else
return null;
}

// Standardize a rule by converting all validators to hashes.
function standardizeRule( rule ) {
rule.elements = convertValidatorToHash( rule.elements, /\s+/ ) || null;
Expand Down Expand Up @@ -1383,8 +1440,13 @@
if ( validator === true )
return true;

// Note: We don't need to remove properties with wildcards from the validator object.
// E.g. data-* is actually an edge case of /^data-.*$/, so when it's accepted
// by `value in validator` it's ok.
var regexp = regexifyPropertiesWithWildcards( validator );

return function( value ) {
return value in validator;
return value in validator || ( regexp && value.match( regexp ) );
};
}

Expand Down
32 changes: 32 additions & 0 deletions core/tools.js
Original file line number Diff line number Diff line change
Expand Up @@ -1137,6 +1137,38 @@
}
},

/**
* Checks if any of the `arr` items match provided regular expression.
*
* @param {Array} arr The array which items will be checked.
* @param {RegExp} regexp The regular expression.
* @returns {Boolean} Returns `true` for the first occurrence of searched pattern.
* @since 4.4
*/
checkIfAnyArrayItemMatches: function( arr, regexp ) {
for ( var i = 0, l = arr.length; i < l; ++i ) {
if ( arr[ i ].match( regexp ) )
return true;
}
return false;
},

/**
* Checks if any of the `obj` properties match provided regular expression.
*
* @param obj The object which properties will be checked.
* @param {RegExp} regexp The regular expression.
* @returns {Boolean} Returns `true` for the first occurrence of searched pattern.
* @since 4.4
*/
checkIfAnyObjectPropertyMatches: function( obj, regexp ) {
for ( var i in obj ) {
if ( i.match( regexp ) )
return true;
}
return false;
},

/**
* The data URI of a transparent image. May be used e.g. in HTML as an image source or in CSS in `url()`.
*
Expand Down

0 comments on commit 6563276

Please sign in to comment.