diff --git a/jade/page-contents/autocomplete_content.html b/jade/page-contents/autocomplete_content.html index 17bd59f122..b04c8699f4 100644 --- a/jade/page-contents/autocomplete_content.html +++ b/jade/page-contents/autocomplete_content.html @@ -39,6 +39,8 @@
The data is a json object where the key is the matching string and the value is an optional image url.
+The key must be a text string. If you trust your data, or have properly sanitized your user input, you may
+ use HTML by setting the option allowUnsafeHTML: true
.
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('.autocomplete');
@@ -112,6 +114,12 @@ Options
Sort function that defines the order of the list of autocomplete options.
+
+ allowUnsafeHTML
+ Boolean
+ false
+ If true will render the key from each item directly as HTML. User input MUST be properly sanitized first.
+
diff --git a/jade/page-contents/toasts_content.html b/jade/page-contents/toasts_content.html
index 1b5ee48c0c..48422f46ea 100644
--- a/jade/page-contents/toasts_content.html
+++ b/jade/page-contents/toasts_content.html
@@ -4,14 +4,14 @@
Materialize provides an easy way for you to send unobtrusive alerts to your users through toasts. These toasts are also placed and sized responsively, try it out by clicking the button below on different device sizes.
- Toast!
+ Toast!
To do this, call the M.toast() function programmatically in JavaScript.
- M.toast({html: 'I am a toast!'})
+ M.toast({text: 'I am a toast!'})
One way to add this into your application is to add this as an onclick event to a button.
- <a onclick="M.toast({html: 'I am a toast'})" class="btn">Toast!</a>
+ <a onclick="M.toast({text: 'I am a toast'})" class="btn">Toast!</a>
@@ -30,11 +30,37 @@ Options
+
+ text
+ String
+ ''
+ The content of the Toast.
+
+
+ unsafeHTML
+ String, HTMLElement
+ ''
+
+ HTML content that will be appended to to text
.
+ Only use properly sanitized or otherwise trusted data for unsafeHTML
.
+
+
html
String
''
- The HTML content of the Toast.
+
+
+ (DEPRECATED): will be removed in a later release.
+
+
+ HTML content that will be appended to text
.
+ Only use properly sanitized or otherwise trusted data for html
.
+
+
+ Will be ignored if unsafeHTML
is set.
+
+
displayLength
@@ -117,11 +143,16 @@ Properties
Custom HTML
- You can pass in an HTML String as the first argument as well. Take a look at the example below, where we pass in text as well as a flat button. If you call an external function instead of in-line JavaScript, you will not need to escape quotation marks.
+ You can pass in an HTML String as the first argument as well. Take a look at the example below, where we pass
+ in text as well as a flat button. If you call an external function instead of in-line JavaScript, you will not
+ need to escape quotation marks.
+
+ Only use a properly sanitized or otherwise trusted HTML string.
+
Toast with Action
var toastHTML = '<span>I am toast content</span><button class="btn-flat toast-action">Undo</button>';
- M.toast({html: toastHTML});
+ M.toast({unsafeHTML: toastHTML});
@@ -129,9 +160,9 @@ Custom HTML
Callback
You can have the toast callback a function when it has been dismissed.
- Toast!
+ Toast!
- <a class="btn" onclick="M.toast({html: 'I am a toast', completeCallback: function(){alert('Your toast was dismissed')}})">Toast!</a>
+ <a class="btn" onclick="M.toast({text: 'I am a toast', completeCallback: function(){alert('Your toast was dismissed')}})">Toast!</a>
@@ -140,11 +171,11 @@ Callback
Styling Toasts
We've added the ability to customize your toasts easily. You can pass in classes as an optional parameter into the toast function. We've added a rounded class for you, but you can create your own CSS classes and apply them to toasts. Checkout out our full example below.
- Round Toast!
+ Round Toast!
// 'rounded' is the class I'm applying to the toast
- M.toast({html: 'I am a toast!', classes: 'rounded'});
+ M.toast({text: 'I am a toast!', classes: 'rounded'});
diff --git a/jade/page-contents/tooltips_content.html b/jade/page-contents/tooltips_content.html
index 404d5aff76..7feae0ff7a 100644
--- a/jade/page-contents/tooltips_content.html
+++ b/jade/page-contents/tooltips_content.html
@@ -70,11 +70,35 @@ Options
0
Delay time before tooltip appears.
+
+ text
+ String
+
+ Text string for the tooltip.
+
+
+ unsafeHTML
+ String
+ null
+ HTML content that will be appended to to text
.
+ Only use properly sanitized or otherwise trusted data for unsafeHTML
.
+
html
String
null
- Can take regular text or HTML strings.
+
+
+ (DEPRECATED): will be removed in a later release.
+
+
+ HTML content that will be appended to text
.
+ Only use properly sanitized or otherwise trusted data for html
.
+
+
+ Will be ignored if unsafeHTML
is set.
+
+
margin
diff --git a/js/autocomplete.js b/js/autocomplete.js
index 1bed2301a2..5523c7522d 100644
--- a/js/autocomplete.js
+++ b/js/autocomplete.js
@@ -9,7 +9,8 @@
sortFunction: function(a, b, inputString) {
// Sort function for sorting autocomplete results
return a.indexOf(inputString) - b.indexOf(inputString);
- }
+ },
+ allowUnsafeHTML: false
};
/**
@@ -282,22 +283,14 @@
/**
* Highlight partial match
*/
- _highlight(string, $el) {
- let img = $el.find('img');
- let matchStart = $el
- .text()
- .toLowerCase()
- .indexOf('' + string.toLowerCase() + ''),
- matchEnd = matchStart + string.length - 1,
- beforeMatch = $el.text().slice(0, matchStart),
- matchText = $el.text().slice(matchStart, matchEnd + 1),
- afterMatch = $el.text().slice(matchEnd + 1);
- $el.html(
- `${beforeMatch}${matchText}${afterMatch}`
- );
- if (img.length) {
- $el.prepend(img);
- }
+ _highlight(input, label) {
+ const start = label.toLowerCase().indexOf('' + input.toLowerCase() + '');
+ const end = start + input.length - 1;
+ //custom filters may return results where the string does not match any part
+ if (start == -1 || end == -1) {
+ return [label, '', ''];
+ }
+ return [label.slice(0, start), label.slice(start, end + 1), label.slice(end + 1)];
}
/**
@@ -376,18 +369,32 @@
// Render
for (let i = 0; i < matchingData.length; i++) {
- let entry = matchingData[i];
- let $autocompleteOption = $('');
+ const entry = matchingData[i];
+ const item = document.createElement('li');
if (!!entry.data) {
- $autocompleteOption.append(
- `${entry.key}`
- );
+ const img = document.createElement('img');
+ img.classList.add("right", "circle");
+ img.src = entry.data;
+ item.appendChild(img);
+ }
+
+ const parts = this._highlight(val, entry.key);
+ const s = document.createElement('span');
+ if (this.options.allowUnsafeHTML) {
+ s.innerHTML = parts[0] + '' + parts[1] + '' + parts[2];
} else {
- $autocompleteOption.append('' + entry.key + '');
+ s.appendChild(document.createTextNode(parts[0]))
+ if (!!parts[1]){
+ const highlight = document.createElement('span');
+ highlight.textContent = parts[1];
+ highlight.classList.add("highlight");
+ s.appendChild(highlight);
+ s.appendChild(document.createTextNode(parts[2]));
+ }
}
+ item.appendChild(s);
- $(this.container).append($autocompleteOption);
- this._highlight(val, $autocompleteOption);
+ $(this.container).append(item);
}
}
diff --git a/js/toasts.js b/js/toasts.js
index b0e4b83aa2..7500b285dd 100644
--- a/js/toasts.js
+++ b/js/toasts.js
@@ -3,6 +3,8 @@
let _defaults = {
html: '',
+ unsafeHTML: '',
+ text: '',
displayLength: 4000,
inDuration: 300,
outDuration: 375,
@@ -18,7 +20,12 @@
* @member Toast#options
*/
this.options = $.extend({}, Toast.defaults, options);
- this.message = this.options.html;
+ this.htmlMessage = this.options.html;
+ // If the new unsafeHTML is used, prefer that
+ if (!!this.options.unsafeHTML){
+ this.htmlMessage = this.options.unsafeHTML;
+ }
+ this.message = this.options.text;
/**
* Describes current pan state toast
@@ -188,28 +195,26 @@
$(toast).addClass(this.options.classes);
}
- // Set content
+ // Set safe text content
+ toast.textContent = this.message;
if (
typeof HTMLElement === 'object'
- ? this.message instanceof HTMLElement
- : this.message &&
- typeof this.message === 'object' &&
- this.message !== null &&
- this.message.nodeType === 1 &&
- typeof this.message.nodeName === 'string'
- ) {
- toast.appendChild(this.message);
-
- // Check if it is jQuery object
- } else if (!!this.message.jquery) {
- $(toast).append(this.message[0]);
-
- // Insert as html;
+ ? this.htmlMessage instanceof HTMLElement
+ : this.htmlMessage &&
+ typeof this.htmlMessage === 'object' &&
+ this.htmlMessage !== null &&
+ this.htmlMessage.nodeType === 1 &&
+ typeof this.htmlMessage.nodeName === 'string'
+ ) { //if the htmlMessage is an HTML node, append it directly
+ toast.appendChild(this.htmlMessage);
+ } else if (!!this.htmlMessage.jquery) { // Check if it is jQuery object, append the node
+ $(toast).append(this.htmlMessage[0]);
} else {
- toast.innerHTML = this.message;
+ // Append as unsanitized html;
+ $(toast).append(this.htmlMessage);
}
- // Append toasft
+ // Append toast
Toast._container.appendChild(toast);
return toast;
}
diff --git a/js/tooltip.js b/js/tooltip.js
index 1769597fb5..a14e8f3f6b 100644
--- a/js/tooltip.js
+++ b/js/tooltip.js
@@ -5,6 +5,8 @@
exitDelay: 200,
enterDelay: 0,
html: null,
+ text: '',
+ unsafeHTML: null,
margin: 5,
inDuration: 250,
outDuration: 200,
@@ -68,13 +70,24 @@
let tooltipContentEl = document.createElement('div');
tooltipContentEl.classList.add('tooltip-content');
- tooltipContentEl.innerHTML = this.options.html;
+ this._setTooltipContent(tooltipContentEl);
+
tooltipEl.appendChild(tooltipContentEl);
document.body.appendChild(tooltipEl);
}
+ _setTooltipContent(tooltipContentEl) {
+ tooltipContentEl.textContent = this.options.text;
+ if (!!this.options.html){
+ $(tooltipContentEl).append(this.options.html);
+ }
+ if (!!this.options.unsafeHTML){
+ $(tooltipContentEl).append(this.options.unsafeHTML);
+ }
+ }
+
_updateTooltipContent() {
- this.tooltipEl.querySelector('.tooltip-content').innerHTML = this.options.html;
+ this._setTooltipContent(this.tooltipEl.querySelector('.tooltip-content'));
}
_setupEventHandlers() {
@@ -285,7 +298,7 @@
let positionOption = this.el.getAttribute('data-position');
if (tooltipTextOption) {
- attributeOptions.html = tooltipTextOption;
+ attributeOptions.text = tooltipTextOption;
}
if (positionOption) {
diff --git a/test/html/autocomplete.html b/test/html/autocomplete.html
new file mode 100644
index 0000000000..ba33043b27
--- /dev/null
+++ b/test/html/autocomplete.html
@@ -0,0 +1,195 @@
+
+
+
+
+
+
+ Materialize - Documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Default autocomplete example
+
+
+
+
+ textsms
+
+
+
+
+
+
+
+ Custom filter function
+
+
+
+
+ textsms
+
+
+
+
+
+
+
+ Limit Set
+
+
+
+
+ textsms
+
+
+
+
+
+
+
+ allowUnsafeHTML: false
+
+
+
+
+ textsms
+
+
+
+
+
+
+
+ allowUnsafeHTML: true
+
+
+
+
+ textsms
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/html/toast.html b/test/html/toast.html
new file mode 100644
index 0000000000..2fdf2c073c
--- /dev/null
+++ b/test/html/toast.html
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+ Materialize - Documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Toast with text!
+ Toast with html!
+ Toast with unsafeHTML!
+ Toast with unsafeHTML and text!
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/html/tooltip.html b/test/html/tooltip.html
new file mode 100644
index 0000000000..19767e7cba
--- /dev/null
+++ b/test/html/tooltip.html
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+ Materialize - Documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file