diff --git a/trunk/class/config.php b/trunk/class/config.php new file mode 100644 index 0000000..617f63d --- /dev/null +++ b/trunk/class/config.php @@ -0,0 +1,80 @@ +foot'; + + /** + * Public Plugin name for dashboard heading + * + * After properly displaying in dashboard headings until WPv5.4, the above started + * in WPv5.5 being torn apart as if the headline was text-align:justify and not + * the last line. That ugly display bug badly affected the plugin’s communication. + * The only working solution found so far is using position:fixed in one heading + * that isn’t translated, and dropping the logo in another, translatable heading. + * + * @since 2.0.4 + * @var string + */ + const C_STR_PLUGIN_HEADING_NAME = 'footnotes'; + + /** + * Html tag for the LOVE symbol. + * + * @author Stefan Herndler + * @since 1.5.0 + * @var string + */ + const C_STR_LOVE_SYMBOL = ''; + + /** + * HTML code for the 'love' symbol used in dashboard heading + * + * @since 2.0.4 + * @var string + */ + const C_STR_LOVE_SYMBOL_HEADING = ''; + + /** + * Short code to DON'T display the 'LOVE ME' slug on certain pages. + * + * @author Stefan Herndler + * @since 1.5.0 + * @var string + */ + const C_STR_NO_LOVE_SLUG = '[[no footnotes: love]]'; +} diff --git a/trunk/class/convert.php b/trunk/class/convert.php new file mode 100644 index 0000000..090189a --- /dev/null +++ b/trunk/class/convert.php @@ -0,0 +1,213 @@ + 26) { + // increase offset and reduce counter + $l_int_Offset++; + $p_int_Value -= 26; + } + // if offset set (more then Z), then add a new letter in front + if ($l_int_Offset > 0) { + $l_str_Return = chr($l_int_Offset + 64); + } + // add the origin letter + $l_str_Return .= chr($p_int_Value + 64); + // return the latin character representing the integer + if ($p_bool_UpperCase) { + return strtoupper($l_str_Return); + } + return strtolower($l_str_Return); + } + + /** + * Converts an integer to a leading-0 integer. + * + * @author Stefan Herndler + * @since 1.0-gamma + * @param int $p_int_Value Value/Index to be converted. + * @return string Value with a leading zero. + */ + private static function toArabicLeading($p_int_Value) { + // add a leading 0 if number lower then 10 + if ($p_int_Value < 10) { + return "0" . $p_int_Value; + } + return $p_int_Value; + } + + /** + * Converts an integer to a romanic letter. + * + * @author Stefan Herndler + * @since 1.0-gamma + * @param int $p_int_Value Value/Index to be converted. + * @return string + */ + private static function toRomanic($p_int_Value) { + // table containing all necessary romanic letters + $l_arr_RomanicLetters = 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 + ); + // return value + $l_str_Return = ''; + // iterate through integer value until it is reduced to 0 + while ($p_int_Value > 0) { + foreach ($l_arr_RomanicLetters as $l_str_Romanic => $l_int_Arabic) { + if ($p_int_Value >= $l_int_Arabic) { + $p_int_Value -= $l_int_Arabic; + $l_str_Return .= $l_str_Romanic; + break; + } + } + } + // return romanic letters as string + return $l_str_Return; + } + + /** + * Converts a string depending on its value to a boolean. + * + * @author Stefan Herndler + * @since 1.0-beta + * @param string $p_str_Value String to be converted to boolean. + * @return bool Boolean representing the string. + */ + public static function toBool($p_str_Value) { + // convert string to lower-case to make it easier + $p_str_Value = strtolower($p_str_Value); + // check if string seems to contain a "true" value + switch ($p_str_Value) { + case "checked": + case "yes": + case "true": + case "on": + case "1": + return true; + } + // nothing found that says "true", so we return false + return false; + } + + /** + * Get a html Array short code depending on Arrow-Array key index. + * + * @author Stefan Herndler + * @since 1.3.2 + * @param int $p_int_Index Index representing the Arrow. If empty all Arrows are specified. + * @return array|string Array of all Arrows if Index is empty otherwise html tag of a specific arrow. + */ + public static function getArrow($p_int_Index = -1) { + // define all possible arrows + $l_arr_Arrows = array("↑", "↥", "↟", "↩", "↲", "↵", "⇑", "⇡", "⇧", "↑"); + // convert index to an integer + if (!is_int($p_int_Index)) { + $p_int_Index = intval($p_int_Index); + } + // return the whole arrow array + if ($p_int_Index < 0 || $p_int_Index > count($l_arr_Arrows)) { + return $l_arr_Arrows; + } + // return a single arrow + return $l_arr_Arrows[$p_int_Index]; + } + + /** + * Displays a Variable. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param mixed $p_mixed_Value + */ + public static function debug($p_mixed_Value) { + if (empty($p_mixed_Value)) { + var_dump($p_mixed_Value); + + } else if (is_array($p_mixed_Value)) { + printf("
");
+			print_r($p_mixed_Value);
+			printf("
"); + + } else if (is_object($p_mixed_Value)) { + printf("
");
+			print_r($p_mixed_Value);
+			printf("
"); + + } else if (is_numeric($p_mixed_Value) || is_int($p_mixed_Value)) { + var_dump($p_mixed_Value); + + } else if (is_date($p_mixed_Value)) { + var_dump($p_mixed_Value); + + } else { + var_dump($p_mixed_Value); + } + echo "
"; + } +} \ No newline at end of file diff --git a/trunk/class/dashboard/init.php b/trunk/class/dashboard/init.php new file mode 100644 index 0000000..19dacd6 --- /dev/null +++ b/trunk/class/dashboard/init.php @@ -0,0 +1,212 @@ +a_arr_SubPageClasses[$l_obj_Class->getPriority()] = $l_obj_Class; + } + } + ksort($this->a_arr_SubPageClasses); + + // register hooks/actions + add_action('admin_init', array($this, 'initializeSettings')); + add_action('admin_menu', array($this, 'registerMainMenu')); + // register AJAX callbacks for Plugin information + add_action("wp_ajax_nopriv_footnotes_getPluginInfo", array($this, "getPluginMetaInformation")); + add_action("wp_ajax_footnotes_getPluginInfo", array($this, "getPluginMetaInformation")); + } + + /** + * Initializes all sub pages and registers the settings. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + public function initializeSettings() { + MCI_Footnotes_Settings::instance()->RegisterSettings(); + // iterate though each sub class of the layout engine and register their sections + /** @var MCI_Footnotes_LayoutEngine $l_obj_LayoutEngineSubClass */ + foreach($this->a_arr_SubPageClasses as $l_obj_LayoutEngineSubClass) { + $l_obj_LayoutEngineSubClass->registerSections(); + } + } + + /** + * Registers the new main menu for the WordPress dashboard. + * Registers all sub menu pages for the new main menu. + * + * @author Stefan Herndler + * @since 2.0.2 + * @see http://codex.wordpress.org/Function_Reference/add_menu_page + */ + public function registerMainMenu() { + global $menu; + // iterate through each main menu + foreach($menu as $l_arr_MainMenu) { + // iterate through each main menu attribute + foreach($l_arr_MainMenu as $l_str_Attribute) { + // main menu already added, append sub pages and stop + if ($l_str_Attribute == self::C_STR_MAIN_MENU_SLUG) { + $this->registerSubPages(); + return; + } + } + } + + // add a new main menu page to the WordPress dashboard + add_menu_page( + self::C_STR_MAIN_MENU_TITLE, // page title + self::C_STR_MAIN_MENU_TITLE, // menu title + 'manage_options', // capability + self::C_STR_MAIN_MENU_SLUG, // menu slug + array($this, "displayOtherPlugins"), // function + plugins_url('footnotes/img/main-menu.png'), // icon url + null // position + ); + $this->registerSubPages(); + } + + /** + * Registers all SubPages for this Plugin. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + private function registerSubPages() { + // first registered sub menu page MUST NOT contain a unique slug suffix + // iterate though each sub class of the layout engine and register their sub page + /** @var MCI_Footnotes_LayoutEngine $l_obj_LayoutEngineSubClass */ + foreach($this->a_arr_SubPageClasses as $l_obj_LayoutEngineSubClass) { + $l_obj_LayoutEngineSubClass->registerSubPage(); + } + } + + /** + * Displays other Plugins from the developers. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + public function displayOtherPlugins() { + printf("

"); + // load template file + $l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_DASHBOARD, "manfisher"); + echo $l_obj_Template->getContent(); + + printf('visit Mark Cheret'); + printf("

"); + + printf(''); + } + + /** + * AJAX call. returns a JSON string containing meta information about a specific WordPress Plugin. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + public function getPluginMetaInformation() { + // get plugin internal name from POST data + $l_str_PluginName = array_key_exists("plugin", $_POST) ? $_POST["plugin"] : null; + if (empty($l_str_PluginName)) { + echo json_encode(array("error" => "Plugin name invalid.")); + exit; + } + $l_str_Url = "https://api.wordpress.org/plugins/info/1.0/".$l_str_PluginName.".json"; + // call URL and collect data + $l_arr_Response = wp_remote_get($l_str_Url); + // check if response is valid + if (is_wp_error($l_arr_Response)) { + echo json_encode(array("error" => "Error receiving Plugin Information from WordPress.")); + exit; + } + if (!array_key_exists("body", $l_arr_Response)) { + echo json_encode(array("error" => "Error reading WordPress API response message.")); + exit; + } + // get the body of the response + $l_str_Response = $l_arr_Response["body"]; + // get plugin object + $l_arr_Plugin = json_decode($l_str_Response, true); + if (empty($l_arr_Plugin)) { + echo json_encode(array("error" => "Error reading Plugin meta information.
URL: " . $l_str_Url . "
Response: " . $l_str_Response)); + exit; + } + + $l_int_NumRatings = array_key_exists("num_ratings", $l_arr_Plugin) ? intval($l_arr_Plugin["num_ratings"]) : 0; + $l_int_Rating = array_key_exists("rating", $l_arr_Plugin) ? floatval($l_arr_Plugin["rating"]) : 0.0; + $l_int_Stars = round(5 * $l_int_Rating / 100.0, 1); + + // return Plugin information as JSON encoded string + echo json_encode( + array( + "error" => "", + "PluginDescription" => array_key_exists("short_description", $l_arr_Plugin) ? html_entity_decode($l_arr_Plugin["short_description"]) : "Error reading Plugin information", + "PluginAuthor" => array_key_exists("author", $l_arr_Plugin) ? html_entity_decode($l_arr_Plugin["author"]) : "unknown", + "PluginRatingText" => $l_int_Stars . " " . __("rating based on", MCI_Footnotes_Config::C_STR_PLUGIN_NAME) . " " . $l_int_NumRatings . " " . __("ratings", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "PluginRating1" => $l_int_Stars >= 0.5 ? "star-full" : "star-empty", + "PluginRating2" => $l_int_Stars >= 1.5 ? "star-full" : "star-empty", + "PluginRating3" => $l_int_Stars >= 2.5 ? "star-full" : "star-empty", + "PluginRating4" => $l_int_Stars >= 3.5 ? "star-full" : "star-empty", + "PluginRating5" => $l_int_Stars >= 4.5 ? "star-full" : "star-empty", + "PluginRating" => $l_int_NumRatings, + "PluginLastUpdated" => array_key_exists("last_updated", $l_arr_Plugin) ? $l_arr_Plugin["last_updated"] : "unknown", + "PluginDownloads" => array_key_exists("downloaded", $l_arr_Plugin) ? $l_arr_Plugin["downloaded"] : "---" + ) + ); + exit; + } +} \ No newline at end of file diff --git a/trunk/class/dashboard/layout.php b/trunk/class/dashboard/layout.php new file mode 100644 index 0000000..4c925c2 --- /dev/null +++ b/trunk/class/dashboard/layout.php @@ -0,0 +1,487 @@ + MCI_Footnotes_Config::C_STR_PLUGIN_NAME . "-" . $p_str_ID, "title" => $p_str_Title, "submit" => $p_bool_hasSubmitButton, "container" => $p_int_SettingsContainerIndex); + } + + /** + * Returns an array describing a meta box. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param string $p_str_SectionID Parent Section ID. + * @param string $p_str_ID Unique ID suffix. + * @param string $p_str_Title Title for the meta box. + * @param string $p_str_CallbackFunctionName Class method name for callback. + * @return array meta box description to be able to append a meta box to the output. + */ + protected function addMetaBox($p_str_SectionID, $p_str_ID, $p_str_Title, $p_str_CallbackFunctionName) { + return array("parent" => MCI_Footnotes_Config::C_STR_PLUGIN_NAME . "-" . $p_str_SectionID, "id" => $p_str_ID, "title" => $p_str_Title, "callback" => $p_str_CallbackFunctionName); + } + + /** + * Registers a sub page. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + public function registerSubPage() { + global $submenu; + // any sub menu for our main menu exists + if (array_key_exists(plugin_basename(MCI_Footnotes_Layout_Init::C_STR_MAIN_MENU_SLUG), $submenu)) { + // iterate through all sub menu entries of the ManFisher main menu + foreach($submenu[plugin_basename(MCI_Footnotes_Layout_Init::C_STR_MAIN_MENU_SLUG)] as $l_arr_SubMenu) { + if ($l_arr_SubMenu[2] == plugin_basename(MCI_Footnotes_Layout_Init::C_STR_MAIN_MENU_SLUG . $this->getSubPageSlug())) { + // remove that sub menu and add it again to move it to the bottom + remove_submenu_page(MCI_Footnotes_Layout_Init::C_STR_MAIN_MENU_SLUG, MCI_Footnotes_Layout_Init::C_STR_MAIN_MENU_SLUG .$this->getSubPageSlug()); + } + } + } + + $this->a_str_SubPageHook = add_submenu_page( + MCI_Footnotes_Layout_Init::C_STR_MAIN_MENU_SLUG, // parent slug + $this->getSubPageTitle(), // page title + $this->getSubPageTitle(), // menu title + 'manage_options', // capability + MCI_Footnotes_Layout_Init::C_STR_MAIN_MENU_SLUG . $this->getSubPageSlug(), // menu slug + array($this, 'displayContent') // function + ); + } + + /** + * Registers all sections for a sub page. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + public function registerSections() { + // iterate through each section + foreach($this->getSections() as $l_arr_Section) { + // append tab to the tab-array + $this->a_arr_Sections[$l_arr_Section["id"]] = $l_arr_Section; + add_settings_section( + $l_arr_Section["id"], // unique id + "", //$l_arr_Section["title"], // title + array($this, 'Description'), // callback function for the description + $l_arr_Section["id"] // parent sub page slug + ); + $this->registerMetaBoxes($l_arr_Section["id"]); + } + } + + /** + * Registers all Meta boxes for a sub page. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param string $p_str_ParentID Parent section unique id. + */ + private function registerMetaBoxes($p_str_ParentID) { + // iterate through each meta box + foreach($this->getMetaBoxes() as $l_arr_MetaBox) { + if ($l_arr_MetaBox["parent"] != $p_str_ParentID) { + continue; + } + add_meta_box( + $p_str_ParentID. "-" . $l_arr_MetaBox["id"], // unique id + $l_arr_MetaBox["title"], // meta box title + array($this, $l_arr_MetaBox["callback"]), // callback function to display (echo) the content + $p_str_ParentID, // post type = parent section id + 'main' // context + ); + } + } + + /** + * Append javascript and css files for specific sub page. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + private function appendScripts() { + // enable meta boxes layout and close functionality + wp_enqueue_script('postbox'); + // add WordPress color picker layout + wp_enqueue_style('wp-color-picker'); + // add WordPress color picker function + wp_enqueue_script('wp-color-picker'); + // register stylesheet + wp_register_style('mci-footnotes-admin-styles', plugins_url('../../css/settings.css', __FILE__)); + // add stylesheet to the output + wp_enqueue_style('mci-footnotes-admin-styles'); + } + + /** + * Displays the content of specific sub page. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + public function displayContent() { + // register and enqueue scripts and styling + $this->appendScripts(); + // get current section + reset($this->a_arr_Sections); + $l_str_ActiveSectionID = isset($_GET['t']) ? $_GET['t'] : key($this->a_arr_Sections); + $l_arr_ActiveSection = $this->a_arr_Sections[$l_str_ActiveSectionID]; + // store settings + $l_bool_SettingsUpdated = false; + if (array_key_exists("save-settings", $_POST)) { + if ($_POST["save-settings"] == "save") { + unset($_POST["save-settings"]); + unset($_POST["submit"]); + $l_bool_SettingsUpdated = $this->saveSettings(); + } + } + + // display all sections and highlight the active section + echo '
'; + echo '
'; + + if ($l_bool_SettingsUpdated) { + echo sprintf('
%s
', __("Settings saved", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)); + } + + // form to submit the active section + echo '
'; + //settings_fields($l_arr_ActiveSection["container"]); + echo ''; + // outputs the settings field of the active section + do_settings_sections($l_arr_ActiveSection["id"]); + do_meta_boxes($l_arr_ActiveSection["id"], 'main', NULL); + + // add submit button to active section if defined + if ($l_arr_ActiveSection["submit"]) { + submit_button(); + } + // close the form to submit data + echo '
'; + // close container for the settings page + echo '
'; + // output special javascript for the expand/collapse function of the meta boxes + echo ''; + } + + /** + * Save all Plugin settings. + * + * @author Stefan Herndler + * @since 1.5.0 + * @return bool + */ + private function saveSettings() { + $l_arr_newSettings = array(); + // get current section + reset($this->a_arr_Sections); + $l_str_ActiveSectionID = isset($_GET['t']) ? $_GET['t'] : key($this->a_arr_Sections); + $l_arr_ActiveSection = $this->a_arr_Sections[$l_str_ActiveSectionID]; + + // iterate through each value that has to be in the specific contaienr + foreach(MCI_Footnotes_Settings::instance()->getDefaults($l_arr_ActiveSection["container"]) as $l_str_Key => $l_mixed_Value) { + // setting is available in the POST array, use it + if (array_key_exists($l_str_Key, $_POST)) { + $l_arr_newSettings[$l_str_Key] = $_POST[$l_str_Key]; + } else { + // setting is not defined in the POST array, define it to avoid the Default value + $l_arr_newSettings[$l_str_Key] = ""; + } + } + // update settings + return MCI_Footnotes_Settings::instance()->saveOptions($l_arr_ActiveSection["container"], $l_arr_newSettings); + } + + /** + * Output the Description of a section. May be overwritten in any section. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + public function Description() { + // default no description will be displayed + } + + /** + * Loads specific setting and returns an array with the keys [id, name, value]. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param string $p_str_SettingKeyName Settings Array key name. + * @return array Contains Settings ID, Settings Name and Settings Value. + */ + protected function LoadSetting($p_str_SettingKeyName) { + // get current section + reset($this->a_arr_Sections); + $p_arr_Return = array(); + $p_arr_Return["id"] = sprintf('%s', $p_str_SettingKeyName); + $p_arr_Return["name"] = sprintf('%s', $p_str_SettingKeyName); + $p_arr_Return["value"] = esc_attr(MCI_Footnotes_Settings::instance()->get($p_str_SettingKeyName)); + return $p_arr_Return; + } + + /** + * Returns a line break to start a new line. + * + * @author Stefan Herndler + * @since 1.5.0 + * @return string + */ + protected function addNewline() { + return '
'; + } + + /** + * Returns a line break to have a space between two lines. + * + * @author Stefan Herndler + * @since 1.5.0 + * @return string + */ + protected function addLineSpace() { + return '

'; + } + + /** + * Returns a simple text inside html text. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param string $p_str_Text Message to be surrounded with simple html tag (span). + * @return string + */ + protected function addText($p_str_Text) { + return sprintf('%s', $p_str_Text); + } + + /** + * Returns the html tag for an input/select label. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param string $p_str_SettingName Name of the Settings key to connect the Label with the input/select field. + * @param string $p_str_Caption Label caption. + * @return string + */ + protected function addLabel($p_str_SettingName, $p_str_Caption) { + if (empty($p_str_Caption)) { + return ""; + } + return sprintf('', $p_str_SettingName, $p_str_Caption); + } + + /** + * Returns the html tag for an input [type = text]. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param string $p_str_SettingName Name of the Settings key to pre load the input field. + * @param int $p_str_MaxLength Maximum length of the input, default 999 characters. + * @param bool $p_bool_Readonly Set the input to be read only, default false. + * @param bool $p_bool_Hidden Set the input to be hidden, default false. + * @return string + */ + protected function addTextBox($p_str_SettingName, $p_str_MaxLength = 999, $p_bool_Readonly = false, $p_bool_Hidden = false) { + $l_str_Style = ""; + // collect data for given settings field + $l_arr_Data = $this->LoadSetting($p_str_SettingName); + if ($p_bool_Hidden) { + $l_str_Style .= 'display:none;'; + } + return sprintf('', + $l_arr_Data["name"], $l_arr_Data["id"], $p_str_MaxLength, + $l_str_Style, $l_arr_Data["value"], $p_bool_Readonly ? 'readonly="readonly"' : ''); + } + + /** + * Returns the html tag for an input [type = checkbox]. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param string $p_str_SettingName Name of the Settings key to pre load the input field. + * @return string + */ + protected function addCheckbox($p_str_SettingName) { + // collect data for given settings field + $l_arr_Data = $this->LoadSetting($p_str_SettingName); + return sprintf('', + $l_arr_Data["name"], $l_arr_Data["id"], + MCI_Footnotes_Convert::toBool($l_arr_Data["value"]) ? 'checked="checked"' : ''); + } + + /** + * Returns the html tag for a select box. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param string $p_str_SettingName Name of the Settings key to pre select the current value. + * @param array $p_arr_Options Possible options to be selected. + * @return string + */ + protected function addSelectBox($p_str_SettingName, $p_arr_Options) { + // collect data for given settings field + $l_arr_Data = $this->LoadSetting($p_str_SettingName); + $l_str_Options = ""; + + /* loop through all array keys */ + foreach ($p_arr_Options as $l_str_Value => $l_str_Caption) { + $l_str_Options .= sprintf('', + $l_str_Value, + $l_arr_Data["value"] == $l_str_Value ? "selected" : "", + $l_str_Caption); + } + return sprintf('', + $l_arr_Data["name"], $l_arr_Data["id"], $l_str_Options); + } + + /** + * Returns the html tag for a text area. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param string $p_str_SettingName Name of the Settings key to pre fill the text area. + * @return string + */ + protected function addTextArea($p_str_SettingName) { + // collect data for given settings field + $l_arr_Data = $this->LoadSetting($p_str_SettingName); + return sprintf('', + $l_arr_Data["name"], $l_arr_Data["id"], $l_arr_Data["value"]); + } + + /** + * Returns the html tag for an input [type = text] with color selection class. + * + * @author Stefan Herndler + * @since 1.5.6 + * @param string $p_str_SettingName Name of the Settings key to pre load the input field. + * @return string + */ + protected function addColorSelection($p_str_SettingName) { + // collect data for given settings field + $l_arr_Data = $this->LoadSetting($p_str_SettingName); + return sprintf('', + $l_arr_Data["name"], $l_arr_Data["id"], $l_arr_Data["value"]); + } + + /** + * Returns the html tag for an input [type = num]. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param string $p_str_SettingName Name of the Settings key to pre load the input field. + * @param int $p_in_Min Minimum value. + * @param int $p_int_Max Maximum value. + * @return string + */ + protected function addNumBox($p_str_SettingName, $p_in_Min, $p_int_Max) { + // collect data for given settings field + $l_arr_Data = $this->LoadSetting($p_str_SettingName); + return sprintf('', + $l_arr_Data["name"], $l_arr_Data["id"], $l_arr_Data["value"], $p_in_Min, $p_int_Max); + } + +} // end of class \ No newline at end of file diff --git a/trunk/class/dashboard/subpage-diagnostics.php b/trunk/class/dashboard/subpage-diagnostics.php new file mode 100644 index 0000000..5a1fd49 --- /dev/null +++ b/trunk/class/dashboard/subpage-diagnostics.php @@ -0,0 +1,140 @@ +addSection("diagnostics", __("Diagnostics", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), null, false) + ); + } + + /** + * Returns an array of all registered meta boxes for each section of the sub page. + * + * @author Stefan Herndler + * @since 1.5.0 + * @return array + */ + protected function getMetaBoxes() { + return array( + $this->addMetaBox("diagnostics", "diagnostics", __("Displays information about the web server, PHP and WordPress", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), "Diagnostics") + ); + } + + /** + * Displays a diagnostics about the web server, php and WordPress. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + public function Diagnostics() { + global $wp_version; + $l_str_PhpExtensions = ""; + // iterate through each PHP extension + foreach (get_loaded_extensions() as $l_int_Index => $l_str_Extension) { + if ($l_int_Index > 0) { + $l_str_PhpExtensions .= ' | '; + } + $l_str_PhpExtensions .= $l_str_Extension . ' ' . phpversion($l_str_Extension); + } + + /** @var WP_Theme $l_obj_CurrentTheme */ + $l_obj_CurrentTheme = wp_get_theme(); + + $l_str_WordPressPlugins = ""; + // iterate through each installed WordPress Plugin + foreach (get_plugins() as $l_arr_Plugin) { + $l_str_WordPressPlugins .= ''; + $l_str_WordPressPlugins .= '' . $l_arr_Plugin["Name"] . ''; + $l_str_WordPressPlugins .= '' . $l_arr_Plugin["Version"] . ' [' . $l_arr_Plugin["PluginURI"] . ']' . ''; + $l_str_WordPressPlugins .= ''; + } + // load template file + $l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_DASHBOARD, "diagnostics"); + // replace all placeholders + $l_obj_Template->replace( + array( + "label-server" => __("Server name", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "server" => $_SERVER["SERVER_NAME"], + + "label-php" => __("PHP version", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "php" => phpversion(), + + "label-user-agent" => __("User agent", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "user-agent" => $_SERVER["HTTP_USER_AGENT"], + + "label-max-execution-time" => __("Max execution time", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "max-execution-time" => ini_get('max_execution_time') . ' ' . __('seconds', MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + + "label-memory-limit" => __("Memory limit", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "memory-limit" => ini_get('memory_limit'), + + "label-php-extensions" => __("PHP extensions", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "php-extensions" => $l_str_PhpExtensions, + + "label-wordpress" => __("WordPress version", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "wordpress" => $wp_version, + + "label-theme" => __("Active Theme", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "theme" => $l_obj_CurrentTheme->get("Name") . " " . $l_obj_CurrentTheme->get("Version") . ", " . $l_obj_CurrentTheme->get("Author"). " [" . $l_obj_CurrentTheme->get("AuthorURI") . "]", + + "plugins" => $l_str_WordPressPlugins + ) + ); + // display template with replaced placeholders + echo $l_obj_Template->getContent(); + } +} \ No newline at end of file diff --git a/trunk/class/dashboard/subpage-main.php b/trunk/class/dashboard/subpage-main.php new file mode 100644 index 0000000..8904a33 --- /dev/null +++ b/trunk/class/dashboard/subpage-main.php @@ -0,0 +1,545 @@ +addSection("settings", __("Settings", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), 0, true); + $l_arr_Tabs[] = $this->addSection("customize", __("Customize", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), 1, true); + if (MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_EXPERT_MODE))) { + $l_arr_Tabs[] = $this->addSection("expert", __("Expert mode", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), 2, true); + } + $l_arr_Tabs[] = $this->addSection("how-to", __("How to", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), null, false); + return $l_arr_Tabs; + } + + /** + * Returns an array of all registered meta boxes for each section of the sub page. + * + * @author Stefan Herndler + * @since 1.5.0 + * @return array + * + * Edited for v2.0.4 to reflect changes in display since WPv5.5 + * Details in class/config.php + */ + protected function getMetaBoxes() { + return array( + // Change string "%s styling" to "Footnotes styling": + $this->addMetaBox("settings", "styling", __("Footnotes styling", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), "Styling"), + $this->addMetaBox("settings", "reference-container", __("References Container", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), "ReferenceContainer"), + // Leave intact since this is not localized: + $this->addMetaBox("settings", "love", MCI_Footnotes_Config::C_STR_PLUGIN_HEADING_NAME . ' ' . MCI_Footnotes_Config::C_STR_LOVE_SYMBOL_HEADING, "Love"), + $this->addMetaBox("settings", "other", __("Other", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), "Other"), + + // This is restored to meet user demand for arrow symbol semantics: + $this->addMetaBox("customize", "hyperlink-arrow", __("Hyperlink symbol in the Reference container", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), "HyperlinkArrow"), + $this->addMetaBox("customize", "superscript", __("Superscript layout", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), "Superscript"), + $this->addMetaBox("customize", "mouse-over-box", __("Mouse-over box", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), "MouseOverBox"), + $this->addMetaBox("customize", "custom-css", __("Add custom CSS to the public page", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), "CustomCSS"), + + $this->addMetaBox("expert", "lookup", __("WordPress hooks to look for Footnote short codes", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), "lookupHooks"), + + $this->addMetaBox("how-to", "help", __("Brief introduction in how to use the plugin", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), "Help"), + $this->addMetaBox("how-to", "donate", __("Help us to improve our Plugin", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), "Donate") + ); + } + + /** + * Displays all settings for the reference container. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + public function ReferenceContainer() { + // options for the positioning of the reference container + $l_arr_Positions = array( + "footer" => __("in the footer", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "post_end" => __("at the end of the post", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "widget" => __("in the widget area", MCI_Footnotes_Config::C_STR_PLUGIN_NAME) + ); + + // load template file + $l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_DASHBOARD, "settings-reference-container"); + // replace all placeholders + $l_obj_Template->replace( + array( + "label-name" => $this->addLabel(MCI_Footnotes_Settings::C_STR_REFERENCE_CONTAINER_NAME, __("References label", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "name" => $this->addTextBox(MCI_Footnotes_Settings::C_STR_REFERENCE_CONTAINER_NAME), + + "label-collapse" => $this->addLabel(MCI_Footnotes_Settings::C_BOOL_REFERENCE_CONTAINER_COLLAPSE, __("Collapse references by default", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "collapse" => $this->addCheckbox(MCI_Footnotes_Settings::C_BOOL_REFERENCE_CONTAINER_COLLAPSE), + + "label-position" => $this->addLabel(MCI_Footnotes_Settings::C_STR_REFERENCE_CONTAINER_POSITION, __("Where shall the reference container appear", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "position" => $this->addSelectBox(MCI_Footnotes_Settings::C_STR_REFERENCE_CONTAINER_POSITION, $l_arr_Positions) + ) + ); + // display template with replaced placeholders + echo $l_obj_Template->getContent(); + } + + /** + * Displays all settings for the footnotes styling. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + public function Styling() { + // define some space for the output + $l_str_Space = "     "; + // options for the combination of identical footnotes + $l_arr_CombineIdentical = array( + "yes" => __("Yes", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "no" => __("No", MCI_Footnotes_Config::C_STR_PLUGIN_NAME) + ); + // options for the start of the footnotes short code + $l_arr_ShortCodeStart = array( + "((" => "((", + htmlspecialchars("") => htmlspecialchars(""), + "[ref]" => "[ref]", + "userdefined" => __('user defined', MCI_Footnotes_Config::C_STR_PLUGIN_NAME) + ); + // options for the end of the footnotes short code + $l_arr_ShortCodeEnd = array( + "))" => "))", + htmlspecialchars("") => htmlspecialchars(""), + "[/ref]" => "[/ref]", + "userdefined" => __('user defined', MCI_Footnotes_Config::C_STR_PLUGIN_NAME) + ); + // options for the counter style of the footnotes + $l_arr_CounterStyle = array( + "arabic_plain" => __("Arabic Numbers - Plain", MCI_Footnotes_Config::C_STR_PLUGIN_NAME) . $l_str_Space . "1, 2, 3, 4, 5, ...", + "arabic_leading" => __("Arabic Numbers - Leading 0", MCI_Footnotes_Config::C_STR_PLUGIN_NAME) . $l_str_Space . "01, 02, 03, 04, 05, ...", + "latin_low" => __("Latin Character - lower case", MCI_Footnotes_Config::C_STR_PLUGIN_NAME) . $l_str_Space . "a, b, c, d, e, ...", + "latin_high" => __("Latin Character - upper case", MCI_Footnotes_Config::C_STR_PLUGIN_NAME) . $l_str_Space . "A, B, C, D, E, ...", + "romanic" => __("Roman Numerals", MCI_Footnotes_Config::C_STR_PLUGIN_NAME) . $l_str_Space . "I, II, III, IV, V, ..." + ); + + // load template file + $l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_DASHBOARD, "settings-styling"); + // replace all placeholders + $l_obj_Template->replace( + array( + "label-identical" => $this->addLabel(MCI_Footnotes_Settings::C_BOOL_COMBINE_IDENTICAL_FOOTNOTES, __("Combine identical footnotes", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "identical" => $this->addSelectBox(MCI_Footnotes_Settings::C_BOOL_COMBINE_IDENTICAL_FOOTNOTES, $l_arr_CombineIdentical), + + "label-short-code-start" => $this->addLabel(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_START, __("Footnote tag starts with", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "short-code-start" => $this->addSelectBox(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_START, $l_arr_ShortCodeStart), + + "label-short-code-end" => $this->addLabel(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_END, __("and ends with", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "short-code-end" => $this->addSelectBox(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_END, $l_arr_ShortCodeEnd), + + "label-short-code-start-user" => $this->addLabel(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_START_USER_DEFINED, ""), + "short-code-start-user" => $this->addTextBox(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_START_USER_DEFINED), + + "label-short-code-end-user" => $this->addLabel(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_END_USER_DEFINED, ""), + "short-code-end-user" => $this->addTextBox(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_END_USER_DEFINED), + + "label-counter-style" => $this->addLabel(MCI_Footnotes_Settings::C_STR_FOOTNOTES_COUNTER_STYLE, __("Counter style", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "counter-style" => $this->addSelectBox(MCI_Footnotes_Settings::C_STR_FOOTNOTES_COUNTER_STYLE, $l_arr_CounterStyle), + + "short-code-start-id" => MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_START, + "short-code-end-id" => MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_END, + "short-code-start-user-id" => MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_START_USER_DEFINED, + "short-code-end-user-id" => MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_END_USER_DEFINED, + ) + ); + // display template with replaced placeholders + echo $l_obj_Template->getContent(); + } + + /** + * Displays all settings for 'I love Footnotes'. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + public function Love() { + // options for the positioning of the reference container + $l_arr_Love = array( + "text-1" => sprintf(__('I %s %s', MCI_Footnotes_Config::C_STR_PLUGIN_NAME), MCI_Footnotes_Config::C_STR_LOVE_SYMBOL, MCI_Footnotes_Config::C_STR_PLUGIN_PUBLIC_NAME), + "text-2" => sprintf(__('this site uses the awesome %s Plugin', MCI_Footnotes_Config::C_STR_PLUGIN_NAME), MCI_Footnotes_Config::C_STR_PLUGIN_PUBLIC_NAME), + "text-3" => sprintf(__('extra smooth %s', MCI_Footnotes_Config::C_STR_PLUGIN_NAME), MCI_Footnotes_Config::C_STR_PLUGIN_PUBLIC_NAME), + "random" => __('random text', MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "no" => sprintf(__("Don't display a %s %s text in my footer.", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), MCI_Footnotes_Config::C_STR_PLUGIN_PUBLIC_NAME, MCI_Footnotes_Config::C_STR_LOVE_SYMBOL) + ); + + // load template file + $l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_DASHBOARD, "settings-love"); + // replace all placeholders + $l_obj_Template->replace( + array( + "label-love" => $this->addLabel(MCI_Footnotes_Settings::C_STR_FOOTNOTES_LOVE, sprintf(__("Tell the world you're using %s", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), MCI_Footnotes_Config::C_STR_PLUGIN_PUBLIC_NAME)), + "love" => $this->addSelectBox(MCI_Footnotes_Settings::C_STR_FOOTNOTES_LOVE, $l_arr_Love), + + "label-no-love" => $this->addText(sprintf(__("Don't tell the world you're using %s on specific pages by adding the following short code:", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), MCI_Footnotes_Config::C_STR_PLUGIN_PUBLIC_NAME)), + "no-love" => $this->addText(MCI_Footnotes_Config::C_STR_NO_LOVE_SLUG) + ) + ); + // display template with replaced placeholders + echo $l_obj_Template->getContent(); + } + + /** + * Displays all settings that are not grouped in special meta boxes. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + public function Other() { + // options for the Footnotes to be replaced in excerpt + $l_arr_Enabled = array( + "yes" => __("Yes", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "no" => __("No", MCI_Footnotes_Config::C_STR_PLUGIN_NAME) + ); + + // load template file + $l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_DASHBOARD, "settings-other"); + // replace all placeholders + $l_obj_Template->replace( + array( + "label-excerpt" => $this->addLabel(MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_IN_EXCERPT, __("Allow footnotes on Summarized Posts", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "excerpt" => $this->addSelectBox(MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_IN_EXCERPT, $l_arr_Enabled), + "label-expert-mode" => $this->addLabel(MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_EXPERT_MODE, __("Enable the Expert mode", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "expert-mode" => $this->addSelectBox(MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_EXPERT_MODE, $l_arr_Enabled) + ) + ); + // display template with replaced placeholders + echo $l_obj_Template->getContent(); + } + + /** + * Displays all settings for the footnotes Superscript. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + public function Superscript() { + // load template file + $l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_DASHBOARD, "customize-superscript"); + // replace all placeholders + $l_obj_Template->replace( + array( + "label-before" => $this->addLabel(MCI_Footnotes_Settings::C_STR_FOOTNOTES_STYLING_BEFORE, __("Before Footnotes index", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "before" => $this->addTextBox(MCI_Footnotes_Settings::C_STR_FOOTNOTES_STYLING_BEFORE), + + "label-after" => $this->addLabel(MCI_Footnotes_Settings::C_STR_FOOTNOTES_STYLING_AFTER, __("After Footnotes index", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "after" => $this->addTextBox(MCI_Footnotes_Settings::C_STR_FOOTNOTES_STYLING_AFTER) + ) + ); + // display template with replaced placeholders + echo $l_obj_Template->getContent(); + } + + /** + * Displays all settings for the footnotes mouse-over box. + * + * @author Stefan Herndler + * @since 1.5.2 + */ + public function MouseOverBox() { + // options for the Footnotes to be replaced in excerpt + $l_arr_Enabled = array( + "yes" => __("Yes", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "no" => __("No", MCI_Footnotes_Config::C_STR_PLUGIN_NAME) + ); + // options for the Mouse-over box position + $l_arr_Position = array( + "top left" => __("top left", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "top center" => __("top center", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "top right" => __("top right", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "center right" => __("center right", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "bottom right" => __("bottom right", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "bottom center" => __("bottom center", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "bottom left" => __("bottom left", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "center left" => __("center left", MCI_Footnotes_Config::C_STR_PLUGIN_NAME) + ); + // load template file + $l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_DASHBOARD, "customize-mouse-over-box"); + // replace all placeholders + $l_obj_Template->replace( + array( + "label-enable" => $this->addLabel(MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_ENABLED, __("Enable the mouse-over box", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "enable" => $this->addSelectBox(MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_ENABLED, $l_arr_Enabled), + + "label-activate-excerpt" => $this->addLabel(MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_EXCERPT_ENABLED, __("Display only an excerpt", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "activate-excerpt" => $this->addSelectBox(MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_EXCERPT_ENABLED, $l_arr_Enabled), + + "label-excerpt-length" => $this->addLabel(MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_EXCERPT_LENGTH, __("Maximum characters for the excerpt", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "excerpt-length" => $this->addTextBox(MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_EXCERPT_LENGTH), + + "label-position" => $this->addLabel(MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_POSITION, __("Position", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "position" => $this->addSelectBox(MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_POSITION, $l_arr_Position), + + "label-offset-x" => $this->addLabel(MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_OFFSET_X, __("Offset X (px)", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "offset-x" => $this->addNumBox(MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_OFFSET_X, -50, 50), + "notice-offset-x" => __("Offset (X axis) in px (may be negative)", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + + "label-offset-y" => $this->addLabel(MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_OFFSET_Y, __("Offset Y (px)", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "offset-y" => $this->addNumBox(MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_OFFSET_Y, -50, 50), + "notice-offset-y" => __("Offset (Y axis) in px (may be negative)", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + + "label-color" => $this->addLabel(MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_COLOR, __("Color", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "color" => $this->addColorSelection(MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_COLOR), + "notice-color" => __("Empty color will use the default color defined by your current theme.", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + + "label-background" => $this->addLabel(MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_BACKGROUND, __("Background color", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "background" => $this->addColorSelection(MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_BACKGROUND), + "notice-background" => __("Empty color will use the default background-color defined by your current theme.", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + + "label-border-width" => $this->addLabel(MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_BORDER_WIDTH, __("Border width (px)", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "border-width" => $this->addNumBox(MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_BORDER_WIDTH, 0, 4), + "notice-border-width" => __("Set the width to 0px to hide the border.", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + + "label-border-color" => $this->addLabel(MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_BORDER_COLOR, __("Border color", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "border-color" => $this->addColorSelection(MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_BORDER_COLOR), + "notice-border-color" => __("Empty color will use the default border-color defined by your current theme.", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + + "label-border-radius" => $this->addLabel(MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_BORDER_RADIUS, __("Border radius (px)", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "border-radius" => $this->addNumBox(MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_BORDER_RADIUS, 0, 20), + "notice-border-radius" => __("Set the radius to 0px to avoid a radius.", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + + "label-max-width" => $this->addLabel(MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_MAX_WIDTH, __("Max. width (px)", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "max-width" => $this->addNumBox(MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_MAX_WIDTH, 0, 1280), + "notice-max-width" => __("Set the max-width to 0px to disable this setting.", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + + "label-box-shadow-color" => $this->addLabel(MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_SHADOW_COLOR, __("Box shadow color", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "box-shadow-color" => $this->addColorSelection(MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_SHADOW_COLOR), + "notice-box-shadow-color" => __("Empty color will use the default box shadow defined by your current theme.", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + + ) + ); + // display template with replaced placeholders + echo $l_obj_Template->getContent(); + } + + /** + * Displays all settings for the prepended symbol + * + * @author Stefan Herndler + * @since 1.5.0 + * + * Edited heading for v2.0.4 + * The former 'hyperlink arrow' became 'prepended arrow' in v2.0.3 after + * a user complaint about missing backlinking semantics of the footnote number. + */ + public function HyperlinkArrow() { + // load template file + $l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_DASHBOARD, "customize-hyperlink-arrow"); + // replace all placeholders + $l_obj_Template->replace( + array( + "label-symbol" => $this->addLabel(MCI_Footnotes_Settings::C_STR_HYPERLINK_ARROW, __("Hyperlink symbol", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "symbol" => $this->addSelectBox(MCI_Footnotes_Settings::C_STR_HYPERLINK_ARROW, MCI_Footnotes_Convert::getArrow()), + + "label-user-defined" => $this->addLabel(MCI_Footnotes_Settings::C_STR_HYPERLINK_ARROW_USER_DEFINED, __("or enter a user defined symbol", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "user-defined" => $this->addTextBox(MCI_Footnotes_Settings::C_STR_HYPERLINK_ARROW_USER_DEFINED), + "comment" => __("if set it overrides the hyperlink symbol above", MCI_Footnotes_Config::C_STR_PLUGIN_NAME) + ) + ); + // display template with replaced placeholders + echo $l_obj_Template->getContent(); + } + + /** + * Displays the custom css box. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + public function CustomCSS() { + // load template file + $l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_DASHBOARD, "customize-css"); + // replace all placeholders + $l_obj_Template->replace( + array( + "label-css" => $this->addLabel(MCI_Footnotes_Settings::C_STR_CUSTOM_CSS, __("Add custom CSS", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "css" => $this->addTextArea(MCI_Footnotes_Settings::C_STR_CUSTOM_CSS), + + "headline" => $this->addText(__("Available CSS classes to customize the footnotes and the reference container", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + + "label-class-1" => ".footnote_plugin_tooltip_text", + "class-1" => $this->addText(__("superscript, Footnotes index", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + + "label-class-2" => ".footnote_tooltip", + "class-2" => $this->addText(__("mouse-over box, tooltip for each superscript", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + + "label-class-3" => ".footnote_plugin_index", + "class-3" => $this->addText(__("1st column of the Reference Container, Footnotes index", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + + "label-class-4" => ".footnote_plugin_text", + "class-4" => $this->addText(__("2nd column of the Reference Container, Footnote text", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)) + ) + ); + // display template with replaced placeholders + echo $l_obj_Template->getContent(); + } + + /** + * Displays available Hooks to look for Footnote short codes. + * + * @author Stefan Herndler + * @since 1.5.5 + */ + public function lookupHooks() { + // load template file + $l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_DASHBOARD, "expert-lookup"); + // replace all placeholders + $l_obj_Template->replace( + array( + "head-hook" => __("WordPress hook function name", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "head-checkbox" => __("Activate", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "head-url" => __("WordPress documentation", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + + "label-the-title" => $this->addLabel(MCI_Footnotes_Settings::C_BOOL_EXPERT_LOOKUP_THE_TITLE, "the_title"), + "the-title" => $this->addCheckbox(MCI_Footnotes_Settings::C_BOOL_EXPERT_LOOKUP_THE_TITLE), + "url-the-title" => "http://codex.wordpress.org/Plugin_API/Filter_Reference/the_title", + + "label-the-content" => $this->addLabel(MCI_Footnotes_Settings::C_BOOL_EXPERT_LOOKUP_THE_CONTENT, "the_content"), + "the-content" => $this->addCheckbox(MCI_Footnotes_Settings::C_BOOL_EXPERT_LOOKUP_THE_CONTENT), + "url-the-content" => "http://codex.wordpress.org/Plugin_API/Filter_Reference/the_content", + + "label-the-excerpt" => $this->addLabel(MCI_Footnotes_Settings::C_BOOL_EXPERT_LOOKUP_THE_EXCERPT, "the_excerpt"), + "the-excerpt" => $this->addCheckbox(MCI_Footnotes_Settings::C_BOOL_EXPERT_LOOKUP_THE_EXCERPT), + "url-the-excerpt" => "http://codex.wordpress.org/Function_Reference/the_excerpt", + + "label-widget-title" => $this->addLabel(MCI_Footnotes_Settings::C_BOOL_EXPERT_LOOKUP_WIDGET_TITLE, "widget_title"), + "widget-title" => $this->addCheckbox(MCI_Footnotes_Settings::C_BOOL_EXPERT_LOOKUP_WIDGET_TITLE), + "url-widget-title" => "http://codex.wordpress.org/Plugin_API/Filter_Reference/widget_title", + + "label-widget-text" => $this->addLabel(MCI_Footnotes_Settings::C_BOOL_EXPERT_LOOKUP_WIDGET_TEXT, "widget_text"), + "widget-text" => $this->addCheckbox(MCI_Footnotes_Settings::C_BOOL_EXPERT_LOOKUP_WIDGET_TEXT), + "url-widget-text" => "http://codex.wordpress.org/Plugin_API/Filter_Reference/widget_text", + + "label-post-object" => $this->addLabel(MCI_Footnotes_Settings::C_BOOL_EXPERT_LOOKUP_THE_POST, "the_post"), + "post-object" => $this->addCheckbox(MCI_Footnotes_Settings::C_BOOL_EXPERT_LOOKUP_THE_POST), + "url-post-object" => "http://codex.wordpress.org/Plugin_API/Filter_Reference/the_post" + ) + ); + // display template with replaced placeholders + echo $l_obj_Template->getContent(); + } + + /** + * Displays a short introduction of the Plugin. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + public function Help() { + global $g_obj_MCI_Footnotes; + // load footnotes starting and end tag + $l_arr_Footnote_StartingTag = $this->LoadSetting(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_START); + $l_arr_Footnote_EndingTag = $this->LoadSetting(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_END); + + if ($l_arr_Footnote_StartingTag["value"] == "userdefined" || $l_arr_Footnote_EndingTag["value"] == "userdefined") { + // load user defined starting and end tag + $l_arr_Footnote_StartingTag = $this->LoadSetting(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_START_USER_DEFINED); + $l_arr_Footnote_EndingTag = $this->LoadSetting(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_END_USER_DEFINED); + } + $l_str_Example = "Hello" . $l_arr_Footnote_StartingTag["value"] . + "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,". + " sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.". + " Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet,". + " consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.". + " At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet." + . $l_arr_Footnote_EndingTag["value"] . " World!"; + + // load template file + $l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_DASHBOARD, "how-to-help"); + // replace all placeholders + $l_obj_Template->replace( + array( + "label-start" => __("Start your footnote with the following short code:", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "start" => $l_arr_Footnote_StartingTag["value"], + + "label-end" => __("...and end your footnote with this short code:", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "end" => $l_arr_Footnote_EndingTag["value"], + + "example-code" => $l_str_Example, + "example-string" => "
" . __("will be displayed as:", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "example" => $g_obj_MCI_Footnotes->a_obj_Task->exec($l_str_Example, true), + + "information" => sprintf(__("For further information please check out our %ssupport forum%s on WordPress.org.", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), '', '') + ) + ); + // call wp_head function to get the Styling of the mouse-over box + $g_obj_MCI_Footnotes->a_obj_Task->wp_head(); + // display template with replaced placeholders + echo $l_obj_Template->getContent(); + } + + /** + * Displays all Donate button to support the developers. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + public function Donate() { + // load template file + $l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_DASHBOARD, "how-to-donate"); + // replace all placeholders + $l_obj_Template->replace( + array( + "caption" => __('Donate now',MCI_Footnotes_Config::C_STR_PLUGIN_NAME) + ) + ); + // display template with replaced placeholders + echo $l_obj_Template->getContent(); + } +} diff --git a/trunk/class/hooks.php b/trunk/class/hooks.php new file mode 100644 index 0000000..08aa338 --- /dev/null +++ b/trunk/class/hooks.php @@ -0,0 +1,88 @@ +ClearAll(); + } + + /** + * Add Links to the Plugin in the "installed Plugins" page. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param array $p_arr_Links Current Links. + * @param string $p_str_PluginFileName Plugins init file name. + * @return array + */ + public static function PluginLinks($p_arr_Links, $p_str_PluginFileName) { + // append link to the WordPress Plugin page + $p_arr_Links[] = sprintf('%s', __('Support', MCI_Footnotes_Config::C_STR_PLUGIN_NAME)); + // append link to the Settings page + $p_arr_Links[] = sprintf('%s', admin_url('admin.php?page=mfmmf-footnotes'), __('Settings', MCI_Footnotes_Config::C_STR_PLUGIN_NAME)); + // append link to the PlayPal Donate function + $p_arr_Links[] = sprintf('%s', __('Donate', MCI_Footnotes_Config::C_STR_PLUGIN_NAME)); + // return new links + return $p_arr_Links; + } +} \ No newline at end of file diff --git a/trunk/class/init.php b/trunk/class/init.php new file mode 100644 index 0000000..d0fdcf1 --- /dev/null +++ b/trunk/class/init.php @@ -0,0 +1,131 @@ +initializeDashboard(); + // initialize the Plugin Task + $this->initializeTask(); + + // Register all Public Stylesheets and Scripts + add_action('init', array($this, 'registerPublic')); + // Enqueue all Public Stylesheets and Scripts + add_action('wp_enqueue_scripts', array($this, 'registerPublic')); + // Register all Widgets of the Plugin. + add_action('widgets_init', array($this, 'initializeWidgets')); + } + + /** + * Initializes all Widgets of the Plugin. + * + * @author Stefan Herndler + * @since 1.5.0 + * + * Edited for 1.6.5: replaced deprecated function create_function() + * + * Contributed by Felipe Lavín Z. Thankfully acknowledged. + * + * Deprecated in PHP 7.2 + * See + * See also: + */ + public function initializeWidgets() { + register_widget("MCI_Footnotes_Widget_ReferenceContainer"); + } + + /** + * Initializes the Dashboard of the Plugin and loads them. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + private function initializeDashboard() { + new MCI_Footnotes_Layout_Init(); + } + + /** + * Initializes the Plugin Task and registers the Task hooks. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + private function initializeTask() { + $this->a_obj_Task = new MCI_Footnotes_Task(); + $this->a_obj_Task->registerHooks(); + } + + /** + * Registers and enqueues scripts and stylesheets to the public pages. + * + * @author Stefan Herndler + * @since 1.5.0 + * + * Updated for v2.0.4 by adding jQueryUI from WordPress following @check2020de: + * + * See + * + * jQueryUI re-enables the tooltip infobox disabled when WPv5.5 was released. + */ + public function registerPublic() { + + // add the jQuery plugin (already registered by WordPress) + wp_enqueue_script( 'jquery' ); + // Add jQueryUI: 'no need to enqueue -core, because dependencies are set' + wp_enqueue_script( 'jquery-ui-widget' ); + wp_enqueue_script( 'jquery-ui-mouse' ); + wp_enqueue_script( 'jquery-ui-accordion' ); + wp_enqueue_script( 'jquery-ui-autocomplete' ); + wp_enqueue_script( 'jquery-ui-slider' ); + + // Add jQuery tools: + wp_enqueue_script('mci-footnotes-js-jquery-tools', plugins_url('../js/jquery.tools.min.js', __FILE__)); + + // IMPORTANT: up-to-date plugin version number for cache busting. + wp_enqueue_style('mci-footnotes-css-public', plugins_url('../css/public.css', __FILE__), '', '2.0.6'); + } +} diff --git a/trunk/class/language.php b/trunk/class/language.php new file mode 100644 index 0000000..9ec44b5 --- /dev/null +++ b/trunk/class/language.php @@ -0,0 +1,58 @@ + + // + // "Fatal error: Uncaught ArgumentCountError: Too few arguments […]" + // 2020-10-26T1609+0100 + return; + } + // fallback to english + self::load("en_GB"); + } + + /** + * Loads a specific text domain. + * + * @author Stefan Herndler + * @since 1.5.1 + * @param string $p_str_LanguageCode Language Code to load a specific text domain. + * @return bool + */ + private static function load($p_str_LanguageCode) { + return load_textdomain(MCI_Footnotes_Config::C_STR_PLUGIN_NAME, + dirname(__FILE__) . "/../languages/" . $p_str_LanguageCode . '.mo'); + } +} diff --git a/trunk/class/settings.php b/trunk/class/settings.php new file mode 100644 index 0000000..ec2e764 --- /dev/null +++ b/trunk/class/settings.php @@ -0,0 +1,591 @@ + array( + self::C_STR_REFERENCE_CONTAINER_NAME => 'References', + self::C_BOOL_REFERENCE_CONTAINER_COLLAPSE => '', + self::C_STR_REFERENCE_CONTAINER_POSITION => 'post_end', + // Identical footnotes should not be combined by default + // as long as the feature raises criticism for malfunctioning: + // + self::C_BOOL_COMBINE_IDENTICAL_FOOTNOTES => '', + self::C_STR_FOOTNOTES_SHORT_CODE_START => '((', + self::C_STR_FOOTNOTES_SHORT_CODE_END => '))', + self::C_STR_FOOTNOTES_SHORT_CODE_START_USER_DEFINED => '', + self::C_STR_FOOTNOTES_SHORT_CODE_END_USER_DEFINED => '', + self::C_STR_FOOTNOTES_COUNTER_STYLE => 'arabic_plain', + self::C_STR_FOOTNOTES_LOVE => 'no', + self::C_BOOL_FOOTNOTES_IN_EXCERPT => 'yes', + self::C_BOOL_FOOTNOTES_EXPERT_MODE => 'no' + ), + "footnotes_storage_custom" => array( + self::C_STR_FOOTNOTES_STYLING_BEFORE => '', + self::C_STR_FOOTNOTES_STYLING_AFTER => ')', + self::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_ENABLED => 'yes', + self::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_EXCERPT_ENABLED => 'no', + self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_EXCERPT_LENGTH => 150, + self::C_STR_FOOTNOTES_MOUSE_OVER_BOX_POSITION => 'top right', + self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_OFFSET_X => 10, + self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_OFFSET_Y => 10, + self::C_STR_FOOTNOTES_MOUSE_OVER_BOX_COLOR => '', + self::C_STR_FOOTNOTES_MOUSE_OVER_BOX_BACKGROUND => '#fff7a7', + self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_BORDER_WIDTH => 1, + self::C_STR_FOOTNOTES_MOUSE_OVER_BOX_BORDER_COLOR => '#cccc99', + self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_BORDER_RADIUS => 3, + self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_MAX_WIDTH => 0, + self::C_STR_FOOTNOTES_MOUSE_OVER_BOX_SHADOW_COLOR => '#666666', + self::C_STR_HYPERLINK_ARROW => '↑', + self::C_STR_HYPERLINK_ARROW_USER_DEFINED => '', + self::C_STR_CUSTOM_CSS => '' + ), + // These should all be enabled by default. + // See + "footnotes_storage_expert" => array( + self::C_BOOL_EXPERT_LOOKUP_THE_TITLE => 'yes', + self::C_BOOL_EXPERT_LOOKUP_THE_CONTENT => 'yes', + self::C_BOOL_EXPERT_LOOKUP_THE_EXCERPT => 'yes', + self::C_BOOL_EXPERT_LOOKUP_WIDGET_TITLE => 'yes', + self::C_BOOL_EXPERT_LOOKUP_WIDGET_TEXT => 'yes', + self::C_BOOL_EXPERT_LOOKUP_THE_POST => 'yes' + ) + ); + + /** + * Contains all Settings from each Settings container as soon as this class is initialized. + * + * @author Stefan Herndler + * @since 1.5.0 + * @var array + */ + private $a_arr_Settings = array(); + + /** + * Class Constructor. Loads all Settings from each WordPress Settings container. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + private function __construct() { + $this->loadAll(); + } + + /** + * Returns a singleton of this class. + * + * @author Stefan Herndler + * @since 1.5.0 + * @return MCI_Footnotes_Settings + */ + public static function instance() { + // no instance defined yet, load it + if (self::$a_obj_Instance === null) { + self::$a_obj_Instance = new self(); + } + // return a singleton of this class + return self::$a_obj_Instance; + } + + /** + * Returns the name of a specified Settings Container. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param int $p_int_Index Settings Container Array Key Index. + * @return string Settings Container name. + */ + public function getContainer($p_int_Index) { + return $this->a_arr_Container[$p_int_Index]; + } + + /** + * Returns the default values of a specific Settings Container. + * + * @author Stefan Herndler + * @since 1.5.6 + * @param int $p_int_Index Settings Container Aray Key Index. + * @return array + */ + public function getDefaults($p_int_Index) { + return $this->a_arr_Default[$this->a_arr_Container[$p_int_Index]]; + } + + /** + * Loads all Settings from each Settings container. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + private function loadAll() { + // clear current settings + $this->a_arr_Settings = array(); + for ($i = 0; $i < count($this->a_arr_Container); $i++) { + // load settings + $this->a_arr_Settings = array_merge($this->a_arr_Settings, $this->Load($i)); + } + } + + /** + * Loads all Settings from specified Settings Container. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param int $p_int_Index Settings Container Array Key Index. + * @return array Settings loaded from Container of Default Settings if Settings Container is empty (first usage). + */ + private function Load($p_int_Index) { + // load all settings from container + $l_arr_Options = get_option($this->getContainer($p_int_Index)); + // load all default settings + $l_arr_Default = $this->a_arr_Default[$this->getContainer($p_int_Index)]; + + // no settings found, set them to their default value + if (empty($l_arr_Options)) { + return $l_arr_Default; + } + // iterate through all available settings ( = default values) + foreach($l_arr_Default as $l_str_Key => $l_str_Value) { + // available setting not found in the container + if (!array_key_exists($l_str_Key, $l_arr_Options)) { + // define the setting with its default value + $l_arr_Options[$l_str_Key] = $l_str_Value; + } + } + // iterate through each setting in the container + foreach($l_arr_Options as $l_str_Key => $l_str_Value) { + // remove all whitespace at the beginning and end of a setting + //$l_str_Value = trim($l_str_Value); + // write the sanitized value back to the setting container + $l_arr_Options[$l_str_Key] = $l_str_Value; + } + // return settings loaded from Container + return $l_arr_Options; + } + + /** + * Updates a whole Settings container. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param int $p_int_Index Index of the Settings container. + * @param array $p_arr_newValues new Settings. + * @return bool + */ + public function saveOptions($p_int_Index, $p_arr_newValues) { + if (update_option($this->getContainer($p_int_Index), $p_arr_newValues)) { + $this->loadAll(); + return true; + } + return false; + } + + /** + * Returns the value of specified Settings name. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param string $p_str_Key Settings Array Key name. + * @return mixed Value of the Setting on Success or Null in Settings name is invalid. + */ + public function get($p_str_Key) { + return array_key_exists($p_str_Key, $this->a_arr_Settings) ? $this->a_arr_Settings[$p_str_Key] : null; + } + + /** + * Deletes each Settings Container and loads the default values for each Settings Container. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + public function ClearAll() { + // iterate through each Settings Container + for ($i = 0; $i < count($this->a_arr_Container); $i++) { + // delete the settings container + delete_option($this->getContainer($i)); + } + // set settings back to the default values + $this->a_arr_Settings = $this->a_arr_Default; + } + + /** + * Register all Settings Container for the Plugin Settings Page in the Dashboard. + * Settings Container Label will be the same as the Settings Container Name. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + public function RegisterSettings() { + // register all settings + for ($i = 0; $i < count($this->a_arr_Container); $i++) { + register_setting($this->getContainer($i), $this->getContainer($i)); + } + } +} diff --git a/trunk/class/task.php b/trunk/class/task.php new file mode 100644 index 0000000..f6b3f87 --- /dev/null +++ b/trunk/class/task.php @@ -0,0 +1,537 @@ + + * Documentation: + * + * Still need to assess priority levels, see bug reported in: + * + * + * Rolled back in v2.0.6. + */ + public function registerHooks() { + // append custom css to the header + add_filter('wp_head', array($this, "wp_head"),PHP_INT_MAX); + + // append the love and share me slug to the footer + add_filter('wp_footer', array($this, "wp_footer"),PHP_INT_MAX); + + if (MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_EXPERT_LOOKUP_THE_TITLE))) { + add_filter('the_title', array($this, "the_title"),PHP_INT_MAX); + } + if (MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_EXPERT_LOOKUP_THE_CONTENT))) { + add_filter('the_content', array($this, "the_content"),PHP_INT_MAX); + } + if (MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_EXPERT_LOOKUP_THE_EXCERPT))) { + add_filter('the_excerpt', array($this, "the_excerpt"),PHP_INT_MAX); + } + if (MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_EXPERT_LOOKUP_WIDGET_TITLE))) { + add_filter('widget_title', array($this, "widget_title"),PHP_INT_MAX); + } + if (MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_EXPERT_LOOKUP_WIDGET_TEXT))) { + add_filter('widget_text', array($this, "widget_text"),PHP_INT_MAX); + } + if (MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_EXPERT_LOOKUP_THE_POST))) { + add_filter('the_post', array($this, "the_post"),PHP_INT_MAX); + } + // reset stored footnotes when displaying the header + self::$a_arr_Footnotes = array(); + self::$a_bool_AllowLoveMe = true; + } + + /** + * Outputs the custom css to the header of the public page. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + public function wp_head() { + $l_str_Color = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_COLOR); + $l_str_Background = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_BACKGROUND); + $l_int_BorderWidth = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_BORDER_WIDTH); + $l_str_BorderColor = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_BORDER_COLOR); + $l_int_BorderRadius = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_BORDER_RADIUS); + $l_int_MaxWidth = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_MAX_WIDTH); + $l_str_BoxShadowColor = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_SHADOW_COLOR); + ?> + + get(MCI_Footnotes_Settings::C_STR_REFERENCE_CONTAINER_POSITION) == "footer") { + echo $this->ReferenceContainer(); + } + // get setting for love and share this plugin + $l_str_LoveMeIndex = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_LOVE); + // check if the admin allows to add a link to the footer + if (empty($l_str_LoveMeIndex) || strtolower($l_str_LoveMeIndex) == "no" || !self::$a_bool_AllowLoveMe) { + return; + } + // set a hyperlink to the word "footnotes" in the Love slug + $l_str_LinkedName = sprintf('%s',MCI_Footnotes_Config::C_STR_PLUGIN_PUBLIC_NAME); + // get random love me text + if (strtolower($l_str_LoveMeIndex) == "random") { + $l_str_LoveMeIndex = "text-" . rand(1,3); + } + switch ($l_str_LoveMeIndex) { + case "text-1": + $l_str_LoveMeText = sprintf(__('I %s %s', MCI_Footnotes_Config::C_STR_PLUGIN_NAME), MCI_Footnotes_Config::C_STR_LOVE_SYMBOL, $l_str_LinkedName); + break; + case "text-2": + $l_str_LoveMeText = sprintf(__('this site uses the awesome %s Plugin', MCI_Footnotes_Config::C_STR_PLUGIN_NAME), $l_str_LinkedName); + break; + case "text-3": + default: + $l_str_LoveMeText = sprintf(__('extra smooth %s', MCI_Footnotes_Config::C_STR_PLUGIN_NAME), $l_str_LinkedName); + break; + } + echo sprintf('
%s
', $l_str_LoveMeText); + } + + /** + * Replaces footnotes in the post/page title. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param string $p_str_Content Widget content. + * @return string Content with replaced footnotes. + */ + public function the_title($p_str_Content) { + // appends the reference container if set to "post_end" + return $this->exec($p_str_Content, false); + } + + /** + * Replaces footnotes in the content of the current page/post. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param string $p_str_Content Page/Post content. + * @return string Content with replaced footnotes. + */ + public function the_content($p_str_Content) { + // appends the reference container if set to "post_end" + return $this->exec($p_str_Content, MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_REFERENCE_CONTAINER_POSITION) == "post_end" ? true : false); + } + + /** + * Replaces footnotes in the excerpt of the current page/post. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param string $p_str_Content Page/Post content. + * @return string Content with replaced footnotes. + */ + public function the_excerpt($p_str_Content) { + return $this->exec($p_str_Content, false, !MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_IN_EXCERPT))); + } + + /** + * Replaces footnotes in the widget title. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param string $p_str_Content Widget content. + * @return string Content with replaced footnotes. + */ + public function widget_title($p_str_Content) { + // appends the reference container if set to "post_end" + return $this->exec($p_str_Content, false); + } + + /** + * Replaces footnotes in the content of the current widget. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param string $p_str_Content Widget content. + * @return string Content with replaced footnotes. + */ + public function widget_text($p_str_Content) { + // appends the reference container if set to "post_end" + return $this->exec($p_str_Content, MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_REFERENCE_CONTAINER_POSITION) == "post_end" ? true : false); + } + + /** + * Replaces footnotes in each Content var of the current Post object. + * + * @author Stefan Herndler + * @since 1.5.4 + * @param array|WP_Post $p_mixed_Posts + */ + public function the_post(&$p_mixed_Posts) { + // single WP_Post object received + if (!is_array($p_mixed_Posts)) { + $p_mixed_Posts = $this->replacePostObject($p_mixed_Posts); + return; + } + // array of WP_Post objects received + for($l_int_Index = 0; $l_int_Index < count($p_mixed_Posts); $l_int_Index++) { + $p_mixed_Posts[$l_int_Index] = $this->replacePostObject($p_mixed_Posts[$l_int_Index]); + } + } + + /** + * Replace all Footnotes in a WP_Post object. + * + * @author Stefan Herndler + * @since 1.5.6 + * @param WP_Post $p_obj_Post + * @return WP_Post + */ + private function replacePostObject($p_obj_Post) { + //MCI_Footnotes_Convert::debug($p_obj_Post); + $p_obj_Post->post_content = $this->exec($p_obj_Post->post_content); + $p_obj_Post->post_content_filtered = $this->exec($p_obj_Post->post_content_filtered); + $p_obj_Post->post_excerpt = $this->exec($p_obj_Post->post_excerpt); + return $p_obj_Post; + } + + /** + * Replaces all footnotes that occur in the given content. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param string $p_str_Content Any string that may contain footnotes to be replaced. + * @param bool $p_bool_OutputReferences Appends the Reference Container to the output if set to true, default true. + * @param bool $p_bool_HideFootnotesText Hide footnotes found in the string. + * @return string + */ + public function exec($p_str_Content, $p_bool_OutputReferences = false, $p_bool_HideFootnotesText = false) { + // replace all footnotes in the content, settings are converted to html characters + $p_str_Content = $this->search($p_str_Content, true, $p_bool_HideFootnotesText); + // replace all footnotes in the content, settings are NOT converted to html characters + $p_str_Content = $this->search($p_str_Content, false, $p_bool_HideFootnotesText); + + // append the reference container + if ($p_bool_OutputReferences) { + $p_str_Content = $p_str_Content . $this->ReferenceContainer(); + } + + // take a look if the LOVE ME slug should NOT be displayed on this page/post, remove the short code if found + if (strpos($p_str_Content, MCI_Footnotes_Config::C_STR_NO_LOVE_SLUG) !== false) { + self::$a_bool_AllowLoveMe = false; + $p_str_Content = str_replace(MCI_Footnotes_Config::C_STR_NO_LOVE_SLUG, "", $p_str_Content); + } + // return the content with replaced footnotes and optional reference container append + return $p_str_Content; + } + + /** + * Replaces all footnotes in the given content and appends them to the static property. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param string $p_str_Content Content to be searched for footnotes. + * @param bool $p_bool_ConvertHtmlChars html encode settings, default true. + * @param bool $p_bool_HideFootnotesText Hide footnotes found in the string. + * @return string + */ + public function search($p_str_Content, $p_bool_ConvertHtmlChars, $p_bool_HideFootnotesText) { + // prepare prepending post ID to make footnote IDs unique wrt archive view: + self::$a_str_Prefix = get_the_id() . '_'; + // contains the index for the next footnote on this page + $l_int_FootnoteIndex = count(self::$a_arr_Footnotes) + 1; + // contains the starting position for the lookup of a footnote + $l_int_PosStart = 0; + // get start and end tag for the footnotes short code + $l_str_StartingTag = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_START); + $l_str_EndingTag = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_END); + if ($l_str_StartingTag == "userdefined" || $l_str_EndingTag == "userdefined") { + $l_str_StartingTag = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_START_USER_DEFINED); + $l_str_EndingTag = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_END_USER_DEFINED); + } + // decode html special chars + if ($p_bool_ConvertHtmlChars) { + $l_str_StartingTag = htmlspecialchars($l_str_StartingTag); + $l_str_EndingTag = htmlspecialchars($l_str_EndingTag); + } + // if footnotes short code is empty, return the content without changes + if (empty($l_str_StartingTag) || empty($l_str_EndingTag)) { + return $p_str_Content; + } + + if (!$p_bool_HideFootnotesText) { + // load template file + $l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_PUBLIC, "footnote"); + $l_obj_TemplateTooltip = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_PUBLIC, "tooltip"); + } else { + $l_obj_Template = null; + $l_obj_TemplateTooltip = null; + } + + // search footnotes short codes in the content + do { + // get first occurrence of the footnote short code [start] + $i_int_len_Content = strlen($p_str_Content); + if ($l_int_PosStart > $i_int_len_Content) $l_int_PosStart = $i_int_len_Content; + $l_int_PosStart = strpos($p_str_Content, $l_str_StartingTag, $l_int_PosStart); + // no short code found, stop here + if ($l_int_PosStart === false) { + break; + } + // get first occurrence of a footnote short code [end] + $l_int_PosEnd = strpos($p_str_Content, $l_str_EndingTag, $l_int_PosStart); + // no short code found, stop here + if ($l_int_PosEnd === false) { + break; + } + // calculate the length of the footnote + $l_int_Length = $l_int_PosEnd - $l_int_PosStart; + // get footnote text + $l_str_FootnoteText = substr($p_str_Content, $l_int_PosStart + strlen($l_str_StartingTag), $l_int_Length - strlen($l_str_StartingTag)); + // Text to be displayed instead of the footnote + $l_str_FootnoteReplaceText = ""; + // display the footnote as mouse-over box + if (!$p_bool_HideFootnotesText) { + $l_str_Index = MCI_Footnotes_Convert::Index($l_int_FootnoteIndex, MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_COUNTER_STYLE)); + + // display only an excerpt of the footnotes text if enabled + $l_str_ExcerptText = $l_str_FootnoteText; + $l_bool_EnableExcerpt = MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_EXCERPT_ENABLED)); + $l_int_MaxLength = intval(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_EXCERPT_LENGTH)); + if ($l_bool_EnableExcerpt) { + $l_str_DummyText = strip_tags($l_str_FootnoteText); + if (is_int($l_int_MaxLength) && strlen($l_str_DummyText) > $l_int_MaxLength) { + $l_str_ExcerptText = substr($l_str_DummyText, 0, $l_int_MaxLength); + $l_str_ExcerptText = substr($l_str_ExcerptText, 0, strrpos($l_str_ExcerptText, ' ')); + // Removed hyperlink navigation on user request, but left element for style. + $l_str_ExcerptText .= ' … ' . sprintf(__("%scontinue%s", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), '', ''); + } + } + + // fill the footnotes template + $l_obj_Template->replace( + array( + "id" => self::$a_str_Prefix . $l_str_Index, + "index" => $l_str_Index, + "text" => MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_ENABLED)) ? $l_str_ExcerptText : "", + "before" => MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_STYLING_BEFORE), + "after" => MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_STYLING_AFTER) + ) + ); + $l_str_FootnoteReplaceText = $l_obj_Template->getContent(); + // reset the template + $l_obj_Template->reload(); + if (MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_ENABLED))) { + $l_int_OffsetY = intval(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_OFFSET_Y)); + $l_int_OffsetX = intval(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_INT_FOOTNOTES_MOUSE_OVER_BOX_OFFSET_X)); + $l_obj_TemplateTooltip->replace( + array( + "id" => self::$a_str_Prefix . $l_str_Index, + "position" => MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_MOUSE_OVER_BOX_POSITION), + "offset-y" => !empty($l_int_OffsetY) ? $l_int_OffsetY : 0, + "offset-x" => !empty($l_int_OffsetX) ? $l_int_OffsetX : 0 + ) + ); + $l_str_FootnoteReplaceText .= $l_obj_TemplateTooltip->getContent(); + $l_obj_TemplateTooltip->reload(); + } + } + // replace the footnote with the template + $p_str_Content = substr_replace($p_str_Content, $l_str_FootnoteReplaceText, $l_int_PosStart, $l_int_Length + strlen($l_str_EndingTag)); + // add footnote only if not empty + if (!empty($l_str_FootnoteText)) { + // set footnote to the output box at the end + self::$a_arr_Footnotes[] = $l_str_FootnoteText; + // increase footnote index + $l_int_FootnoteIndex++; + } + // add offset to the new starting position + $l_int_PosStart += $l_int_Length + strlen($l_str_EndingTag); + $l_int_PosStart = $l_int_Length + strlen($l_str_FootnoteReplaceText); + } while (true); + + // return content + return $p_str_Content; + } + + /** + * Generates the reference container. + * + * @author Stefan Herndler + * @since 1.5.0 + * @return string + * + * Edited for v2.0.6: appended post ID to support autoload / infinite scroll. + * Requested by @docteurfitness: + * Related request: + * 2020-11-04T0358+0100 + */ + public function ReferenceContainer() { + // no footnotes has been replaced on this page + if (empty(self::$a_arr_Footnotes)) { + return ""; + } + // get html arrow + $l_str_Arrow = MCI_Footnotes_Convert::getArrow(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_HYPERLINK_ARROW)); + // set html arrow to the first one if invalid index defined + if (is_array($l_str_Arrow)) { + $l_str_Arrow = MCI_Footnotes_Convert::getArrow(0); + } + // get user defined arrow + $l_str_ArrowUserDefined = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_HYPERLINK_ARROW_USER_DEFINED); + if (!empty($l_str_ArrowUserDefined)) { + $l_str_Arrow = $l_str_ArrowUserDefined; + } + + // load template file + $l_str_Body = ""; + $l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_PUBLIC, "reference-container-body"); + + // loop through all footnotes found in the page + for ($l_str_Index = 0; $l_str_Index < count(self::$a_arr_Footnotes); $l_str_Index++) { + // get footnote text + $l_str_FootnoteText = self::$a_arr_Footnotes[$l_str_Index]; + // if footnote is empty, get to the next one + if (empty($l_str_FootnoteText)) { + continue; + } + // get footnote index + $l_str_FirstFootnoteIndex = ($l_str_Index + 1); + $l_str_FootnoteIndex = MCI_Footnotes_Convert::Index(($l_str_Index + 1), MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_COUNTER_STYLE)); + + // check if it isn't the last footnote in the array + if ($l_str_FirstFootnoteIndex < count(self::$a_arr_Footnotes) && MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_COMBINE_IDENTICAL_FOOTNOTES))) { + // get all footnotes that I haven't passed yet + for ($l_str_CheckIndex = $l_str_FirstFootnoteIndex; $l_str_CheckIndex < count(self::$a_arr_Footnotes); $l_str_CheckIndex++) { + // check if a further footnote is the same as the actual one + if ($l_str_FootnoteText == self::$a_arr_Footnotes[$l_str_CheckIndex]) { + // set the further footnote as empty so it won't be displayed later + self::$a_arr_Footnotes[$l_str_CheckIndex] = ""; + // add the footnote index to the actual index + $l_str_FootnoteIndex .= ", " . MCI_Footnotes_Convert::Index(($l_str_CheckIndex + 1), MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_COUNTER_STYLE)); + } + } + } + // replace all placeholders in the template + $l_obj_Template->replace( + array( + "index" => $l_str_FootnoteIndex, + "id" => self::$a_str_Prefix . MCI_Footnotes_Convert::Index($l_str_FirstFootnoteIndex, MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_COUNTER_STYLE)), + "arrow" => $l_str_Arrow, + "text" => $l_str_FootnoteText + ) + ); + // extra line breaks for page source legibility: + $footnote_item_temp = $l_obj_Template->getContent(); + $footnote_item_temp .= "\r\n\r\n"; + $l_str_Body .= $footnote_item_temp; + $l_obj_Template->reload(); + } + + // load template file + $l_obj_TemplateContainer = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_PUBLIC, "reference-container"); + $l_obj_TemplateContainer->replace( + array( + "label" => MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_REFERENCE_CONTAINER_NAME), + "button-style" => !MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_REFERENCE_CONTAINER_COLLAPSE)) ? 'display: none;' : '', + "id" => "footnote_references_container_" . get_the_id(), + "style" => MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_REFERENCE_CONTAINER_COLLAPSE)) ? 'display: none;' : '', + "content" => $l_str_Body + ) + ); + + // free all found footnotes if reference container will be displayed + self::$a_arr_Footnotes = array(); + + return $l_obj_TemplateContainer->getContent(); + } +} diff --git a/trunk/class/template.php b/trunk/class/template.php new file mode 100644 index 0000000..cc47091 --- /dev/null +++ b/trunk/class/template.php @@ -0,0 +1,132 @@ +a_str_OriginalContent = str_replace("\n", "", file_get_contents($l_str_TemplateFile)); + $this->a_str_OriginalContent = str_replace("\r", "", $this->a_str_OriginalContent); + $this->a_str_OriginalContent = str_replace("\t", " ", $this->a_str_OriginalContent); + $this->a_str_OriginalContent = preg_replace('# +#', " ", $this->a_str_OriginalContent); + $this->reload(); + } + + /** + * Replace all placeholders specified in array. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param array $p_arr_Placeholders Placeholders (key = placeholder, value = value). + * @return bool True on Success, False if Placeholders invalid. + */ + public function replace($p_arr_Placeholders) { + // no placeholders set + if (empty($p_arr_Placeholders)) { + return false; + } + // template content is empty + if (empty($this->a_str_ReplacedContent)) { + return false; + } + // iterate through each placeholder and replace it with its value + foreach($p_arr_Placeholders as $l_str_Placeholder => $l_str_Value) { + $this->a_str_ReplacedContent = str_replace("[[" . $l_str_Placeholder . "]]", $l_str_Value, $this->a_str_ReplacedContent); + } + // success + return true; + } + + /** + * Reloads the original content of the template file. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + public function reload() { + $this->a_str_ReplacedContent = $this->a_str_OriginalContent; + } + + /** + * Returns the content of the template file with replaced placeholders. + * + * @author Stefan Herndler + * @since 1.5.0 + * @return string Template content with replaced placeholders. + */ + public function getContent() { + return $this->a_str_ReplacedContent; + } + +} // end of class diff --git a/trunk/class/widgets/base.php b/trunk/class/widgets/base.php new file mode 100644 index 0000000..39641a7 --- /dev/null +++ b/trunk/class/widgets/base.php @@ -0,0 +1,75 @@ + echo the Widget Content + * **public function form($instance)** -> echo the Settings of the Widget + * + * @author Stefan Herndler + * @since 1.5.0 + */ +abstract class MCI_Footnotes_WidgetBase extends WP_Widget { + + /** + * Returns an unique ID as string used for the Widget Base ID. + * + * @author Stefan Herndler + * @since 1.5.0 + * @return string + */ + abstract protected function getID(); + + /** + * Returns the Public name of child Widget to be displayed in the Configuration page. + * + * @author Stefan Herndler + * @since 1.5.0 + * @return string + */ + abstract protected function getName(); + + /** + * Returns the Description of the child widget. + * + * @author Stefan Herndler + * @since 1.5.0 + * @return string + */ + abstract protected function getDescription(); + + /** + * Returns the width of the Widget. Default width is 250 pixel. + * + * @author Stefan Herndler + * @since 1.5.0 + * @return int + */ + protected function getWidgetWidth() { + return 250; + } + + /** + * Class Constructor. Registers the child Widget to WordPress. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + public function __construct() { + $l_arr_WidgetOptions = array("classname" => __CLASS__, "description" => $this->getDescription()); + $l_arr_ControlOptions = array("id_base" => strtolower($this->getID()), "width" => $this->getWidgetWidth()); + // registers the Widget + parent::__construct( + strtolower($this->getID()), // unique ID for the widget, has to be lowercase + $this->getName(), // Plugin name to be displayed + $l_arr_WidgetOptions, // Optional Widget Options + $l_arr_ControlOptions // Optional Widget Control Options + ); + } +} diff --git a/trunk/class/widgets/reference-container.php b/trunk/class/widgets/reference-container.php new file mode 100644 index 0000000..58a5747 --- /dev/null +++ b/trunk/class/widgets/reference-container.php @@ -0,0 +1,79 @@ +get(MCI_Footnotes_Settings::C_STR_REFERENCE_CONTAINER_POSITION) == "widget") { + echo $g_obj_MCI_Footnotes->a_obj_Task->ReferenceContainer(); + } + } +} \ No newline at end of file diff --git a/trunk/class/wysiwyg.php b/trunk/class/wysiwyg.php new file mode 100644 index 0000000..d8b558b --- /dev/null +++ b/trunk/class/wysiwyg.php @@ -0,0 +1,83 @@ +getContent(); + } + + /** + * Includes the Plugins WYSIWYG editor script. + * + * @author Stefan Herndler + * @since 1.5.0 + * @param array $p_arr_Plugins Scripts to be included to the editor. + * @return array + */ + public static function includeScripts($p_arr_Plugins) { + $p_arr_Plugins[MCI_Footnotes_Config::C_STR_PLUGIN_NAME] = plugins_url('/../js/wysiwyg-editor.js', __FILE__); + return $p_arr_Plugins; + } + + /** + * AJAX Callback function when the Footnotes Button is clicked. Either in the Plain text or Visual editor. + * Returns an JSON encoded array with the Footnotes start and end short code. + * + * @author Stefan Herndler + * @since 1.5.0 + */ + public static function ajaxCallback() { + // get start and end tag for the footnotes short code + $l_str_StartingTag = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_START); + $l_str_EndingTag = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_END); + if ($l_str_StartingTag == "userdefined" || $l_str_EndingTag == "userdefined") { + $l_str_StartingTag = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_START_USER_DEFINED); + $l_str_EndingTag = MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_END_USER_DEFINED); + } + echo json_encode(array("start" => htmlspecialchars($l_str_StartingTag), "end" => htmlspecialchars($l_str_EndingTag))); + exit; + } +} \ No newline at end of file diff --git a/trunk/css/public.css b/trunk/css/public.css new file mode 100755 index 0000000..43768ff --- /dev/null +++ b/trunk/css/public.css @@ -0,0 +1,190 @@ +/** + * Created by Stefan Herndler. + * User: Stefan + * Created-Date: 15.05.14 + * Created-Time: 16:21 + * Since: 1.0 + * Version: 2.0.6 + * + * Last modified: 2020-11-04T0437+0100 + */ + + +/* MCI Footnotes logo + * + * The classes with 'heading' fix display in dashboard + * See class/config.php and css/settings.css + */ + +.footnotes_logo, +.footnotes_logo:hover, +.footnotes_logo_heading { + text-decoration: none; + font-weight: normal; +} +.footnotes_logo_part1, +.footnotes_logo_part1_heading { + color: #2bb975; +} +.footnotes_logo_part2, +.footnotes_logo_part2_heading { + color: #545f5a; +} + +/* Inline footnote referrers + * aka superscript footnote anchors + * + * Class footnote_plugin_tooltip_text is the referrer and surroundings + */ + +.footnote_plugin_tooltip_text { + cursor: pointer; + z-index: 1; +} +.footnote_plugin_tooltip_text { + display: inline-block; + text-decoration: none; +} +.footnote_plugin_tooltip_text:hover { + text-decoration: underline; +} + +/* tooltip infobox */ + +span.footnote_tooltip { + font-size: inherit; + text-align: left; + line-height: 1.2em; + z-index: 99; +} +.continue { + font-style: italic; + color: green; + text-decoration: none !important; + cursor: pointer; +} +.continue:hover { + color: blue; + text-decoration: underline !important; +} + +/* Footnotes reference container + */ + +/* label */ +.footnote_container_prepare { + display: block !important; + padding-top: 24px !important; + margin-bottom: -5px; +} +.footnote_container_prepare > p { + line-height: 1.3 !important; + margin-top: 1em !important; + margin-bottom: 0.25em !important; + padding: 0 !important; + font-weight: normal !important; + overflow: hidden !important; + border-bottom: 1px solid #aaaaaa !important; + display: block !important; + -webkit-margin-before: 0.83em !important; + -webkit-margin-after: 0.83em !important; + -webkit-margin-start: 0px !important; + -webkit-margin-end: 0px !important; + text-align: left !important; + vertical-align: middle; +} +.footnote_container_prepare > p > span:first-child { + text-align: left !important; + font-size: 1.5em !important; +} + +/* collapse button */ +#footnote_reference_container_collapse_button { + cursor: pointer; +} +.footnote_container_prepare > p > span:last-child a { + text-decoration: none; +} +.footnote_container_prepare > p > span:last-child a:hover { + text-decoration: underline; + color: #008800; +} + +/* Table starts here */ +.footnote-reference-container { + width: 100%; + border: none; +} + +/* footnotes + * class footnote_plugin_link is for backcompat. + * Used in reference-container-body.html + * See +.footnote_plugin_link, */ +.footnote_plugin_index, +.footnote_plugin_text { + border:none !important; + text-align: left !important; + vertical-align: top !important; + padding: 10px 5px 5px 0 !important; +} +.footnote_plugin_index a, +.footnote_plugin_text a { + text-decoration: none !important; +} +.footnote_plugin_index:hover, +.footnote_plugin_text a:hover { + text-decoration: underline !important; +} +.footnote_plugin_index { + cursor: pointer; + overflow-wrap: unset; + word-wrap: unset; + word-wrap: normal !important; + word-break: unset; + word-break: keep-all !important; + max-width: 140px; + width: 1px; /*auto-extending column to fit widest*/ + white-space: nowrap; + overflow: hidden; +} +.footnote_plugin_text { + width: unset; /*unset width of text column to fix site issues*/ +} + +/* Responsive*/ +@media only screen and (max-width: 768px) { + .footnote_plugin_index { + max-width: 100px; + } +} + +/* Footnotes printing style rules + * + * Printing a table, browsers tend to avoid page breaks, + * but it takes a wrapper to avoid a page break before the table. + * + * UI elements (button, arrows) and link styling are removed. + */ + +.footnote_container_overall_wrapper { + page-break-inside: avoid; +} + +@media print { + .footnote_tooltip, + .footnote_reference_container_collapse_button_outfit, + .footnote_plugin_index_arrow { + display: none; + } + .footnote_plugin_tooltip_text { + color: inherit; + } + .footnote_plugin_index a { + color: inherit; + text-decoration: none !important; + } + div.post-meta-edit-link-wrapper { /* Edit button in WP2020*/ + display: none; /*(added as a service)*/ + } +} diff --git a/trunk/css/settings.css b/trunk/css/settings.css new file mode 100755 index 0000000..7d86001 --- /dev/null +++ b/trunk/css/settings.css @@ -0,0 +1,92 @@ +/** + * Created by Stefan Herndler. + * User: Stefan + * Created-Date: 15.05.14 + * Created-Time: 16:21 + * Since: 1.0 + * Version: 2.0.4 + * Last modified: 2020-11-01T0415+0100 + */ + + +/* MCI Footnotes logo + * + * The classes with 'heading' fix display in dashboard + * See class/config.php and css/public.css + */ + + .postbox-header { + position: relative; + padding: 0 20px; +} +.footnotes_logo_heading { + display: inline-block; + float: left; + position: absolute; +} +.footnotes_logo_part1_heading { + left: 20px; +} +.footnotes_logo_part2_heading { + left: 51px; +} +.footnotes_heart_heading { + color:#ff6d3b; + font-weight:bold; + position: absolute; + left: 96px; +} + + +input[type=text], input[type=password], textarea, select { + padding-left: 8px !important; + padding-right: 8px !important; + width: 80% !important; +} + +textarea { + height: 250px; +} + +label { + display: inline-block; +} + +.postbox > h3 { + height: 32px !important; + line-height: 32px !important; +} + +.postbox > h3 > span { + padding-left: 10px; +} + +.postbox > .inside > table { + border: none !important; +} + +.postbox > .inside >table > tbody > tr > td:first-child { + width: 15% !important; + font-weight: bold !important; +} + +.footnote_placeholder_box_container { + text-align: center !important; +} + +span.footnote_highlight_placeholder { + font-weight: bold !important; + padding-left: 8px !important; + padding-right: 8px !important; +} + +.footnote_placeholder_box_example { + border: 2px solid #2bb975 !important; + border-radius: 4px !important; + padding-top: 16px !important; + padding-bottom: 16px !important; + width: 50% !important; + display: block !important; + margin: 20px auto !important; + text-align: center !important; +} diff --git a/trunk/features.txt b/trunk/features.txt new file mode 100644 index 0000000..c5a4b23 --- /dev/null +++ b/trunk/features.txt @@ -0,0 +1,20 @@ + + +== Footnotes Features == +- Performance of the task so PHP won't throw an error when there are more than 120? Footnotes on a single page + - Maybe increase PHP max execution time while processing the Footnotes task +- different background for every odd table row + +- Offer a set of pre-defined styles for the footnotes.Reference.Container +There should be 2 pre-defined styles for the footnotes.Reference.Container and the ability to customize or add templates. +the currently used one should be one of those templates and pre-defined styles offered but not the default setting. + + +== Footnotes Bugs == +- Setting "Excerpt No" doesn't work + + +== TODO == + - Statistics: How many Footnotes in each post/page + - Convert from other Footnote Plugins (e.g. ' ((' from Civil Footnotes) + - Anonymous stats to the developers \ No newline at end of file diff --git a/trunk/footnotes.php b/trunk/footnotes.php new file mode 100755 index 0000000..28e7152 --- /dev/null +++ b/trunk/footnotes.php @@ -0,0 +1,45 @@ +run(); diff --git a/trunk/img/fn-wysiwyg.png b/trunk/img/fn-wysiwyg.png new file mode 100644 index 0000000..5d1b250 Binary files /dev/null and b/trunk/img/fn-wysiwyg.png differ diff --git a/trunk/img/main-menu.png b/trunk/img/main-menu.png new file mode 100644 index 0000000..a737fbc Binary files /dev/null and b/trunk/img/main-menu.png differ diff --git a/trunk/includes.php b/trunk/includes.php new file mode 100644 index 0000000..aa35d1c --- /dev/null +++ b/trunk/includes.php @@ -0,0 +1,37 @@ + + * 2020-10-26T2005+0100 + * Last modified: 2020-10-26T2006+0100 + */ +(function (a) { + a.tools = a.tools || {version: "v1.2.7"}; + var b; + b = a.tools.expose = {conf: {maskId: "exposeMask", loadSpeed: "slow", closeSpeed: "fast", closeOnClick: !0, closeOnEsc: !0, zIndex: 9998, opacity: .8, startOpacity: 0, color: "#fff", onLoad: null, onClose: null}}; + function c() { + if (a.browser && a.browser.msie) { + var b = a(document).height(), c = a(window).height(); + return[window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth, b - c < 20 ? c : b] + } + return[a(document).width(), a(document).height()] + } + + function d(b) { + if (b)return b.call(a.mask) + } + + var e, f, g, h, i; + a.mask = {load: function (j, k) { + if (g)return this; + typeof j == "string" && (j = {color: j}), j = j || h, h = j = a.extend(a.extend({}, b.conf), j), e = a("#" + j.maskId), e.length || (e = a("
").attr("id", j.maskId), a("body").append(e)); + var l = c(); + e.css({position: "absolute", top: 0, left: 0, width: l[0], height: l[1], display: "none", opacity: j.startOpacity, zIndex: j.zIndex}), j.color && e.css("backgroundColor", j.color); + if (d(j.onBeforeLoad) === !1)return this; + j.closeOnEsc && a(document).on("keydown.mask", function (b) { + b.keyCode == 27 && a.mask.close(b) + }), j.closeOnClick && e.on("click.mask", function (b) { + a.mask.close(b) + }), a(window).on("resize.mask", function () { + a.mask.fit() + }), k && k.length && (i = k.eq(0).css("zIndex"), a.each(k, function () { + var b = a(this); + /relative|absolute|fixed/i.test(b.css("position")) || b.css("position", "relative") + }), f = k.css({zIndex: Math.max(j.zIndex + 1, i == "auto" ? 0 : i)})), e.css({display: "block"}).fadeTo(j.loadSpeed, j.opacity, function () { + a.mask.fit(), d(j.onLoad), g = "full" + }), g = !0; + return this + }, close: function () { + if (g) { + if (d(h.onBeforeClose) === !1)return this; + e.fadeOut(h.closeSpeed, function () { + d(h.onClose), f && f.css({zIndex: i}), g = !1 + }), a(document).off("keydown.mask"), e.off("click.mask"), a(window).off("resize.mask") + } + return this + }, fit: function () { + if (g) { + var a = c(); + e.css({width: a[0], height: a[1]}) + } + }, getMask: function () { + return e + }, isLoaded: function (a) { + return a ? g == "full" : g + }, getConf: function () { + return h + }, getExposed: function () { + return f + }}, a.fn.mask = function (b) { + a.mask.load(b); + return this + }, a.fn.expose = function (b) { + a.mask.load(b, this); + return this + } +})(jQuery); +(function () { + var a = document.all, b = "http://www.adobe.com/go/getflashplayer", c = typeof jQuery == "function", d = /(\d+)[^\d]+(\d+)[^\d]*(\d*)/, e = {width: "100%", height: "100%", id: "_" + ("" + Math.random()).slice(9), allowfullscreen: !0, allowscriptaccess: "always", quality: "high", version: [3, 0], onFail: null, expressInstall: null, w3c: !1, cachebusting: !1}; + window.attachEvent && window.attachEvent("onbeforeunload", function () { + __flash_unloadHandler = function () { + }, __flash_savedUnloadHandler = function () { + } + }); + function f(a, b) { + if (b)for (var c in b)b.hasOwnProperty(c) && (a[c] = b[c]); + return a + } + + function g(a, b) { + var c = []; + for (var d in a)a.hasOwnProperty(d) && (c[d] = b(a[d])); + return c + } + + window.flashembed = function (a, b, c) { + typeof a == "string" && (a = document.getElementById(a.replace("#", ""))); + if (a) { + typeof b == "string" && (b = {src: b}); + return new j(a, f(f({}, e), b), c) + } + }; + var h = f(window.flashembed, {conf: e, getVersion: function () { + var a, b; + try { + b = navigator.plugins["Shockwave Flash"].description.slice(16) + } catch (c) { + try { + a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"), b = a && a.GetVariable("$version") + } catch (e) { + try { + a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"), b = a && a.GetVariable("$version") + } catch (f) { + } + } + } + b = d.exec(b); + return b ? [b[1], b[3]] : [0, 0] + }, asString: function (a) { + if (a === null || a === undefined)return null; + var b = typeof a; + b == "object" && a.push && (b = "array"); + switch (b) { + case"string": + a = a.replace(new RegExp("([\"\\\\])", "g"), "\\$1"), a = a.replace(/^\s?(\d+\.?\d*)%/, "$1pct"); + return"\"" + a + "\""; + case"array": + return"[" + g(a,function (a) { + return h.asString(a) + }).join(",") + "]"; + case"function": + return"\"function()\""; + case"object": + var c = []; + for (var d in a)a.hasOwnProperty(d) && c.push("\"" + d + "\":" + h.asString(a[d])); + return"{" + c.join(",") + "}" + } + return String(a).replace(/\s/g, " ").replace(/\'/g, "\"") + }, getHTML: function (b, c) { + b = f({}, b); + var d = ""; + b.width = b.height = b.id = b.w3c = b.src = null, b.onFail = b.version = b.expressInstall = null; + for (var e in b)b[e] && (d += ""); + var g = ""; + if (c) { + for (var i in c)if (c[i]) { + var j = c[i]; + g += i + "=" + encodeURIComponent(/function|object/.test(typeof j) ? h.asString(j) : j) + "&" + } + g = g.slice(0, -1), d += "" + } + d += ""; + return d + }, isSupported: function (a) { + return i[0] > a[0] || i[0] == a[0] && i[1] >= a[1] + }}), i = h.getVersion(); + + function j(c, d, e) { + if (h.isSupported(d.version))c.innerHTML = h.getHTML(d, e); else if (d.expressInstall && h.isSupported([6, 65]))c.innerHTML = h.getHTML(f(d, {src: d.expressInstall}), {MMredirectURL: location.href, MMplayerType: "PlugIn", MMdoctitle: document.title}); else { + c.innerHTML.replace(/\s/g, "") || (c.innerHTML = "

Flash version " + d.version + " or greater is required

" + (i[0] > 0 ? "Your version is " + i : "You have no flash plugin installed") + "

" + (c.tagName == "A" ? "

Click here to download latest version

" : "

Download latest version from here

"), c.tagName == "A" && (c.onclick = function () { + location.href = b + })); + if (d.onFail) { + var g = d.onFail.call(this); + typeof g == "string" && (c.innerHTML = g) + } + } + a && (window[d.id] = document.getElementById(d.id)), f(this, {getRoot: function () { + return c + }, getOptions: function () { + return d + }, getConf: function () { + return e + }, getApi: function () { + return c.firstChild + }}) + } + + c && (jQuery.tools = jQuery.tools || {version: "v1.2.7"}, jQuery.tools.flashembed = {conf: e}, jQuery.fn.flashembed = function (a, b) { + return this.each(function () { + jQuery(this).data("flashembed", flashembed(this, a, b)) + }) + }) +})(); +(function (a) { + var b, c, d, e; + a.tools = a.tools || {version: "v1.2.7"}, a.tools.history = {init: function (g) { + e || (a.browser && a.browser.msie && a.browser.version < "8" ? c || (c = a("