├── .gitignore ├── LICENSE.txt ├── README.md ├── images ├── deckbox_logo.png └── mtg.png ├── lib └── bbp-do-shortcodes.php ├── readme.txt ├── resources ├── css │ └── wp_deckbox_mtg.css ├── tinymce3 │ └── editor_plugin.js └── tooltip_extension.js ├── screenshot-1.png ├── screenshot-2.png ├── script ├── run.sh └── wp_release └── wp_deckbox_mtg.php /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea* 2 | .DS_Store -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2013 Sebastian Zaha 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person 6 | obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without 8 | restriction, including without limitation the rights to use, 9 | copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 | OTHER DEALINGS IN THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Plugin for MTG Card Tooltips 2 | ============================ 3 | 4 | Enables card images to show on mouseover for Magic the Gathering cards. It 5 | provides a button (and corresponding shortcode tags) that wrap card names or 6 | deck listings and turn them into smart card links with image tooltips. 7 | 8 | 9 | More Information 10 | ---------------- 11 | 12 | For more details, screenshots and installation instructions please see the 13 | [official wordpress readme.txt](https://github.com/SebastianZaha/wordpress_mtg_tooltips/blob/master/readme.txt). 14 | 15 | For bbpress forum compatibility I have included in the distribution Pippin's 16 | fix for bbpress shortcodes [from here](http://wordpress.org/extend/plugins/bbpress-do-short-codes/). 17 | 18 | 19 | Examples 20 | -------- 21 | 22 | ``` 23 | [d title="Really Small Deck" style="embedded"] 24 | Creatures 25 | 2 Bloodbraid Elf 26 | 4 Grizzly Bears 27 | 28 | Spells 29 | 4 Lightning Bolt 30 | 31 | Sideboard 32 | 4 Cultivate 33 | [/d] 34 | ``` 35 | 36 | produces the following result: 37 | 38 | ![screenshot](https://raw.github.com/SebastianZaha/wordpress_mtg_tooltips/master/screenshot-2.png) 39 | 40 | 41 | Support and Development 42 | ----------------------- 43 | 44 | The code in this plugin is inspired from other shortcode-type wordpress plugins that looked 45 | solid to me. The spacing and conventions try to stay close to the 46 | [pear standards](http://pear.php.net/manual/en/standards.php). I am not a PHP developer, so I'm 47 | pretty sure the code here is not *the right way to do it*. 48 | 49 | I'll gladly accept pull requests with improvements and / or code cleanup. 50 | 51 | -------------------------------------------------------------------------------- /images/deckbox_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deckbox/wordpress_mtg_tooltips/4ab8c3da941efa6047846fd5d6a441cfce407ef6/images/deckbox_logo.png -------------------------------------------------------------------------------- /images/mtg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deckbox/wordpress_mtg_tooltips/4ab8c3da941efa6047846fd5d6a441cfce407ef6/images/mtg.png -------------------------------------------------------------------------------- /lib/bbp-do-shortcodes.php: -------------------------------------------------------------------------------- 1 | [args]\n\nTasks:\n" "${0}" 17 | compgen -A function | grep -v "^_" | cat -n 18 | } 19 | 20 | # This idea is heavily inspired by: https://github.com/adriancooney/Taskfile 21 | TIMEFORMAT=$'\nTask completed in %3lR' 22 | time "${@:-help}" -------------------------------------------------------------------------------- /script/wp_release: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Defaults 4 | CURRENT_DIR=`pwd` 5 | PLUGIN_NAME='' 6 | SVN_REMOTE='' 7 | SVN_DIR='' 8 | SVN_MSG='Updating with version %s' 9 | SVN_USR='' 10 | SVN_PWD='' 11 | GIT_REMOTE='' 12 | GIT_COMMIT='' 13 | GIT_DIR='' 14 | 15 | help() { 16 | echo -e "\033[1;34mdeploy.sh\033[0m clones your git repository and pushes the content to a specified 17 | subversion repository. It's written to deploy new versions of Wordpress plugins. 18 | 19 | \033[0;34m-n \033[1;32mPlugin name\033[0m What's the name of your plugin? 20 | \033[0;34m-s \033[1;32mSVN remote\033[0m Where's your SVN repository? 21 | \033[0;34m-m \033[1;32mSVN message \033[0;33m[optional]\033[0m A message for the subversion commit (default: $SVN_MSG) 22 | \033[0;34m-u \033[1;32mSVN username \033[0;33m[optional]\033[0m Subversion remote username 23 | \033[0;34m-p \033[1;32mSVN password \033[0;33m[optional]\033[0m Subversion remote password 24 | \033[0;34m-g \033[1;32mGit remote\033[0m Where's your git repository? 25 | \033[0;34m-c \033[1;32mGit commit \033[0;33m[optional]\033[0m If you want to commit a specified commit 26 | " 27 | } 28 | 29 | # Some loading animation :) 30 | 31 | spinner() { 32 | s='.oOo' 33 | #ds=`date "+%H:%M:%S"` 34 | while [ `ps -p $1 -o pid=` ]; do 35 | for (( n=0; n<${#s}; n+=1 )); do 36 | if [ `ps -p $1 -o pid=` ]; then 37 | break; 38 | fi 39 | printf "$2${s:$n:1}$3"; sleep 0.1; printf "\r" 40 | done 41 | done 42 | #de=`date "+%H:%M:%S"` 43 | #echo -e "$2# [$ds-$de]$3" 44 | echo -e "$2#$3" 45 | } 46 | 47 | quit() { 48 | cd $CURRENT_DIR 49 | 50 | rm -Rf $GIT_DIR & 51 | spinner $! "\033[0;34m" " \033[0mRemoving temporary git clone" 52 | 53 | rm -Rf $SVN_DIR & 54 | spinner $! "\033[0;34m" " \033[0mRemoving temporary svn checkout" 55 | } 56 | 57 | # Gather options and arguments 58 | 59 | while getopts ":n:s:m:u:p:g:c:" opt; do 60 | case $opt in 61 | n ) PLUGIN_NAME=$OPTARG;; 62 | s ) SVN_REMOTE=$OPTARG;; 63 | m ) SVN_MSG=$OPTARG;; 64 | u ) SVN_USR=$OPTARG;; 65 | p ) SVN_PWD=$OPTARG;; 66 | g ) GIT_REMOTE=$OPTARG;; 67 | c ) GIT_COMMIT=$OPTARG;; 68 | \? ) help; echo -e "Option \033[1;34m-$OPTARG\033[0m does not exist"; exit;; 69 | : ) help; echo -e "Option \033[1;34m-$OPTARG\033[0m wants an argument"; exit;; 70 | esac 71 | done 72 | 73 | # Start display what we're doing 74 | 75 | echo -e "\033[0;34mDeploying wordpress plugin\033[0m" 76 | 77 | # Check plugin name 78 | 79 | if [ "$PLUGIN_NAME" ]; then 80 | echo -e "Plugin name: $PLUGIN_NAME" 81 | fi 82 | 83 | while [ ! "$PLUGIN_NAME" ]; do 84 | read -p "Plugin name: " PLUGIN_NAME 85 | done 86 | 87 | # Check git repository remote 88 | 89 | if [ "$GIT_REMOTE" ]; then 90 | echo -e "Git repository remote URL: $GIT_REMOTE" 91 | fi 92 | 93 | while [ ! "$GIT_REMOTE" ]; do 94 | read -p "Git repository remote URL: " GIT_REMOTE 95 | 96 | if [ ! "$GIT_COMMIT" ]; then 97 | read -p "Specify a commit (leave blank for ^HEAD): " GIT_COMMIT 98 | fi 99 | done 100 | 101 | # Clone the with git 102 | 103 | GIT_DIR="/tmp/$PLUGIN_NAME-git" 104 | if [ -d $GIT_DIR ]; then 105 | cd $GIT_DIR 106 | git pull -q origin & 107 | spinner $! "\033[0;34m" " \033[0mPulling in: $GIT_DIR" 108 | cd $CURRENT_DIR 109 | else 110 | git clone -q $GIT_REMOTE $GIT_DIR & 111 | spinner $! "\033[0;34m" " \033[0mCloning into: $GIT_DIR" 112 | fi 113 | 114 | # Get a specified commit, if there is one 115 | 116 | if [ "$GIT_COMMIT" ]; then 117 | cd $GIT_DIR; 118 | echo -e "Using commit: $GIT_COMMIT" 119 | git checkout -q $GIT_COMMIT 120 | cd $CURRENT_DIR; 121 | fi 122 | 123 | # Check version in readme.txt is the same as plugin file 124 | 125 | PLUGIN_FILE="$GIT_DIR/$PLUGIN_NAME.php" 126 | 127 | for FILE in `ls $GIT_DIR/*.php`; do 128 | if [ -f "$FILE" ]; then 129 | if grep -q "^Plugin Name:" $FILE & grep -q "^Version:" $FILE; then 130 | echo -e "Using $FILE" 131 | PLUGIN_FILE="$FILE" 132 | fi 133 | fi 134 | done 135 | 136 | if [ -f "$GIT_DIR/readme.txt" ] & [ -f "$PLUGIN_FILE" ]; then 137 | NEWVERSION1=`grep "^ \?\(* \)\?Stable tag" $GIT_DIR/readme.txt | awk '{ print $NF}'` 138 | NEWVERSION2=`grep "^Version" $PLUGIN_FILE | awk '{ print $NF}'` 139 | else 140 | echo -e "FAIL: Could not find $GIT_DIR/readme.txt and/or $PLUGIN_FILE" 141 | quit 142 | exit 143 | fi 144 | 145 | if [ "$NEWVERSION1" != "$NEWVERSION2" ]; then 146 | echo -e "FAIL: Versions don't match - $NEWVERSION1 != $NEWVERSION2" 147 | quit 148 | exit 149 | fi 150 | 151 | echo -e "Version to deploy: $NEWVERSION1" 152 | 153 | # Check svn repository 154 | 155 | if [ "$SVN_REMOTE" ]; then 156 | echo "Subversion repository remote URL: $SVN_REMOTE" 157 | fi 158 | 159 | while [ ! "$SVN_REMOTE" ]; do 160 | read -p "Subversion repository remote URL: " SVN_REMOTE 161 | 162 | if [ ! "$SVN_USR" ]; then 163 | read -p "Subversion repository username (optional): " SVN_USR 164 | fi 165 | 166 | if [ "$SVN_USR" ] & [ ! "$SVN_PWD" ]; then 167 | read -r "Subversion repository password (optional): " SVN_PWD 168 | fi 169 | done 170 | 171 | # Checkout the SVN repository 172 | 173 | SVN_DIR="/tmp/$PLUGIN_NAME-svn" 174 | if [ -d "$SVN_DIR" ]; then 175 | cd $SVN_DIR; 176 | svn --quiet up & 177 | spinner $! "\033[0;34m" " \033[0mUpdating: $SVN_DIR" 178 | cd $CURRENT_DIR; 179 | else 180 | svn --quiet co $SVN_REMOTE $SVN_DIR & 181 | spinner $! "\033[0;34m" " \033[0mCheckout into: $SVN_DIR" 182 | fi 183 | 184 | # Check if there's already a tag with version 185 | 186 | if [ -d "$SVN_DIR/tags/$NEWVERSION1" ]; then 187 | echo -e "Version $NEWVERSION1 already exist" 188 | quit 189 | exit 190 | fi 191 | 192 | # Copy files from git to svn directories 193 | 194 | cd $GIT_DIR 195 | git checkout-index -q -a -f --prefix=$SVN_DIR/trunk/ & 196 | spinner $! "\033[0;34m" " \033[0mCopying files to: $SVN_DIR/trunk" 197 | cd $CURRENT_DIR; 198 | 199 | # Change to SVN dir and commit changes 200 | 201 | echo -e "Committing subversion repository's trunk with files copied from git" 202 | cd $SVN_DIR/trunk 203 | SVN_MSG=$( printf "$SVN_MSG" $NEWVERSION1 ) 204 | if [ "$SVN_USR" ]; then 205 | SVN_USR="--username $SVN_USR" 206 | fi 207 | if [ "$SVN_PWD" ]; then 208 | SVN_PWD="--password $SVN_PWD" 209 | fi 210 | 211 | svn stat | grep '^?' | awk '{print $2}' | xargs svn add 212 | svn ci $SVN_USR $SVN_PWD -m "$SVN_MSG" 213 | 214 | echo -e "Committing new version tag: $NEWVERSION1" 215 | cd .. 216 | svn copy $SVN_REMOTE/trunk $SVN_REMOTE/tags/$NEWVERSION1 $SVN_USR $SVN_PWD -m "Version tag $NEWVERSION1" 217 | 218 | quit 219 | echo "COMPLETE" -------------------------------------------------------------------------------- /wp_deckbox_mtg.php: -------------------------------------------------------------------------------- 1 | _name = 'Magic the Gathering Card Tooltips'; 40 | $this->_optionName = 'deckbox_tooltip_options'; 41 | $this->_value = array(); 42 | $this->_styles = array('tooltip', 'embedded'); 43 | $this->_resources_dir = plugins_url().'/magic-the-gathering-card-tooltips/resources/'; 44 | $this->_images_dir = plugins_url().'/magic-the-gathering-card-tooltips/images/'; 45 | 46 | $this->loadSettings(); 47 | $this->init(); 48 | $this->handlePostback(); 49 | } 50 | 51 | function init() { 52 | add_action('admin_menu', array($this, 'add_option_menu')); 53 | $this->add_shortcodes(); 54 | $this->add_scripts(); 55 | $this->add_buttons(); 56 | } 57 | 58 | function init_css() { 59 | echo '' . "\n"; 61 | } 62 | 63 | function add_shortcodes() { 64 | add_shortcode('mtg_card', array($this,'parse_mtg_card')); 65 | add_shortcode('card', array($this,'parse_mtg_card')); 66 | add_shortcode('c', array($this,'parse_mtg_card')); 67 | add_shortcode('mtg_deck', array($this,'parse_mtg_deck')); 68 | add_shortcode('deck', array($this,'parse_mtg_deck')); 69 | add_shortcode('d', array($this,'parse_mtg_deck')); 70 | } 71 | 72 | function add_buttons() { 73 | if ( ! current_user_can('edit_posts') && ! current_user_can('edit_pages') ) 74 | return; 75 | 76 | // Add only in Rich Editor mode 77 | if ( get_user_option('rich_editing') == 'true') { 78 | add_filter("mce_external_plugins", array($this,"add_tinymce_plugin")); 79 | add_filter('mce_buttons', array($this,'register_button')); 80 | } 81 | } 82 | 83 | function register_button($buttons) { 84 | array_push($buttons, "separator", "deckbox"); 85 | return $buttons; 86 | } 87 | 88 | function add_tinymce_plugin($plugin_array) { 89 | $plugin_array['deckbox'] = $this->_resources_dir.'tinymce3/editor_plugin.js'; 90 | return $plugin_array; 91 | } 92 | 93 | function add_scripts() { 94 | wp_enqueue_script('deckbox', 'https://deckbox.org/javascripts/tooltip.js'); 95 | wp_enqueue_script('deckbox_extensions', $this->_resources_dir.'tooltip_extension.js', array('jquery')); 96 | add_action('wp_head', array($this, 'init_css')); 97 | } 98 | 99 | function parse_mtg_card($atts, $content=null) { 100 | return '' . $content . ''; 101 | } 102 | 103 | function cleanup_shortcode_content($content) { 104 | $dirty_lines = preg_split("/[\n\r]/", $content); 105 | $lines = array(); 106 | 107 | foreach ($dirty_lines as $line) { 108 | $clean = trim(strip_tags($line)); 109 | if ($clean != "") { 110 | $lines[] = $clean; 111 | } 112 | } 113 | 114 | return $lines; 115 | } 116 | 117 | function parse_mtg_deck($atts, $content=null) { 118 | extract(shortcode_atts(array( 119 | "title" => null, 120 | "style" => null, 121 | ), $atts)); 122 | 123 | if ($title) { 124 | $response = '

' . esc_html($title) . '

'; 125 | } 126 | $style = $this->get_clean_style($style); 127 | 128 | $response .= ''; 135 | $response .= '
'; 132 | 133 | $lines = $this->cleanup_shortcode_content($content); 134 | $response .= $this->parse_mtg_deck_lines($lines, $style) . '
'; 136 | 137 | return $response; 138 | } 139 | 140 | function parse_mtg_deck_lines($lines, $style) { 141 | $current_count = 0; 142 | $current_title = ''; 143 | $current_body = ''; 144 | $first_card = null; 145 | $second_column = false; 146 | $html = ''; 147 | 148 | for ($i = 0; $i < count($lines); $i++) { 149 | $line = $lines[$i]; 150 | 151 | if (preg_match('/^([0-9]+)(.*)/', $line, $bits)) { 152 | $card_name = trim($bits[2]); 153 | $first_card = $first_card == null ? $card_name : $first_card; 154 | $card_name = str_replace("’", "'", $card_name); 155 | $line = $bits[1] . ' ' . $card_name . '
'; 157 | $current_body .= $line; 158 | $current_count += intval($bits[1]); 159 | } else { 160 | // Beginning of a new category. If this was not the first one, we put the previous one 161 | // into the response body. 162 | if ($current_title != "") { 163 | $html .= '' . $current_title . ' (' . 164 | $current_count . ')
'; 165 | $html .= $current_body; 166 | if (preg_match("/Sideboard/", $line) && !$second_column) { 167 | $html .= ''; 168 | $second_column = true; 169 | } else if (preg_match("/Lands/", $line) && !$second_column) { 170 | $html .= ''; 171 | $second_column = true; 172 | } else { 173 | $html .= '
'; 174 | } 175 | } 176 | $current_title = $line; $current_count = 0; $current_body = ''; 177 | } 178 | } 179 | $html .= '' . $current_title . ' (' . $current_count . 180 | ')
' . $current_body; 181 | 182 | if ($style == 'embedded') { 183 | $html .= ''; 185 | } 186 | 187 | return $html; 188 | } 189 | 190 | function add_option_menu() { 191 | $title = ''; 192 | if ( version_compare(get_bloginfo('version'), '2.6.999', '>')) { 193 | $title = 'deckbox.org '; 194 | } 195 | $title .= ' Deckbox Tooltips'; 196 | 197 | add_options_page('Deckbox Tooltips', $title, 'read', 'magic-the-gathering-card-tooltips', 198 | array($this, 'draw_menu')); 199 | } 200 | 201 | function draw_menu() { 202 | echo ' 203 |
204 |

Deckbox MtG Card Tooltips Settings


205 |
206 |

General Settings

207 |
208 |
209 | '.wp_nonce_field('deckbox_settings_action', 'deckbox_settings_nonce', true, false).' 210 | 211 | 212 | 215 | 219 | 220 | 223 | 227 | 228 | 231 | 235 | 236 | 239 | 243 | 244 |
213 | 214 | 216 | 217 | 218 |
221 | 222 | 224 | px 226 |
229 | 230 | 232 | % 234 |
237 | 238 | 240 | % 242 |
245 |

246 |
247 |
248 |
249 |
250 | '; 251 | } 252 | 253 | function get_clean_style($style) { 254 | // Check if $style is provided and exists in predefined styles 255 | if ($style && in_array($style, $this->_styles)) { 256 | return $style; 257 | } 258 | 259 | // Get the default style index from settings 260 | $default_index = $this->get_setting('style') - 1; 261 | 262 | // Ensure the default index exists in the styles array 263 | return isset($this->_styles[$default_index]) ? $this->_styles[$default_index] : $this->_styles[0]; 264 | } 265 | 266 | function get_setting($setting) { 267 | return $this->_value['tooltip'][0][$setting]; 268 | } 269 | 270 | function get_style_options() { 271 | $options = ''; 272 | for ($i = 0; $i < count($this->_styles); $i++) { 273 | $n = $i + 1; 274 | $selected = $this->get_setting('style') == $n ? ' selected="selected"' : ''; 275 | $options .= ''; 276 | } 277 | return $options; 278 | } 279 | 280 | function loadSettings() { 281 | $dbValue = get_option($this->_optionName); 282 | if (strlen($dbValue) > 0) { 283 | $this->_value = json_decode($dbValue,true); 284 | 285 | if (empty($this->_value['tooltip'][0]['style'])) { 286 | $this->_value['tooltip'][0]['style'] = self::DEFAULT_STYLE; 287 | } 288 | if (empty($this->_value['tooltip'][0]['deck_width'])) { 289 | $this->_value['tooltip'][0]['deck_width'] = self::DEFAULT_DECK_WIDTH; 290 | } 291 | if (empty($this->_value['tooltip'][0]['font_size'])) { 292 | $this->_value['tooltip'][0]['font_size'] = self::DEFAULT_FONT_SIZE; 293 | } 294 | if (empty($this->_value['tooltip'][0]['line_height'])) { 295 | $this->_value['tooltip'][0]['line_height'] = self::DEFAULT_LINE_HEIGHT; 296 | } 297 | 298 | $this->_initialValue = $this->_value; 299 | } else { 300 | $deprecated = ' '; 301 | $autoload = 'yes'; 302 | $value = '{"tooltip":[{"style":"", "deck_width":"", "font_size":"", "line_height":""}]}'; 303 | $result = add_option( $this->_optionName, $value, $deprecated, $autoload ); 304 | $this->loadSettings(); 305 | } 306 | } 307 | 308 | function handlePostback() { 309 | if (isset($_POST['isPostback'])) { 310 | // Validate the nonce 311 | if (!isset($_POST['deckbox_settings_nonce']) || 312 | !wp_verify_nonce($_POST['deckbox_settings_nonce'], 'deckbox_settings_action')) { 313 | wp_die('Security check failed!'); 314 | } 315 | 316 | // Check user capabilities 317 | if (!current_user_can('manage_options')) { 318 | wp_die('You do not have sufficient permissions to access this page.'); 319 | } 320 | 321 | $v = array(); 322 | $v['tooltip'][] = array( 323 | 'style' => isset($_POST['tooltip_style']) ? absint($_POST['tooltip_style']) : self::DEFAULT_STYLE, 324 | 'deck_width' => isset($_POST['tooltip_deck_width']) ? absint($_POST['tooltip_deck_width']) : self::DEFAULT_DECK_WIDTH, 325 | 'font_size' => isset($_POST['tooltip_font_size']) ? absint($_POST['tooltip_font_size']) : self::DEFAULT_FONT_SIZE, 326 | 'line_height' => isset($_POST['tooltip_line_height']) ? absint($_POST['tooltip_line_height']) : self::DEFAULT_LINE_HEIGHT); 327 | $this->_value = $v; 328 | $this->save(); 329 | } 330 | } 331 | 332 | function save() { 333 | if (($this->_initialValue != $this->_value)) { 334 | update_option($this->_optionName, json_encode($this->_value)); 335 | echo '

settings saved

'; 336 | } 337 | } 338 | } 339 | } 340 | --------------------------------------------------------------------------------