• 1

Read this first!

We do not monitor these forums. The forum is provided to exchange information and experience with other users ONLY. Forum responses are not guaranteed.

However, please submit a ticket if you have an active subscription and wish to receive support. Our ticketing system is the only way of getting in touch with RSJoomla! and receiving the official RSJoomla! Customer Support.

For more information, the Support Policy is located here.

Thank you!

TOPIC: Auto insert speaker from description

Auto insert speaker from description 2 months 2 weeks ago #44103

I tried a method to automatically insert speakers by scanning the event description.
When the event description contains the string "speaker=", the corresponding value is automatically added to the speaker section.
I’m facing one issue though: I’d like the insertion to happen in real time, but currently, I need to save the event in order to see the changes.

who can you help me?

<?php
/**
* @package RSEvents!Pro
* @copyright (C) 2020 www.rsjoomla.com
* @license GPL, www.gnu.org/copyleft/gpl.html
*/

defined('_JEXEC') or die('Restricted access');

use Joomla\CMS\Language\Text;
use Joomla\CMS\Factory;
?>

<fieldset class="options-form">
<?php
// Messaggio automatico di suggerimento speaker (container)
echo '<div id="speakers-suggestion-top" style="
display:none;
margin-bottom:10px;
padding:8px 12px;
border:1px solid #f0ad4e;
border-radius:6px;
background:#fcf8e3;
font-weight:500;
color:#8a6d3b;">
</div>';
?>

<legend><?php echo Text::_('COM_RSEVENTSPRO_EVENT_INFORMATION'); ?></legend>

<?php // Nome evento ?>
<?php echo $this->form->renderField('name'); ?>

<?php // Pubblica / Featured ?>
<?php echo $this->form->renderField('published'); ?>
<?php echo $this->form->renderField('featured'); ?>

<?php // Data/Ora inizio e fine ?>
<?php echo $this->form->renderField('start'); ?>
<div id="rsepro-end-date-id">
<?php echo $this->form->renderField('end'); ?>
</div>

<?php // Tutto il giorno ?>
<?php echo $this->form->renderField('allday'); ?>

<?php // Eventi ricorrenti ?>
<?php if (empty($this->item->parent)) : ?>
<?php echo $this->form->renderField('recurring'); ?>
<div id="rsepro-recurring-info" style="display: <?php echo $this->item->recurring ? 'block' : 'none'; ?>;">
<?php echo $this->form->renderField('interval'); ?>
<?php echo $this->form->renderField('cycle'); ?>
<?php echo $this->form->renderField('limit'); ?>
</div>
<?php endif; ?>
<?php echo $this->form->renderField('comments'); ?>
<?php echo $this->form->renderField('registration'); ?>
<?php echo $this->form->renderField('rsvp'); ?>
<div id="rsepro-feedback-id" style="display:<?php echo $this->item->registration || $this->item->rsvp ? 'inline-block' : 'none'; ?>;"><?php echo $this->form->renderField('feedback'); ?></div>
<div id="rsepro-feedback-disable"<?php echo !$this->item->feedback ? ' style="display: none;"' : ''; ?>><?php echo $this->form->renderField('disable_feedback'); ?></div>

<div class="control-group">
<div class="control-label">
<label for="jform_location"><?php echo Text::_('COM_RSEVENTSPRO_EVENT_LOCATION'); ?></label>
</div>
<div class="controls">
<input class="span10 form-control" type="text" value="<?php echo $this->escape($this->item->locationname); ?>" id="rsepro-location" autocomplete="off" />
<?php echo $this->form->getInput('location'); ?>

<div class="rsepro-locations-container" style="visibility: hidden;">
<div class="<?php echo RSEventsproAdapterGrid::card(); ?> well-small">
<div class="card-body">
<ul id="rsepro-locations" class="<?php echo RSEventsproAdapterGrid::styles(array('unstyled')); ?> rsepro-well"></ul>
</div>
</div>
</div>

<div class="rsepro-location-container" style="visibility: hidden; overflow: hidden;">
<div class="<?php echo RSEventsproAdapterGrid::card(); ?> well-small rsepro-well">
<div class="card-body">
<div class="control-group">
<div class="control-label">
<label for="location_address"><?php echo Text::_('COM_RSEVENTSPRO_EVENT_LOCATION_ADDRESS'); ?></label>
</div>
<div class="controls">
<input class="span10 form-control" type="text" value="" id="location_address" name="location_address" />
</div>
</div>
<div class="control-group">
<div class="control-label">
<label for="location_URL"><?php echo Text::_('COM_RSEVENTSPRO_LOCATION_URL'); ?></label>
</div>
<div class="controls">
<input class="span10 form-control" type="text" value="" id="location_URL" name="location_URL" />
</div>
</div>
<div class="control-group">
<div class="control-label">
<label for="location_description"><?php echo Text::_('COM_RSEVENTSPRO_EVENT_LOCATION_DESCRIPTION'); ?></label>
</div>
<div class="controls">
<textarea id="location_description" name="location_description" class="span10 form-control"></textarea>
</div>
</div>
<?php if ($this->config->map) { ?>
<div class="control-group">
<div class="controls">
<div class="rsepro-location-map" id="rsepro-location-map"></div>
<input type="hidden" name="location_coordinates" value="" id="location_coordinates" />
</div>
</div>
<?php } ?>
<div class="control-group">
<div class="controls">
<button type="button" class="btn btn-primary" id="rsepro-save-location"><?php echo Text::_('COM_RSEVENTSPRO_EVENT_LOCATION_ADD_LOCATION'); ?></button>
<button type="button" class="btn btn-danger" id="rsepro-cancel-location"><?php echo Text::_('COM_RSEVENTSPRO_GLOBAL_CANCEL_BTN'); ?></button>
</div>
</div>
</div>
</div>
</div>

</div>
</div>

<?php // Abilita Commenti, Registrazione, RSVP ?>
<?php echo $this->form->renderField('enable_comments'); ?>
<?php echo $this->form->renderField('enable_registration'); ?>
<?php echo $this->form->renderField('enable_rsvp'); ?>

<?php // Località e altre dipendenze ?>
<?php echo $this->dependencies->renderField('location'); ?>
<?php echo $this->dependencies->renderField('speakers'); ?>
<?php echo $this->dependencies->renderField('sponsors'); ?>
<?php echo $this->dependencies->renderField('groups'); ?>

<?php // Itemid, descrizioni ?>
<?php echo $this->form->renderField('itemid'); ?>
<?php echo $this->form->renderField('small_description'); ?>
<?php echo $this->form->getInput('description'); ?>

<div class="clearfix"></div>

<div class="form-actions">
<button class="btn btn-success rsepro-event-update" type="button">
<?php echo Text::_('COM_RSEVENTSPRO_UPDATE_EVENT'); ?>
</button>
<button class="btn btn-danger rsepro-event-cancel" type="button">
<?php echo Text::_('COM_RSEVENTSPRO_GLOBAL_CANCEL_BTN'); ?>
</button>
</div>
</fieldset>

<script>
document.addEventListener('DOMContentLoaded', function() {
// --- Funzioni varie della form ---
// 1) Cambio automatico dell'ora di fine (+3h)
var startInput = document.getElementById('jform_start');
var endInput = document.getElementById('jform_end');

if (startInput && endInput) {
startInput.addEventListener('change', function(){
var startDate = new Date(startInput.value);
if (!isNaN(startDate.getTime())) {
var endDate = new Date(startDate.getTime() + 3 * 60 * 60 * 1000);
var year = endDate.getFullYear();
var month = ('0' + (endDate.getMonth() + 1)).slice(-2);
var day = ('0' + endDate.getDate()).slice(-2);
var hours = ('0' + endDate.getHours()).slice(-2);
var mins = ('0' + endDate.getMinutes()).slice(-2);
endInput.value = year + '-' + month + '-' + day + ' ' + hours + ':' + mins;
}
});
}

// 2) Warning eventi simili
var nameInput = document.getElementById('jform_name');
if (!nameInput) return;
var nameWarning = document.createElement('div');
nameWarning.id = "name-warning";
nameWarning.style.color = "red";
nameWarning.style.display = "none";
nameWarning.style.marginTop = "5px";
nameWarning.textContent = "Attenzione: un evento simile è già presente nel database.";
nameInput.parentNode.appendChild(nameWarning);

var similarEventsContainer = document.createElement('div');
similarEventsContainer.id = "similar-events-list";
similarEventsContainer.style.color = "red";
similarEventsContainer.style.display = "none";
similarEventsContainer.style.marginTop = "5px";
nameInput.parentNode.appendChild(similarEventsContainer);

var existingEvents = <?php
$db = Factory::getDbo();
$query = $db->getQuery(true)
->select($db->quoteName())
->from($db->quoteName('#__rseventspro_events'))
->where($db->quoteName('published') . ' = 1');
$db->setQuery($query);
echo json_encode($db->loadObjectList());
?>;
function cleanString(str) {
return str.replace(/[^\w\s]|_/g, "").replace(/\s+/g, " ").trim();
}
function levenshtein(a, b) {
if (a.length === 0) return b.length;
if (b.length === 0) return a.length;
var matrix = [];
for (var i = 0; i <= b.length; i++) { matrix = ; }
for (var j = 0; j <= a.length; j++) { matrix[0][j] = j; }
for (var i = 1; i <= b.length; i++) {
for (var j = 1; j <= a.length; j++) {
if (b.charAt(i-1) === a.charAt(j-1)) {
matrix[j] = matrix[i-1][j-1];
} else {
matrix[j] = Math.min(
matrix[i-1][j-1] + 1,
matrix[j-1] + 1,
matrix[i-1][j] + 1
);
}
}
}
return matrix[b.length][a.length];
}
function similarity(s1, s2) {
s1 = cleanString(s1.toLowerCase());
s2 = cleanString(s2.toLowerCase());
var longer = s1.length >= s2.length ? s1 : s2;
var shorter = s1.length < s2.length ? s1 : s2;
var len = longer.length;
if (len === 0) return 100;
return ((len - levenshtein(longer, shorter)) / len) * 100;
}
nameInput.addEventListener('input', function(){
var v = this.value.trim();
if (v.length < 3) {
nameWarning.style.display = 'none';
similarEventsContainer.style.display = 'none';
similarEventsContainer.innerHTML = "";
return;
}
var found = existingEvents.filter(function(ev){
return similarity(v, ev.name) >= 50;
});
if (found.length > 0) {
nameWarning.style.display = 'block';
var html = "<strong>Eventi simili trovati:</strong><br/>";
found.forEach(function(ev){
var link = 'index.php?option=com_rseventspro&view=event&layout=edit&id=' + ev.id + '&tab=0';
html += '<a href="' + link + '" target=\"_blank\">' + ev.name + ' - ' + ev.start + '</a><br/>';
});
similarEventsContainer.innerHTML = html;
similarEventsContainer.style.display = 'block';
} else {
nameWarning.style.display = 'none';
similarEventsContainer.style.display = 'none';
similarEventsContainer.innerHTML = "";
}
});

// 3) Auto-flag registrazione
var autoApprove = document.getElementById('jform_registration');
if (autoApprove) {
autoApprove.checked = true;
}
});
</script>

<?php
/// Elenco speaker (id e name) dalla tabella rseventspro_speakers
$db = Factory::getDbo();
$spQuery = $db->getQuery(true)
->select($db->quoteName())
->from($db->quoteName('#__rseventspro_speakers'));
$db->setQuery($spQuery);
$speakersList = $db->loadObjectList();
?>

<script>
(function() {
const speakersData = <?php echo json_encode($speakersList ?: []); ?>;
const nameToId = {};
const speakerNames = [];
speakersData.forEach(s => {
if (!s) return;
const name = (s.name || '').trim();
if (!name) return;
speakerNames.push(name);
nameToId[name.toLowerCase()] = String(s.id);
});

function escapeRegExp(s) {
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

function findSpeakersSelect() {
return document.getElementById('speakers');
}

function ensureOptions(select, ids, nameToId) {
const existing = new Set(Array.from(select.options).map(o => String(o.value)));
ids.forEach(id => {
if (!existing.has(String(id))) {
const name = Object.keys(nameToId).find(nm => nameToId[nm] == id);
if (name) {
const opt = document.createElement('option');
opt.value = id;
opt.text = name.charAt(0).toUpperCase() + name.slice(1);
select.appendChild(opt);
}
}
});
}

function setSelectedValues(select, values) {
if (!select) return false;
// Unione manuali + automatici, no duplicati
const manualSelected = Array.from(select.selectedOptions || []).map(o => String(o.value));
const allSelected = Array.from(new Set([...manualSelected, ...(values || []).map(String)]));
for (let i = 0; i < select.options.length; i++) {
const opt = select.options;
opt.selected = allSelected.includes(String(opt.value));
}
if (window.Choices && select._choices) {
select._choices.setChoiceByValue(allSelected);
select._choices._render();
}
select.dispatchEvent(new Event('change', { bubbles: true }));
}


function updateSuggestionUI(names) {
const container = document.getElementById('speakers-suggestion-top');
if (!container) return;
if (names && names.length) {
container.textContent = 'Suggerimento: nel testo sono presenti questi speaker: ' + names.join(', ') + '. Sono stati selezionati automaticamente. Puoi modificare la selezione manualmente.';
container.style.display = 'block';
} else {
container.textContent = '';
container.style.display = 'none';
}
}

function getDescriptionText() {
try {
if (window.tinymce && tinymce.activeEditor && typeof tinymce.activeEditor.getContent === 'function') {
return (tinymce.activeEditor.getContent({ format: 'text' }) || '').toLowerCase();
}
} catch (e) {}
const el = document.getElementById('jform_description');
if (el) return (el.value || el.textContent || '').toLowerCase();
const elAlt = document.querySelector('[name="jform[description]"]');
return ((elAlt && (elAlt.value || elAlt.textContent)) || '').toLowerCase();
}

// Aggiorna il select speakers ogni volta che nella descrizione appare uno speaker
function evaluate() {
const text = getDescriptionText();
if (!text || !speakerNames.length) {
updateSuggestionUI([]);
return;
}
const hits = [];
speakerNames.forEach(nm => {
if (!nm) return;
const re = new RegExp('\\b' + escapeRegExp(nm.toLowerCase()) + '\\b', 'i');
if (re.test(text)) hits.push(nm);
});
const uniqueNames = Array.from(new Set(hits));
updateSuggestionUI(uniqueNames);
// Qui aggiorniamo SEMPRE il select appena viene trovato uno speaker nel testo
const ids = uniqueNames.map(n => nameToId[n.toLowerCase()]).filter(Boolean);
const sel = findSpeakersSelect();
if (!sel) return;
ensureOptions(sel, ids, nameToId);
setSelectedValues(sel, ids);
}

document.addEventListener('DOMContentLoaded', function() {
const sel = findSpeakersSelect();
if (window.Choices && sel) {
sel._choices = new Choices(sel, {
removeItemButton: true,
shouldSort: false
});
}
// Aggiorna sempre il select speakers quando la descrizione cambia
const descEl = document.getElementById('jform_description') || document.querySelector('[name="jform[description]"]');
if (descEl) {
descEl.addEventListener('input', evaluate);
descEl.addEventListener('blur', evaluate);
descEl.addEventListener('change', evaluate);
}
// Per TinyMCE e altri editor WYSIWYG
setTimeout(evaluate, 200);
let poll = setInterval(evaluate, 1000);
window.addEventListener('beforeunload', function () { clearInterval(poll); });
});
})();

</script>
The administrator has disabled public write access.
  • 1

Read this first!

We do not monitor these forums. The forum is provided to exchange information and experience with other users ONLY. Forum responses are not guaranteed.

However, please submit a ticket if you have an active subscription and wish to receive support. Our ticketing system is the only way of getting in touch with RSJoomla! and receiving the official RSJoomla! Customer Support.

For more information, the Support Policy is located here.

Thank you!