AlkantarClanX12
Current Path : /proc/self/root/home/thanudqk/128shen.com/wp-content/plugins/embedpress/assets/js/ |
Current File : //proc/self/root/home/thanudqk/128shen.com/wp-content/plugins/embedpress/assets/js/preview.js |
/** * @package EmbedPress * @author EmbedPress <help@embedpress.com> * @copyright Copyright (C) 2018 EmbedPress. All rights reserved. * @license GPLv2 or later * @since 1.0 */ (function ($, String, $data, undefined) { 'use strict'; $(window.document).ready(function () { String.prototype.capitalizeFirstLetter = function () { return this.charAt(0).toUpperCase() + this.slice(1); }; String.prototype.isValidUrl = function () { var rule = /^(https?|embedpresss?):\/\//i; return rule.test(this.toString()); }; String.prototype.hasShortcode = function (shortcode) { var shortcodeRule = new RegExp('\\[' + shortcode + '(?:\\]|.+?\\])', 'ig'); return !!this.toString().match(shortcodeRule); }; String.prototype.stripShortcode = function (shortcode) { var stripRule = new RegExp('(\\[' + shortcode + '(?:\\]|.+?\\])|\\[\\/' + shortcode + '\\])', 'ig'); return this.toString().replace(stripRule, ''); }; String.prototype.setShortcodeAttribute = function (attr, value, shortcode, replaceInsteadOfMerge) { replaceInsteadOfMerge = typeof replaceInsteadOfMerge === 'undefined' ? false : replaceInsteadOfMerge; var subject = this.toString(); if (subject.hasShortcode(shortcode)) { var attributes = subject.getShortcodeAttributes(shortcode); if (attributes.hasOwnProperty(attr)) { if (replaceInsteadOfMerge) { attributes[attr] = value; } else { attributes[attr] += ' ' + value; } } else { attributes[attr] = value; } if (!!Object.keys(attributes).length) { var parsedAttributes = []; for (var ats in attributes) { parsedAttributes.push(ats + '="' + attributes[ats] + '"'); } subject = '[' + shortcode + ' ' + parsedAttributes.join(' ') + ']' + subject.stripShortcode(shortcode) + '[/' + shortcode + ']'; } else { subject = '[' + shortcode + ']' + subject.stripShortcode(shortcode) + '[/' + shortcode + ']'; } return subject; } else { return subject; } }; String.prototype.getShortcodeAttributes = function (shortcode) { var subject = this.toString(); if (subject.hasShortcode(shortcode)) { var attributes = {}; var propertiesString = (new RegExp(/\[embed\s*(.*?)\]/ig)).exec(subject)[1]; // Separate all shortcode attributes from the rest of the string if (propertiesString.length > 0) { var extractAttributesRule = new RegExp(/(\!?\w+-?\w*)(?:="(.+?)")?/ig); // Extract attributes and their values var match; while (match = extractAttributesRule.exec(propertiesString)) { var attrName = match[1]; var attrValue; if (match[2] === undefined) { // Prevent `class` property being empty an treated as a boolean param if (attrName.toLowerCase() !== 'class') { if (attrName.indexOf('!') === 0) { attrName = attrName.replace('!', ''); attrValue = 'false'; } else { attrValue = 'true'; } attributes[attrName] = attrValue; } } else { attrValue = match[2]; if (attrValue.isBoolean()) { attrValue = attrValue.isFalse() ? 'false' : 'true'; } attributes[attrName] = attrValue; } } match = extractAttributesRule = null; } propertiesString = null; return attributes; } else { return {}; } }; String.prototype.isBoolean = function () { var subject = this.toString().trim().toLowerCase(); return subject.isTrue(false) || subject.isFalse(); }; String.prototype.isTrue = function (defaultValue) { var subject = this.toString().trim().toLowerCase(); defaultValue = typeof defaultValue === undefined ? true : defaultValue; switch (subject) { case '': defaultValue += ''; return !defaultValue.isFalse(); case '1': case 'true': case 'on': case 'yes': case 'y': return true; default: return false; } }; String.prototype.isFalse = function () { var subject = this.toString().trim().toLowerCase(); switch (subject) { case '0': case 'false': case 'off': case 'no': case 'n': case 'nil': case 'null': return true; default: return false; } }; var SHORTCODE_REGEXP = new RegExp('\\[\/?' + $data.EMBEDPRESS_SHORTCODE + '\\]', 'gi'); var EmbedPress = function () { var self = this; var PLG_SYSTEM_ASSETS_CSS_PATH = $data.EMBEDPRESS_URL_ASSETS + 'css'; var PLG_CONTENT_ASSETS_CSS_PATH = PLG_SYSTEM_ASSETS_CSS_PATH; /** * The default params * * @type Object */ self.params = { baseUrl: '', versionUID: '0' }; /** * True, if user agent is iOS * @type Boolean True, if is iOS */ self.iOS = /iPad|iPod|iPhone/.test(window.navigator.userAgent); /** * The active wrapper, activated by the mouse enter event * @type Element */ self.activeWrapper = null; self.activeWrapperForModal = null; /** * The active controller panel * @type Element */ self.activeControllerPanel = null; /** * A list containing all loaded editor instances on the page * @type Array */ self.loadedEditors = []; /** * Init the plugin * * @param object params Override the plugin's params * @return void */ self.init = function (params) { $.extend(self.params, params); // Fix iOS doesn't firing click events on 'standard' elements if (self.iOS) { $(window.document.body).css('cursor', 'pointer'); } $(self.onReady); }; self.addEvent = function (event, element, callback) { if (typeof element.on !== 'undefined') { element.on(event, callback); } else { if (element['on' + event.capitalizeFirstLetter()]) { element['on' + event.capitalizeFirstLetter()].add(callback); } } }; self.isEmpty = function (list) { return list.length === 0; }; self.isDefined = function (attribute) { return (typeof attribute !== 'undefined') && (attribute !== null); }; self.makeId = function () { var text = ''; var possible = 'abcdefghijklmnopqrstuvwxyz0123456789'; for (var i = 0; i < 5; i++) text += possible.charAt(Math.floor(Math.random() * possible.length)); return text; }; self.loadAsyncDynamicJsCodeFromElement = function (subject, wrapper, editorInstance) { subject = $(subject); if (subject.prop('tagName') && subject.prop('tagName').toLowerCase() === 'script') { var scriptSrc = subject.attr('src') || null; if (!scriptSrc) { self.addScriptDeclaration(wrapper, subject.html(), editorInstance); } else { self.addScript(scriptSrc, null, wrapper, editorInstance); } } else { var innerScriptsList = $('script', subject); if (innerScriptsList.length > 0) { $.each(innerScriptsList, function (innerScriptIndex, innerScript) { self.loadAsyncDynamicJsCodeFromElement(innerScript, wrapper, editorInstance); }); } } }; /** * Method executed on the document ready event * * @return void */ self.onReady = function () { var findEditors = function () { // Wait until the editor is available var interval = window.setInterval( function () { var editorsFound = self.getEditors(); if (editorsFound.length) { self.loadedEditors = editorsFound; for (var editorIndex = 0; editorIndex < self.loadedEditors.length; editorIndex++) { self.onFindEditor(self.loadedEditors[editorIndex]); } window.clearInterval(interval); return self.loadedEditors; } }, 250 ); }; if (self.tinymceIsAvailable()) { findEditors(); } // Add support for the Beaver Builder. if (typeof FLLightbox !== 'undefined') { $.each(FLLightbox._instances, function (index) { FLLightbox._instances[index].on('open', function () { setTimeout(function () { findEditors(); }, 500); }); FLLightbox._instances[index].on('didHideLightbox', function () { setTimeout(function () { findEditors(); }, 500); }); }); } }; /** * Detects if tinymce object is available * @return Boolean True, if available */ self.tinymceIsAvailable = function () { return typeof window.tinymce === 'object' || typeof window.tinyMCE === 'object'; }; /** * Returns true if the controller panel is active * @return Boolean True, if the controller panel is active */ self.controllerPanelIsActive = function () { return typeof self.activeControllerPanel !== 'undefined' && self.activeControllerPanel !== null; }; /** * Returns the editor * @return Object The editor */ self.getEditors = function () { if (!window.tinymce || !window.tinymce.editors || window.tinymce.editors.length === 0) { return []; } return window.tinymce.editors || []; }; /** * Parses the content, sending it to the component which will * look for urls to be parsed into embed codes * * @param string content The content * @param function onsuccess The callback called on success * @return void */ self.getParsedContent = function (content, onsuccess) { // Get the parsed content $.ajax({ type: 'POST', url: self.params.baseUrl + 'wp-admin/admin-ajax.php', data: { action: 'embedpress_do_ajax_request', subject: content }, success: onsuccess, dataType: 'json', async: true }); }; self.addStylesheet = function (url, editorInstance) { var head = editorInstance.getDoc().getElementsByTagName('head')[0]; var $style = $('<link rel="stylesheet" type="text/css" href="' + url + '">'); $style.appendTo(head); }; self.convertURLSchemeToPattern = function (scheme) { var prefix = '(.*)((?:http|embedpress)s?:\\/\\/(?:www\\.)?', suffix = '[\\/]?)(.*)', pattern; scheme = scheme.replace(/\*/g, '[a-zA-Z0-9=&_\\-\\?\\.\\/!\\+%:@,#]+'); scheme = scheme.replace(/\./g, '\\.'); scheme = scheme.replace(/\//g, '\\/'); return prefix + scheme + suffix; }; self.getProvidersURLPatterns = function () { // @todo: Add option to disable/enable the providers var patterns = []; self.each($data.urlSchemes, function convertEachURLSchemesToPattern (scheme) { patterns.push(self.convertURLSchemeToPattern(scheme)); }); return patterns; }; self.addScript = function (source, callback, wrapper, editorInstance) { var doc = editorInstance.getDoc(); if (typeof wrapper === 'undefined' || !wrapper) { wrapper = $(doc.getElementsByTagName('head')[0]); } var $script = $(doc.createElement('script')); $script.attr('async', 1); if (typeof callback === 'function') { $script.ready(callback); } $script.attr('src', source); wrapper.append($script); }; self.addScriptDeclaration = function (wrapper, declaration, editorInstance) { var doc = editorInstance.getDoc(), $script = $(doc.createElement('script')); $(wrapper).append($script); $script.text(declaration); }; self.addURLsPlaceholder = function (node, url, editorInstance) { var uid = self.makeId(); var wrapperClasses = ['embedpress_wrapper', 'embedpress_placeholder', 'wpview', 'wpview-wrap']; var shortcodeAttributes = node.value.getShortcodeAttributes($data.EMBEDPRESS_SHORTCODE); var customAttributes = shortcodeAttributes; var customClasses = ''; if (!!Object.keys(shortcodeAttributes).length) { var specialAttributes = ['class', 'href', 'data-href']; // Iterates over each attribute of shortcodeAttributes to add the prefix "data-" if missing var dataPrefix = 'data-'; var prefixedShortcodeAttributes = []; for (var attr in shortcodeAttributes) { if (specialAttributes.indexOf(attr) === -1) { if (attr.indexOf(dataPrefix) !== 0) { prefixedShortcodeAttributes[dataPrefix + attr] = shortcodeAttributes[attr]; } else { prefixedShortcodeAttributes[attr] = shortcodeAttributes[attr]; } } else { attr = attr.replace(dataPrefix, ''); if (attr === 'class') { wrapperClasses.push(shortcodeAttributes[attr]); } } } shortcodeAttributes = prefixedShortcodeAttributes; prefixedShortcodeAttributes = dataPrefix = null; } if (('data-width' in shortcodeAttributes || 'data-height' in shortcodeAttributes) && 'data-responsive' in shortcodeAttributes) { shortcodeAttributes['data-responsive'] = 'false'; } var wrapper = new self.Node('div', 1); var wrapperSettings = { 'class': Array.from(new Set(wrapperClasses)).join(' '), 'data-url': url, 'data-uid': uid, 'id': 'embedpress_wrapper_' + uid, 'data-loading-text': 'Loading your embed...' }; wrapperSettings = $.extend({}, wrapperSettings, shortcodeAttributes); if (wrapperSettings.class.indexOf('is-loading') === -1) { wrapperSettings.class += ' is-loading'; } wrapper.attr(wrapperSettings); var panel = new self.Node('div', 1); panel.attr({ 'id': 'embedpress_controller_panel_' + uid, 'class': 'embedpress_controller_panel embedpress_ignore_mouseout hidden' }); wrapper.append(panel); function createGhostNode (htmlTag, content) { htmlTag = htmlTag || 'span'; content = content || ' '; var ghostNode = new self.Node(htmlTag, 1); ghostNode.attr({ 'class': 'hidden' }); var ghostText = new self.Node('#text', 3); ghostText.value = content; ghostNode.append(ghostText); return ghostNode; } var editButton = new self.Node('div', 1); editButton.attr({ 'id': 'embedpress_button_edit_' + uid, 'class': 'embedpress_ignore_mouseout embedpress_controller_button' }); var editButtonIcon = new self.Node('div', 1); editButtonIcon.attr({ 'class': 'embedpress-icon-pencil embedpress_ignore_mouseout' }); editButtonIcon.append(createGhostNode()); editButton.append(editButtonIcon); panel.append(editButton); var removeButton = new self.Node('div', 1); removeButton.attr({ 'id': 'embedpress_button_remove_' + uid, 'class': 'embedpress_ignore_mouseout embedpress_controller_button' }); var removeButtonIcon = new self.Node('div', 1); removeButtonIcon.attr({ 'class': 'embedpress-icon-x embedpress_ignore_mouseout' }); removeButtonIcon.append(createGhostNode()); removeButton.append(removeButtonIcon); panel.append(removeButton); node.value = node.value.trim(); node.replace(wrapper); // Trigger the timeout which will load the content window.setTimeout(function () { self.parseContentAsync(uid, url, customAttributes, editorInstance); }, 200); return wrapper; }; 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', { 'url': rawUrl, 'meta': { '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); } nextSibling = null; } wrapperParent = null; // Check if the url could not be embedded for some reason. if (rawUrl === embeddedContent) { // Echoes the raw url $wrapper.replaceWith($('<p>' + rawUrl + '</p>')); return; } $wrapper.removeClass('is-loading'); // Parse as DOM element var $content; try { $content = $(embeddedContent); } catch (err) { // Fallback to a div, if the result is not a html markup, e.g. a url $content = $('<div>'); $content.html(embeddedContent); } if (!$('iframe', $content).length && result.data.provider_name!=='Infogram') { var contentWrapper = $($content).clone(); contentWrapper.html(''); $wrapper.removeClass('embedpress_placeholder'); $wrapper.append(contentWrapper); setTimeout(function () { editorInstance.undoManager.transact(function () { var iframe = editorInstance.getDoc().createElement('iframe'); iframe.src = tinymce.Env.ie ? 'javascript:""' : ''; iframe.frameBorder = '0'; iframe.allowTransparency = 'true'; iframe.scrolling = 'no'; iframe.class = 'wpview-sandbox'; iframe.style.width = '100%'; contentWrapper.append(iframe); var iframeWindow = iframe.contentWindow; // Content failed to load. if (!iframeWindow) { return; } var iframeDoc = iframeWindow.document; $(iframe).load(function () { var maximumChecksAllowed = 8; var checkIndex = 0; var checkerInterval = setInterval(function () { if (checkIndex === maximumChecksAllowed) { clearInterval(checkerInterval); setTimeout(function () { $wrapper.css('width', iframe.width); $wrapper.css('height', iframe.height); }, 100); } else { if (customAttributes.height) { iframe.height = customAttributes.height; iframe.style.height = customAttributes.height + 'px'; } else { iframe.height = $('body', iframeDoc).height(); } if (customAttributes.width) { iframe.width = customAttributes.width; iframe.style.width = customAttributes.width + 'px'; } else { iframe.width = $('body', iframeDoc).width(); } checkIndex++; } }, 250); }); iframeDoc.open(); iframeDoc.write( '<!DOCTYPE html>' + '<html>' + '<head>' + '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />' + '<style>' + 'html {' + 'background: transparent;' + 'padding: 0;' + 'margin: 0;' + '}' + '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 {' + 'display: none;' + 'content: "";' + '}' + '</style>' + '</head>' + '<body id="wpview-iframe-sandbox" class="' + editorInstance.getBody().className + '" style="display: inline-block; width: 100%;" >' + $content.html() + '</body>' + '</html>' ); iframeDoc.close(); }); }, 50); } else { $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', { 'meta': result.data, 'url': rawUrl, 'wrapper': $wrapper }); }); }; 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); }); }, 300); }); } 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); }); } return wrapper; }; self.encodeEmbedURLSpecialChars = function (content) { if (content.match(SHORTCODE_REGEXP)) { var subject = content.replace(SHORTCODE_REGEXP, ''); if (!subject.isValidUrl()) { return content; } content = subject; subject = null; } // 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(); return content; }; 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; break; } } if (shouldRemoveDynamicWidthClass !== false) { classesList.splice(shouldRemoveDynamicWidthClass, 1); if (classesList.length === 0) { delete attributes.class; } attributes.class = classesList.join(' '); } shouldRemoveDynamicWidthClass = classesList = classIndex = null; } if (isEncoded && applyShortcode) { var shortcode = '[' + $data.EMBEDPRESS_SHORTCODE; if (!!Object.keys(attributes).length) { var attrValue; 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) { } else { if (attrValue.isBoolean()) { shortcode += ' '; if (attrValue.isFalse()) { shortcode += '!'; } shortcode += attrName; } else { shortcode += ' ' + attrName + '="' + attrValue + '"'; } } } attrValue = attrName = null; } content = shortcode + ']' + content + '[/' + $data.EMBEDPRESS_SHORTCODE + ']'; } return content; }; /** * Method executed after find the editor. It will make additional * configurations and add the content's stylesheets for the preview * * @return void */ 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); }); doc = null; // 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) { return; } var subject = node.value.trim(); if (!subject.isValidUrl()) { if (!subject.match(SHORTCODE_REGEXP)) { return; } } subject = self.decodeEmbedURLSpecialChars(subject); if (!subject.isValidUrl()) { if (!subject.match(SHORTCODE_REGEXP)) { return; } } 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); setTimeout(function () { var doc = editorInstance.getDoc(); if (doc === null) { return; } 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(); } else { 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); } } else { $('<p> </p>').insertAfter(previewWrapper); } setTimeout(function () { editorInstance.selection.select(editorInstance.getBody(), true); editorInstance.selection.collapse(false); }, 50); }, 50); } else { // No match. So we move on to check the next url pattern. tryToMatchContentAgainstUrlPatternWithIndex(urlPatternIndex + 1); } } })(0); }); }); // 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) { return; } 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; }).length > 0; if (isWrapped) { 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]; } } else { var customClasses = []; 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) : ''; p.append(text.clone()); node.replace(text); text.replace(p); } }); }); editorInstance.serializer.addNodeFilter('p', function addNodeFilterIntoSerializer (nodes, arg) { self.each(nodes, function eachNodeInSerializer (node) { if (node.firstChild == node.lastChild) { if (node.firstChild && 'value' in node.firstChild && (node.firstChild.value === ' ' || !node.firstChild.value.trim().length)) { node.remove(); } } }); }); //@todo:isthiseachreallynecessary? // Add event to reconfigure wrappers every time the content is loaded tinymce.each(tinymce.editors, function onEachEditor (editor) { self.addEvent('loadContent', editor, function onInitEditor (ed) { self.configureWrappers(editor); }); }); // Add the edit form // @todo: This is needed only for JCE, to fix the img placeholder. Try to find out a better approach to avoid the placeholder blink window.setTimeout( function afterTimeoutOnFindEditor () { /* * This is required because after load/refresh the page, the * onLoadContent is not being triggered automatically, so * we force the event */ editorInstance.load(); }, // If in JCE the user see the placeholder (img) instead of the iframe after load/refresh the pagr, this time is too short 500 ); } // Let's make sure the inner doc has been fully loaded first. var checkTimesLimit = 100; var checkIndex = 0; var statusCheckerInterval = setInterval(function () { if (checkIndex === checkTimesLimit) { clearInterval(statusCheckerInterval); alert('For some reason TinyMCE was not fully loaded yet. Please, refresh the page and try again.'); } else { var doc = editorInstance.getDoc(); if (doc) { clearInterval(statusCheckerInterval); onFindEditorCallback(); } else { checkIndex++; } } }, 250); }; self.fixIframeSize = function (iframe) { var maxWidth = 480; if ($(iframe).width() > maxWidth && !$(iframe).data('size-fixed')) { var ratio = $(iframe).height() / $(iframe).width(); $(iframe).width(maxWidth); $(iframe).height(maxWidth * ratio); $(iframe).css('max-width', maxWidth); $(iframe).attr('max-width', maxWidth); $(iframe).data('size-fixed', true); } }; /** * Function triggered on mouse enter the wrapper * * @param object e The event * @return void */ self.onMouseEnter = function (e, editorInstance) { self.displayPreviewControllerPanel($(e.currentTarget), editorInstance); }; /** * Function triggered on mouse get out of the wrapper * * @param object e The event * @return void */ self.onMouseOut = function (e) { // Check if the destiny is not a child element // Chrome if (self.isDefined(e.toElement)) { if (e.toElement.parentElement == e.fromElement || $(e.toElement).hasClass('embedpress_ignore_mouseout') ) { return false; } } // Firefox if (self.isDefined(e.relatedTarget)) { if ($(e.relatedTarget).hasClass('embedpress_ignore_mouseout')) { return false; } } self.hidePreviewControllerPanel(); }; /** * Callback triggered by paste events. This should be hooked by TinyMCE's paste_preprocess * setting. A normal bind to the onPaste event doesn't work correctly all the times * (specially when you copy and paste content from the same editor). * * @param mixed - plugin * @param mixed - args * * @return void */ self.onPaste = function (plugin, args) { var urlPatternRegex = new RegExp(/(https?):\/\/([w]{3}\.)?.+?(?:\s|$)/i); var urlPatternsList = self.getProvidersURLPatterns(); // Split the pasted content into separated lines. var contentLines = args.content.split(/\n/g) || []; contentLines = contentLines.map(function (line, itemIndex) { // Check if there's a url into `line`. if (line.match(urlPatternRegex)) { // Split the current line across its space-characters to isolate the url. let termsList = line.trim().split(/\s+/); termsList = termsList.map(function (term, termIndex) { // Check if the term into the current line is a url. var match = term.match(urlPatternRegex); if (match) { for (var urlPatternIndex = 0; urlPatternIndex < urlPatternsList.length; urlPatternIndex++) { // Isolates that url from the rest of the content if the service is supported. var urlPattern = new RegExp(urlPatternsList[urlPatternIndex]); if (urlPattern.test(term)) { return '</p><p>' + match[0] + '</p><p>'; } } } return term; }); termsList[termsList.length - 1] = termsList[termsList.length - 1] + '<br>'; line = termsList.join(' '); } return line; }); // Check if the text was transformed or not. If it was, add wrappers var content = contentLines.join(''); if (content.replace(/<br>$/, '') !== args.content) { args.content = '<p>' + args.content + '</p>'; } }; /** * Method trigered on every node change, to detect new lines. It will * try to fix a default behavior for some editors of clone the parent * element when adding a line break. This will clone the embed wrapper * if we set the cursor after a preview wrapper and hit enter. * * @param object e The event * @return void */ self.onNodeChange = function (e) { // Fix the clone parent on break lines issue // Check if a line break was added if (e.element.tagName === 'BR') { // Check one of the parent elements is a clonned embed wrapper if (e.parents.length > 0) { $.each(e.parents, function (index, parent) { if ($(parent).hasClass('embedpress_wrapper')) { // Remove the cloned wrapper and replace with a 'br' tag $(parent).replaceWith($('<br>')); } }); } } else if (e.element.tagName === 'IFRAME') { if (e.parents.length > 0) { $.each(e.parents, function (index, parent) { parent = $(parent); if (parent.hasClass('embedpress_wrapper')) { var wrapper = $('.embedpress-wrapper', parent); if (wrapper.length > 1) { wrapper.get(0).remove(); } } }); } } }; self.onKeyDown = function (e, editorInstance) { var node = editorInstance.selection.getNode(); if (e.keyCode == 8 || e.keyCode == 46) { if (node.nodeName.toLowerCase() === 'p') { var children = $(node).children(); if (children.length > 0) { $.each(children, function () { // On delete, make sure to remove the wrapper and children, not only the wrapper if ($(this).hasClass('embedpress_wrapper') || $(this).hasClass('embedpress_ignore_mouseout')) { $(this).remove(); editorInstance.focus(); } }); } } } else { // Ignore the arrows keys var arrowsKeyCodes = [37, 38, 39, 40]; if (arrowsKeyCodes.indexOf(e.keyCode) == -1) { // Check if we are inside a preview wrapper if ($(node).hasClass('embedpress_wrapper') || $(node).hasClass('embedpress_ignore_mouseout')) { // Avoid delete the wrapper or block line break if we are inside the wrapper if (e.keyCode == 13) { wrapper = $(self.getWrapperFromChild(node)); if (wrapper.length > 0) { // Creates a temporary element which will be inserted after the wrapper var tmpId = '__embedpress__tmp_' + self.makeId(); wrapper.after($('<span id="' + tmpId + '"></span>')); // Get and select the temporary element var span = editorInstance.dom.select('span#' + tmpId)[0]; editorInstance.selection.select(span); // Remove the temporary element $(span).remove(); } return true; } else { // If we are inside the embed preview, ignore any key to avoid edition return self.cancelEvent(e, editorInstance); } } } } return true; }; self.getWrapperFromChild = function (element) { // Is the wrapper if ($(element).hasClass('embedpress_wrapper')) { return element; } else { var $parent = $(element).parent(); if ($parent.length > 0) { return self.getWrapperFromChild($parent[0]); } } return false; }; self.onUndo = function (e, editorInstance) { // Force re-render everything editorInstance.load(); }; self.cancelEvent = function (e, editorInstance) { e.preventDefault(); e.stopPropagation(); editorInstance.dom.events.cancel(); return false; }; /** * Method executed when the edit button is clicked. It will display * a field with the current url, to update the current embed's source * url. * * @param Object e The event * @return void */ self.onClickEditButton = function (e, editorInstance) { // Prevent edition of the panel self.cancelEvent(e, editorInstance); self.activeWrapperForModal = self.activeWrapper; var $wrapper = self.activeWrapperForModal; var wrapperUid = $wrapper.prop('id').replace('embedpress_wrapper_', ''); var customAttributes = {}; var $embedInnerWrapper = $('.embedpress-wrapper', $wrapper); var embedItem = $('iframe', $wrapper); if (!embedItem.length) { embedItem = null; } if ($embedInnerWrapper.length > 1){ $.each($embedInnerWrapper[0].attributes, function () { if (this.specified) { if (this.name !== 'class') { customAttributes[this.name.replace('data-', '').toLowerCase()] = this.value; } } }); } var embedWidth = (((embedItem && embedItem.width()) || $embedInnerWrapper.data('width')) || $embedInnerWrapper.width()) || ''; var embedHeight = (((embedItem && embedItem.height()) || $embedInnerWrapper.data('height')) || $embedInnerWrapper.height()) || ''; embedItem = $embedInnerWrapper = null; $('<div class="loader-indicator"><i class="embedpress-icon-reload"></i></div>').appendTo($wrapper); setTimeout(function () { $.ajax({ type: 'GET', url: self.params.baseUrl + 'wp-admin/admin-ajax.php', data: { action: 'embedpress_get_embed_url_info', url: self.decodeEmbedURLSpecialChars($wrapper.data('url'), false) }, beforeSend: function (request, requestSettings) { $('.loader-indicator', $wrapper).addClass('is-loading'); }, success: function (response) { if (!response) { bootbox.alert('Unable to get a valid response from the server.'); return; } if (response.canBeResponsive) { var embedShouldBeResponsive = true; if ('width' in customAttributes || 'height' in customAttributes) { embedShouldBeResponsive = false; } else if ('responsive' in customAttributes && customAttributes['responsive'].isFalse()) { embedShouldBeResponsive = false; } } bootbox.dialog({ className: 'embedpress-modal', title: 'Editing Embed properties', message: '<form id="form-' + wrapperUid + '" embedpress>' + '<div class="row">' + '<div class="col-md-12">' + '<div class="form-group">' + '<label for="input-url-' + wrapperUid + '">Url</label>' + '<input class="form-control" type="url" id="input-url-' + wrapperUid + '" value="' + self.decodeEmbedURLSpecialChars($wrapper.data('url'), false) + '">' + '</div>' + '</div>' + '</div>' + '<div class="row">' + (response.canBeResponsive ? '<div class="col-md-12">' + '<label>Responsive</label>' + '<div class="form-group">' + '<label class="radio-inline">' + '<input type="radio" name="input-responsive-' + wrapperUid + '" id="input-responsive-1-' + wrapperUid + '" value="1"' + (embedShouldBeResponsive ? ' checked="checked"' : '') + '> Yes' + '</label>' + '<label class="radio-inline">' + '<input type="radio" name="input-responsive-' + wrapperUid + '" id="input-responsive-0-' + wrapperUid + '" value="0"' + (!embedShouldBeResponsive ? ' checked="checked"' : '') + '> No' + '</label>' + '</div>' + '</div>' : '') + '<div class="col-md-6">' + '<div class="form-group">' + '<label for="input-width-' + wrapperUid + '">Width</label>' + '<input class="form-control" type="integer" id="input-width-' + wrapperUid + '" value="' + embedWidth + '"' + (embedShouldBeResponsive ? ' disabled' : '') + '>' + '</div>' + '</div>' + '<div class="col-md-6">' + '<div class="form-group">' + '<label for="input-height-' + wrapperUid + '">Height</label>' + '<input class="form-control" type="integer" id="input-height-' + wrapperUid + '" value="' + embedHeight + '"' + (embedShouldBeResponsive ? ' disabled' : '') + '>' + '</div>' + '</div>' + '</div>' + '</form>', buttons: { danger: { label: 'Cancel', className: 'btn-default', callback: function () { // do nothing self.activeWrapperForModal = null; } }, success: { label: 'Save', className: 'btn-primary', callback: function () { var $wrapper = self.activeWrapperForModal; // Select the current wrapper as a base for the new element editorInstance.focus(); editorInstance.selection.select($wrapper[0]); $wrapper.children().remove(); $wrapper.remove(); if (response.canBeResponsive) { if ($('#form-' + wrapperUid + ' input[name="input-responsive-' + wrapperUid + '"]:checked').val().isFalse()) { var embedCustomWidth = $('#input-width-' + wrapperUid).val(); if (parseInt(embedCustomWidth) > 0) { customAttributes['width'] = embedCustomWidth; } var embedCustomHeight = $('#input-height-' + wrapperUid).val(); if (parseInt(embedCustomHeight) > 0) { customAttributes['height'] = embedCustomHeight; } customAttributes['responsive'] = 'false'; } else { delete customAttributes['width']; delete customAttributes['height']; customAttributes['responsive'] = 'true'; } } else { var embedCustomWidth = $('#input-width-' + wrapperUid).val(); if (parseInt(embedCustomWidth) > 0) { customAttributes['width'] = embedCustomWidth; } var embedCustomHeight = $('#input-height-' + wrapperUid).val(); if (parseInt(embedCustomHeight) > 0) { customAttributes['height'] = embedCustomHeight; } } var customAttributesList = []; if (!!Object.keys(customAttributes).length) { for (var attrName in customAttributes) { customAttributesList.push(attrName + '="' + customAttributes[attrName] + '"'); } } var shortcode = '[' + $data.EMBEDPRESS_SHORTCODE + (customAttributesList.length > 0 ? ' ' + customAttributesList.join(' ') : '') + ']' + $('#input-url-' + wrapperUid).val() + '[/' + $data.EMBEDPRESS_SHORTCODE + ']'; // We do not directly replace the node because it was causing a bug on a second edit attempt editorInstance.execCommand('mceInsertContent', false, shortcode); self.configureWrappers(editorInstance); } } } }); $('form[embedpress]').on('change', 'input[type="radio"]', function (e) { var self = $(this); var form = self.parents('form[embedpress]'); $('input[type="integer"]', form).prop('disabled', self.val().isTrue()); }); }, complete: function (request, textStatus) { $('.loader-indicator', $wrapper).removeClass('is-loading'); setTimeout(function () { $('.loader-indicator', $wrapper).remove(); }, 350); }, dataType: 'json', async: true }); }, 200); return false; }; /** * Method executed when the remove button is clicked. It will remove * the preview and embed code, adding a mark to ignore the url * * @param Object e The event * @return void */ self.onClickRemoveButton = function (e, editorInstance) { // Prevent edition of the panel self.cancelEvent(e, editorInstance); var $wrapper = self.activeWrapper; $wrapper.children().remove(); $wrapper.remove(); return false; }; self.recursivelyAddClass = function (element, className) { $(element).children().each(function (index, child) { $(child).addClass(className); var grandChild = $(child).children(); if (grandChild.length > 0) { self.recursivelyAddClass(child, className); } }); }; self.setInterval = function (callback, time, timeout) { var elapsed = 0; var iteraction = 0; var interval = window.setInterval(function () { elapsed += time; iteraction++; if (elapsed <= timeout) { callback(iteraction, elapsed); } else { self.stopInterval(interval); } }, time); return interval; }; self.stopInterval = function (interval) { window.clearInterval(interval); interval = null; }; /** * Configure unconfigured embed wrappers, adding events and css * @return void */ self.configureWrappers = function (editorInstance) { window.setTimeout( function configureWrappersTimeOut () { var doc = editorInstance.getDoc(), $wrapper = null; // Get all the wrappers var wrappers = doc.getElementsByClassName('embedpress_wrapper'); if (wrappers.length > 0) { for (var i = 0; i < wrappers.length; i++) { $wrapper = $(wrappers[i]); // Check if the wrapper wasn't already configured if ($wrapper.data('configured') != true) { // A timeout was set to avoid block the content loading window.setTimeout(function () { // @todo: Check if we need a limit of levels to avoid use too much resources self.recursivelyAddClass($wrapper, 'embedpress_ignore_mouseout'); }, 500); // Fix the wrapper size. Wait until find the child iframe. L var interval = self.setInterval(function (iteraction) { var $childIframes = $wrapper.find('iframe'); if ($childIframes.length > 0) { $.each($childIframes, function (index, iframe) { // Facebook has more than one iframe, we need to ignore the Cross Domain Iframes if ($(iframe).attr('id') !== 'fb_xdm_frame_https' && $(iframe).attr('id') !== 'fb_xdm_frame_http' ) { $wrapper.css('width', $(iframe).width() + 'px'); self.stopInterval(interval); } }); } }, 500, 8000); $wrapper.data('configured', true); } } } }, 200 ); }; /** * Hide the controller panel * * @return void */ self.hidePreviewControllerPanel = function () { if (self.controllerPanelIsActive()) { $(self.activeControllerPanel).addClass('hidden'); self.activeControllerPanel = null; self.activeWrapper = null; } }; /** * Get an element by id in the editor's content * * @param String id The element id * @return Element The found element or null, wrapped by jQuery */ self.getElementInContentById = function (id, editorInstance) { var doc = editorInstance.getDoc(); if (doc === null) { return; } return $(doc.getElementById(id)); }; /** * Show the controller panel * * @param element $wrapper The wrapper which will be activate * @return void */ self.displayPreviewControllerPanel = function ($wrapper, editorInstance) { if (self.controllerPanelIsActive() && $wrapper !== self.activeWrapper) { self.hidePreviewControllerPanel(); } if (!self.controllerPanelIsActive() && !$wrapper.hasClass('is-loading')) { var uid = $wrapper.data('uid'); var $panel = self.getElementInContentById('embedpress_controller_panel_' + uid, editorInstance); if (!$panel.data('event-set')) { var $editButton = self.getElementInContentById('embedpress_button_edit_' + uid, editorInstance); var $removeButton = self.getElementInContentById('embedpress_button_remove_' + uid, editorInstance); self.addEvent('mousedown', $editButton, function (e) { self.onClickEditButton(e, editorInstance); }); self.addEvent('mousedown', $removeButton, function (e) { self.onClickRemoveButton(e, editorInstance); }); $panel.data('event-set', true); } // Update the position of the control bar var next = $panel.next()[0]; if (typeof next !== 'undefined') { if (next.nodeName.toLowerCase() === 'iframe') { $panel.css('left', ($(next).width() / 2)); } } // Show the bar $panel.removeClass('hidden'); self.activeControllerPanel = $panel; self.activeWrapper = $wrapper; } }; }; if (!window.EmbedPress) { window.EmbedPress = new EmbedPress(); } // Initialize EmbedPress for all the current editors. window.EmbedPress.init($data.previewSettings); }); })(jQuery, String, $data);