default.php
6 days ago
default_diff.php
6 days ago
default_editor.php
6 days ago
default_file.php
6 days ago
default_folder.php
6 days ago
default_guide.php
6 days ago
default_editor.php
455 lines
| 1 | <?php |
| 2 | /** |
| 3 | * @package VikAppointments |
| 4 | * @subpackage core |
| 5 | * @author E4J s.r.l. |
| 6 | * @copyright Copyright (C) 2024 E4J s.r.l. All Rights Reserved. |
| 7 | * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL |
| 8 | * @link https://vikwp.com |
| 9 | */ |
| 10 | |
| 11 | // No direct access |
| 12 | defined('ABSPATH') or die('No script kiddies please!'); |
| 13 | |
| 14 | $vik = VAPApplication::getInstance(); |
| 15 | |
| 16 | ?> |
| 17 | |
| 18 | <style> |
| 19 | .vap-overrides-manager .overrides-body .override-file { |
| 20 | display: flex; |
| 21 | align-items: center; |
| 22 | padding: 10px; |
| 23 | border-bottom: 1px solid #ccc; |
| 24 | } |
| 25 | .vap-overrides-manager .overrides-body .override-file #override-options { |
| 26 | font-size: 16px; |
| 27 | margin-right: 10px; |
| 28 | } |
| 29 | .vap-overrides-manager .overrides-body .override-file input { |
| 30 | flex: 1; |
| 31 | margin-right: 4px; |
| 32 | } |
| 33 | |
| 34 | .vap-overrides-manager .overrides-body .overrides-differences { |
| 35 | border-bottom: 1px solid #ccc; |
| 36 | } |
| 37 | .vap-overrides-manager .overrides-body .overrides-differences .notice { |
| 38 | margin: 10px; |
| 39 | } |
| 40 | |
| 41 | .vap-overrides-manager .overrides-body .overrides-editor[data-layout="columns"] { |
| 42 | display: flex; |
| 43 | flex-wrap: wrap; |
| 44 | } |
| 45 | .vap-overrides-manager .overrides-body .overrides-editor[data-layout="columns"] > * { |
| 46 | width: 50%; |
| 47 | box-sizing: border-box; |
| 48 | } |
| 49 | .vap-overrides-manager .overrides-body .overrides-editor[data-layout="columns"] > *:only-of-type { |
| 50 | width: 100%; |
| 51 | } |
| 52 | |
| 53 | .vap-overrides-manager .overrides-body .overrides-editor .overrides-editor-default { |
| 54 | visibility: hidden; |
| 55 | position: fixed; |
| 56 | transform: translateX(200%); |
| 57 | } |
| 58 | .vap-overrides-manager .overrides-body .overrides-editor[data-layout="columns"] .overrides-editor-default, |
| 59 | .vap-overrides-manager .overrides-body .overrides-editor[data-layout="rows"] .overrides-editor-default { |
| 60 | visibility: visible; |
| 61 | position: initial; |
| 62 | transform: none; |
| 63 | } |
| 64 | .vap-overrides-manager .overrides-body .overrides-editor[data-layout="columns"] .overrides-editor-default { |
| 65 | border-left: 1px solid #ccc; |
| 66 | } |
| 67 | .vap-overrides-manager .overrides-body .overrides-editor[data-layout="rows"] .overrides-editor-default { |
| 68 | border-top: 1px solid #ccc; |
| 69 | } |
| 70 | |
| 71 | .vap-overrides-manager .overrides-body .CodeMirror { |
| 72 | height: 100%; |
| 73 | } |
| 74 | </style> |
| 75 | |
| 76 | <!-- Toolbar --> |
| 77 | |
| 78 | <div class="override-file"> |
| 79 | <i class="fas fa-cog" id="override-options"></i> |
| 80 | |
| 81 | <input type="text" readonly value="<?php echo $this->escape($this->filters['override']); ?>" /> |
| 82 | |
| 83 | <button type="button" class="button" id="override-copy"><?php echo __('Copy'); ?></button> |
| 84 | </div> |
| 85 | |
| 86 | <!-- Differences --> |
| 87 | |
| 88 | <div class="overrides-differences" style="display: none;"> |
| 89 | <?php |
| 90 | if (empty($this->filters['differences'])) |
| 91 | { |
| 92 | echo $vik->alert(__('The are no differences among the override and the original file.', 'vikappointments')); |
| 93 | } |
| 94 | else |
| 95 | { |
| 96 | echo $this->loadTemplate('diff'); |
| 97 | } |
| 98 | ?> |
| 99 | </div> |
| 100 | |
| 101 | <!-- Editor box --> |
| 102 | |
| 103 | <div class="overrides-editor"> |
| 104 | |
| 105 | <div class="overrides-editor-code"> |
| 106 | <?php |
| 107 | // Display code mirror editor. |
| 108 | // Take the editor outside the form in order to |
| 109 | // prevent XSS blocks handled by the browser. |
| 110 | echo $vik->getCodeMirror('__code', $this->filters['code']); |
| 111 | ?> |
| 112 | </div> |
| 113 | |
| 114 | <div class="overrides-editor-default"> |
| 115 | <?php |
| 116 | // Display code mirror editor. |
| 117 | // Take the editor outside the form in order to |
| 118 | // prevent XSS blocks handled by the browser. |
| 119 | echo $vik->getCodeMirror('__default', $this->filters['defaultcode']); |
| 120 | ?> |
| 121 | </div> |
| 122 | |
| 123 | </div> |
| 124 | |
| 125 | <?php |
| 126 | JText::script('VAPCONNECTIONLOSTERROR'); |
| 127 | JText::script('JLIB_APPLICATION_SAVE_SUCCESS'); |
| 128 | JText::script('VAPCONFDIALOGMSG'); |
| 129 | ?> |
| 130 | |
| 131 | <script> |
| 132 | (function($) { |
| 133 | 'use strict'; |
| 134 | |
| 135 | $(function() { |
| 136 | // mark default editor as readonly |
| 137 | Joomla.editors.instances.__default.element.codemirror.setOption('readOnly', true); |
| 138 | |
| 139 | let hasOverride = <?php echo $this->filters['hasoverride'] ? 'true' : 'false'; ?>; |
| 140 | let isPublished = <?php echo $this->filters['published'] ? 'true' : 'false'; ?>; |
| 141 | |
| 142 | // implement copy callback |
| 143 | $('#override-copy').on('click', function() { |
| 144 | // copy path within the clipboard |
| 145 | copyToClipboard($(this).prev('input')).then(() => { |
| 146 | // display successful message on copy |
| 147 | VAPToast.dispatch(new VAPToastMessageOS({ |
| 148 | body: '<?php echo addslashes(__('Copied!')); ?>', |
| 149 | status: VAPToast.SUCCESS_STATUS, |
| 150 | delay: 'auto', |
| 151 | })); |
| 152 | }).catch(() => { |
| 153 | // cannot copy |
| 154 | VAPToast.dispatch(new VAPToastMessageOS({ |
| 155 | body: '<?php echo addslashes(__('Cannot copy the files! Please proceed manually.')); ?>', |
| 156 | status: VAPToast.ERROR_STATUS, |
| 157 | delay: 'auto', |
| 158 | })); |
| 159 | }); |
| 160 | }); |
| 161 | |
| 162 | let isSaving = false; |
| 163 | |
| 164 | // override click of toolbar button |
| 165 | Joomla.submitbutton = (task) => { |
| 166 | if (task == 'override.save') { |
| 167 | if (isSaving) { |
| 168 | // already saving, do not go ahead |
| 169 | return false; |
| 170 | } |
| 171 | |
| 172 | isSaving = true; |
| 173 | |
| 174 | // extract code from editor |
| 175 | let code = Joomla.editors.instances.__code.getValue(); |
| 176 | |
| 177 | // build post data object |
| 178 | const postData = { |
| 179 | code: code, |
| 180 | client: '<?php echo addslashes($this->filters['client']); ?>', |
| 181 | selectedfile: '<?php echo addslashes($this->filters['file']); ?>', |
| 182 | overridefile: '<?php echo base64_encode($this->filters['override']); ?>', |
| 183 | status: isPublished || !hasOverride ? 1 : 0, |
| 184 | }; |
| 185 | |
| 186 | // save code |
| 187 | UIAjax.do( |
| 188 | 'admin-ajax.php?action=vikappointments&task=override.save', |
| 189 | postData, |
| 190 | (resp) => { |
| 191 | // display successful message |
| 192 | VAPToast.dispatch(new VAPToastMessageOS({ |
| 193 | body: Joomla.JText._('JLIB_APPLICATION_SAVE_SUCCESS'), |
| 194 | status: VAPToast.SUCCESS_STATUS, |
| 195 | delay: 'auto', |
| 196 | })); |
| 197 | |
| 198 | if (!hasOverride) { |
| 199 | // add override style to file link |
| 200 | $('a.file[data-path="' + postData.selectedfile + '"]') |
| 201 | .find('i').addClass('has-override'); |
| 202 | |
| 203 | // we now have an active override |
| 204 | hasOverride = isPublished = true; |
| 205 | } |
| 206 | |
| 207 | // no more pending changes after save |
| 208 | SOMETHING_HAS_CHANGED = false; |
| 209 | |
| 210 | isSaving = false; |
| 211 | }, |
| 212 | (error) => { |
| 213 | // prompt error message |
| 214 | VAPToast.dispatch(new VAPToastMessageOS({ |
| 215 | body: error.responseText || Joomla.JText._('VAPCONNECTIONLOSTERROR'), |
| 216 | status: VAPToast.ERROR_STATUS, |
| 217 | })); |
| 218 | |
| 219 | isSaving = false; |
| 220 | } |
| 221 | ); |
| 222 | } else { |
| 223 | // submit form |
| 224 | Joomla.submitform(task, document.adminForm); |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | let layoutMode; |
| 229 | |
| 230 | // retrieve current layout mode from local storage, if suppoered |
| 231 | if (typeof Storage !== 'undefined') { |
| 232 | layoutMode = localStorage.getItem('overrideLayoutMode'); |
| 233 | |
| 234 | // init layout data |
| 235 | $('.overrides-editor').attr('data-layout', layoutMode); |
| 236 | } |
| 237 | |
| 238 | // layout mode button click implementor |
| 239 | const saveOverrideLayoutMode = function(root, event) { |
| 240 | // register layout mode |
| 241 | layoutMode = this.layoutMode; |
| 242 | |
| 243 | // register layout within the local storage, if supported |
| 244 | if (typeof Storage !== 'undefined') { |
| 245 | localStorage.setItem('overrideLayoutMode', layoutMode); |
| 246 | } |
| 247 | |
| 248 | // apply layout data |
| 249 | $('.overrides-editor').attr('data-layout', layoutMode); |
| 250 | }; |
| 251 | |
| 252 | // check whether the current button is selected |
| 253 | const isLayoutModeSelected = function(root, event) { |
| 254 | if (this.layoutMode == layoutMode || (!this.layoutMode && !layoutMode)) { |
| 255 | return 'fas fa-check'; |
| 256 | } |
| 257 | |
| 258 | return ''; |
| 259 | }; |
| 260 | |
| 261 | let showDifferences = 0 |
| 262 | |
| 263 | if (typeof Storage !== 'undefined') { |
| 264 | showDifferences = parseInt(localStorage.getItem('overrideShowDifferences')) || 0; |
| 265 | } |
| 266 | |
| 267 | if (showDifferences) { |
| 268 | $('.overrides-differences').show(); |
| 269 | } else { |
| 270 | $('.overrides-differences').hide(); |
| 271 | } |
| 272 | |
| 273 | // set up context menu for layout handling |
| 274 | $('#override-options').vikContextMenu({ |
| 275 | clickable: true, |
| 276 | buttons: [ |
| 277 | // HIDE NAVIGATOR |
| 278 | { |
| 279 | state: 1, |
| 280 | text: '<?php echo addslashes(__('Show files tree', 'vikappointments')); ?>', |
| 281 | action: function(root, event) { |
| 282 | // get opposite state |
| 283 | this.state ^= 1; |
| 284 | |
| 285 | if (this.state) { |
| 286 | $('.overrides-navigator').show(); |
| 287 | } else { |
| 288 | $('.overrides-navigator').hide(); |
| 289 | } |
| 290 | }, |
| 291 | icon: function(root, event) { |
| 292 | if (this.state) { |
| 293 | return 'fas fa-check'; |
| 294 | } |
| 295 | |
| 296 | return ''; |
| 297 | }, |
| 298 | }, |
| 299 | // HIDE NAVIGATOR |
| 300 | { |
| 301 | state: showDifferences, |
| 302 | text: '<?php echo addslashes(__('Show differences', 'vikappointments')); ?>', |
| 303 | separator: true, |
| 304 | action: function(root, event) { |
| 305 | // get opposite state |
| 306 | this.state ^= 1; |
| 307 | |
| 308 | if (this.state) { |
| 309 | $('.overrides-differences').show(); |
| 310 | } else { |
| 311 | $('.overrides-differences').hide(); |
| 312 | } |
| 313 | |
| 314 | if (typeof Storage !== 'undefined') { |
| 315 | localStorage.setItem('overrideShowDifferences', this.state); |
| 316 | } |
| 317 | }, |
| 318 | icon: function(root, event) { |
| 319 | if (this.state) { |
| 320 | return 'fas fa-check'; |
| 321 | } |
| 322 | |
| 323 | return ''; |
| 324 | }, |
| 325 | }, |
| 326 | // HIDE ORIGINAL CODE |
| 327 | { |
| 328 | text: '<?php echo addslashes(__('Hide original file', 'vikappointments')); ?>', |
| 329 | action: saveOverrideLayoutMode, |
| 330 | icon: isLayoutModeSelected, |
| 331 | layoutMode: '', |
| 332 | }, |
| 333 | // SHOW IN COLUMNS |
| 334 | { |
| 335 | text: '<?php echo addslashes(__('Show both in columns', 'vikappointments')); ?>', |
| 336 | action: saveOverrideLayoutMode, |
| 337 | icon: isLayoutModeSelected, |
| 338 | layoutMode: 'columns', |
| 339 | }, |
| 340 | // SHOW IN ROWS |
| 341 | { |
| 342 | text: '<?php echo addslashes(__('Show one over the other', 'vikappointments')); ?>', |
| 343 | action: saveOverrideLayoutMode, |
| 344 | icon: isLayoutModeSelected, |
| 345 | layoutMode: 'rows', |
| 346 | separator: true, |
| 347 | }, |
| 348 | // ACTIVATE |
| 349 | { |
| 350 | text: '<?php echo addslashes(__('Activate')); ?>', |
| 351 | class: 'success', |
| 352 | separator: true, |
| 353 | action: (root, event) => { |
| 354 | // submit form to publish override |
| 355 | Joomla.submitbutton('override.publish'); |
| 356 | }, |
| 357 | visible: (root, event) => { |
| 358 | // display button only in case of deactivated override |
| 359 | return hasOverride === true && isPublished === false; |
| 360 | }, |
| 361 | }, |
| 362 | // DEACTIVATE |
| 363 | { |
| 364 | text: '<?php echo addslashes(__('Deactivate')); ?>', |
| 365 | class: 'warning', |
| 366 | separator: true, |
| 367 | action: (root, event) => { |
| 368 | // submit form to publish override |
| 369 | Joomla.submitbutton('override.unpublish'); |
| 370 | }, |
| 371 | disabled: (root, event) => { |
| 372 | // disable button in case of missing override |
| 373 | return hasOverride === false; |
| 374 | }, |
| 375 | visible: (root, event) => { |
| 376 | // display button only in case of activated override |
| 377 | return hasOverride === true && isPublished === true; |
| 378 | }, |
| 379 | }, |
| 380 | // SAVE |
| 381 | { |
| 382 | text: '<?php echo addslashes(__('Save')); ?>', |
| 383 | action: (root, event) => { |
| 384 | Joomla.submitbutton('override.save'); |
| 385 | }, |
| 386 | // Always keep button hidden. Declare it just |
| 387 | // to implement the CMD+S shortcut for saving. |
| 388 | visible: false, |
| 389 | shortcut: (() => { |
| 390 | if (window.navigator.platform.match(/^MAC/i)) { |
| 391 | // Mac OS |
| 392 | return ['meta', 's']; |
| 393 | } |
| 394 | // Windows |
| 395 | return ['ctrl', 's']; |
| 396 | |
| 397 | })(), |
| 398 | }, |
| 399 | // DELETE |
| 400 | { |
| 401 | icon: 'fas fa-times', |
| 402 | text: '<?php echo addslashes(__('Delete')); ?>', |
| 403 | class: 'danger', |
| 404 | action: (root, event) => { |
| 405 | // dispatch confirmation and delete in a thread so that |
| 406 | // we can complete the closure of the context menu |
| 407 | setTimeout(() => { |
| 408 | // ask for a confirmation |
| 409 | const r = confirm(Joomla.JText._('VAPCONFDIALOGMSG')); |
| 410 | |
| 411 | // unset flag because we don't care of any pending |
| 412 | // changes in case we are going to delete the file |
| 413 | SOMETHING_HAS_CHANGED = false; |
| 414 | |
| 415 | if (r) { |
| 416 | // delete override |
| 417 | Joomla.submitbutton('override.delete'); |
| 418 | } |
| 419 | }, 32); |
| 420 | }, |
| 421 | disabled: (root, event) => { |
| 422 | // disable button in case of missing override |
| 423 | return hasOverride === false; |
| 424 | }, |
| 425 | }, |
| 426 | ], |
| 427 | }); |
| 428 | |
| 429 | // flag used to check whether the code has changed |
| 430 | let SOMETHING_HAS_CHANGED = false; |
| 431 | |
| 432 | Joomla.editors.instances.__code.element.codemirror.on('change', () => { |
| 433 | // the user change the content of the editor, register flag |
| 434 | SOMETHING_HAS_CHANGED = true; |
| 435 | }); |
| 436 | |
| 437 | // register event to block the user while attempting |
| 438 | // to leave the page with pending changes |
| 439 | $(window).on('beforeunload', (event) => { |
| 440 | // check whether something has changed |
| 441 | if (SOMETHING_HAS_CHANGED) { |
| 442 | // The translated message is meant to work only |
| 443 | // for internal purposes as almost all the browsers |
| 444 | // uses their own localised strings. |
| 445 | const dialogText = 'Do you want to leave the page? Your changes will be lost if you don\'t save them.'; |
| 446 | |
| 447 | event.returnValue = dialogText; |
| 448 | |
| 449 | // return the message to trigger the browser prompt |
| 450 | return dialogText; |
| 451 | } |
| 452 | }); |
| 453 | }); |
| 454 | })(jQuery); |
| 455 | </script> |