modal.php
542 lines
| 1 | <?php |
| 2 | /** |
| 3 | * @package VikAppointments |
| 4 | * @subpackage core |
| 5 | * @author E4J s.r.l. |
| 6 | * @copyright Copyright (C) 2021 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 | JHtml::fetch('bootstrap.tooltip', '.hasTooltip'); |
| 15 | JHtml::fetch('vaphtml.assets.fontawesome'); |
| 16 | |
| 17 | if ($this->firstConfig) |
| 18 | { |
| 19 | JHtml::fetch('vaphtml.assets.toast', 'bottom-center', '.vap-media-modal'); |
| 20 | JText::script('VAPMEDIAFIRSTCONFIG'); |
| 21 | } |
| 22 | |
| 23 | $files = $this->rows; |
| 24 | $selected = $this->selected; |
| 25 | $multiple = $this->multiple; |
| 26 | |
| 27 | $vik = VAPApplication::getInstance(); |
| 28 | |
| 29 | $model = $this->getModel(); |
| 30 | |
| 31 | ?> |
| 32 | |
| 33 | <div class="vap-media-modal"> |
| 34 | |
| 35 | <div class="vap-media-grid-box"> |
| 36 | |
| 37 | <div class="btn-toolbar" style="height: 32px;"> |
| 38 | |
| 39 | <div class="btn-group pull-left input-append hide-with-size-320"> |
| 40 | <input type="text" id="mediakeysearch" size="32" value="" placeholder="<?php echo JText::translate('JSEARCH_FILTER_SUBMIT'); ?>" autocomplete="off" /> |
| 41 | |
| 42 | <button type="button" class="btn" onclick="jQuery('#mediakeysearch').trigger('change');"> |
| 43 | <i class="fas fa-search"></i> |
| 44 | </button> |
| 45 | </div> |
| 46 | |
| 47 | <div class="btn-group pull-left hide-with-size-390"> |
| 48 | <button type="button" class="btn" onclick="jQuery('#mediakeysearch').val('').trigger('change');"><?php echo JText::translate('JSEARCH_FILTER_CLEAR'); ?></button> |
| 49 | </div> |
| 50 | |
| 51 | </div> |
| 52 | |
| 53 | <?php |
| 54 | $attrs = array(); |
| 55 | $attrs['id'] = 'no-media-results-alert'; |
| 56 | |
| 57 | if ($files) |
| 58 | { |
| 59 | $attrs['style'] = 'display:none;'; |
| 60 | } |
| 61 | |
| 62 | echo $vik->alert(JText::translate('JGLOBAL_NO_MATCHING_RESULTS'), 'warning', false, $attrs); |
| 63 | ?> |
| 64 | |
| 65 | <div class="vap-media-gallery"> |
| 66 | |
| 67 | <?php |
| 68 | foreach ($files as $media) |
| 69 | { |
| 70 | ?> |
| 71 | <div class="vap-media-block" |
| 72 | data-name="<?php echo $this->escape($media['name']); ?>" |
| 73 | data-ext="<?php echo $this->escape($media['file_ext']); ?>" |
| 74 | data-size="<?php echo $this->escape($media['size']); ?>" |
| 75 | data-date="<?php echo $this->escape($media['creation']); ?>" |
| 76 | data-width="<?php echo $this->escape(isset($media['width']) ? $media['width'] : ''); ?>" |
| 77 | data-height="<?php echo $this->escape(isset($media['height']) ? $media['height'] : ''); ?>" |
| 78 | data-selected="<?php echo in_array($media['name'], $selected) ? 1 : 0; ?>" |
| 79 | > |
| 80 | <div class="media-preview"> |
| 81 | <div class="media-thumbnail"> |
| 82 | <div class="media-centered"> |
| 83 | <?php |
| 84 | // render media by using model |
| 85 | echo $model->renderMedia($media); |
| 86 | ?> |
| 87 | </div> |
| 88 | </div> |
| 89 | </div> |
| 90 | </div> |
| 91 | <?php |
| 92 | } |
| 93 | ?> |
| 94 | |
| 95 | </div> |
| 96 | </div> |
| 97 | |
| 98 | <div class="vap-media-sidebar"> |
| 99 | |
| 100 | <div class="vap-media-droptarget" id="media-upload-box"> |
| 101 | <p class="icon"> |
| 102 | <i class="fas fa-upload" style="font-size: 48px;"></i> |
| 103 | </p> |
| 104 | |
| 105 | <div class="lead"> |
| 106 | <a href="javascript:void(0)" id="media-upload-file"><?php echo JText::translate('VAPMANUALUPLOAD'); ?></a> <?php echo JText::translate('VAPMEDIADRAGDROP'); ?> |
| 107 | </div> |
| 108 | |
| 109 | <p class="maxsize"> |
| 110 | <?php echo JText::sprintf('JGLOBAL_MAXIMUM_UPLOAD_SIZE_LIMIT', JHtml::fetch('vikappointments.maxuploadsize')); ?> |
| 111 | </p> |
| 112 | |
| 113 | <input type="file" id="media-legacy-upload" multiple style="display: none;" /> |
| 114 | </div> |
| 115 | |
| 116 | <div class="vap-media-inspector"> |
| 117 | |
| 118 | <div class="inspector-title"> |
| 119 | <span><?php echo JText::translate('VAPMANAGEMEDIATITLE1'); ?></span> |
| 120 | <a href="javascript:void(0)" id="clear-media-selection"> |
| 121 | <i class="far fa-window-close"></i> |
| 122 | </a> |
| 123 | </div> |
| 124 | |
| 125 | <div class="selected-media-pool"> |
| 126 | |
| 127 | <div class="media-info-box" data-name=""> |
| 128 | <div class="media-thumbnail media-thumbnail-image"> |
| 129 | <a href="#" target="_blank"> |
| 130 | <img src="" /> |
| 131 | </a> |
| 132 | </div> |
| 133 | |
| 134 | <div class="media-details"> |
| 135 | <div class="filename"></div> |
| 136 | <div class="uploaded"></div> |
| 137 | <div class="file-size"></div> |
| 138 | <div class="dimensions"></div> |
| 139 | |
| 140 | <a href="javascript:void(0)" class="delete-media-image" onclick="vapDeleteMediaFile(this);"><?php echo JText::translate('VAP_DELETE_PERMANENTLY'); ?></a> |
| 141 | </div> |
| 142 | </div> |
| 143 | |
| 144 | </div> |
| 145 | |
| 146 | </div> |
| 147 | |
| 148 | </div> |
| 149 | |
| 150 | </div> |
| 151 | |
| 152 | <?php |
| 153 | JText::script('VAP_DEF_N_SELECTED'); |
| 154 | JText::script('VAP_DEF_N_SELECTED_1'); |
| 155 | JText::script('VAP_DEF_N_SELECTED_0'); |
| 156 | JText::script('VAPSYSTEMCONFIRMATIONMSG'); |
| 157 | ?> |
| 158 | |
| 159 | <script type="text/javascript"> |
| 160 | |
| 161 | if (!window.parent.hasOwnProperty('VAP_TMP_FILES')) { |
| 162 | window.parent.VAP_TMP_FILES = []; |
| 163 | } |
| 164 | |
| 165 | vapShowMediaInspector(); |
| 166 | |
| 167 | jQuery(function() { |
| 168 | |
| 169 | jQuery('.vap-media-block').on('click', vapHandleMediaClick); |
| 170 | |
| 171 | jQuery('#mediakeysearch').on('change', function() { |
| 172 | |
| 173 | var search = jQuery(this).val().toLowerCase(); |
| 174 | |
| 175 | var at_least_one = false; |
| 176 | |
| 177 | jQuery('.vap-media-block').each(function() { |
| 178 | |
| 179 | if (!search.length || vapMatchingMediaBox(this, search)) { |
| 180 | jQuery(this).show(); |
| 181 | at_least_one = true; |
| 182 | } else { |
| 183 | jQuery(this).hide(); |
| 184 | } |
| 185 | |
| 186 | }); |
| 187 | |
| 188 | if (at_least_one) { |
| 189 | jQuery('#no-media-results-alert').hide(); |
| 190 | } else { |
| 191 | jQuery('#no-media-results-alert').show(); |
| 192 | } |
| 193 | |
| 194 | }); |
| 195 | |
| 196 | jQuery('#clear-media-selection').on('click', function() { |
| 197 | // clear all selected media |
| 198 | jQuery('.vap-media-block[data-selected="1"]').trigger('click'); |
| 199 | }); |
| 200 | |
| 201 | }); |
| 202 | |
| 203 | function vapHandleMediaClick() { |
| 204 | var checked = parseInt(jQuery(this).attr('data-selected')) ? 0 : 1; |
| 205 | |
| 206 | <?php |
| 207 | if (!$multiple) |
| 208 | { |
| 209 | ?> |
| 210 | if (checked) { |
| 211 | jQuery('.vap-media-block[data-selected="1"]').each(function() { |
| 212 | jQuery(this).attr('data-selected', 0); |
| 213 | }); |
| 214 | } |
| 215 | |
| 216 | window.parent.VAP_TMP_FILES = []; |
| 217 | <?php |
| 218 | } |
| 219 | ?> |
| 220 | |
| 221 | jQuery(this).attr('data-selected', checked); |
| 222 | |
| 223 | var file = jQuery(this).data('name'); |
| 224 | var index = window.parent.VAP_TMP_FILES.indexOf(file); |
| 225 | |
| 226 | if (checked && index === -1) { |
| 227 | // add file to list |
| 228 | window.parent.VAP_TMP_FILES.push(file); |
| 229 | } |
| 230 | |
| 231 | if (!checked && index !== -1) { |
| 232 | // remove file from list |
| 233 | window.parent.VAP_TMP_FILES.splice(index, 1); |
| 234 | } |
| 235 | |
| 236 | if (window.parent.VAP_TMP_FILES.length) { |
| 237 | vapShowMediaInspector(); |
| 238 | } else { |
| 239 | vapHideMediaInspector(); |
| 240 | } |
| 241 | } |
| 242 | |
| 243 | function vapMatchingMediaBox(box, search) { |
| 244 | // search by media name |
| 245 | var media_name = jQuery(box).data('name').trim().toLowerCase(); |
| 246 | |
| 247 | if (media_name.indexOf(search) !== -1) { |
| 248 | return true; |
| 249 | } |
| 250 | |
| 251 | return false; |
| 252 | } |
| 253 | |
| 254 | // inspector |
| 255 | |
| 256 | jQuery(function() { |
| 257 | /** |
| 258 | * Assign the transition animations 32 ms after the page loading. |
| 259 | * Hack for Safari, which seems to apply the transition also |
| 260 | * for the initial state of the inspector, causing an unwanted |
| 261 | * animation when the page loads. |
| 262 | */ |
| 263 | setTimeout(function() { |
| 264 | jQuery('.vap-media-inspector').css('transition', '0.4s ease-out all'); |
| 265 | jQuery('.vap-media-inspector').css('-moz-transition', '0.4s ease-out all'); |
| 266 | jQuery('.vap-media-inspector').css('-webkit-transition', '0.4s ease-out all'); |
| 267 | }, 32); |
| 268 | }); |
| 269 | |
| 270 | function vapShowMediaInspector() { |
| 271 | var inspector = jQuery('.vap-media-inspector'); |
| 272 | if (!inspector.hasClass('slide-in')) { |
| 273 | jQuery('.vap-media-inspector').addClass('slide-in'); |
| 274 | } |
| 275 | |
| 276 | // directly use the list of temporary file |
| 277 | var list = window.parent.VAP_TMP_FILES; |
| 278 | |
| 279 | // filter the list and remove all the files that doesn't exist |
| 280 | list = list.filter(function(file) { |
| 281 | return jQuery('.vap-media-block[data-name="' + file + '"]').length ? true : false |
| 282 | }); |
| 283 | |
| 284 | // update reference as certain images might have been deleted |
| 285 | window.parent.VAP_TMP_FILES = list; |
| 286 | |
| 287 | if (list.length == 0) { |
| 288 | // hide media inspector because, even if the selection pool owned some files, |
| 289 | // all them didn't exist and were removed to avoid unexpected behaviors |
| 290 | vapHideMediaInspector(); |
| 291 | } |
| 292 | |
| 293 | <?php |
| 294 | if ($multiple) |
| 295 | { |
| 296 | ?> |
| 297 | // remove all except for first media box |
| 298 | jQuery('.vap-media-inspector .media-info-box:not(:first-child)').remove(); |
| 299 | |
| 300 | for (var i = 0; i < list.length; i++) { |
| 301 | if (i > 0) { |
| 302 | var clone = jQuery('.vap-media-inspector .media-info-box').last().clone(); |
| 303 | jQuery('.selected-media-pool').append(clone); |
| 304 | } |
| 305 | |
| 306 | vapFillInspectorMediaInfo(list[i]); |
| 307 | } |
| 308 | <?php |
| 309 | } |
| 310 | else |
| 311 | { |
| 312 | ?> |
| 313 | vapFillInspectorMediaInfo(list[0]); |
| 314 | <?php |
| 315 | } |
| 316 | ?> |
| 317 | |
| 318 | jQuery('.vap-media-inspector .media-info-box').show(); |
| 319 | } |
| 320 | |
| 321 | function vapFillInspectorMediaInfo(filename) { |
| 322 | var media = jQuery('.vap-media-block[data-name="' + filename + '"]'); |
| 323 | |
| 324 | var mediaUrl = media.find('*[src],*[data-src]'); |
| 325 | mediaUrl = mediaUrl.attr('src') || mediaUrl.data('src'); |
| 326 | |
| 327 | var box = jQuery('.vap-media-inspector .media-info-box').last(); |
| 328 | |
| 329 | box.attr('data-name', media.data('name')) |
| 330 | .find('.media-thumbnail-image a') |
| 331 | .attr('href', mediaUrl) |
| 332 | .html(media.find('.media-centered').html()); |
| 333 | |
| 334 | box.find('.media-details .filename').text(media.data('name')); |
| 335 | box.find('.media-details .uploaded').text(media.data('date')); |
| 336 | box.find('.media-details .file-size').text(media.data('size')); |
| 337 | |
| 338 | if (media.data('width')) { |
| 339 | box.find('.media-details .dimensions').text(media.data('width') + 'x' + media.data('height') + ' pixel').show(); |
| 340 | } else { |
| 341 | box.find('.media-details .dimensions').hide(); |
| 342 | } |
| 343 | } |
| 344 | |
| 345 | function vapHideMediaInspector() { |
| 346 | jQuery('.vap-media-inspector .media-info-box').hide(); |
| 347 | jQuery('.vap-media-inspector').removeClass('slide-in'); |
| 348 | } |
| 349 | |
| 350 | function vapDeleteMediaFile(link) { |
| 351 | // double confirm |
| 352 | var r = confirm(Joomla.JText._('VAPSYSTEMCONFIRMATIONMSG')); |
| 353 | |
| 354 | if (!r) { |
| 355 | return false; |
| 356 | } |
| 357 | |
| 358 | // find media name |
| 359 | var media = jQuery(link).closest('.media-info-box').attr('data-name'); |
| 360 | |
| 361 | // delete media |
| 362 | UIAjax.do( |
| 363 | 'index.php?option=com_vikappointments&task=media.delete&ajax=1', |
| 364 | { |
| 365 | cid: [media], |
| 366 | path: '<?php echo base64_encode($this->path); ?>', |
| 367 | } |
| 368 | ); |
| 369 | |
| 370 | // toggle media selection and then remove it |
| 371 | jQuery('.vap-media-block[data-name="' + media + '"]').trigger('click').remove(); |
| 372 | } |
| 373 | |
| 374 | // files upload |
| 375 | |
| 376 | jQuery(function() { |
| 377 | |
| 378 | var dragCounter = 0; |
| 379 | |
| 380 | // drag&drop actions on target div |
| 381 | |
| 382 | jQuery('#media-upload-box.vap-media-droptarget').on('drag dragstart dragend dragover dragenter dragleave drop', function(e) { |
| 383 | e.preventDefault(); |
| 384 | e.stopPropagation(); |
| 385 | }); |
| 386 | |
| 387 | jQuery('#media-upload-box.vap-media-droptarget').on('dragenter', function(e) { |
| 388 | // increase the drag counter because we may |
| 389 | // enter into a child element |
| 390 | dragCounter++; |
| 391 | |
| 392 | jQuery(this).addClass('drag-enter'); |
| 393 | }); |
| 394 | |
| 395 | jQuery('#media-upload-box.vap-media-droptarget').on('dragleave', function(e) { |
| 396 | // decrease the drag counter to check if we |
| 397 | // left the main container |
| 398 | dragCounter--; |
| 399 | |
| 400 | if (dragCounter <= 0) { |
| 401 | jQuery(this).removeClass('drag-enter'); |
| 402 | } |
| 403 | }); |
| 404 | |
| 405 | jQuery('#media-upload-box.vap-media-droptarget').on('drop', function(e) { |
| 406 | |
| 407 | jQuery(this).removeClass('drag-enter'); |
| 408 | |
| 409 | var files = e.originalEvent.dataTransfer.files; |
| 410 | |
| 411 | vapDispatchMediaUploads(files); |
| 412 | |
| 413 | }); |
| 414 | |
| 415 | jQuery('#media-upload-box.vap-media-droptarget #media-upload-file').on('click', function() { |
| 416 | jQuery('input#media-legacy-upload').val(null).trigger('click'); |
| 417 | }); |
| 418 | |
| 419 | jQuery('input#media-legacy-upload').on('change', function() { |
| 420 | vapDispatchMediaUploads(jQuery(this)[0].files); |
| 421 | }); |
| 422 | |
| 423 | }); |
| 424 | |
| 425 | // upload |
| 426 | |
| 427 | function vapDispatchMediaUploads(files) { |
| 428 | for (var i = 0; i < files.length; i++) { |
| 429 | var status = new UploadingMediaFile(); |
| 430 | status.setFileName(files[i].name); |
| 431 | status.setProgress(0); |
| 432 | |
| 433 | jQuery('.vap-media-gallery').prepend(status.getHtml()); |
| 434 | |
| 435 | vapMediaFileUploadThread(status, files[i]); |
| 436 | } |
| 437 | } |
| 438 | |
| 439 | function UploadingMediaFile() { |
| 440 | // create parent |
| 441 | this.fileBlock = jQuery('<div class="vap-media-block" data-name="" data-selected="0"></div>'); |
| 442 | |
| 443 | // create media thumbnail |
| 444 | this.fileThumb = jQuery('<div class="media-preview"><div class="media-thumbnail"><div class="media-centered"><i class="fas fa-file-image"></i></div></div></div>').appendTo(this.fileBlock); |
| 445 | |
| 446 | this.setFileName = function(name) { |
| 447 | this.fileBlock.attr('data-name', name); |
| 448 | } |
| 449 | |
| 450 | this.setProgress = function(progress) { |
| 451 | var opacity = parseFloat(progress / 100); |
| 452 | |
| 453 | this.fileThumb.find('i.fas').css('opacity', opacity); |
| 454 | } |
| 455 | |
| 456 | this.complete = function(file) { |
| 457 | this.setProgress(100); |
| 458 | |
| 459 | this.fileBlock.attr('data-name', file.name); |
| 460 | this.fileBlock.attr('data-ext', file.file_ext); |
| 461 | this.fileBlock.attr('data-size', file.size); |
| 462 | this.fileBlock.attr('data-date', file.creation); |
| 463 | this.fileBlock.attr('data-width', file.width); |
| 464 | this.fileBlock.attr('data-height', file.height); |
| 465 | |
| 466 | // append file preview |
| 467 | this.fileThumb.find('.media-centered').html(file.html); |
| 468 | } |
| 469 | |
| 470 | this.getHtml = function() { |
| 471 | return this.fileBlock; |
| 472 | } |
| 473 | } |
| 474 | |
| 475 | function vapMediaFileUploadThread(status, file) { |
| 476 | jQuery.noConflict(); |
| 477 | |
| 478 | var formData = new FormData(); |
| 479 | formData.append('file', file); |
| 480 | formData.append('path', '<?php echo base64_encode($this->path); ?>'); |
| 481 | |
| 482 | UIAjax.upload( |
| 483 | // end-point URL |
| 484 | 'index.php?option=com_vikappointments&task=media.dropupload', |
| 485 | // file post data |
| 486 | formData, |
| 487 | // success callback |
| 488 | function(resp) { |
| 489 | // finalize upload |
| 490 | status.complete(resp); |
| 491 | |
| 492 | // register click event and trigger it for media auto-selection |
| 493 | jQuery(status.fileBlock).on('click', vapHandleMediaClick).trigger('click'); |
| 494 | |
| 495 | // refresh search after uploading the image |
| 496 | jQuery('#mediakeysearch').trigger('change'); |
| 497 | }, |
| 498 | // failure callback |
| 499 | function(error) { |
| 500 | // raise alert |
| 501 | alert(error.responseText); |
| 502 | |
| 503 | // remove file from gallery |
| 504 | jQuery('.vap-media-block[data-name="' + file.name + '"]').remove(); |
| 505 | }, |
| 506 | // progress callback |
| 507 | function(progress) { |
| 508 | // update progress |
| 509 | status.setProgress(progress); |
| 510 | } |
| 511 | ); |
| 512 | } |
| 513 | |
| 514 | <?php |
| 515 | /** |
| 516 | * Display a toast message to inform the administrator |
| 517 | * that it is recommended to set up the media configuration |
| 518 | * before uploading the images for the first time. |
| 519 | */ |
| 520 | if ($this->firstConfig) |
| 521 | { |
| 522 | ?> |
| 523 | jQuery(function() { |
| 524 | // display toast message with a delay of 256 ms |
| 525 | setTimeout(function() { |
| 526 | ToastMessage.dispatch({ |
| 527 | text: Joomla.JText._('VAPMEDIAFIRSTCONFIG'), |
| 528 | status: 2, |
| 529 | delay: 15000, |
| 530 | action: function() { |
| 531 | // open new media view in a blank page |
| 532 | window.open('index.php?option=com_vikappointments&task=media.add&configure=1', '_blank'); |
| 533 | }, |
| 534 | }); |
| 535 | }, 256); |
| 536 | }); |
| 537 | <?php |
| 538 | } |
| 539 | ?> |
| 540 | |
| 541 | </script> |
| 542 |