: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
editButtonIcon.append(createGhostNode());
editButton.append(editButtonIcon);
panel.append(editButton);
var removeButton = new self.Node('div', 1);
'id': 'embedpress_button_remove_' + uid,
'class': 'embedpress_ignore_mouseout embedpress_controller_button'
var removeButtonIcon = new self.Node('div', 1);
'class': 'embedpress-icon-x embedpress_ignore_mouseout'
removeButtonIcon.append(createGhostNode());
removeButton.append(removeButtonIcon);
panel.append(removeButton);
node.value = node.value.trim();
// Trigger the timeout which will load the content
window.setTimeout(function () {
self.parseContentAsync(uid, url, customAttributes, editorInstance);
self.parseContentAsync = function (uid, url, customAttributes, editorInstance) {
customAttributes = typeof customAttributes === 'undefined' ? {} : customAttributes;
url = self.decodeEmbedURLSpecialChars(url, true, customAttributes);
var rawUrl = url.stripShortcode($data.EMBEDPRESS_SHORTCODE);
$(self).triggerHandler('EmbedPress.beforeEmbed', {
'attributes': customAttributes || {}
// Get the parsed embed code from the EmbedPress plugin
self.getParsedContent(url, function getParsedContentCallback (result) {
var embeddedContent = (typeof result.data === 'object' ? result.data.embed : result.data).stripShortcode($data.EMBEDPRESS_SHORTCODE);
var $wrapper = $(self.getElementInContentById('embedpress_wrapper_' + uid, editorInstance));
var wrapperParent = $($wrapper.parent());
// Check if $wrapper was rendered inside a <p> element.
if (wrapperParent.prop('tagName') && wrapperParent.prop('tagName').toUpperCase() === 'P') {
wrapperParent.replaceWith($wrapper);
// Check if there's at least one "space" after $wrapper.
var nextSibling = $($wrapper).next();
if (!nextSibling.length || nextSibling.prop('tagName').toUpperCase() !== 'P') {
//$('<p> </p>').insertAfter($wrapper);
// Check if the url could not be embedded for some reason.
if (rawUrl === embeddedContent) {
$wrapper.replaceWith($('<p>' + rawUrl + '</p>'));
$wrapper.removeClass('is-loading');
$content = $(embeddedContent);
// Fallback to a div, if the result is not a html markup, e.g. a url
$content.html(embeddedContent);
if (!$('iframe', $content).length && result.data.provider_name!=='Infogram') {
var contentWrapper = $($content).clone();
$wrapper.removeClass('embedpress_placeholder');
$wrapper.append(contentWrapper);
editorInstance.undoManager.transact(function () {
var iframe = editorInstance.getDoc().createElement('iframe');
iframe.src = tinymce.Env.ie ? 'javascript:""' : '';
iframe.frameBorder = '0';
iframe.allowTransparency = 'true';
iframe.class = 'wpview-sandbox';
iframe.style.width = '100%';
contentWrapper.append(iframe);
var iframeWindow = iframe.contentWindow;
// Content failed to load.
var iframeDoc = iframeWindow.document;
$(iframe).load(function () {
var maximumChecksAllowed = 8;
var checkerInterval = setInterval(function () {
if (checkIndex === maximumChecksAllowed) {
clearInterval(checkerInterval);
$wrapper.css('width', iframe.width);
$wrapper.css('height', iframe.height);
if (customAttributes.height) {
iframe.height = customAttributes.height;
iframe.style.height = customAttributes.height + 'px';
iframe.height = $('body', iframeDoc).height();
if (customAttributes.width) {
iframe.width = customAttributes.width;
iframe.style.width = customAttributes.width + 'px';
iframe.width = $('body', iframeDoc).width();
'<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />' +
'background: transparent;' +
'body#wpview-iframe-sandbox {' +
'background: transparent;' +
'padding: 1px 0 !important;' +
'margin: -1px 0 0 !important;' +
'body#wpview-iframe-sandbox:before,' +
'body#wpview-iframe-sandbox:after {' +
'<body id="wpview-iframe-sandbox" class="' + editorInstance.getBody().className + '" style="display: inline-block; width: 100%;" >' +
$wrapper.removeClass('embedpress_placeholder');
self.appendElementsIntoWrapper($content, $wrapper, editorInstance);
$wrapper.append($('<span class="wpview-end"></span>'));
if (result && result.data && typeof result.data === 'object') {
result.data.width = $($wrapper).width();
result.data.height = $($wrapper).height();
$(self).triggerHandler('EmbedPress.afterEmbed', {
self.appendElementsIntoWrapper = function (elementsList, wrapper, editorInstance) {
if (elementsList.length > 0) {
$.each(elementsList, function appendElementIntoWrapper (elementIndex, element) {
// Check if the element is a script and do not add it now (if added here it wouldn't be executed)
if (element.tagName && element.tagName.toLowerCase() !== 'script') {
wrapper.append($(element));
if (element.tagName.toLowerCase() === 'iframe') {
$(element).ready(function () {
window.setTimeout(function () {
$.each(editorInstance.dom.select('div.embedpress_wrapper iframe'), function (elementIndex, iframe) {
self.fixIframeSize(iframe);
} else if (element.tagName.toLowerCase() === 'div') {
if ($('img', $(element)).length || $('blockquote', wrapper).length) {
// This ensures that the embed wrapper have the same width as its content
$($(element).parents('.embedpress_wrapper').get(0)).addClass('dynamic-width');
$(element).css('max-width', $($(element).parents('body').get(0)).width());
self.loadAsyncDynamicJsCodeFromElement(element, wrapper, editorInstance);
self.encodeEmbedURLSpecialChars = function (content) {
if (content.match(SHORTCODE_REGEXP)) {
var subject = content.replace(SHORTCODE_REGEXP, '');
if (!subject.isValidUrl()) {
// Bypass the autolink plugin, avoiding to have the url converted to a link automatically
content = content.replace(/http(s?)\:\/\//i, 'embedpress$1://');
// Bypass the autolink plugin, avoiding to have some urls with @ being treated as email address (e.g. GMaps)
content = content.replace('@', '::__at__::').trim();
self.decodeEmbedURLSpecialChars = function (content, applyShortcode, attributes) {
var encodingRegexpRule = /embedpress(s?):\/\//;
applyShortcode = (typeof applyShortcode === 'undefined') ? true : applyShortcode;
attributes = (typeof attributes === 'undefined') ? {} : attributes;
var isEncoded = content.match(encodingRegexpRule);
// Restore http[s] in the url (converted to bypass autolink plugin)
content = content.replace(/embedpress(s?):\/\//, 'http$1://');
content = content.replace('::__at__::', '@').trim();
if ('class' in attributes) {
var classesList = attributes.class.split(/\s/g);
var shouldRemoveDynamicWidthClass = false;
for (var classIndex = 0; classIndex < classesList.length; classIndex++) {
if (classesList[classIndex] === 'dynamic-width') {
shouldRemoveDynamicWidthClass = classIndex;
if (shouldRemoveDynamicWidthClass !== false) {
classesList.splice(shouldRemoveDynamicWidthClass, 1);
if (classesList.length === 0) {
attributes.class = classesList.join(' ');
shouldRemoveDynamicWidthClass = classesList = classIndex = null;
if (isEncoded && applyShortcode) {
var shortcode = '[' + $data.EMBEDPRESS_SHORTCODE;
if (!!Object.keys(attributes).length) {
for (var attrName in attributes) {
attrValue = attributes[attrName];
// Prevent `class` property being empty an treated as a boolean param
if (attrName.toLowerCase() === 'class' && !attrValue.length) {
if (attrValue.isBoolean()) {
if (attrValue.isFalse()) {
shortcode += ' ' + attrName + '="' + attrValue + '"';
attrValue = attrName = null;
content = shortcode + ']' + content + '[/' + $data.EMBEDPRESS_SHORTCODE + ']';
* Method executed after find the editor. It will make additional
* configurations and add the content's stylesheets for the preview
self.onFindEditor = function (editorInstance) {
self.each = tinymce.each;
self.extend = tinymce.extend;
self.JSON = tinymce.util.JSON;
self.Node = tinymce.html.Node;
function onFindEditorCallback () {
$(window.document.getElementsByTagName('head')[0]).append($('<link rel="stylesheet" type="text/css" href="' + (PLG_SYSTEM_ASSETS_CSS_PATH + '/vendor/bootstrap/bootstrap.min.css?v=' + self.params.versionUID) + '">'));
self.addStylesheet(PLG_SYSTEM_ASSETS_CSS_PATH + '/font.css?v=' + self.params.versionUID, editorInstance, editorInstance);
self.addStylesheet(PLG_SYSTEM_ASSETS_CSS_PATH + '/preview.css?v=' + self.params.versionUID, editorInstance, editorInstance);
self.addStylesheet(PLG_CONTENT_ASSETS_CSS_PATH + '/embedpress.css?v=' + self.params.versionUID, editorInstance, editorInstance);
self.addEvent('nodechange', editorInstance, self.onNodeChange);
self.addEvent('keydown', editorInstance, function (e) {
self.onKeyDown(e, editorInstance);
var onUndoCallback = function (e) {
self.onUndo(e, editorInstance);
self.addEvent('undo', editorInstance, onUndoCallback); // TinyMCE
self.addEvent('undo', editorInstance.undoManager, onUndoCallback); // JCE
var doc = editorInstance.getDoc();
$(doc).on('mouseenter', '.embedpress_wrapper', function (e) {
self.onMouseEnter(e, editorInstance);
$(doc).on('mouseout', '.embedpress_wrapper', self.onMouseOut);
$(doc).on('mousedown', '.embedpress_wrapper > .embedpress_controller_panel', function (e) {
self.cancelEvent(e, editorInstance);
// Add the node filter that will convert the url into the preview box for the embed code
editorInstance.parser.addNodeFilter('#text', function addNodeFilterIntoParser (nodes, arg) {
self.each(nodes, function eachNodeInParser (node) {
// Stop if the node is "isolated". It would generate an error in the browser console and break.
if (node.parent === null && node.prev === null) {
var subject = node.value.trim();
if (!subject.isValidUrl()) {
if (!subject.match(SHORTCODE_REGEXP)) {
subject = self.decodeEmbedURLSpecialChars(subject);
if (!subject.isValidUrl()) {
if (!subject.match(SHORTCODE_REGEXP)) {
subject = node.value.stripShortcode($data.EMBEDPRESS_SHORTCODE).trim();
// These patterns need to have groups for the pre and post texts
// @TODO: maybe remove this list of URLs? Let the server side code decide what URL should be parsed
var patterns = self.getProvidersURLPatterns();
(function tryToMatchContentAgainstUrlPatternWithIndex (urlPatternIndex) {
if (urlPatternIndex < patterns.length) {
var urlPattern = patterns[urlPatternIndex];
var urlPatternRegex = new RegExp(urlPattern);
var url = self.decodeEmbedURLSpecialChars(subject).trim();
var matches = url.match(urlPatternRegex);
// Check if content matches the url pattern.
if (matches && matches !== null && !!matches.length) {
url = self.encodeEmbedURLSpecialChars(matches[2]);
var wrapper = self.addURLsPlaceholder(node, url, editorInstance);
var doc = editorInstance.getDoc();
var previewWrapper = $(doc.querySelector('#' + wrapper.attributes.map['id']));
var previewWrapperParent = $(previewWrapper.parent());
if (previewWrapperParent && previewWrapperParent.prop('tagName') && previewWrapperParent.prop('tagName').toUpperCase() === 'P') {
previewWrapperParent.replaceWith(previewWrapper);
var previewWrapperOlderSibling = previewWrapper.prev();
if (previewWrapperOlderSibling && previewWrapperOlderSibling.prop('tagName') && previewWrapperOlderSibling.prop('tagName').toUpperCase() === 'P' && !previewWrapperOlderSibling.html().replace(/\ \;/i, '').length) {
previewWrapperOlderSibling.remove();
if (typeof previewWrapperOlderSibling.html() !== 'undefined') {
if (previewWrapperOlderSibling.html().match(/<[\/]?br>/)) {
if (!previewWrapperOlderSibling.prev().length) {
previewWrapperOlderSibling.remove();
var previewWrapperYoungerSibling = previewWrapper.next();
if (previewWrapperYoungerSibling && previewWrapperYoungerSibling.length && previewWrapperYoungerSibling.prop('tagName').toUpperCase() === 'P') {
if (!previewWrapperYoungerSibling.next().length && !previewWrapperYoungerSibling.html().replace(/\ \;/i, '').length) {
previewWrapperYoungerSibling.remove();
$('<p> </p>').insertAfter(previewWrapper);
$('<p> </p>').insertAfter(previewWrapper);
editorInstance.selection.select(editorInstance.getBody(), true);
editorInstance.selection.collapse(false);
// No match. So we move on to check the next url pattern.
tryToMatchContentAgainstUrlPatternWithIndex(urlPatternIndex + 1);
// Add the filter that will convert the preview box/embed code back to the raw url
editorInstance.serializer.addNodeFilter('div', function addNodeFilterIntoSerializer (nodes, arg) {
self.each(nodes, function eachNodeInSerializer (node) {
// Stop if the node is "isolated". It would generate an error in the browser console and break.
if (node.parent === null && node.prev === null) {
var nodeClasses = (node.attributes.map.class || '').split(' ');
var wrapperFactoryClasses = ['embedpress_wrapper', 'embedpress_placeholder', 'wpview', 'wpview-wrap'];
var isWrapped = nodeClasses.filter(function (n) {
return wrapperFactoryClasses.indexOf(n) != -1;
var factoryAttributes = ['id', 'style', 'data-loading-text', 'data-uid', 'data-url'];
var customAttributes = {};
var dataPrefix = 'data-';
for (var attr in node.attributes.map) {
if (attr.toLowerCase() !== 'class') {
if (factoryAttributes.indexOf(attr) < 0) {
// Remove the "data-" prefix for more readability
customAttributes[attr.replace(dataPrefix, '')] = node.attributes.map[attr];
for (var wrapperClassIndex in nodeClasses) {
var wrapperClass = nodeClasses[wrapperClassIndex];
if (wrapperFactoryClasses.indexOf(wrapperClass) === -1) {
customClasses.push(wrapperClass);
if (!!customClasses.length) {
customAttributes.class = customClasses.join(' ');
var p = new self.Node('p', 1);
var text = new self.Node('#text', 3);
text.value = (node.attributes.map && typeof node.attributes.map['data-url'] != 'undefined') ? self.decodeEmbedURLSpecialChars(node.attributes.map['data-url'].trim(), true, customAttributes) : '';
editorInstance.serializer.addNodeFilter('p', function addNodeFilterIntoSerializer (nodes, arg) {