├── lang ├── raph-it_IT.mo └── raph-it_IT.po ├── .gitignore ├── composer.json ├── LICENSE ├── src ├── PostProvider.php ├── AdminForm.php ├── Renderer.php └── FormData.php ├── README.md ├── Raph.php └── js ├── raph.min.js └── raph.js /lang/raph-it_IT.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gmazzap/Raph/HEAD/lang/raph-it_IT.mo -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Thumbs.db 2 | ehthumbs.db 3 | Desktop.ini 4 | $RECYCLE.BIN/ 5 | .DS_Store 6 | .coverage 7 | .tox 8 | .idea/ 9 | vendor/ 10 | composer.lock 11 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gmazzap/raph", 3 | "description": "WordPress plugin that renders shortcodes in posts content.", 4 | "keywords": [ 5 | "wordpress" 6 | ], 7 | "type": "wordpress-plugin", 8 | "authors": [ 9 | { 10 | "name": "Giuseppe Mazzapica", 11 | "email": "giuseppe.mazzapica@gmail.com", 12 | "homepage": "http://gm.zoomlab.it", 13 | "role": "Developer" 14 | } 15 | ], 16 | "support": { 17 | "issues": "https://github.com/Giuseppe-Mazzapica/Raph/issues", 18 | "source": "https://github.com/Giuseppe-Mazzapica/Raph" 19 | }, 20 | "license": "MIT", 21 | "require": { 22 | "php": ">=5.4" 23 | }, 24 | "autoload": { 25 | "psr-4": { 26 | "Raph\\": "src/" 27 | } 28 | }, 29 | "minimum-stability": "dev", 30 | "prefer-stable": true, 31 | "config": { 32 | "optimize-autoloader": true 33 | }, 34 | "extra": { 35 | "branch-alias": { 36 | "dev-master": "0.3.x-dev" 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Giuseppe Mazzapica 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/PostProvider.php: -------------------------------------------------------------------------------- 1 | 4 | * @license http://opensource.org/licenses/MIT MIT 5 | */ 6 | namespace Raph; 7 | 8 | use WP_Post; 9 | 10 | /** 11 | * Handle post object recognition on post editing admin screen. 12 | * 13 | * @package Raph 14 | */ 15 | class PostProvider 16 | { 17 | /** 18 | * @var WP_Post 19 | */ 20 | private $post; 21 | 22 | /** 23 | * Run on 'admin_init' and get current post object information form request (for existing post) 24 | * or from 'new_to_auto-draft' hoof for new posts. 25 | * 26 | * @return PostProvider 27 | */ 28 | public function init() 29 | { 30 | $this->fromRequest() or $this->onTransition(); 31 | 32 | return $this; 33 | } 34 | 35 | /** 36 | * @return WP_Post 37 | */ 38 | public function get() 39 | { 40 | return $this->post; 41 | } 42 | 43 | private function fromRequest() 44 | { 45 | if (is_null($this->post)) { 46 | $p_get = filter_input(INPUT_GET, 'post', FILTER_SANITIZE_NUMBER_INT); 47 | $p_post = filter_input(INPUT_POST, 'post', FILTER_SANITIZE_NUMBER_INT); 48 | if ($p_get > 0 || $p_post > 0) { 49 | $this->post = $p_get > 0 ? get_post($p_get) : get_post($p_post); 50 | } 51 | } 52 | 53 | return $this->post instanceof WP_Post; 54 | } 55 | 56 | private function onTransition() 57 | { 58 | if ($GLOBALS['pagenow'] === 'post-new.php' && is_null($this->post)) { 59 | add_action('new_to_auto-draft', function (WP_Post $post) { 60 | $this->post = $post; 61 | }, 0); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/AdminForm.php: -------------------------------------------------------------------------------- 1 | 4 | * @license http://opensource.org/licenses/MIT MIT 5 | */ 6 | namespace Raph; 7 | 8 | /** 9 | * Adds plugin scripts and scripts data. 10 | * 11 | * @package Raph 12 | */ 13 | class AdminForm 14 | { 15 | /** 16 | * @var \Raph\FormData 17 | */ 18 | private $formData; 19 | 20 | /** 21 | * @param \Raph\FormData $formData 22 | */ 23 | public function __construct(FormData $formData) 24 | { 25 | $this->formData = $formData; 26 | } 27 | 28 | /** 29 | * Adds Raph button to TinyMCE toolbar and connect it with javascript file. 30 | * Runs on 'admin_init' hook (se in main plugin file). 31 | */ 32 | public function setup() 33 | { 34 | add_action('admin_head', function () { 35 | echo " 36 | 40 | "; 41 | }); 42 | add_action('admin_enqueue_scripts', function () { 43 | wp_localize_script('editor', 'Raph', $this->formData->data()); 44 | }); 45 | add_filter('mce_buttons', function (array $buttons) { 46 | return array_merge($buttons, ['raphRender']); 47 | }); 48 | add_filter('mce_external_plugins', function (array $plugins) { 49 | return array_merge($plugins, ['raphRender' => $this->scriptUrl()]); 50 | }); 51 | } 52 | 53 | private function scriptUrl() 54 | { 55 | $name = defined('WP_DEBUG') && WP_DEBUG ? "/js/raph.js" : "/js/raph.min.js"; 56 | 57 | return plugins_url($name, dirname(__DIR__).'/Raph.php'); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lang/raph-it_IT.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Project-Id-Version: Raph v0.1\n" 4 | "Report-Msgid-Bugs-To: \n" 5 | "POT-Creation-Date: \n" 6 | "PO-Revision-Date: 2015-02-01 06:59:12+0000\n" 7 | "Last-Translator: admin \n" 8 | "Language-Team: \n" 9 | "MIME-Version: 1.0\n" 10 | "Content-Type: text/plain; charset=UTF-8\n" 11 | "Content-Transfer-Encoding: 8bit\n" 12 | "Plural-Forms: nplurals=2; plural=n != 1;\n" 13 | "X-Generator: CSL v1.x\n" 14 | "X-Poedit-Language: Italian\n" 15 | "X-Poedit-Country: ITALY\n" 16 | "X-Poedit-SourceCharset: utf-8\n" 17 | "X-Poedit-KeywordsList: __;_e;__ngettext:1,2;_n:1,2;__ngettext_noop:1,2;_n_noop:1,2;_c,_nc:4c,1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;_nx_noop:4c,1,2;\n" 18 | "X-Poedit-Basepath: \n" 19 | "X-Poedit-Bookmarks: \n" 20 | "X-Poedit-SearchPath-0: .\n" 21 | "X-Textdomain-Support: yes" 22 | 23 | #: src/FormData.php:53 24 | #@ raph 25 | msgid "Render Shortcodes" 26 | msgstr "Renderizza Shortcode" 27 | 28 | #: src/FormData.php:54 29 | #@ raph 30 | msgid "No shortcodes to render." 31 | msgstr "Nessuno shortcode da renderizzare." 32 | 33 | #: src/FormData.php:55 34 | #@ raph 35 | msgid "Restore." 36 | msgstr "Ripristina." 37 | 38 | #: src/FormData.php:57 39 | #@ raph 40 | msgid "Shortcodes rendered. Save post to make changes effective." 41 | msgstr "Shortcode renderizzati. Salva il post per rendere effettive le modifiche." 42 | 43 | #: src/FormData.php:61 44 | #@ raph 45 | msgid "Sorry, an error occurred while rendering shortcodes." 46 | msgstr "Spiacenti, si è verificato un errore." 47 | 48 | #: src/FormData.php:64 49 | #@ raph 50 | msgid "Content has changed since last rendering." 51 | msgstr "Il contenuto è cambiato dall'ultimo rendering." 52 | 53 | #: src/FormData.php:65 54 | #@ raph 55 | msgid "By restoring you will lost those changes." 56 | msgstr "Se ripristini, il contenuto modificato dopo il rendering sarà perso." 57 | 58 | -------------------------------------------------------------------------------- /src/Renderer.php: -------------------------------------------------------------------------------- 1 | 4 | * @license http://opensource.org/licenses/MIT MIT 5 | */ 6 | namespace Raph; 7 | 8 | /** 9 | * Used to render post shortcodes via AJAX. 10 | * 11 | * @package Raph 12 | */ 13 | class Renderer 14 | { 15 | /** 16 | * @var \Raph\FormData 17 | */ 18 | private $formData; 19 | 20 | /** 21 | * @param \Raph\FormData $formData 22 | */ 23 | public function __construct(FormData $formData) 24 | { 25 | $this->formData = $formData; 26 | } 27 | 28 | /** 29 | * Does security checks then takes content from AJAX POST data and send back rendered content 30 | * as JSON. Runs on 'wp_ajax_raph-render' action (set in main plugin file). 31 | */ 32 | public function render() 33 | { 34 | if (defined('DOING_AJAX') && DOING_AJAX) { 35 | $check = $this->formData->check(); 36 | $check or wp_send_json_error(); 37 | $this->buildContext($check); 38 | $data = [ 39 | 'success' => true, 40 | 'data' => ['content' => do_shortcode($check['content'])], 41 | ]; 42 | @header('Content-Type: application/json; charset='.get_option('blog_charset')); 43 | echo wp_json_encode($data, JSON_PRETTY_PRINT); 44 | wp_die(); 45 | } 46 | } 47 | 48 | private function buildContext(array $data) 49 | { 50 | global $wp, $wp_the_query, $post; 51 | $v = $data['type'] === 'page' ? 'page_id' : 'p'; 52 | $wp->query_vars = [$v => $data['pid'], 'suppress_filters' => true]; 53 | $wp->build_query_string(); 54 | add_action('parse_query', function () { 55 | remove_all_actions('pre_get_posts'); 56 | }, PHP_INT_MAX); 57 | $wp_the_query->query($wp->query_vars); 58 | $post = $wp_the_query->post; 59 | setup_postdata($post); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Raph 2 | 3 | > **WordPress plugin that helps you to covert shortcodes to HTML.** 4 | 5 | ---- 6 | 7 | ## Sorry? 8 | 9 | Shortcodes may be useful, but rendering them "on the fly" can be a performance killer. 10 | 11 | Moreover, shortcodes added by themes or by plugins, lock you in with those products, because you if you change 12 | theme or uninstall plugins that add shortcodes, your content will be bungled when not lost. 13 | 14 | Have you ever desired get rid of a plugin, but can't because of shorteds? Now you can. 15 | 16 | ## How it Works 17 | 18 | Raph adds a button in in post editor toolbar. When you click that button 19 | 20 | - if *nothing is selected* all the shortcodes in the post are converted to the same HTML they would output in frontend 21 | - if *something is selected*, than only shortcodes in selection are converted 22 | 23 | HTML is generated via AJAX and isn't saved until post is saved. 24 | 25 | When post is saved, shortcodes are definitely converted to HTML, it means you can even disable the plugin (or switch the theme) that added the original shortcode. 26 | 27 | After having rendered shortcodes there is the possibility to immediately restore shortcodes by clicking a link. 28 | 29 | ---- 30 | 31 | ## Demo 32 | 33 | ![Raph demo](http://zoomlab.it/public/raph_plugin_03.gif) 34 | 35 | ---- 36 | 37 | ## FAQ 38 | 39 | - ***How can I bulk convert shortcodes?*** 40 | 41 | At the moment that isn't possible. *Maybe* it will be in future versions. 42 | 43 | - ***I selected a shortcode and clicked render button, but nothing happen, is it broken?*** 44 | 45 | No. When you select some text, you have to keep the selection as is until rendering is complete. Otherwise Raph don't know where to put rendered HTML, and to avoid to mess up your post content it does nohing. 46 | 47 | 48 | 49 | ## Requirements 50 | 51 | - PHP 5.4+ 52 | - WordPress 4.0+ 53 | 54 | ---- 55 | 56 | ## Installation 57 | 58 | The plugin is a Composer package and can be installed in plugin directory via: 59 | 60 | composer create-project gmazzap/raph 61 | 62 | Alternatively, you can 63 | 64 | - download [last release](https://github.com/Giuseppe-Mazzapica/Raph/releases) zip file 65 | - clone this repo using git 66 | 67 | ---- 68 | 69 | ## License 70 | 71 | Raph is licensed under [MIT](http://opensource.org/licenses/MIT). 72 | -------------------------------------------------------------------------------- /Raph.php: -------------------------------------------------------------------------------- 1 | init())), 'setup']); 59 | } 60 | -------------------------------------------------------------------------------- /js/raph.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Part of Raph WordPress plugin 3 | * Author: Giuseppe Mazzapica 4 | * License: MIT 5 | */ 6 | !function(e,n,t,o,a){"use strict";t.methods={},t.backup={},t.info={},t.methods.updateEditor=function(e){if(t.info.whileRendering)return!1;var n=t.methods.getContent(e);-1!==n.content.search(/\[.+\]/)?n.isSelection?t.methods.render(e,n.content,n.isSelection):e.windowManager.confirm(t.i18n.confAll,function(o){o&&t.methods.render(e,n.content,n.isSelection)}):t.methods.htmlNotice(t.i18n.noShortcodes,"error")},t.methods.getContent=function(e){var n,o;return e.selection.isCollapsed()?(n=e.getContent(),o=!1):(n=e.selection.getContent(),o=!0,t.info.currentSelection=n),{content:n,isSelection:o}},t.methods.render=function(n,o,a){t.methods.startRendering(n),t.methods.backup(n,n.getContent()),e("#raph-notice").length&&e("#raph-notice").remove(),t.methods.ajaxCall(o).done(function(e){t.methods.ajaxDone(e,n,a)}).fail(function(){t.methods.htmlNotice(t.i18n.ajaxError,"error"),t.backup={}}).always(function(){t.methods.endRendering(n)})},t.methods.ajaxCall=function(n){return e.ajax({type:"POST",url:o,dataType:"json",cache:!1,data:{action:"raph-render",pid:t.data.pid,type:t.data.type,raphCheck:t.data.raphCheck,content:n}})},t.methods.ajaxDone=function(e,n,o){if(e.success&&e.data.content){if(o&&n.selection.getContent()!==t.info.currentSelection)return t.backup={},!1;o?n.selection.setContent(e.data.content):n.setContent(e.data.content);var a=t.i18n.notice;a+=' '+t.i18n.restore+"",t.methods.htmlNotice(a,"updated"),n.onChange.add(function(){t.backup.editor&&(t.backup.changed=!0)})}else t.methods.htmlNotice(t.i18n.ajaxError,"error"),t.backup={}},t.methods.htmlNotice=function(n,t){e("#wp-content-wrap").prepend('

'+n+"

"),"error"===t&&setTimeout(function(){e("#raph-notice").remove()},5e3)},t.methods.backup=function(e,n){t.backup.editor=e,t.backup.content=n,t.backup.changed=!1},t.methods.restoreContentConfirm=function(){if(t.backup.editor){var e=!t.backup.changed;e?t.methods.restoreContent():t.backup.editor.windowManager.confirm(t.i18n.conf1+"\n"+t.i18n.conf2,function(){t.methods.restoreContent()})}},t.methods.restoreContent=function(){t.backup.editor&&(t.backup.editor.setContent(t.backup.content),e("#raph-notice").remove(),t.backup={})},t.methods.startRendering=function(e){var n=e.controlManager.buttons.raphRender;n.icon("raph dashicons-clock"),n.disabled(!0),t.info.whileRendering=!0},t.methods.endRendering=function(e){var n=e.controlManager.buttons.raphRender;n.icon("raph dashicons-admin-appearance"),n.disabled(!1),t.info={}},n.PluginManager.add("raphRender",function(e){e.addButton("raphRender",{title:t.i18n.buttonTitle,icon:"raph dashicons-admin-appearance",onclick:function(){t.methods.updateEditor(e)}})}),e(a).on("click","#raph-restore",function(e){e.preventDefault(),t.methods.restoreContentConfirm()})}(jQuery,tinymce,Raph,ajaxurl,document); -------------------------------------------------------------------------------- /src/FormData.php: -------------------------------------------------------------------------------- 1 | 4 | * @license http://opensource.org/licenses/MIT MIT 5 | */ 6 | namespace Raph; 7 | 8 | use WP_Post; 9 | 10 | /** 11 | * Used by Renderer and AdminForm classes to, respectively, retrieve and set data for post 12 | * rendering. 13 | * 14 | * @package Raph 15 | */ 16 | class FormData 17 | { 18 | /** 19 | * @var string 20 | */ 21 | private static $nonce = 'raph_render'; 22 | 23 | /** 24 | * @var \Raph\PostProvider 25 | */ 26 | private $postProvider; 27 | 28 | /** 29 | * @param \Raph\PostProvider $postProvider 30 | */ 31 | public function __construct(PostProvider $postProvider = null) 32 | { 33 | $this->postProvider = $postProvider; 34 | } 35 | 36 | /** 37 | * Return the data to be passed to javascript and be used to translate UI and send AJAX request. 38 | * 39 | * @return array 40 | */ 41 | public function data() 42 | { 43 | $post = $this->postProvider instanceof PostProvider ? $this->postProvider->get() : null; 44 | 45 | if ($post instanceof WP_Post) { 46 | return [ 47 | 'i18n' => [ 48 | 'buttonTitle' => __('Render Shortcodes', 'raph'), 49 | 'noShortcodes' => __('No shortcodes to render.', 'raph'), 50 | 'restore' => __('Restore.', 'raph'), 51 | 'notice' => __( 52 | 'Shortcodes rendered. Save post to make changes effective.', 53 | 'raph' 54 | ), 55 | 'ajaxError' => __( 56 | 'Sorry, an error occurred while rendering shortcodes.', 57 | 'raph' 58 | ), 59 | 'conf1' => __('Content has changed since last rendering.', 'raph'), 60 | 'conf2' => __('By restoring you will lost those changes.', 'raph'), 61 | 'confAll' => __('Do you want to render ALL shortcodes?', 'raph'), 62 | ], 63 | 'data' => [ 64 | 'pid' => absint($post->ID), 65 | 'type' => filter_var($post->post_type, FILTER_SANITIZE_STRING), 66 | 'raphCheck' => wp_create_nonce($this->nonceAction($post->ID)), 67 | ] 68 | ]; 69 | } 70 | } 71 | 72 | /** 73 | * Verify that $_POST data for a post and that current user has the capability to edit the post. 74 | * 75 | * @return bool|array 76 | */ 77 | public function check() 78 | { 79 | $data = filter_input_array(INPUT_POST, [ 80 | 'pid' => FILTER_SANITIZE_NUMBER_INT, 81 | 'type' => FILTER_SANITIZE_STRING, 82 | 'raphCheck' => FILTER_SANITIZE_STRING, 83 | 'content' => FILTER_REQUIRE_SCALAR 84 | ]); 85 | 86 | return 87 | wp_verify_nonce($data['raphCheck'], $this->nonceAction($data['pid'])) 88 | && $this->userCan($data['pid'], $data['type']) 89 | && ! empty($data['content']) 90 | ? $data 91 | : false; 92 | } 93 | 94 | private function nonceAction($id) 95 | { 96 | return self::$nonce.md5($id.LOGGED_IN_SALT.get_current_blog_id()); 97 | } 98 | 99 | private function userCan($id, $type) 100 | { 101 | $postType = get_post_type_object($type); 102 | 103 | return is_object($postType) && current_user_can($postType->cap->edit_post, $id); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /js/raph.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Part of Raph WordPress plugin 3 | * Author: Giuseppe Mazzapica 4 | * License: MIT 5 | */ 6 | 7 | (function ( $, T, R, ajaxurl, document ) { 8 | 9 | "use strict"; 10 | 11 | R.methods = {}; 12 | R.backup = {}; 13 | R.info = {}; 14 | 15 | /** 16 | * First function launched when Raph button is clicked. 17 | * Gets data, performs checks and launches rendering. 18 | * 19 | * @param {tinymce.Editor} editor TinyMCE Editor object 20 | */ 21 | R.methods.updateEditor = function ( editor ) { 22 | if ( R.info.whileRendering ) { 23 | return false; 24 | } 25 | var get = R.methods.getContent( editor ); 26 | if ( get.content.search( /\[.+\]/ ) !== -1 ) { 27 | if ( !get.isSelection ) { 28 | editor.windowManager.confirm( R.i18n.confAll, function ( confirm ) { 29 | if ( confirm ) { 30 | R.methods.render( editor, get.content, get.isSelection ); 31 | } 32 | } ); 33 | } else { 34 | R.methods.render( editor, get.content, get.isSelection ); 35 | } 36 | } else { 37 | R.methods.htmlNotice( R.i18n.noShortcodes, 'error' ); 38 | } 39 | }; 40 | 41 | /** 42 | * Get content to process from editor, and check if is a selection or the whole post content. 43 | * 44 | * @param {String} editor 45 | * @returns {{content: String, isSelection: Boolean}} 46 | */ 47 | R.methods.getContent = function ( editor ) { 48 | var content, isSelection; 49 | if ( !editor.selection.isCollapsed() ) { 50 | content = editor.selection.getContent(); 51 | isSelection = true; 52 | R.info.currentSelection = content; 53 | } else { 54 | content = editor.getContent(); 55 | isSelection = false; 56 | } 57 | return { 58 | content: content, 59 | isSelection: isSelection 60 | }; 61 | }; 62 | 63 | /** 64 | * Launches the AJAX call, and output a notice in both cases request was successful or not. 65 | * 66 | * @param {tinymce.Editor} editor TinyMCE Editor object 67 | * @param {String} content Current editor content 68 | * @param {Boolean} isSelection When true content is a selection 69 | */ 70 | R.methods.render = function ( editor, content, isSelection ) { 71 | R.methods.startRendering( editor ); 72 | R.methods.backup( editor, editor.getContent() ); 73 | if ( $( '#raph-notice' ).length ) { 74 | $( '#raph-notice' ).remove(); 75 | } 76 | R.methods.ajaxCall( content ) 77 | .done( function ( result ) { 78 | R.methods.ajaxDone( result, editor, isSelection ); 79 | } ).fail( function () { 80 | R.methods.htmlNotice( R.i18n.ajaxError, 'error' ); 81 | R.backup = {}; 82 | } ).always( function () { 83 | R.methods.endRendering( editor ); 84 | } ); 85 | }; 86 | 87 | /** 88 | * Performs the AJAX request. 89 | * 90 | * @param {String} content Current shortcode content 91 | * @returns {jqXHR} 92 | */ 93 | R.methods.ajaxCall = function ( content ) { 94 | return $.ajax( { 95 | type: "POST", 96 | url: ajaxurl, 97 | dataType: "json", 98 | cache: false, 99 | data: { 100 | action: 'raph-render', 101 | pid: R.data.pid, 102 | type: R.data.type, 103 | raphCheck: R.data.raphCheck, 104 | content: content 105 | } 106 | } ); 107 | }; 108 | 109 | /** 110 | * Runs when AJAx request was successful. 111 | * Updates editor content and print success notice. 112 | * Finally adds an event to editor to see when editor content has been changed. 113 | * 114 | * @param {Object} result JSON returned by AJAX 115 | * @param {tinymce.Editor} editor TinyMCE Editor object 116 | * @param {Boolean} selection When true content is a selection 117 | */ 118 | R.methods.ajaxDone = function ( result, editor, selection ) { 119 | if ( result.success && result.data.content ) { 120 | if ( selection && editor.selection.getContent() !== R.info.currentSelection ) { 121 | R.backup = {}; 122 | return false; 123 | } else if ( !selection ) { 124 | editor.setContent( result.data.content ); 125 | } else { 126 | editor.selection.setContent( result.data.content ); 127 | } 128 | var text = R.i18n.notice; 129 | text += ' ' + R.i18n.restore + ''; 130 | R.methods.htmlNotice( text, 'updated' ); 131 | editor.onChange.add( function () { 132 | if ( R.backup.editor ) { 133 | R.backup.changed = true; 134 | } 135 | } ); 136 | } else { 137 | R.methods.htmlNotice( R.i18n.ajaxError, 'error' ); 138 | R.backup = {}; 139 | } 140 | }; 141 | 142 | /** 143 | * Used to print both success and error notice. 144 | * Error notices are auto deleted via timeout. 145 | * 146 | * @param {String} text Notice text 147 | * @param {String} type Used for HTML class of the notics 148 | */ 149 | R.methods.htmlNotice = function ( text, type ) { 150 | $( '#wp-content-wrap' ).prepend( 151 | '

' + text + '

' 152 | ); 153 | if ( type === 'error' ) { 154 | setTimeout( function () { 155 | $( '#raph-notice' ).remove(); 156 | }, 5000 ); 157 | } 158 | }; 159 | 160 | /** 161 | * Stores original content and editor object to be used for restoring if required. 162 | * 163 | * @param {tinymce.Editor} editor TinyMCE Editor object 164 | * @param {String} content Content before rendering 165 | */ 166 | R.methods.backup = function ( editor, content ) { 167 | R.backup.editor = editor; 168 | R.backup.content = content; 169 | R.backup.changed = false; 170 | }; 171 | 172 | /** 173 | * Runs when a content restore is required by user. 174 | * If the content has changed a confirmation is required, because new content will be lost. 175 | */ 176 | R.methods.restoreContentConfirm = function () { 177 | if ( R.backup.editor ) { 178 | var should = !R.backup.changed; 179 | if ( !should ) { 180 | R.backup.editor.windowManager.confirm( 181 | R.i18n.conf1 + "\n" + R.i18n.conf2, 182 | function ( confirm ) { 183 | R.methods.restoreContent(); 184 | } 185 | ); 186 | } else { 187 | R.methods.restoreContent(); 188 | } 189 | } 190 | 191 | }; 192 | 193 | /** 194 | * Actually restores editor content to how it was before rendering. 195 | */ 196 | R.methods.restoreContent = function () { 197 | if ( R.backup.editor ) { 198 | R.backup.editor.setContent( R.backup.content ); 199 | $( '#raph-notice' ).remove(); 200 | R.backup = {}; 201 | } 202 | }; 203 | 204 | /** 205 | * Set flags variable, add modal and disable button when rendering starts 206 | * 207 | * @param {tinymce.Editor} editor TinyMCE Editor object 208 | */ 209 | R.methods.startRendering = function ( editor ) { 210 | var button = editor.controlManager.buttons.raphRender; 211 | button.icon( 'raph dashicons-clock' ); 212 | button.disabled( true ); 213 | R.info.whileRendering = true; 214 | }; 215 | 216 | /** 217 | * Set flags variable, remove modal and re-enable button when rendering ends 218 | * 219 | * @param {tinymce.Editor} editor TinyMCE Editor object 220 | */ 221 | R.methods.endRendering = function ( editor ) { 222 | var button = editor.controlManager.buttons.raphRender; 223 | button.icon( 'raph dashicons-admin-appearance' ); 224 | button.disabled( false ); 225 | R.info = {}; 226 | }; 227 | 228 | /** 229 | * Uses TinyMCE API to add Raph custom button. 230 | */ 231 | T.PluginManager.add( 'raphRender', function ( editor ) { 232 | editor.addButton( 'raphRender', { 233 | title: R.i18n.buttonTitle, 234 | icon: 'raph dashicons-admin-appearance', 235 | onclick: function () { 236 | R.methods.updateEditor( editor ); 237 | } 238 | } ); 239 | } ); 240 | 241 | // Events 242 | 243 | $( document ).on( 'click', '#raph-restore', function ( e ) { 244 | e.preventDefault(); 245 | R.methods.restoreContentConfirm(); 246 | } ); 247 | 248 | })( jQuery, tinymce, Raph, ajaxurl, document ); --------------------------------------------------------------------------------