| 1 |
<?php |
| 2 |
/** |
| 3 |
* @package VikBooking |
| 4 |
* @subpackage com_vikbooking |
| 5 |
* @author Alessio Gaggii - e4j - Extensionsforjoomla.com |
| 6 |
* @copyright Copyright (C) 2018 e4j - Extensionsforjoomla.com. All rights reserved. |
| 7 |
* @license GNU General Public License version 2 or later; see LICENSE |
| 8 |
* @link https://vikwp.com |
| 9 |
*/ |
| 10 |
|
| 11 |
defined('ABSPATH') or die('No script kiddies please!'); |
| 12 |
|
| 13 |
/** |
| 14 |
* Class handler for admin widget "sticky notes". This widget has settings. |
| 15 |
* |
| 16 |
* @since 1.14.0 (J) - 1.4.0 (WP) |
| 17 |
*/ |
| 18 |
class VikBookingAdminWidgetStickyNotes extends VikBookingAdminWidget |
| 19 |
{ |
| 20 |
/** |
| 21 |
* The instance counter of this widget. Since we do not load individual parameters |
| 22 |
* for each widget's instance, we use a static counter to determine its settings. |
| 23 |
* |
| 24 |
* @var int |
| 25 |
*/ |
| 26 |
protected static $instance_counter = -1; |
| 27 |
|
| 28 |
/** |
| 29 |
* We detect the Operating System through the browser useer agent |
| 30 |
* to display different information about the shortcuts to use. |
| 31 |
* |
| 32 |
* @var string |
| 33 |
*/ |
| 34 |
protected $isMac = false; |
| 35 |
|
| 36 |
/** |
| 37 |
* Class constructor will define the widget name and identifier. |
| 38 |
*/ |
| 39 |
public function __construct() |
| 40 |
{ |
| 41 |
// call parent constructor |
| 42 |
parent::__construct(); |
| 43 |
|
| 44 |
// declare name, description and identifier |
| 45 |
$this->widgetName = JText::translate('VBO_W_STICKYN_TITLE'); |
| 46 |
$this->widgetDescr = JText::translate('VBO_W_STICKYN_DESCR'); |
| 47 |
$this->widgetId = basename(__FILE__, '.php'); |
| 48 |
|
| 49 |
/** |
| 50 |
* Define widget and icon and style name. |
| 51 |
* |
| 52 |
* @since 1.15.0 (J) - 1.5.0 (WP) |
| 53 |
*/ |
| 54 |
$this->widgetIcon = '<i class="' . VikBookingIcons::i('thumbtack') . '"></i>'; |
| 55 |
$this->widgetStyleName = 'yellow'; |
| 56 |
|
| 57 |
// load widget's settings |
| 58 |
$this->widgetSettings = $this->loadSettings(); |
| 59 |
|
| 60 |
// determine if the operating system is MacOS or iOS |
| 61 |
$ua = JFactory::getApplication()->input->server->getString('HTTP_USER_AGENT', ''); |
| 62 |
if (stripos($ua, 'windows') === false && (stripos($ua, 'mac') !== false || stripos($ua, 'iphone') !== false || stripos($ua, 'ipad') !== false)) { |
| 63 |
$this->isMac = true; |
| 64 |
} |
| 65 |
} |
| 66 |
|
| 67 |
/** |
| 68 |
* Custom method for this widget only to update one sticky note. |
| 69 |
* The method is called by the admin controller through an AJAX request. |
| 70 |
* The visibility should be public, it should not exit the process, and |
| 71 |
* any content sent to output will be returned to the AJAX response. |
| 72 |
* |
| 73 |
* @param int $force_note_index the new index can be forced to insert a new note. |
| 74 |
* @param int $force_instance the widget's instance to force. |
| 75 |
* @param string $force_txt the text of the sticky note to force. |
| 76 |
* |
| 77 |
* @return void it may output a log with the new widget instance assigned. |
| 78 |
*/ |
| 79 |
public function updateStickyNote($force_note_index = null, $force_instance = null, $force_txt = null) |
| 80 |
{ |
| 81 |
$note_instance = VikRequest::getInt('note_instance', -1, 'request'); |
| 82 |
$note_txt = VikRequest::getString('note_txt', '', 'request', VIKREQUEST_ALLOWRAW); |
| 83 |
$note_index = VikRequest::getInt('note_index', 0, 'request'); |
| 84 |
|
| 85 |
if ($force_note_index !== null && $force_note_index >= 0) { |
| 86 |
// use the forced index instead |
| 87 |
$note_index = $force_note_index; |
| 88 |
} |
| 89 |
|
| 90 |
if ($force_instance !== null && $force_instance >= 0) { |
| 91 |
// use the forced instance instead |
| 92 |
$note_instance = $force_instance; |
| 93 |
} |
| 94 |
|
| 95 |
if (is_string($force_txt) && strlen($force_txt)) { |
| 96 |
// use the forced text instead |
| 97 |
$note_txt = $force_txt; |
| 98 |
} |
| 99 |
|
| 100 |
// make sure the settings of the widget are an array |
| 101 |
if (!is_array($this->widgetSettings)) { |
| 102 |
$this->widgetSettings = array(); |
| 103 |
} |
| 104 |
|
| 105 |
// create the new sticky note object |
| 106 |
$username = $this->getLoggedUserName(); |
| 107 |
$sticky_note = new stdClass; |
| 108 |
$sticky_note->html = $note_txt; |
| 109 |
$sticky_note->ts = time(); |
| 110 |
if (!empty($username)) { |
| 111 |
$sticky_note->user = $username; |
| 112 |
} |
| 113 |
|
| 114 |
// eventually append debugging result |
| 115 |
$result_log = ''; |
| 116 |
|
| 117 |
// eventually append the new widget instance assigned for newly added widgets via AJAX |
| 118 |
$new_instance_response = ''; |
| 119 |
|
| 120 |
if (!count($this->widgetSettings)) { |
| 121 |
// push the first sticky note as the first instance of this widget |
| 122 |
$this->widgetSettings = array( |
| 123 |
array($sticky_note) |
| 124 |
); |
| 125 |
$result_log = 'pushing the first sticky note as the first instance of the widget'; |
| 126 |
$new_instance_response = '[instance=0]'; |
| 127 |
} elseif (isset($this->widgetSettings[$note_instance])) { |
| 128 |
// this instance was saved already |
| 129 |
if (isset($this->widgetSettings[$note_instance][$note_index])) { |
| 130 |
// we already have this exact sticky note index, so we replace it |
| 131 |
$this->widgetSettings[$note_instance][$note_index] = $sticky_note; |
| 132 |
$result_log = 'replacing requested note index in existing widget instance'; |
| 133 |
} else { |
| 134 |
// we push a new sticky note |
| 135 |
array_push($this->widgetSettings[$note_instance], $sticky_note); |
| 136 |
$result_log = 'adding a new note to the existing widget instance'; |
| 137 |
} |
| 138 |
} else { |
| 139 |
// this is a new instance of the widget, which has settings already - push the new instance and the new sticky note |
| 140 |
array_push($this->widgetSettings, array($sticky_note)); |
| 141 |
$result_log = 'pushing a new instance and note to the settings'; |
| 142 |
$new_instance_response = '[instance=' . (count($this->widgetSettings) - 1) . ']'; |
| 143 |
} |
| 144 |
|
| 145 |
// update widget's settings |
| 146 |
$this->updateSettings(json_encode($this->widgetSettings)); |
| 147 |
|
| 148 |
echo 'e4j.ok' . (!empty($result_log) ? '(' . $result_log . ')' : '') . $new_instance_response; |
| 149 |
} |
| 150 |
|
| 151 |
/** |
| 152 |
* Custom method for this widget only to delete one sticky note. |
| 153 |
* The method is called by the admin controller through an AJAX request. |
| 154 |
* The visibility should be public, it should not exit the process, and |
| 155 |
* any content sent to output will be returned to the AJAX response. |
| 156 |
*/ |
| 157 |
public function deleteStickyNote() |
| 158 |
{ |
| 159 |
$note_instance = VikRequest::getInt('note_instance', -1, 'request'); |
| 160 |
$note_index = VikRequest::getInt('note_index', 0, 'request'); |
| 161 |
|
| 162 |
// make sure the settings of the widget are an array |
| 163 |
if (!is_array($this->widgetSettings)) { |
| 164 |
echo 'e4j.error.no settings found'; |
| 165 |
return; |
| 166 |
} |
| 167 |
|
| 168 |
// make sure the instance of the widget exists |
| 169 |
if (!isset($this->widgetSettings[$note_instance]) || !is_array($this->widgetSettings[$note_instance])) { |
| 170 |
echo 'e4j.error.instance not found'; |
| 171 |
return; |
| 172 |
} |
| 173 |
|
| 174 |
// make sure the index of the note exists |
| 175 |
if (!isset($this->widgetSettings[$note_instance][$note_index])) { |
| 176 |
echo 'e4j.error.note index not found, maybe it was never updated before'; |
| 177 |
return; |
| 178 |
} |
| 179 |
|
| 180 |
// splice the array to remove the requested note |
| 181 |
array_splice($this->widgetSettings[$note_instance], $note_index, 1); |
| 182 |
|
| 183 |
// update widget's settings |
| 184 |
$this->updateSettings(json_encode($this->widgetSettings)); |
| 185 |
|
| 186 |
echo 'e4j.ok'; |
| 187 |
} |
| 188 |
|
| 189 |
/** |
| 190 |
* Custom method for this widget only to sort one sticky note. |
| 191 |
* The method is called by the admin controller through an AJAX request. |
| 192 |
* The visibility should be public, it should not exit the process, and |
| 193 |
* any content sent to output will be returned to the AJAX response. |
| 194 |
*/ |
| 195 |
public function sortStickyNote() |
| 196 |
{ |
| 197 |
$note_instance = VikRequest::getInt('note_instance', -1, 'request'); |
| 198 |
$note_index_new = VikRequest::getInt('note_index_new', 0, 'request'); |
| 199 |
$note_index_old = VikRequest::getInt('note_index_old', 0, 'request'); |
| 200 |
|
| 201 |
if ($note_index_new == $note_index_old) { |
| 202 |
// nothing to do, as notes can be sorted only within the same instance |
| 203 |
echo 'e4j.error.same position given for sticky note'; |
| 204 |
return; |
| 205 |
} |
| 206 |
|
| 207 |
// make sure the settings of the widget are an array |
| 208 |
if (!is_array($this->widgetSettings)) { |
| 209 |
echo 'e4j.error.no settings found'; |
| 210 |
return; |
| 211 |
} |
| 212 |
|
| 213 |
// make sure the instance of the widget exists |
| 214 |
if (!isset($this->widgetSettings[$note_instance]) || !is_array($this->widgetSettings[$note_instance])) { |
| 215 |
echo 'e4j.error.instance not found'; |
| 216 |
return; |
| 217 |
} |
| 218 |
|
| 219 |
// make sure the old index of the note exists |
| 220 |
if (!isset($this->widgetSettings[$note_instance][$note_index_old])) { |
| 221 |
// check if this note was moved before getting saved, so as soon as it was added |
| 222 |
if (count($this->widgetSettings[$note_instance]) == $note_index_old) { |
| 223 |
// append the newly created (empty) note before moving it |
| 224 |
$this->updateStickyNote($note_index_old, $note_instance); |
| 225 |
// reload the widget's settings after they have been updated with the new note |
| 226 |
$this->widgetSettings = $this->loadSettings(); |
| 227 |
// proceed below with moving the sticky note |
| 228 |
} else { |
| 229 |
// unable to proceed |
| 230 |
echo 'e4j.error.original note index not found, maybe it was never updated before'; |
| 231 |
return; |
| 232 |
} |
| 233 |
} |
| 234 |
|
| 235 |
// make sure the new index can fit |
| 236 |
if ($note_index_new > (count($this->widgetSettings[$note_instance]) - 1)) { |
| 237 |
echo 'e4j.error.new index exceeds the highest position available'; |
| 238 |
return; |
| 239 |
} |
| 240 |
|
| 241 |
// move the sticky note from the old index to the new index |
| 242 |
$extracted = array_splice($this->widgetSettings[$note_instance], $note_index_old, 1); |
| 243 |
array_splice($this->widgetSettings[$note_instance], $note_index_new, 0, $extracted); |
| 244 |
|
| 245 |
// update widget's settings |
| 246 |
$this->updateSettings(json_encode($this->widgetSettings)); |
| 247 |
|
| 248 |
echo 'e4j.ok'; |
| 249 |
} |
| 250 |
|
| 251 |
/** |
| 252 |
* Preload the necessary assets. |
| 253 |
* |
| 254 |
* @return void |
| 255 |
*/ |
| 256 |
public function preload() |
| 257 |
{ |
| 258 |
// JS lang def |
| 259 |
JText::script('VBO_STICKYN_TITLE'); |
| 260 |
JText::script('VBO_STICKYN_TEXT'); |
| 261 |
JText::script('VBO_STICKYN_TEXT2'); |
| 262 |
JText::script('VBO_STICKYN_CUSTOMURI'); |
| 263 |
JText::script('VBO_WIDGETS_CONFRMELEM'); |
| 264 |
} |
| 265 |
|
| 266 |
public function render(?VBOMultitaskData $data = null) |
| 267 |
{ |
| 268 |
// increase widget's instance counter |
| 269 |
static::$instance_counter++; |
| 270 |
|
| 271 |
// check whether the widget is being rendered via AJAX when adding it through the customizer |
| 272 |
$is_ajax = $this->isAjaxRendering(); |
| 273 |
|
| 274 |
// check whether we are in the multitask panel |
| 275 |
$is_multitask = $this->isMultitaskRendering(); |
| 276 |
|
| 277 |
// check whether the widget requires settings |
| 278 |
$needs_settings = !$is_ajax; |
| 279 |
$data_instance = !$is_ajax ? static::$instance_counter : '-1'; |
| 280 |
if ($is_multitask && $is_ajax) { |
| 281 |
$guess_inst_counter = $this->guessMultitaskStickyInstance($data); |
| 282 |
if ($guess_inst_counter !== false) { |
| 283 |
// force the loading of the guessed widget instance's settings |
| 284 |
static::$instance_counter = $guess_inst_counter; |
| 285 |
$data_instance = $guess_inst_counter; |
| 286 |
$needs_settings = true; |
| 287 |
} |
| 288 |
} |
| 289 |
|
| 290 |
// generate a unique ID for the sticky notes wrapper instance |
| 291 |
$wrapper_instance = !$is_ajax ? static::$instance_counter : rand(); |
| 292 |
$wrapper_id = 'vbo-widget-sticky-' . $wrapper_instance; |
| 293 |
|
| 294 |
// load the settings for this specific instance of the widget |
| 295 |
$instance_settings = array(); |
| 296 |
if ($needs_settings && is_array($this->widgetSettings) && isset($this->widgetSettings[static::$instance_counter])) { |
| 297 |
$instance_settings = is_array($this->widgetSettings[static::$instance_counter]) ? $this->widgetSettings[static::$instance_counter] : array(); |
| 298 |
} |
| 299 |
|
| 300 |
?> |
| 301 |
<div class="vbo-admin-widget-wrapper"> |
| 302 |
<div class="vbo-admin-widget-head"> |
| 303 |
<h4><?php echo $this->widgetIcon; ?> <span><?php echo $this->widgetName; ?></span></h4> |
| 304 |
<div class="btn-toolbar pull-right vbo-btn-toolbar-hastext"> |
| 305 |
<span class="vbo-sticky-shortcuts-help"<?php echo count($instance_settings) ? ' style="display: none;"' : ''; ?>> |
| 306 |
<?php |
| 307 |
echo $this->vbo_app->createPopover(array( |
| 308 |
'title' => JText::translate('VBO_W_STICKYN_HELP_TITLE'), |
| 309 |
'content' => JText::translate(($this->isMac ? 'VBO_W_STICKYN_HELP_DESCR_MAC' : 'VBO_W_STICKYN_HELP_DESCR')), |
| 310 |
'icon_class' => VikBookingIcons::i('keyboard'), |
| 311 |
'placement' => 'left' |
| 312 |
)); |
| 313 |
?> |
| 314 |
</span> |
| 315 |
</div> |
| 316 |
</div> |
| 317 |
<div id="<?php echo $wrapper_id; ?>" class="vbo-admin-widget-sticky-notes-wrap" data-instance="<?php echo $data_instance; ?>"> |
| 318 |
<ul class="vbo-admin-widget-sticky-notes-list"> |
| 319 |
<?php |
| 320 |
foreach ($instance_settings as $k => $sticky_note) { |
| 321 |
?> |
| 322 |
<li class="vbo-sticky-note"> |
| 323 |
<div class="vbo-sticky-note-cmds"> |
| 324 |
<span class="vbo-sticky-note-cmd-drag"><?php VikBookingIcons::e('ellipsis-v'); ?></span> |
| 325 |
<span class="vbo-sticky-note-cmd-trash" onclick="vboWidgetStickyNoteDelete(this);"><?php VikBookingIcons::e('trash'); ?></span> |
| 326 |
</div> |
| 327 |
<div contenteditable="true" spellcheck="false" class="vbo-widget-sticky-canvas"> |
| 328 |
<?php echo $sticky_note->html; ?> |
| 329 |
</div> |
| 330 |
<div class="vbo-sticky-note-sign"> |
| 331 |
<span class="vbo-sticky-note-sign-dt"><?php echo date(str_replace("/", $this->datesep, $this->df).' H:i', $sticky_note->ts); ?></span> |
| 332 |
<?php |
| 333 |
if (!empty($sticky_note->user)) { |
| 334 |
?> |
| 335 |
<span class="vbo-sticky-note-sign-user"><?php echo $sticky_note->user; ?></span> |
| 336 |
<?php |
| 337 |
} |
| 338 |
?> |
| 339 |
</div> |
| 340 |
</li> |
| 341 |
<?php |
| 342 |
} |
| 343 |
?> |
| 344 |
<li class="vbo-sticky-note-add"> |
| 345 |
<div class="vbo-sticky-note-add-inner" onclick="vboWidgetStickyNoteAdd(this);"> |
| 346 |
<span><?php VikBookingIcons::e('plus-circle'); ?></span> |
| 347 |
</div> |
| 348 |
</li> |
| 349 |
</ul> |
| 350 |
</div> |
| 351 |
</div> |
| 352 |
|
| 353 |
<script type="text/javascript"> |
| 354 |
// declare global variables for notes sorting |
| 355 |
var vbo_stickynote_initial_pos = null; |
| 356 |
|
| 357 |
jQuery(function() { |
| 358 |
|
| 359 |
// register input event listener for each sticky note |
| 360 |
var stickies<?php echo $wrapper_instance; ?> = document.querySelectorAll('#<?php echo $wrapper_id; ?> .vbo-widget-sticky-canvas'); |
| 361 |
for (var i = 0; i < stickies<?php echo $wrapper_instance; ?>.length; i++) { |
| 362 |
stickies<?php echo $wrapper_instance; ?>[i].addEventListener('input', VBOCore.debounceEvent(vboWidgetStickyNoteUpdateTxt, 750)); |
| 363 |
} |
| 364 |
|
| 365 |
if (typeof jQuery.fn.sortable !== 'undefined') { |
| 366 |
/** |
| 367 |
* Make all sticky notes sortable. Do not use .disableSelection() or this |
| 368 |
* will break all [contenteditable] elements and their focus/selection events. |
| 369 |
*/ |
| 370 |
jQuery('#<?php echo $wrapper_id; ?> .vbo-admin-widget-sticky-notes-list').sortable({ |
| 371 |
cursor: 'move', |
| 372 |
handle: '.vbo-sticky-note-cmd-drag', |
| 373 |
items: 'li.vbo-sticky-note', |
| 374 |
revert: false, |
| 375 |
start: function(event, ui) { |
| 376 |
// update sticky note initial position |
| 377 |
vbo_stickynote_initial_pos = jQuery('#<?php echo $wrapper_id; ?>').find('.vbo-sticky-note').index(jQuery(ui.item)); |
| 378 |
}, |
| 379 |
update: function(event, ui) { |
| 380 |
// get sticky note new position |
| 381 |
var now_note = jQuery(ui.item); |
| 382 |
var new_note_index = jQuery('#<?php echo $wrapper_id; ?>').find('.vbo-sticky-note').index(now_note); |
| 383 |
var widget_instance = now_note.closest('.vbo-admin-widget-sticky-notes-wrap').attr('data-instance'); |
| 384 |
|
| 385 |
if (vbo_stickynote_initial_pos === null) { |
| 386 |
return; |
| 387 |
} |
| 388 |
|
| 389 |
// the widget method to call |
| 390 |
var call_method = 'sortStickyNote'; |
| 391 |
|
| 392 |
// make a silent request to remove the sticky note |
| 393 |
VBOCore.doAjax( |
| 394 |
"<?php echo $this->getExecWidgetAjaxUri(); ?>", |
| 395 |
{ |
| 396 |
widget_id: "<?php echo $this->getIdentifier(); ?>", |
| 397 |
call: call_method, |
| 398 |
note_index_old: vbo_stickynote_initial_pos, |
| 399 |
note_index_new: new_note_index, |
| 400 |
note_instance: widget_instance, |
| 401 |
tmpl: "component" |
| 402 |
}, |
| 403 |
function(response) { |
| 404 |
// unset global note position var |
| 405 |
vbo_stickynote_initial_pos = null; |
| 406 |
try { |
| 407 |
var obj_res = typeof response === 'string' ? JSON.parse(response) : response; |
| 408 |
if (!obj_res.hasOwnProperty(call_method)) { |
| 409 |
console.error('Unexpected JSON response', obj_res); |
| 410 |
} |
| 411 |
} catch(err) { |
| 412 |
console.error('could not parse JSON response', err, response); |
| 413 |
} |
| 414 |
}, |
| 415 |
function(error) { |
| 416 |
// unset global note position var |
| 417 |
vbo_stickynote_initial_pos = null; |
| 418 |
console.error(error); |
| 419 |
} |
| 420 |
); |
| 421 |
} |
| 422 |
}); |
| 423 |
} else { |
| 424 |
// hide sortable handler |
| 425 |
jQuery('#<?php echo $wrapper_id; ?> .vbo-admin-widget-sticky-notes-list').find('.vbo-sticky-note-cmd-drag').hide(); |
| 426 |
} |
| 427 |
|
| 428 |
}); |
| 429 |
</script> |
| 430 |
|
| 431 |
<?php |
| 432 |
if (static::$instance_counter === 0 || $is_ajax) { |
| 433 |
?> |
| 434 |
<script type="text/javascript"> |
| 435 |
jQuery(function() { |
| 436 |
|
| 437 |
/** |
| 438 |
* Add event listener to keydown for shortcuts during typing on contenteditable elements. |
| 439 |
*/ |
| 440 |
document.onkeydown = function(e) { |
| 441 |
e = e || window.event; |
| 442 |
var active_el = document.activeElement; |
| 443 |
var exec_cmd = null; |
| 444 |
var exec_val = null; |
| 445 |
if ((!e.metaKey && !e.ctrlKey) || !active_el || !active_el.hasAttribute('contenteditable')) { |
| 446 |
return; |
| 447 |
} |
| 448 |
|
| 449 |
if (e.keyCode == 66) { |
| 450 |
// CMD + B detected |
| 451 |
exec_cmd = 'bold'; |
| 452 |
} else if (e.keyCode == 85) { |
| 453 |
// CMD + U detected |
| 454 |
exec_cmd = 'underline'; |
| 455 |
} else if (e.keyCode == 73) { |
| 456 |
// CMD + I detected |
| 457 |
exec_cmd = 'italic'; |
| 458 |
} else if (e.keyCode == 83) { |
| 459 |
// CMD + S |
| 460 |
exec_cmd = 'strikeThrough'; |
| 461 |
} else if (e.keyCode == 72 || e.keyCode == 84) { |
| 462 |
// CMD + H || CMD + T detected |
| 463 |
exec_cmd = 'formatBlock'; |
| 464 |
exec_val = 'h2'; |
| 465 |
} else if (e.keyCode == 80) { |
| 466 |
// CMD + P |
| 467 |
exec_cmd = 'formatBlock'; |
| 468 |
exec_val = 'p'; |
| 469 |
} else if (e.keyCode == 79 || e.keyCode == 78) { |
| 470 |
// CMD + O || CMD + N detected |
| 471 |
exec_cmd = 'insertOrderedList'; |
| 472 |
} else if (e.keyCode == 76) { |
| 473 |
// CMD + L |
| 474 |
if (window.getSelection()) { |
| 475 |
var range = window.getSelection().getRangeAt(0); |
| 476 |
exec_val = range.toString(); |
| 477 |
if (exec_val && exec_val.length) { |
| 478 |
// some text is selected |
| 479 |
if (exec_val.match(/\b(?:(?:https?|ftp):\/\/|www\.)[-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i)) { |
| 480 |
// URI selected, set command to create a link |
| 481 |
exec_cmd = 'createLink'; |
| 482 |
} else { |
| 483 |
// just some plain text was selected, ask for a custom URI |
| 484 |
e.preventDefault(); |
| 485 |
var link_uri = prompt(Joomla.JText._('VBO_STICKYN_CUSTOMURI'), '<?php echo JUri::root(); ?>'); |
| 486 |
if (link_uri != null && link_uri != '' && link_uri.indexOf('http') >= 0) { |
| 487 |
exec_val = '<a href="' + link_uri + '">' + exec_val + '</a>'; |
| 488 |
exec_cmd = 'insertHTML'; |
| 489 |
} |
| 490 |
} |
| 491 |
} else { |
| 492 |
// no text selected, create an unordered list |
| 493 |
exec_val = null; |
| 494 |
exec_cmd = 'insertUnorderedList'; |
| 495 |
} |
| 496 |
} else { |
| 497 |
// cannot access text selection, create an unordered list also in this case |
| 498 |
exec_val = null; |
| 499 |
exec_cmd = 'insertUnorderedList'; |
| 500 |
} |
| 501 |
} else if (e.keyCode == 77 && window.getSelection()) { |
| 502 |
// CMD + M |
| 503 |
var txtsel = window.getSelection().getRangeAt(0).toString(); |
| 504 |
if (txtsel && txtsel.length && txtsel.indexOf('<') === 0 && txtsel.substr(-1, 1) == '>') { |
| 505 |
// HTML tag selected, convert it from plain text to HTML code |
| 506 |
if (txtsel.indexOf('><') >= 0) { |
| 507 |
// hack for converting icons, where empty tags are not parsed correctly |
| 508 |
txtsel = txtsel.replace('><', '> <'); |
| 509 |
} |
| 510 |
exec_val = txtsel + ' '; |
| 511 |
exec_cmd = 'insertHTML'; |
| 512 |
} |
| 513 |
} |
| 514 |
|
| 515 |
if (exec_cmd !== null) { |
| 516 |
e.preventDefault(); |
| 517 |
document.execCommand(exec_cmd, false, exec_val); |
| 518 |
active_el.focus(); |
| 519 |
|
| 520 |
return false; |
| 521 |
} |
| 522 |
} |
| 523 |
|
| 524 |
/** |
| 525 |
* Listen to mousedown event for clicks on links inside the elements |
| 526 |
* with contenteditable, otherwise links in sticky notes won't open. |
| 527 |
*/ |
| 528 |
jQuery(document.body).on('mousedown', '.vbo-widget-sticky-canvas[contenteditable]', function(e) { |
| 529 |
var elem = jQuery(e.target); |
| 530 |
if (elem.is('a')) { |
| 531 |
var goto = elem.attr('href'); |
| 532 |
if (goto && goto.length && goto.indexOf('http') >= 0) { |
| 533 |
e.preventDefault(); |
| 534 |
window.open(goto, '_blank'); |
| 535 |
return false; |
| 536 |
} |
| 537 |
} |
| 538 |
}); |
| 539 |
}); |
| 540 |
</script> |
| 541 |
|
| 542 |
<script type="text/javascript"> |
| 543 |
function vboWidgetStickyNoteAdd(elem) { |
| 544 |
// display the help for the shortcuts instructions |
| 545 |
jQuery(elem).closest('.vbo-admin-widget-wrapper').find('.vbo-sticky-shortcuts-help').fadeIn(); |
| 546 |
// sticky note default HTML placeholder |
| 547 |
var sticky_placeholder = '<h2>' + Joomla.JText._('VBO_STICKYN_TITLE') + '</h2>' + "\n"; |
| 548 |
sticky_placeholder += '<p>' + Joomla.JText._('VBO_STICKYN_TEXT') + '</p>' + "\n"; |
| 549 |
sticky_placeholder += '<p>' + Joomla.JText._('VBO_STICKYN_TEXT2') + '</p>' + "\n"; |
| 550 |
// build new sticky note HTML |
| 551 |
var html_sticky_new = '<div class="vbo-sticky-note-cmds">'; |
| 552 |
html_sticky_new += ' <span class="vbo-sticky-note-cmd-drag"><?php VikBookingIcons::e('ellipsis-v'); ?></span>'; |
| 553 |
html_sticky_new += ' <span class="vbo-sticky-note-cmd-trash" onclick="vboWidgetStickyNoteDelete(this);"><?php VikBookingIcons::e('trash'); ?></span>'; |
| 554 |
html_sticky_new += '</div>'; |
| 555 |
html_sticky_new += '<div contenteditable="true" spellcheck="false" class="vbo-widget-sticky-canvas">'; |
| 556 |
html_sticky_new += sticky_placeholder; |
| 557 |
html_sticky_new += '</div>'; |
| 558 |
|
| 559 |
// build new element and add HTML to it |
| 560 |
var sticky_new = document.createElement('li'); |
| 561 |
sticky_new.setAttribute('class', 'vbo-sticky-note'); |
| 562 |
sticky_new.innerHTML = html_sticky_new; |
| 563 |
|
| 564 |
// attach listener for input event |
| 565 |
sticky_new.addEventListener('input', VBOCore.debounceEvent(vboWidgetStickyNoteUpdateTxt, 750)); |
| 566 |
|
| 567 |
// add new element to the document, before the button to add new sticky notes |
| 568 |
var append_to = jQuery(elem).closest('.vbo-admin-widget-sticky-notes-list').find('.vbo-sticky-note-add'); |
| 569 |
append_to.before(jQuery(sticky_new)); |
| 570 |
|
| 571 |
/** |
| 572 |
* The input event is immediately triggered so that the newly added note will be saved to avoid |
| 573 |
* problems when like adding two notes before even typing some text, and then moving/removing them. |
| 574 |
*/ |
| 575 |
sticky_new.dispatchEvent(new Event('input')); |
| 576 |
} |
| 577 |
|
| 578 |
function vboWidgetStickyNoteDelete(elem) { |
| 579 |
var note_elem = jQuery(elem); |
| 580 |
var note_index = note_elem.closest('.vbo-admin-widget-sticky-notes-list').find('.vbo-sticky-note').index(note_elem.closest('.vbo-sticky-note')); |
| 581 |
var widget_instance = note_elem.closest('.vbo-admin-widget-sticky-notes-wrap').attr('data-instance'); |
| 582 |
|
| 583 |
var confirm_lbl = Joomla.JText._('VBO_WIDGETS_CONFRMELEM'); |
| 584 |
confirm_lbl = confirm_lbl.length ? confirm_lbl : 'Continue?'; |
| 585 |
if (confirm(confirm_lbl)) { |
| 586 |
// the widget method to call |
| 587 |
var call_method = 'deleteStickyNote'; |
| 588 |
|
| 589 |
// make a silent request to remove the sticky note |
| 590 |
VBOCore.doAjax( |
| 591 |
"<?php echo $this->getExecWidgetAjaxUri(); ?>", |
| 592 |
{ |
| 593 |
widget_id: "<?php echo $this->getIdentifier(); ?>", |
| 594 |
call: call_method, |
| 595 |
note_index: note_index, |
| 596 |
note_instance: widget_instance, |
| 597 |
tmpl: "component" |
| 598 |
}, |
| 599 |
function(response) { |
| 600 |
try { |
| 601 |
var obj_res = typeof response === 'string' ? JSON.parse(response) : response; |
| 602 |
if (!obj_res.hasOwnProperty(call_method)) { |
| 603 |
console.error('Unexpected JSON response', obj_res); |
| 604 |
} |
| 605 |
} catch(err) { |
| 606 |
console.error('could not parse JSON response', err, response); |
| 607 |
} |
| 608 |
}, |
| 609 |
function(error) { |
| 610 |
console.error(error); |
| 611 |
} |
| 612 |
); |
| 613 |
|
| 614 |
// remove the sticky note from the document |
| 615 |
note_elem.closest('li.vbo-sticky-note').remove(); |
| 616 |
} |
| 617 |
} |
| 618 |
|
| 619 |
function vboWidgetStickyNoteUpdateTxt(event) { |
| 620 |
var note_elem = jQuery(this); |
| 621 |
// display the help for the shortcuts instructions |
| 622 |
note_elem.closest('.vbo-admin-widget-wrapper').find('.vbo-sticky-shortcuts-help').fadeIn(); |
| 623 |
// element "this" may be different depending on how the event was triggered |
| 624 |
if (note_elem.find('.vbo-widget-sticky-canvas').length) { |
| 625 |
var note_txt = note_elem.find('.vbo-widget-sticky-canvas').html(); |
| 626 |
} else { |
| 627 |
var note_txt = note_elem.html(); |
| 628 |
} |
| 629 |
var note_index = note_elem.closest('.vbo-admin-widget-sticky-notes-list').find('.vbo-sticky-note').index(note_elem.closest('.vbo-sticky-note')); |
| 630 |
var widget_instance = note_elem.closest('.vbo-admin-widget-sticky-notes-wrap').attr('data-instance'); |
| 631 |
|
| 632 |
// the widget method to call |
| 633 |
var call_method = 'updateStickyNote'; |
| 634 |
|
| 635 |
// make a silent request to update the sticky note details |
| 636 |
VBOCore.doAjax( |
| 637 |
"<?php echo $this->getExecWidgetAjaxUri(); ?>", |
| 638 |
{ |
| 639 |
widget_id: "<?php echo $this->getIdentifier(); ?>", |
| 640 |
call: call_method, |
| 641 |
note_txt: note_txt, |
| 642 |
note_index: note_index, |
| 643 |
note_instance: widget_instance, |
| 644 |
tmpl: "component" |
| 645 |
}, |
| 646 |
function(response) { |
| 647 |
try { |
| 648 |
var obj_res = typeof response === 'string' ? JSON.parse(response) : response; |
| 649 |
if (!obj_res.hasOwnProperty(call_method)) { |
| 650 |
console.error('Unexpected JSON response', obj_res); |
| 651 |
} else { |
| 652 |
// response for the method updateStickyNote() may contain the new instance given to the widget |
| 653 |
if (widget_instance < 0 && obj_res[call_method].indexOf('[instance=') >= 0) { |
| 654 |
// extract the new instance assigned |
| 655 |
var resp_left = obj_res[call_method].split('[instance='); |
| 656 |
var widget_instance_new = resp_left[1].split(']')[0]; |
| 657 |
if (widget_instance_new && widget_instance_new.length) { |
| 658 |
// update widget's instance |
| 659 |
note_elem.closest('.vbo-admin-widget-sticky-notes-wrap').attr('data-instance', widget_instance_new); |
| 660 |
} |
| 661 |
} |
| 662 |
} |
| 663 |
} catch(err) { |
| 664 |
console.error('could not parse JSON response', err, response); |
| 665 |
} |
| 666 |
}, |
| 667 |
function(error) { |
| 668 |
console.error(error); |
| 669 |
} |
| 670 |
); |
| 671 |
} |
| 672 |
</script> |
| 673 |
<?php |
| 674 |
} |
| 675 |
} |
| 676 |
|
| 677 |
/** |
| 678 |
* Protected method to guess if the widget being rendered via AJAX in the |
| 679 |
* multitask panel should load specific settings. Should be called when |
| 680 |
* settings have been loaded, and if AJAX + multitask rendering is detected. |
| 681 |
* It's assumed that the AJAX rendering of a multitask widget takes place one |
| 682 |
* second before the AJAX event that updates the multitask map to push the widget. |
| 683 |
* |
| 684 |
* @param ?VBOMultitaskData $data the data object injected to the widget. |
| 685 |
* |
| 686 |
* @return bool|int false on failure, guessed settings index otherwise. |
| 687 |
*/ |
| 688 |
protected function guessMultitaskStickyInstance(?VBOMultitaskData $data = null) |
| 689 |
{ |
| 690 |
if (!is_array($this->widgetSettings) || !count($this->widgetSettings)) { |
| 691 |
// nothing to guess if this widget has got no saved settings |
| 692 |
return false; |
| 693 |
} |
| 694 |
|
| 695 |
if (!is_object($data)) { |
| 696 |
// multitask data object must be set |
| 697 |
return false; |
| 698 |
} |
| 699 |
|
| 700 |
// the page must be set in the multitask object |
| 701 |
$vbo_page = $data->getPage(); |
| 702 |
if (empty($vbo_page)) { |
| 703 |
// nothing to guess if no current page set |
| 704 |
return false; |
| 705 |
} |
| 706 |
|
| 707 |
// get the map for the current page |
| 708 |
$page_map = VikBooking::getAdminWidgetsInstance()->getMultitaskingMap($vbo_page, $whole = false); |
| 709 |
if (!is_array($page_map) || !count($page_map)) { |
| 710 |
// the multitask panel of this page has got no widgets saved, return the first index for settings |
| 711 |
return 0; |
| 712 |
} |
| 713 |
|
| 714 |
// count how many widgets of this type are already on this page |
| 715 |
$guessed_index = 0; |
| 716 |
foreach ($page_map as $widget_type) { |
| 717 |
if ($widget_type == $this->getIdentifier()) { |
| 718 |
$guessed_index++; |
| 719 |
} |
| 720 |
} |
| 721 |
|
| 722 |
// return the guessed index, which will load the next hypothetical instance |
| 723 |
return $guessed_index; |
| 724 |
} |
| 725 |
} |
| 726 |
|