PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.8.16
VikBooking Hotel Booking Engine & PMS v1.8.16
1.8.16 1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 All 37 releases
← All changes | admin/helpers/widgets/sticky_notes.php +725 -0 1.6.3 → 1.8.16 View file →
@@ -1,0 +1,725 @@
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 +}