Changeset 3425938
- Timestamp:
- 12/23/2025 07:42:05 AM (3 months ago)
- Location:
- citation-note
- Files:
-
- 14 added
- 8 edited
-
tags/1.1.0 (added)
-
tags/1.1.0/assets (added)
-
tags/1.1.0/assets/css (added)
-
tags/1.1.0/assets/css/citation-note-editor.css (added)
-
tags/1.1.0/assets/css/citation-note-style.css (added)
-
tags/1.1.0/assets/js (added)
-
tags/1.1.0/assets/js/citation-note-editor.js (added)
-
tags/1.1.0/assets/js/citation-note.js (added)
-
tags/1.1.0/citation-note.php (added)
-
tags/1.1.0/lib (added)
-
tags/1.1.0/lib/class-citenote-admin-settings.php (added)
-
tags/1.1.0/lib/class-citenote-data.php (added)
-
tags/1.1.0/lib/class-citenote-editor-fields.php (added)
-
tags/1.1.0/readme.txt (added)
-
trunk/assets/css/citation-note-editor.css (modified) (2 diffs)
-
trunk/assets/css/citation-note-style.css (modified) (3 diffs)
-
trunk/assets/js/citation-note-editor.js (modified) (2 diffs)
-
trunk/assets/js/citation-note.js (modified) (3 diffs)
-
trunk/citation-note.php (modified) (1 diff)
-
trunk/lib/class-citenote-data.php (modified) (2 diffs)
-
trunk/lib/class-citenote-editor-fields.php (modified) (11 diffs)
-
trunk/readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
citation-note/trunk/assets/css/citation-note-editor.css
r3317114 r3425938 1 citenote_placeholder { 1 citenote_placeholder, 2 citenoteplaceholder { 2 3 background-color: #fff4a3; 3 4 padding: 0 2px; … … 5 6 font-style: italic; 6 7 } 7 .editor-styles-wrapper citenote_placeholder { 8 9 .editor-styles-wrapper citenote_placeholder, 10 .editor-styles-wrapper citenoteplaceholder { 8 11 background-color: #fff4a3; 9 12 padding: 0 2px; -
citation-note/trunk/assets/css/citation-note-style.css
r3317114 r3425938 1 1 /* citation footnotes */ 2 2 3 citenote_placeholder { 3 citenote_placeholder, 4 citenoteplaceholder { 4 5 display: none; 5 6 } … … 31 32 color: inherit; 32 33 text-decoration: inherit; 33 transition: all .4s ease;34 transition: all 0.4s ease; 34 35 } 35 36 … … 44 45 padding: 12px; 45 46 border-radius: 8px; 46 z-index: 10000;47 z-index: 49; 47 48 font-size: 0.875rem; 48 49 display: none; -
citation-note/trunk/assets/js/citation-note-editor.js
r3317114 r3425938 52 52 registerFormatType("citenote/placeholder", { 53 53 title: "Citation Note", 54 tagName: "citenote _placeholder",54 tagName: "citenoteplaceholder", 55 55 className: null, 56 56 edit: CitationNoteButton, … … 62 62 * 63 63 */ 64 jQuery(document).ready(function ($) { 65 // Initialize TinyMCE for existing textareas 66 // add new fields when clicking the add button 67 $("#citation-note-add-repeater-group").on("click", function (e) { 68 e.preventDefault(); 69 const $button = $(this); 70 $button.prop("disabled", true); // Prevent rapid multiple clicks 71 72 let ajax = $.ajax({ 73 url: citenoteAjax.ajax_url, 74 type: "POST", 75 data: { 76 action: citenoteAjax.action_name, 77 _nonce: citenoteAjax.nonce, 78 row_number: $("#citation-note-repeater-table tbody tr").length + 1, 64 jQuery(function ($) { 65 // jQuery(document).ready(function ($) { }); 66 $(window).on("load", function () { 67 68 // 69 function initializeEditor($textarea) { 70 const editorId = $textarea.attr("id"); 71 if (!editorId || !window.tinymce) return; 72 // Avoid double initialization 73 if (!tinymce.get(editorId) && editorId && typeof tinymce !== "undefined") { 74 tinymce.execCommand("mceAddEditor", false, editorId); 75 } 76 } 77 78 // 79 function destroyEditor($textarea) { 80 const editorId = $textarea.attr("id"); 81 if (editorId && tinymce.get(editorId)) { 82 // tinymce.get(editorId).remove(); 83 tinymce.execCommand("mceRemoveEditor", false, editorId); 84 } 85 } 86 87 // Initialize TinyMCE for existing textareas 88 // add new fields when clicking the add button 89 $("#citation-note-add-repeater-group").on("click", function (e) { 90 e.preventDefault(); 91 const $button = $(this); 92 $button.prop("disabled", true); // Prevent rapid multiple clicks 93 94 let ajax = $.ajax({ 95 url: citenoteAjax.ajax_url, 96 type: "POST", 97 data: { 98 action: citenoteAjax.action_name, 99 _nonce: citenoteAjax.nonce, 100 row_number: $("#citation-note-repeater-table tbody tr").length + 1, 101 }, 102 }); 103 104 ajax.done(function (response) { 105 let row = $(response); 106 $("#citation-note-repeater-table tbody").append(row); 107 108 // Reinitialize TinyMCE if the row contains an editor 109 row.find("textarea").each(function () { 110 initializeEditor($(this)); 111 }); 112 }); 113 ajax.fail(function (response) { 114 console.error("Error:", response.responseText); 115 }); 116 ajax.always(function (response) { 117 // console.log(response); 118 $button.prop("disabled", false); 119 }); 120 }); 121 122 // Initialize TinyMCE for existing textareas 123 // This will initialize TinyMCE for all textareas in the table 124 // $("#citation-note-repeater-table tbody tr").each(function () { 125 // $(this) 126 // .find("textarea") 127 // .each(function () { 128 // initializeEditor($(this)); 129 // }); 130 // }); 131 132 // Remove group button 133 // This will remove the group from the table 134 $(document).on("click", ".citation-note-remove-group", function () { 135 $(this).prop("disabled", true); 136 if (confirm("Are you sure you want to remove this citation?")) { 137 $(this).closest("tr").remove(); 138 } 139 $(this).prop("disabled", false); 140 }); 141 142 /** 143 * Validate number input to allow only digits 144 * This will allow only digits in the input field 145 * and remove any non-digit characters 146 */ 147 $(document).on("input", ".input-row_number", function () { 148 let value = $(this).val().replace(/\D/g, ""); 149 $(this).val(value); 150 }); 151 152 // Validate number input for duplicates 153 // generate a unique placeholder for each input 154 $(document).on( 155 "blur", 156 "#citation-note-repeater-table .input-row_number", 157 function () { 158 var $input = $(this); 159 var index = $input.data("index"); 160 var value = $input.val(); 161 162 // Check for duplicates 163 var isDuplicate = false; 164 $(".input-row_number") 165 .not($input) 166 .each(function () { 167 if ($(this).val().trim() === value) { 168 isDuplicate = true; 169 return false; // break loop 170 } 171 }); 172 // If the value is empty, we don't consider it a duplicate 173 if (isDuplicate) { 174 $input.val(""); 175 $input.css("border", "2px solid red"); 176 $(".yi_citation_" + index).text("Duplicate! " + "citation_" + value); 177 } else { 178 $input.css("border", ""); 179 $(".yi_citation_" + index).text("citation_" + value); 180 } 181 // 182 } 183 ); 184 185 // Toggle collapse/expand 186 $("#citation-note-repeater-table").on( 187 "click", 188 ".toggle-yi-citation-row", 189 function () { 190 const $tr = $(this).closest("tr"); 191 // Toggle the expand/collapse of the row 192 $tr.find(".citation-expandable").toggle(); 193 $tr.find(".citation-collapseable").toggle(); 194 195 // Optionally, change the button text when toggled (e.g., "Show" / "Hide") 196 const buttonText = $tr.find(".citation-expandable").is(":visible") 197 ? "Collapse" 198 : "Expand"; 199 $(this).text(buttonText); 200 } 201 ); 202 203 // Collapse all rows 204 $("#citenote-collapse-all").click(function () { 205 $("#citation-note-repeater-table tbody tr .citation-expandable").each( 206 function () { 207 $(this).hide(); // Hide all expandable content 208 } 209 ); 210 $("#citation-note-repeater-table tbody tr .citation-collapseable").each( 211 function () { 212 $(this).show(); // Hide all expandable content 213 } 214 ); 215 $("#citation-note-repeater-table tbody tr .toggle-yi-citation-row").each( 216 function () { 217 $(this).text("Expand"); 218 } 219 ); 220 }); 221 222 // Expand all rows 223 $("#citenote-expand-all").click(function () { 224 $("#citation-note-repeater-table tbody tr .citation-expandable").each( 225 function () { 226 $(this).show(); // Show all expandable content 227 } 228 ); 229 $("#citation-note-repeater-table tbody tr .citation-collapseable").each( 230 function () { 231 $(this).hide(); // Hide all expandable content 232 } 233 ); 234 $("#citation-note-repeater-table tbody tr .toggle-yi-citation-row").each( 235 function () { 236 $(this).text("Collapse"); 237 } 238 ); 239 }); 240 241 // Re-arrange rows 242 $("#citation-note-repeater-table tbody").sortable({ 243 handle: ".row-drag-handler", 244 axis: "y", 245 // update: function (event, ui) { 246 // }, 247 stop: function (event, ui) { 248 try { 249 // Try reinitializing TinyMCE for any textarea in the moved row 250 ui.item.find("textarea").each(function () { 251 destroyEditor($(this)); 252 initializeEditor($(this)); 253 }); 254 // Remove inline width styles added during sort 255 ui.item.find("td").css("width", ""); 256 } catch (error) { 257 // Revert sort by canceling the move 258 $tbody.sortable("cancel"); 259 } 79 260 }, 80 261 }); 81 82 ajax.done(function (response) {83 let row = $(response);84 $("#citation-note-repeater-table tbody").append(row);85 86 // Reinitialize TinyMCE if the row contains an editor87 row.find("textarea").each(function () {88 const editorId = $(this).attr("id");89 if (editorId && typeof tinymce !== "undefined") {90 tinymce.execCommand("mceAddEditor", false, editorId);91 }92 });93 });94 ajax.fail(function (response) {95 console.error("Error:", response.responseText);96 });97 ajax.always(function (response) {98 // console.log(response);99 $button.prop("disabled", false);100 });101 });102 103 // Initialize TinyMCE for existing textareas104 // This will initialize TinyMCE for all textareas in the table105 $("#citation-note-repeater-table tbody tr").each(function () {106 $(this)107 .find("textarea")108 .each(function () {109 const editorId = $(this).attr("id");110 if (editorId && typeof tinymce !== "undefined") {111 tinymce.execCommand("mceAddEditor", false, editorId);112 }113 });114 });115 116 // Remove group button117 // This will remove the group from the table118 $(document).on("click", ".citation-note-remove-group", function () {119 $(this).prop("disabled", true);120 if (confirm("Are you sure you want to remove this citation?")) {121 $(this).closest("tr").remove();122 }123 $(this).prop("disabled", false);124 });125 126 /**127 * Validate number input to allow only digits128 * This will allow only digits in the input field129 * and remove any non-digit characters130 */131 $(document).on("input", ".input-row_number", function () {132 let value = $(this).val().replace(/\D/g, "");133 $(this).val(value);134 });135 136 // Validate number input for duplicates137 // generate a unique placeholder for each input138 $(document).on(139 "blur",140 "#citation-note-repeater-table .input-row_number",141 function () {142 var $input = $(this);143 var index = $input.data("index");144 var value = $input.val();145 146 // Check for duplicates147 var isDuplicate = false;148 $(".input-row_number")149 .not($input)150 .each(function () {151 if ($(this).val().trim() === value) {152 isDuplicate = true;153 return false; // break loop154 }155 });156 // If the value is empty, we don't consider it a duplicate157 if (isDuplicate) {158 $input.val("");159 $input.css("border", "2px solid red");160 $(".yi_citation_" + index).text("Duplicate! " + "citation_" + value);161 } else {162 $input.css("border", "");163 $(".yi_citation_" + index).text("citation_" + value);164 }165 //166 }167 );168 169 // Toggle collapse/expand170 $("#citation-note-repeater-table").on(171 "click",172 ".toggle-yi-citation-row",173 function () {174 const $tr = $(this).closest("tr");175 // Toggle the expand/collapse of the row176 $tr.find(".citation-expandable").toggle();177 $tr.find(".citation-collapseable").toggle();178 179 // Optionally, change the button text when toggled (e.g., "Show" / "Hide")180 const buttonText = $tr.find(".citation-expandable").is(":visible")181 ? "Collapse"182 : "Expand";183 $(this).text(buttonText);184 }185 );186 187 // Collapse all rows188 $("#citenote-collapse-all").click(function () {189 $("#citation-note-repeater-table tbody tr .citation-expandable").each(190 function () {191 $(this).hide(); // Hide all expandable content192 }193 );194 $("#citation-note-repeater-table tbody tr .citation-collapseable").each(195 function () {196 $(this).show(); // Hide all expandable content197 }198 );199 $("#citation-note-repeater-table tbody tr .toggle-yi-citation-row").each(200 function () {201 $(this).text("Expand");202 }203 );204 });205 206 // Expand all rows207 $("#citenote-expand-all").click(function () {208 $("#citation-note-repeater-table tbody tr .citation-expandable").each(209 function () {210 $(this).show(); // Show all expandable content211 }212 );213 $("#citation-note-repeater-table tbody tr .citation-collapseable").each(214 function () {215 $(this).hide(); // Hide all expandable content216 }217 );218 $("#citation-note-repeater-table tbody tr .toggle-yi-citation-row").each(219 function () {220 $(this).text("Collapse");221 }222 );223 });224 225 // Re-arrange rows226 $("#citation-note-repeater-table tbody").sortable({227 handle: ".row-drag-handler",228 axis: "y",229 // update: function (event, ui) {230 // },231 stop: function (event, ui) {232 try {233 // Try reinitializing TinyMCE for any textarea in the moved row234 ui.item.find("textarea").each(function () {235 let editorId = $(this).attr("id");236 // if (editorId && typeof tinymce !== 'undefined') {237 // Remove existing editor (if any)238 tinymce.execCommand("mceRemoveEditor", false, editorId);239 // Re-add TinyMCE240 tinymce.execCommand("mceAddEditor", false, editorId);241 // }242 });243 // Remove inline width styles added during sort244 ui.item.find("td").css("width", "");245 } catch (error) {246 // Revert sort by canceling the move247 $tbody.sortable("cancel");248 }249 },250 262 }); 251 263 }); -
citation-note/trunk/assets/js/citation-note.js
r3329829 r3425938 1 1 // jQuery(document).ready(function ($) {}); 2 2 document.addEventListener("DOMContentLoaded", () => { 3 var citenoteWrapper = document.querySelector( '.citation-note-wrapper');3 var citenoteWrapper = document.querySelector(".citation-note-wrapper"); 4 4 if (citenoteWrapper) { 5 5 const popup = document.createElement("div"); … … 37 37 const arrowLeft = refCenter - left; 38 38 popup.style.setProperty("--arrow-left", `${arrowLeft}px`); 39 40 39 } 41 40 function hidePopupDelayed() { … … 74 73 ref.remove(); 75 74 }); 76 console.log('citation footnoes list output is not set. please add shortcode [citenote_display_list] at the end of the page content.') 75 console.log( 76 "citation footnoes list output is not set. please add shortcode [citenote_display_list] at the end of the page content." 77 ); 77 78 } 78 79 }); -
citation-note/trunk/citation-note.php
r3317116 r3425938 9 9 * Requires at least: 6.8 10 10 * Requires PHP: 8.0 11 * Tested up to: 6. 812 * Version: 1. 0.011 * Tested up to: 6.9 12 * Version: 1.1.0 13 13 * Author: santoshtmp7 14 14 * License: GPLv2 or later -
citation-note/trunk/lib/class-citenote-data.php
r3317093 r3425938 89 89 } 90 90 91 $pattern = '/<citenote_placeholder>(.*?)<\/citenote_placeholder>/'; 91 // $pattern = '/<citenote_placeholder>(.*?)<\/citenote_placeholder>/'; // it has 1 group 92 $pattern = '/<(citenote(?:_placeholder|placeholder))>(.*?)<\/\1>/s'; // it has 2 group 92 93 // Replace with preg_replace_callback 93 94 $content = preg_replace_callback( … … 95 96 function ($matches) use (&$citenote_post_citaion_list, $citenote_list, $post_id) { 96 97 // 97 $citenote_placeholder = trim($matches[ 1]);98 $citenote_placeholder = trim($matches[2]); 98 99 if (!$citenote_placeholder) { 99 100 return ''; // If placeholder is empty, return empty string -
citation-note/trunk/lib/class-citenote-editor-fields.php
r3317093 r3425938 1 1 <?php 2 3 /** 4 * Citation Note – Editor & Meta Fields 5 * Reference: 6 * wp_ajax_action https://developer.wordpress.org/reference/hooks/wp_ajax_action/ 7 * add_meta_boxes https://developer.wordpress.org/reference/hooks/add_meta_boxes/ 8 * save_post https://developer.wordpress.org/reference/hooks/save_post/ 9 * wp_kses_post() https://developer.wordpress.org/reference/functions/wp_kses_post/ 10 * wp_kses_allowed_html https://developer.wordpress.org/reference/hooks/wp_kses_allowed_html/ 11 * content_save_pre https://developer.wordpress.org/reference/hooks/field_no_prefix_save_pre/ 12 * rest_post_dispatch https://developer.wordpress.org/reference/hooks/rest_post_dispatch/ 13 * wp_editor() https://developer.wordpress.org/reference/functions/wp_editor/ 14 * 15 */ 2 16 3 17 namespace citenote; … … 20 34 */ 21 35 function __construct() { 22 // 36 // Gutenberg assets 23 37 add_action('enqueue_block_editor_assets', [$this, 'citenote_enqueue_block_editor_assets']); 24 add_filter('wp_kses_allowed_html', [$this, 'citenote_wp_kses_allowed_html'], 10, 2);38 // Meta box 25 39 add_action('add_meta_boxes', [$this, 'citenote_add_meta_boxes']); 40 // AJAX 26 41 add_action('wp_ajax_citenote_updateCitationEditField', [$this, 'citenote_updateCitationEditField']); 42 // Save meta 27 43 add_action('save_post', [$this, 'citenote_save_post']); 28 } 29 30 /** 31 * 44 // KSES fallback (classic + safety) 45 add_filter('wp_kses_allowed_html', [$this, 'citenote_wp_kses_allowed_html'], 99, 2); 46 // Normalize BEFORE save (all editors) 47 add_action('content_save_pre', [$this, 'content_change_citenoteplaceholder_tag']); 48 // Normalize when loading into classic editor 49 add_filter('content_edit_pre', [$this, 'content_change_citenoteplaceholder_tag']); 50 // Normalize when loading into Gutenberg editor 51 add_filter('rest_post_dispatch', [$this, 'content_rest_post_change_citenoteplaceholder_tag'], 10, 3); 52 } 53 54 55 56 /** 57 * Enqueue assets for citation support. 58 * 59 * Loads JavaScript and CSS only for allowed post types. 60 * Also localizes configuration and security data for AJAX usage. 61 * 62 * Hooked to: enqueue_block_editor_assets 63 * 64 * @return void 32 65 */ 33 66 public function citenote_enqueue_block_editor_assets() { … … 40 73 ['wp-rich-text', 'wp-editor', 'wp-block-editor', 'wp-element', 'wp-components', 'jquery', 'jquery-ui-sortable'], 41 74 filemtime(CITENOTE_PLUGIN_DIR . 'assets/js/citation-note-editor.js'), 42 array( 43 'in_footer' => true, 44 'strategy' => 'defer', 45 ) 75 true 46 76 ); 47 77 wp_localize_script('citation-note-editor-script', 'citenoteAjax', [ … … 62 92 63 93 /** 64 * 94 * Normalize legacy citation tags when loading post into Gutenberg editor. 95 * 96 * Runs during REST API preload for block editor. 97 * 98 * @param WP_REST_Response $response 99 * @param WP_REST_Server $server 100 * @param WP_REST_Request $request 101 * 102 * @return WP_REST_Response 103 */ 104 public function content_rest_post_change_citenoteplaceholder_tag($response, $server, $request) { 105 106 // Only when loading post into editor 107 if ($request->get_param('context') !== 'edit') { 108 return $response; 109 } 110 111 // data is in content 112 $data = $response->get_data(); 113 if (is_array($data) && isset($data['content']['raw'])) { 114 $data['content']['raw'] = preg_replace( 115 '/<citenote_placeholder>(.*?)<\/citenote_placeholder>/s', 116 '<citenoteplaceholder>$1</citenoteplaceholder>', 117 $data['content']['raw'] 118 ); 119 } 120 121 $response->set_data($data); 122 return $response; 123 } 124 125 /** 126 * Normalize legacy citation tags before saving post content. 127 * 128 * @param string $content 129 * @return string 130 */ 131 public function content_change_citenoteplaceholder_tag($content) { 132 return preg_replace( 133 '/<citenote_placeholder>(.*?)<\/citenote_placeholder>/s', 134 '<citenoteplaceholder>$1</citenoteplaceholder>', 135 $content 136 ); 137 } 138 139 /** 140 * Allow citation tags 141 * 142 * NOTE: 143 * Gutenberg may still strip invalid tags before KSES runs. 144 * 145 * @param array $allowed 146 * @param string $context 147 * @return array 65 148 */ 66 149 public function citenote_wp_kses_allowed_html($allowed, $context) { 67 if (is_array($allowed)) { 68 $allowed['citenote_placeholder'] = array(); // No attributes allowed 69 } 150 if (!is_array($allowed)) { 151 return $allowed; 152 } 153 154 $allowed['citenote_placeholder'] = array(); 155 $allowed['citenoteplaceholder'] = array(); 70 156 return $allowed; 71 157 } 72 158 73 159 /** 74 * Add Custom meata box in the post type 160 * 161 * Register the Citation List meta box for supported post types. 162 * 163 * Hooked to: add_meta_boxes 75 164 * https://developer.wordpress.org/reference/hooks/add_meta_boxes/ 165 * 166 * @return void 76 167 */ 77 168 public function citenote_add_meta_boxes() { … … 88 179 89 180 /** 90 * add_citenote_meta_box 181 * Render the Citation List meta box UI. 182 * 183 * Displays a sortable, repeatable list of citation fields 184 * with TinyMCE editors for descriptions. 185 * 186 * @param \WP_Post $post Current post object. 187 * 188 * @return void 91 189 */ 92 190 function citenote_add_citenote_meta_box($post) { … … 136 234 137 235 /** 138 * Example ajax 236 * AJAX callback to render a new citation field row. 237 * 238 * Verifies nonce for security and outputs HTML for 239 * a new repeater row used in the citation meta box. 240 * 241 * Hooked to: wp_ajax_citenote_updateCitationEditField 242 * 243 * @return void Outputs HTML and exits. 139 244 */ 140 245 function citenote_updateCitationEditField() { … … 153 258 } 154 259 155 // 260 /** 261 * Output a single citation repeater row. 262 * 263 * Used for both initial meta box rendering and 264 * AJAX-generated rows. 265 * 266 * @param array $field Citation field data. 267 * 268 * @return void Outputs HTML table row. 269 */ 156 270 public function citenote_get_field_row($field) { 157 271 $index = (isset($field['index'])) ? $field['index'] : time(); … … 194 308 'media_buttons' => false, 195 309 'teeny' => false, 196 'quicktags' => true,310 'quicktags' => false, 197 311 ] 198 312 ); … … 206 320 : '<em>.....</em>'; ?> 207 321 </p> 208 209 322 </div> 210 323 </td> … … 217 330 } 218 331 219 220 /** 221 * Save post 332 /** 333 * Save citation list meta data when the post is saved. 334 * 335 * - Verifies nonce 336 * - Skips autosaves and revisions 337 * - Sanitizes citation descriptions using wp_kses_post() 338 * - Stores structured citation data in post meta 339 * 340 * Hooked to: save_post 222 341 * https://developer.wordpress.org/reference/hooks/save_post/ 223 * 342 * 343 * @param int $post_id Post ID being saved. 344 * 345 * @return void 224 346 */ 225 347 public function citenote_save_post($post_id) { … … 257 379 258 380 /** 259 * ==== END ====381 * End of CITENOTE_Editor_Fields class. 260 382 */ 261 383 } -
citation-note/trunk/readme.txt
r3317116 r3425938 5 5 Requires at least: 6.8 6 6 Requires PHP: 8.0 7 Tested up to: 6. 88 Stable tag: 1. 0.07 Tested up to: 6.9 8 Stable tag: 1.1.0 9 9 License: GPLv2 or later 10 10 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 62 62 63 63 == Changelog == 64 = 1.1.0 = 65 * Compatible to 6.9 66 * Fix citenoteplaceholder tag 64 67 = 1.0.0 = 65 68 * Initial release of Citation Note.
Note: See TracChangeset
for help on using the changeset viewer.