feat: Update version to 3.0.5 and enhance CustomBranding with new search form functionality and improved styling
This commit is contained in:
@@ -14,7 +14,7 @@ export const MaxBrandingDepth: number = 8;
|
||||
export const MaxBrandingElements: number = 200;
|
||||
export const MaxBrandingConfigurationLength: number = 100000;
|
||||
|
||||
const AllowedTags: string[] = ['div', 'span', 'p', 'a', 'button', 'img', 'h1', 'h2', 'h3', 'strong', 'em', 'nav', 'section'];
|
||||
const AllowedTags: string[] = ['div', 'span', 'p', 'a', 'button', 'form', 'input', 'img', 'h1', 'h2', 'h3', 'strong', 'em', 'nav', 'section'];
|
||||
const GlobalAttributes: string[] = ['id', 'class', 'title', 'role', 'aria-label', 'aria-hidden', 'aria-current', 'aria-live'];
|
||||
const AllowedStyles: string[] = [
|
||||
'align-items', 'background', 'background-color', 'border', 'border-bottom', 'border-color', 'border-left',
|
||||
@@ -254,6 +254,10 @@ function normalizeElement(value: any, depth: number, state: INormalizationState)
|
||||
state.warnings.push('Image without alt attribute was rejected.');
|
||||
return undefined;
|
||||
}
|
||||
if (tag === 'form' && !attributes.action) {
|
||||
state.warnings.push('Form without a safe action URL was rejected.');
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const styles: { [key: string]: string } = {};
|
||||
if (value.styles && typeof value.styles === 'object') {
|
||||
@@ -272,7 +276,7 @@ function normalizeElement(value: any, depth: number, state: INormalizationState)
|
||||
const content: string = value.content === undefined || value.content === null
|
||||
? ''
|
||||
: String(value.content).substring(0, 4000);
|
||||
const children: IBrandingElement[] = tag === 'img'
|
||||
const children: IBrandingElement[] = tag === 'img' || tag === 'input'
|
||||
? []
|
||||
: normalizeElements(value.children, depth + 1, state);
|
||||
if ((tag === 'a' || tag === 'button') && !content && children.length === 0 && !attributes['aria-label']) {
|
||||
@@ -293,6 +297,8 @@ function normalizeAttributes(tag: string, value: any, state: INormalizationState
|
||||
const result: { [key: string]: string } = {};
|
||||
if (!value || typeof value !== 'object') {
|
||||
if (tag === 'button') { result.type = 'button'; }
|
||||
if (tag === 'form') { result.method = 'get'; }
|
||||
if (tag === 'input') { result.type = 'search'; result.name = 'q'; }
|
||||
return result;
|
||||
}
|
||||
for (const rawName in value) {
|
||||
@@ -303,9 +309,9 @@ function normalizeAttributes(tag: string, value: any, state: INormalizationState
|
||||
state.warnings.push('Attribute "' + name + '" was rejected.');
|
||||
continue;
|
||||
}
|
||||
if (name === 'href' || name === 'src') {
|
||||
if (name === 'href' || name === 'src' || name === 'action') {
|
||||
const safeUrl: string = sanitizeNavigationUrl(rawValue, state.siteCollectionUrl, name === 'href');
|
||||
if (safeUrl) { result[name] = safeUrl; } else { state.warnings.push('URL attribute was rejected.'); }
|
||||
if (safeUrl && safeUrl.indexOf('//') !== 0) { result[name] = safeUrl; } else { state.warnings.push('URL attribute was rejected.'); }
|
||||
} else if (name === 'target') {
|
||||
if (rawValue === '_blank' || rawValue === '_self') { result[name] = rawValue; }
|
||||
} else if (name === 'id' || name === 'class') {
|
||||
@@ -315,12 +321,24 @@ function normalizeAttributes(tag: string, value: any, state: INormalizationState
|
||||
} else if (name === 'aria-hidden') {
|
||||
if (rawValue === 'true' || rawValue === 'false') { result[name] = rawValue; }
|
||||
} else if (name === 'type' && tag === 'button') {
|
||||
result.type = 'button';
|
||||
result.type = rawValue.toLowerCase() === 'submit' ? 'submit' : 'button';
|
||||
} else if (name === 'type' && tag === 'input') {
|
||||
result.type = 'search';
|
||||
} else if (name === 'method' && tag === 'form') {
|
||||
result.method = 'get';
|
||||
} else if (name === 'name' && tag === 'input') {
|
||||
if (/^[a-z0-9_-]{1,64}$/i.test(rawValue)) { result.name = rawValue; }
|
||||
} else if (name === 'autocomplete' && tag === 'input') {
|
||||
if (rawValue === 'on' || rawValue === 'off') { result.autocomplete = rawValue; }
|
||||
} else if (name === 'maxlength' && tag === 'input') {
|
||||
if (/^\d{1,4}$/.test(rawValue)) { result.maxlength = rawValue; }
|
||||
} else {
|
||||
result[name] = rawValue;
|
||||
}
|
||||
}
|
||||
if (tag === 'button') { result.type = 'button'; }
|
||||
if (tag === 'button' && result.type !== 'submit') { result.type = 'button'; }
|
||||
if (tag === 'form') { result.method = 'get'; }
|
||||
if (tag === 'input') { result.type = 'search'; result.name = result.name || 'q'; }
|
||||
if (tag === 'a' && result.target === '_blank') { result.rel = 'noopener noreferrer'; }
|
||||
return result;
|
||||
}
|
||||
@@ -330,6 +348,8 @@ function isAttributeAllowed(tag: string, name: string): boolean {
|
||||
if (tag === 'a') { return ['href', 'target'].indexOf(name) >= 0; }
|
||||
if (tag === 'img') { return ['src', 'alt', 'width', 'height'].indexOf(name) >= 0; }
|
||||
if (tag === 'button') { return ['type', 'disabled', 'aria-expanded', 'aria-controls'].indexOf(name) >= 0; }
|
||||
if (tag === 'form') { return ['action', 'method'].indexOf(name) >= 0; }
|
||||
if (tag === 'input') { return ['type', 'name', 'placeholder', 'autocomplete', 'maxlength'].indexOf(name) >= 0; }
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user