PluginProbe
VikBooking Hotel Booking Engine & PMS / trunk
VikBooking Hotel Booking Engine & PMS vtrunk
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 1.7.3 All 36 releases
vikbooking / admin / helpers / widgets / sticky_notes.php

sticky_notes.php in VikBooking Hotel Booking Engine & PMS trunk, at admin/helpers/widgets/sticky_notes.php

726 lines 26.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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