match_count = 0; $this->footnotes = array(); $this->errors = array(); //setup default options array $this->default_options = array( 'number_system' => 'lower-alpha', 'cite_number_location' => 'sup', //CSS Classes 'cite_link_class' => 'ajs-footnote', 'note_list_class' => 'ajs-fn', 'backlink_text' => '(back)', 'encode_html_specials' => 'false', 'display_notes_list' => 'true', //Popups 'display_popups' => 'true', 'popup_container_element' => 'div', 'popup_display_effect_in' => 'fadeIn', 'popup_display_effect_out' => 'fadeOut', 'popup_duration_in' => 200, 'popup_duration_out' => 200, 'popup_border_color' => '#888888', 'popup_border_style' => 'solid', 'popup_border_width' => 1, 'popup_border_width_unit' => 'px', 'footnotes_open' => '((', 'footnotes_close' => '))', //CSS & JS ID 'id_lead' => 'ajs-fn-id', //Styling //footnote list 'footnote_list_color' => '#666666', 'footnote_list_size' => '0.8', 'footnote_list_size_unit' => 'em', //popups 'popup_text_size' => 1, 'popup_text_size_unit' => 'em', 'popup_width' => '20', 'popup_width_unit' => 'em', 'popup_bgcolor' => '#f8f8f8', 'popup_fgcolor' => '000', 'popup_padding_right' => '1', 'popup_padding_right_unit' => 'em', 'popup_padding_left' => '1', 'popup_padding_left_unit' => 'em', 'popup_padding_top' => 0.5, 'popup_padding_top_unit'=> 'em', 'popup_padding_bottom' => 0.5, 'popup_padding_bottom_unit' => 'em', 'popup_shadow_hval' => 0.3, 'popup_shadow_h_unit' => 'em', 'popup_shadow_vval' => 0.3, 'popup_shadow_v_unit' => 'em', 'popup_shadow_blur' => 0.3, 'popup_shadow_blur_unit' => 'em', 'popup_shadow_spread' => 0, 'popup_shadow_spread_unit' => 'px', 'popup_shadow_color' => '#ebebeb', 'popup_top_left_corner' => '4', 'popup_top_left_corner_unit' => 'px', 'popup_top_right_corner' => '4', 'popup_top_right_corner_unit' => 'px', 'popup_bottom_left_corner' => '4', 'popup_bottom_left_corner_unit' => 'px', 'popup_bottom_right_corner' => '4', 'popup_bottom_right_corner_unit' => 'px', 'version' => AJS_FOOTNOTES_VERSION ); //get options from the DB if they're there if (!$this->options = get_option('ajs_footnote_options')){ //set the default options as the options... $this->options = $this->default_options; update_option('ajs_footnote_options', $this->options); } else { //Set any option that has no value if ($this->options['version'] != AJS_FOOTNOTES_VERSION) { $this->options = $this->options + $this->default_options; } $this->options['version'] = AJS_FOOTNOTES_VERSION; update_option('ajs_footnote_options', $this->options); } if( !empty($_POST['save_options'])) { $this->errors = $this->checkPostValues($_POST); //no errors, then we merge with the default options and save... if( count($this->errors) == 0 ) { $this->options = $_POST + $this->default_options; update_option('ajs_footnote_options', $this->options); } } elseif (!empty($_POST['reset_options'])) { update_option('ajs_footnote_options', ''); update_option('ajs_footnote_options', $this->default_options); } //Hooks add_action('the_content', array($this, 'make_notes')); //process the content add_action('wp_head', array($this, 'insertCSS')); //insert proper CSS styling if($this->options['display_popups']) { add_action('wp_enqueue_scripts', array($this, 'q_scripts')); add_action('wp_footer', array($this, 'insertJavaScript')); } add_action('admin_enqueue_scripts', array($this, 'enqueueAdminScripts')); add_action('admin_menu', array($this, 'addOptionsPage')); //so you can edit opts } /** * Looks through the content and greps footnotes. * @param $content string The post content via WP * @return string The new content with footnotes inserted */ public function make_notes($content) { global $post; //have to empty array for Blog roll $this->footnotes = array(); $this->match_count = 0; $notated_content = ''; //holds the content $note_list = ''; $popup_list = ''; /** * TODO: Deal with pagination nightmare (maybe next version) */ //Retrieve the footnotes from the text and replace them with the appropriate reference using a callback $notated_content= preg_replace_callback("/(".preg_quote($this->options['footnotes_open'])."|)(.*)(".preg_quote($this->options['footnotes_close'])."|<\/footnote>)/Us", array(&$this, 'remove_note_content'), $content); //Populate the notes list (if such a thing exists) if ($this->options['display_notes_list']) { $note_list = '
    '.PHP_EOL; for($ii = 0; $ii < count($this->footnotes); $ii++) { $note_list .= '
  1. '.$this->footnotes[$ii].'  '.$this->options['backlink_text'].'
  2. '.PHP_EOL; } $note_list .= '
'.PHP_EOL; } if($this->options['display_popups']) { for($ii = 0; $ii < count($this->footnotes); $ii++) { $popup_list .= $this->create_popups($ii); } } $notated_content .= $note_list.$popup_list; return $notated_content; } /** * This function creates the containers that hold the popup notes. * @param string $number The index of this note in the $this->footnotes array * @return string The HTML to produce the popup. */ private function create_popups($number) { global $post; $note_content = ($this->options['encode_html_specials'] == 'true')? htmlentities($this->footnotes[$number]) : $this->footnotes[$number]; $container_open = '<'.$this->options['popup_container_element'].' id="'.$this->options['id_lead'].'_'.($number+1).'-'.$post->ID.'" style="display:none;margin:0;" class="ajs-footnote-popup">'; $container_open .= '<'.$this->options['popup_container_element'].'>'; $container_close = str_repeat('options['popup_container_element'].'>', 2); return $container_open.$note_content.$container_close; } /** * This function logs the matched footnote and returns the formated identifier to preg_replace * @param array $matches * @return string The formatted footnote identifier */ private function remove_note_content($matches) { global $post; $this->match_count++; //slice off the identifying strings $matched_string = array_slice($matches, 2, -1); $this->footnotes[] = implode('', $matched_string); //Convert (if needed) $display_value = $this->convert_numeral($this->match_count); //Return the numbered reference $numbered_link = ''.$display_value.''; //Format the reference character(s) if ($this->options['cite_number_location'] == 'sup') { $output = ''.$numbered_link.''; } else if($this->options['cite_number_location'] == 'sub') { $output = ''.$numbered_link.''; } else { //inline $output = ''.$numbered_link.''; } return $output; } /** * This function enqueues the JS used by thte plugins */ public function q_scripts() { wp_enqueue_script( 'hoverIntent', plugins_url('hoverIntent.js', __FILE__), array('jquery') ); } /** * This function inserts the jQuery required to make the popups work. (It never runs if popups are disabled. */ public function insertJavaScript() { /** * TODO: Make sure popups will fit on screen (requires jqueryui; postponed until next version.) */ ?> options = get_option('ajs_footnote_options'); foreach($this->options as $key=>$val) { $new_opts[$key] = htmlentities2($val); } $this->options = $new_opts; unset($new_opts); if(count($this->errors > 0)) { $optionsPage = new optionsPage($this->options, $this->errors); } else { $optionsPage = new optionsPage($this->options); } } /** * This function converts a decimal numeral into the requested format * @param int $n The decimal number * @return string Representing the formated number */ private function convert_numeral($n) { if($this->options['number_system'] == 'decimal') { return $n; } $converted_number = null; switch($this->options['number_system']) { case 'decimal-leading-zero': $w = max(2, strlen($n)); $converted_number = sprintf("%0{$w}d", $n); break; case 'lower-roman': $converted_number = $this->convertDecToRoman($n, true); break; case 'upper-roman': $converted_number = $this->convertDecToRoman($n); break; case 'lower-alpha': $converted_number = $this->convertDecToAlpha($n, true); break; case 'upper-alpha': $converted_number = $this->convertDecToAlpha($n); break; default: $converted_number = $n; } return $converted_number; } /** * This function turns a decimal value into its Roman Numeral equivalent * @param int $n The decimal number we're converting * @param bool $mode If mode is true, the value is returned in lower case * @return string The Roman Numeral representation of the decimal $n */ private function convertDecToRoman($n, $mode = false) { //Alogrithm by pradeep @ http://www.go4expert.com/articles/roman-php-t4948/ $lookup = array( 'M' => 1000, 'CM' => 900, 'D' => 500, 'CD' => 400, 'C' => 100, 'XC' => 90, 'L' => 50, 'XL' => 40, 'X' => 10, 'IX' => 9, 'V' => 5, 'IV'=> 4, 'I' => 1 ); $result = ''; foreach ($lookup as $roman=>$decimal) { $matches = intval($n / $decimal); $result .= str_repeat($roman, $matches); $n = $n % $decimal; } return ($mode)? strtolower($result) : $result; } /** * This function turns a decimal value into a corresponding letter (or repeated letter) so 27 = AA. * @param int $n The decimal value to convert * @param bool $mode If true, lower case letter(s) returned * @return string The decimal as an alphabetic representation */ private function convertDecToAlpha($n, $mode = false) { $letter = chr(($n % 26)+96); $letter .= (floor($n/26))? str_repeat($letter, floor($n/26)) : ''; return ($mode)? $letter : strtoupper($letter); } /** * This function checks to see if the submitted values are valid. * @param array $_POST values passed from Options */ private function checkPostValues($post) { $errors = array(); /*Popup & Footnote Values*/ $numeric = array( 'popup_duration_in', 'popup_duration_out', 'popup_border_width', 'popup_width', 'popup_text_size', 'popup_padding_right', 'popup_padding_left', 'popup_padding_top', 'popup_padding_bottom', 'popup_shadow_hval', 'popup_shadow_vval', 'popup_shadow_blur', 'popup_shadow_spread', 'popup_top_left_corner', 'popup_top_right_corner', 'popup_bottom_left_corner', 'popup_bottom_right_corner', 'footnote_list_size' ); $hexColor = array( 'popup_bgcolor', 'popup_fgcolor', 'popup_shadow_color', 'popup_border_color', 'footnote_list_color' ); //Merge Color Checks foreach ( $numeric as $value ) { if (!isset($post[$value])) { $errors[$value] = 'You must enter a value here.'; } else { if (!is_numeric($post[$value])) { $errors[$value] = 'This value must be a number.'; } } } foreach ( $hexColor as $value ) { if (!isset($post[$value])) { $errors[$value] = 'You must enter a value here.'; } else { if (!preg_match('/^#[a-f0-9]{6}$/i', $post[$value])) { $errors[$value] = 'You must enter a 6 digit hexadecimal number with the hash (#).'; } } } return $errors; } } ?>