1*f4b18c92SGill B.jQuery(function() { 2*f4b18c92SGill B. var $board = jQuery('.kanban-board'); 3*f4b18c92SGill B. var $mycard = jQuery('.kanban-card'); 4*f4b18c92SGill B. if (!$board.length) return; 5*f4b18c92SGill B. var boardName = $board.data('board'); 6*f4b18c92SGill B. 7*f4b18c92SGill B. // Helper to send data to PHP 8*f4b18c92SGill B. function saveCardData($card) { 9*f4b18c92SGill B. jQuery.post(DOKU_BASE + 'lib/exe/ajax.php', { 10*f4b18c92SGill B. call: 'kanban_save', // Match this with your action.php check 11*f4b18c92SGill B. board: boardName, 12*f4b18c92SGill B. card_id: $card.data('id'), 13*f4b18c92SGill B. column: $card.closest('.kanban-col').data('id'), 14*f4b18c92SGill B. name: $card.find('.card-title').text(), 15*f4b18c92SGill B. importance: $card.attr('class').split(' ').filter(c => ['high','medium','low'].includes(c))[0] || 'medium', 16*f4b18c92SGill B. desc: $card.find('.card-desc').text(), 17*f4b18c92SGill B. note: $card.find('.card-note').text(), 18*f4b18c92SGill B. checked: $card.find('.checkbox-inline').prop('checked') 19*f4b18c92SGill B. }).done(function(res){ console.log("Saved:", res); }); 20*f4b18c92SGill B. } 21*f4b18c92SGill B. 22*f4b18c92SGill B. // Prevent movement of the card column placeholder 23*f4b18c92SGill B. /* 24*f4b18c92SGill B. jQuery(function() { 25*f4b18c92SGill B. jQuery(".cards-container").sortable({ 26*f4b18c92SGill B. // Only allow children WITHOUT the 'fixed-top-item' class to be moved 27*f4b18c92SGill B. items: "> div:not(.fixed-top)", 28*f4b18c92SGill B. 29*f4b18c92SGill B. // Listen for when an item is being moved to a new position 30*f4b18c92SGill B. update: function(event, ui) { 31*f4b18c92SGill B. // ui.item.index() returns the current position in the DOM 32*f4b18c92SGill B. if (ui.item.index() === 0) { 33*f4b18c92SGill B. // Find the fixed element 34*f4b18c92SGill B. var $fixed = jQuery(this).find(".fixed-top"); 35*f4b18c92SGill B. // Immediately force the dropped item to go AFTER the fixed div 36*f4b18c92SGill B. ui.item.insertAfter($fixed); 37*f4b18c92SGill B. } 38*f4b18c92SGill B. } 39*f4b18c92SGill B. }); 40*f4b18c92SGill B. }); 41*f4b18c92SGill B. */ 42*f4b18c92SGill B. 43*f4b18c92SGill B. // Initialize Drag and Drop ONCE 44*f4b18c92SGill B. 45*f4b18c92SGill B. jQuery(".cards-container").sortable({ 46*f4b18c92SGill B. connectWith: ".cards-container", 47*f4b18c92SGill B. placeholder: "ui-sortable-placeholder", 48*f4b18c92SGill B. tolerance: "pointer", 49*f4b18c92SGill B. 50*f4b18c92SGill B. 51*f4b18c92SGill B. start: function(e, ui) { 52*f4b18c92SGill B. //start-added 53*f4b18c92SGill B. const card = document.querySelector('.kanban-card'); 54*f4b18c92SGill B. 55*f4b18c92SGill B. distance: 15, // Dragging won't trigger until moved 15px 56*f4b18c92SGill B. // Add and start the draggable class only AFTER the 15px threshold is met 57*f4b18c92SGill B. ui.item.addClass("is-dragging"); 58*f4b18c92SGill B. //distance: -15, // Dragging won't trigger until moved -15px 59*f4b18c92SGill B. // Add and start the draggable class only AFTER the -15px threshold is met 60*f4b18c92SGill B. //ui.item.addClass("is-left-dragging"); 61*f4b18c92SGill B. //end-added 62*f4b18c92SGill B. ui.placeholder.height(ui.item.outerHeight()); 63*f4b18c92SGill B. }, 64*f4b18c92SGill B. stop: function(event, ui) { 65*f4b18c92SGill B. //Remove the draggable class when you are done 66*f4b18c92SGill B. ui.item.removeClass("is-dragging"); 67*f4b18c92SGill B. //ui.item.removeClass("is-left-dragging"); 68*f4b18c92SGill B. //Fires once when dropped 69*f4b18c92SGill B. //alert(ui.item.text()); //debugging function works 70*f4b18c92SGill B. //alert(ui.item.data('id')); //debugging function 71*f4b18c92SGill B. //saveCardData(ui.item); 72*f4b18c92SGill B. //Modified to capture the text value in JQuery format 73*f4b18c92SGill B. //saveCardData(ui.item); 74*f4b18c92SGill B. saveCardData(ui.item); //replaced to bring about real name for saving 75*f4b18c92SGill B. //const divId = ui.item.closest('.kanban-col').data('id'); 76*f4b18c92SGill B. //ui.item.closest('.kanban-col').preventDefault(); // This is required to allow a drop 77*f4b18c92SGill B. //console.log("Dropped on ID:", divId); 78*f4b18c92SGill B. } 79*f4b18c92SGill B. }).disableSelection(); 80*f4b18c92SGill B. 81*f4b18c92SGill B. // Fix: Event Delegation for "Add Card" 82*f4b18c92SGill B. $board.on('click', '.add-card-btn', function() { 83*f4b18c92SGill B. var name = prompt("Job Name:"); 84*f4b18c92SGill B. if (!name) return; 85*f4b18c92SGill B. var imp = (prompt("Importance (high, medium, low):", "medium") || "medium").toLowerCase(); 86*f4b18c92SGill B. var cardId = "c" + Date.now(); 87*f4b18c92SGill B. var note = "There are no notes on this card yet."; 88*f4b18c92SGill B. 89*f4b18c92SGill B. var $newCard = jQuery(` 90*f4b18c92SGill B. <div class="kanban-card ${imp}" data-id="${cardId}"> 91*f4b18c92SGill B. <input type="checkbox"> 92*f4b18c92SGill B. <strong class="card-title">${name}</strong> 93*f4b18c92SGill B. <div class="card-desc">Click to add description...</div> 94*f4b18c92SGill B. <div style="color:black;">Refresh for Notes</div> 95*f4b18c92SGill B. <div class="card-note"></div> 96*f4b18c92SGill B. </div> 97*f4b18c92SGill B. `); 98*f4b18c92SGill B. 99*f4b18c92SGill B. jQuery(this).closest('.kanban-col').find('.cards-container').append($newCard); 100*f4b18c92SGill B. saveCardData($newCard); 101*f4b18c92SGill B. }); 102*f4b18c92SGill B. 103*f4b18c92SGill B. //make the kanban cards add note button clickable 104*f4b18c92SGill B. $mycard.on('click', '.btn-notes', function() { 105*f4b18c92SGill B. //var $note = jQuery(this); 106*f4b18c92SGill B. //var currentNote = $note.text(); 107*f4b18c92SGill B. //alert('this is my click'); 108*f4b18c92SGill B. var mynote = prompt("Add Note:",""); 109*f4b18c92SGill B. //Get the current username 110*f4b18c92SGill B. //var userlogin = JSINFO['user']; // Login username 111*f4b18c92SGill B. // Standard DokuWiki configuration object 112*f4b18c92SGill B. //attempt to query the user from the interface first 113*f4b18c92SGill B. var userlogin = jQuery('meta[name="plugin_do_user"]').attr('content'); 114*f4b18c92SGill B. //console.log(JSINFO); //debugging line 115*f4b18c92SGill B. if (!userlogin && typeof JSINFO !== 'undefined') { 116*f4b18c92SGill B. //pull the user from php if the interface query fails 117*f4b18c92SGill B. userlogin = JSINFO['plugin_do_user']; 118*f4b18c92SGill B. } 119*f4b18c92SGill B. //return currentNote + " | " + note; 120*f4b18c92SGill B. if(mynote !== null){ 121*f4b18c92SGill B. //Sanitize the input 122*f4b18c92SGill B. function sanitizeInlineCommands(inputText) { 123*f4b18c92SGill B. // Regex to match "javascript:" and other common inline command patterns 124*f4b18c92SGill B. const commandPattern = /javascript:|on\w+=|style="[^"]*expression[^"]*"|\+/gi; 125*f4b18c92SGill B. 126*f4b18c92SGill B. // Replace found commands with an empty string 127*f4b18c92SGill B. return inputText.replace(commandPattern, ''); 128*f4b18c92SGill B. } 129*f4b18c92SGill B. 130*f4b18c92SGill B. // Example usage 131*f4b18c92SGill B. //const userInput = 'Hello <a href="javascript:alert(1)">Click</a>! <img src=x onerror=alert(1)>'; 132*f4b18c92SGill B. const cleanedNote = sanitizeInlineCommands(mynote); 133*f4b18c92SGill B. //end sanitize 134*f4b18c92SGill B. //Get the current date string 135*f4b18c92SGill B. const date = new Date().toLocaleDateString('en-US'); 136*f4b18c92SGill B. //Get the current time string 137*f4b18c92SGill B. const mytime = new Date().toLocaleTimeString(); 138*f4b18c92SGill B. //Get the closest kanban-card to the object clicked 139*f4b18c92SGill B. var $note = jQuery(this).closest('.kanban-card'); 140*f4b18c92SGill B. // filter() checks if $note IS the class; find() checks if it's INSIDE $note 141*f4b18c92SGill B. var $target = $note.filter('.card-note').add($note.find('.card-note')); 142*f4b18c92SGill B. // 2. Attach new data to the inner div with <br> delimiter 143*f4b18c92SGill B. $target.append("<br>+ " + userlogin + " - " + date + ":" + mytime + " - " + cleanedNote); 144*f4b18c92SGill B. 145*f4b18c92SGill B. saveCardData($note.closest('.kanban-card')); 146*f4b18c92SGill B. } 147*f4b18c92SGill B. }); 148*f4b18c92SGill B. 149*f4b18c92SGill B. // Fix: Event Delegation for Clickable Description 150*f4b18c92SGill B. $board.on('click', '.card-desc', function() { 151*f4b18c92SGill B. var $desc = jQuery(this); 152*f4b18c92SGill B. var currentText = $desc.text() === "Click to add description..." ? "" : $desc.text(); 153*f4b18c92SGill B. var newDesc = prompt("Enter Description:", currentText); 154*f4b18c92SGill B. if (newDesc !== null) { 155*f4b18c92SGill B. $desc.text(newDesc || "Click to add description..."); 156*f4b18c92SGill B. saveCardData($desc.closest('.kanban-card')); 157*f4b18c92SGill B. } 158*f4b18c92SGill B. }); 159*f4b18c92SGill B. // Fix: Event Delegation for Clickable Checkbox 160*f4b18c92SGill B. $board.on('click', '.checkbox-inline', function() { 161*f4b18c92SGill B. var $checkit = jQuery(this); 162*f4b18c92SGill B. var currentVal = $checkit.prop('checked'); 163*f4b18c92SGill B. if ($checkit){ 164*f4b18c92SGill B. saveCardData($checkit.closest('.kanban-card')); 165*f4b18c92SGill B. } 166*f4b18c92SGill B. }); 167*f4b18c92SGill B. 168*f4b18c92SGill B. 169*f4b18c92SGill B.}); 170