Showing
9 changed files
with
164 additions
and
40 deletions
| ... | @@ -600,6 +600,58 @@ module.exports = function (ngApp, events) { | ... | @@ -600,6 +600,58 @@ module.exports = function (ngApp, events) { |
| 600 | } | 600 | } |
| 601 | }]); | 601 | }]); |
| 602 | 602 | ||
| 603 | + ngApp.directive('entityLinkSelector', [function($http) { | ||
| 604 | + return { | ||
| 605 | + restict: 'A', | ||
| 606 | + link: function(scope, element, attrs) { | ||
| 607 | + | ||
| 608 | + const selectButton = element.find('.entity-link-selector-confirm'); | ||
| 609 | + let callback = false; | ||
| 610 | + let entitySelection = null; | ||
| 611 | + | ||
| 612 | + // Handle entity selection change, Stores the selected entity locally | ||
| 613 | + function entitySelectionChange(entity) { | ||
| 614 | + entitySelection = entity; | ||
| 615 | + if (entity === null) { | ||
| 616 | + selectButton.attr('disabled', 'true'); | ||
| 617 | + } else { | ||
| 618 | + selectButton.removeAttr('disabled'); | ||
| 619 | + } | ||
| 620 | + } | ||
| 621 | + events.listen('entity-select-change', entitySelectionChange); | ||
| 622 | + | ||
| 623 | + // Handle selection confirm button click | ||
| 624 | + selectButton.click(event => { | ||
| 625 | + hide(); | ||
| 626 | + if (entitySelection !== null) callback(entitySelection); | ||
| 627 | + }); | ||
| 628 | + | ||
| 629 | + // Show selector interface | ||
| 630 | + function show() { | ||
| 631 | + element.fadeIn(240); | ||
| 632 | + } | ||
| 633 | + | ||
| 634 | + // Hide selector interface | ||
| 635 | + function hide() { | ||
| 636 | + element.fadeOut(240); | ||
| 637 | + } | ||
| 638 | + | ||
| 639 | + // Listen to confirmation of entity selections (doubleclick) | ||
| 640 | + events.listen('entity-select-confirm', entity => { | ||
| 641 | + hide(); | ||
| 642 | + callback(entity); | ||
| 643 | + }); | ||
| 644 | + | ||
| 645 | + // Show entity selector, Accessible globally, and store the callback | ||
| 646 | + window.showEntityLinkSelector = function(passedCallback) { | ||
| 647 | + show(); | ||
| 648 | + callback = passedCallback; | ||
| 649 | + }; | ||
| 650 | + | ||
| 651 | + } | ||
| 652 | + }; | ||
| 653 | + }]); | ||
| 654 | + | ||
| 603 | 655 | ||
| 604 | ngApp.directive('entitySelector', ['$http', '$sce', function ($http, $sce) { | 656 | ngApp.directive('entitySelector', ['$http', '$sce', function ($http, $sce) { |
| 605 | return { | 657 | return { |
| ... | @@ -613,26 +665,60 @@ module.exports = function (ngApp, events) { | ... | @@ -613,26 +665,60 @@ module.exports = function (ngApp, events) { |
| 613 | // Add input for forms | 665 | // Add input for forms |
| 614 | const input = element.find('[entity-selector-input]').first(); | 666 | const input = element.find('[entity-selector-input]').first(); |
| 615 | 667 | ||
| 668 | + // Detect double click events | ||
| 669 | + var lastClick = 0; | ||
| 670 | + function isDoubleClick() { | ||
| 671 | + let now = Date.now(); | ||
| 672 | + let answer = now - lastClick < 300; | ||
| 673 | + lastClick = now; | ||
| 674 | + return answer; | ||
| 675 | + } | ||
| 676 | + | ||
| 616 | // Listen to entity item clicks | 677 | // Listen to entity item clicks |
| 617 | element.on('click', '.entity-list a', function(event) { | 678 | element.on('click', '.entity-list a', function(event) { |
| 618 | event.preventDefault(); | 679 | event.preventDefault(); |
| 619 | event.stopPropagation(); | 680 | event.stopPropagation(); |
| 620 | let item = $(this).closest('[data-entity-type]'); | 681 | let item = $(this).closest('[data-entity-type]'); |
| 621 | - itemSelect(item); | 682 | + itemSelect(item, isDoubleClick()); |
| 622 | }); | 683 | }); |
| 623 | element.on('click', '[data-entity-type]', function(event) { | 684 | element.on('click', '[data-entity-type]', function(event) { |
| 624 | - itemSelect($(this)); | 685 | + itemSelect($(this), isDoubleClick()); |
| 625 | }); | 686 | }); |
| 626 | 687 | ||
| 627 | // Select entity action | 688 | // Select entity action |
| 628 | - function itemSelect(item) { | 689 | + function itemSelect(item, doubleClick) { |
| 629 | let entityType = item.attr('data-entity-type'); | 690 | let entityType = item.attr('data-entity-type'); |
| 630 | let entityId = item.attr('data-entity-id'); | 691 | let entityId = item.attr('data-entity-id'); |
| 631 | - let isSelected = !item.hasClass('selected'); | 692 | + let isSelected = !item.hasClass('selected') || doubleClick; |
| 632 | element.find('.selected').removeClass('selected').removeClass('primary-background'); | 693 | element.find('.selected').removeClass('selected').removeClass('primary-background'); |
| 633 | if (isSelected) item.addClass('selected').addClass('primary-background'); | 694 | if (isSelected) item.addClass('selected').addClass('primary-background'); |
| 634 | let newVal = isSelected ? `${entityType}:${entityId}` : ''; | 695 | let newVal = isSelected ? `${entityType}:${entityId}` : ''; |
| 635 | input.val(newVal); | 696 | input.val(newVal); |
| 697 | + | ||
| 698 | + if (!isSelected) { | ||
| 699 | + events.emit('entity-select-change', null); | ||
| 700 | + } | ||
| 701 | + | ||
| 702 | + if (!doubleClick && !isSelected) return; | ||
| 703 | + | ||
| 704 | + let link = item.find('.entity-list-item-link').attr('href'); | ||
| 705 | + let name = item.find('.entity-list-item-name').text(); | ||
| 706 | + | ||
| 707 | + if (doubleClick) { | ||
| 708 | + events.emit('entity-select-confirm', { | ||
| 709 | + id: Number(entityId), | ||
| 710 | + name: name, | ||
| 711 | + link: link | ||
| 712 | + }); | ||
| 713 | + } | ||
| 714 | + | ||
| 715 | + if (isSelected) { | ||
| 716 | + events.emit('entity-select-change', { | ||
| 717 | + id: Number(entityId), | ||
| 718 | + name: name, | ||
| 719 | + link: link | ||
| 720 | + }); | ||
| 721 | + } | ||
| 636 | } | 722 | } |
| 637 | 723 | ||
| 638 | // Get search url with correct types | 724 | // Get search url with correct types | ... | ... |
| ... | @@ -135,6 +135,11 @@ $(function () { | ... | @@ -135,6 +135,11 @@ $(function () { |
| 135 | $(this).closest('.overlay').fadeOut(240); | 135 | $(this).closest('.overlay').fadeOut(240); |
| 136 | }); | 136 | }); |
| 137 | 137 | ||
| 138 | + $('.overlay').click(function(event) { | ||
| 139 | + if (!$(event.target).hasClass('overlay')) return; | ||
| 140 | + $(this).fadeOut(240); | ||
| 141 | + }); | ||
| 142 | + | ||
| 138 | }); | 143 | }); |
| 139 | 144 | ||
| 140 | // Page specific items | 145 | // Page specific items | ... | ... |
| ... | @@ -96,26 +96,37 @@ var mceOptions = module.exports = { | ... | @@ -96,26 +96,37 @@ var mceOptions = module.exports = { |
| 96 | }, | 96 | }, |
| 97 | file_browser_callback: function (field_name, url, type, win) { | 97 | file_browser_callback: function (field_name, url, type, win) { |
| 98 | 98 | ||
| 99 | - // Show image manager | 99 | + if (type === 'file') { |
| 100 | - window.ImageManager.showExternal(function (image) { | 100 | + window.showEntityLinkSelector(function(entity) { |
| 101 | - | 101 | + var originalField = win.document.getElementById(field_name); |
| 102 | - // Set popover link input to image url then fire change event | 102 | + originalField.value = entity.link; |
| 103 | - // to ensure the new value sticks | 103 | + $(originalField).closest('.mce-form').find('input').eq(2).val(entity.name); |
| 104 | - win.document.getElementById(field_name).value = image.url; | 104 | + }); |
| 105 | - if ("createEvent" in document) { | 105 | + } |
| 106 | - var evt = document.createEvent("HTMLEvents"); | 106 | + |
| 107 | - evt.initEvent("change", false, true); | 107 | + if (type === 'image') { |
| 108 | - win.document.getElementById(field_name).dispatchEvent(evt); | 108 | + // Show image manager |
| 109 | - } else { | 109 | + window.ImageManager.showExternal(function (image) { |
| 110 | - win.document.getElementById(field_name).fireEvent("onchange"); | 110 | + |
| 111 | - } | 111 | + // Set popover link input to image url then fire change event |
| 112 | + // to ensure the new value sticks | ||
| 113 | + win.document.getElementById(field_name).value = image.url; | ||
| 114 | + if ("createEvent" in document) { | ||
| 115 | + var evt = document.createEvent("HTMLEvents"); | ||
| 116 | + evt.initEvent("change", false, true); | ||
| 117 | + win.document.getElementById(field_name).dispatchEvent(evt); | ||
| 118 | + } else { | ||
| 119 | + win.document.getElementById(field_name).fireEvent("onchange"); | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + // Replace the actively selected content with the linked image | ||
| 123 | + var html = '<a href="' + image.url + '" target="_blank">'; | ||
| 124 | + html += '<img src="' + image.thumbs.display + '" alt="' + image.name + '">'; | ||
| 125 | + html += '</a>'; | ||
| 126 | + win.tinyMCE.activeEditor.execCommand('mceInsertContent', false, html); | ||
| 127 | + }); | ||
| 128 | + } | ||
| 112 | 129 | ||
| 113 | - // Replace the actively selected content with the linked image | ||
| 114 | - var html = '<a href="' + image.url + '" target="_blank">'; | ||
| 115 | - html += '<img src="' + image.thumbs.display + '" alt="' + image.name + '">'; | ||
| 116 | - html += '</a>'; | ||
| 117 | - win.tinyMCE.activeEditor.execCommand('mceInsertContent', false, html); | ||
| 118 | - }); | ||
| 119 | }, | 130 | }, |
| 120 | paste_preprocess: function (plugin, args) { | 131 | paste_preprocess: function (plugin, args) { |
| 121 | var content = args.content; | 132 | var content = args.content; | ... | ... |
| ... | @@ -100,3 +100,13 @@ $button-border-radius: 2px; | ... | @@ -100,3 +100,13 @@ $button-border-radius: 2px; |
| 100 | } | 100 | } |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | +.button[disabled] { | ||
| 104 | + background-color: #BBB; | ||
| 105 | + cursor: default; | ||
| 106 | + &:hover { | ||
| 107 | + background-color: #BBB; | ||
| 108 | + cursor: default; | ||
| 109 | + box-shadow: none; | ||
| 110 | + } | ||
| 111 | +} | ||
| 112 | + | ... | ... |
| ... | @@ -39,25 +39,28 @@ | ... | @@ -39,25 +39,28 @@ |
| 39 | } | 39 | } |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | -.popup-header { | 42 | +.corner-button { |
| 43 | + position: absolute; | ||
| 44 | + top: 0; | ||
| 45 | + right: 0; | ||
| 46 | + margin: 0; | ||
| 47 | + height: 40px; | ||
| 48 | + border-radius: 0; | ||
| 49 | + box-shadow: none; | ||
| 50 | +} | ||
| 51 | + | ||
| 52 | +.popup-header, .popup-footer { | ||
| 43 | display: block; | 53 | display: block; |
| 44 | position: relative; | 54 | position: relative; |
| 45 | height: 40px; | 55 | height: 40px; |
| 46 | - .popup-close { | ||
| 47 | - position: absolute; | ||
| 48 | - top: 0; | ||
| 49 | - right: 0; | ||
| 50 | - margin: 0; | ||
| 51 | - height: 40px; | ||
| 52 | - border-radius: 0; | ||
| 53 | - box-shadow: none; | ||
| 54 | - } | ||
| 55 | .popup-title { | 56 | .popup-title { |
| 56 | color: #FFF; | 57 | color: #FFF; |
| 57 | padding: 8px $-m; | 58 | padding: 8px $-m; |
| 58 | } | 59 | } |
| 59 | } | 60 | } |
| 60 | - | 61 | +#entity-selector-wrap .popup-body .form-group { |
| 62 | + margin: 0; | ||
| 63 | +} | ||
| 61 | .image-manager-body { | 64 | .image-manager-body { |
| 62 | min-height: 60vh; | 65 | min-height: 60vh; |
| 63 | } | 66 | } | ... | ... |
| 1 | <div class="book entity-list-item" data-entity-type="book" data-entity-id="{{$book->id}}"> | 1 | <div class="book entity-list-item" data-entity-type="book" data-entity-id="{{$book->id}}"> |
| 2 | - <h3 class="text-book"><a class="text-book" href="{{$book->getUrl()}}"><i class="zmdi zmdi-book"></i>{{$book->name}}</a></h3> | 2 | + <h3 class="text-book"><a class="text-book entity-list-item-link" href="{{$book->getUrl()}}"><i class="zmdi zmdi-book"></i><span class="entity-list-item-name">{{$book->name}}</span></a></h3> |
| 3 | @if(isset($book->searchSnippet)) | 3 | @if(isset($book->searchSnippet)) |
| 4 | <p class="text-muted">{!! $book->searchSnippet !!}</p> | 4 | <p class="text-muted">{!! $book->searchSnippet !!}</p> |
| 5 | @else | 5 | @else | ... | ... |
| ... | @@ -6,8 +6,8 @@ | ... | @@ -6,8 +6,8 @@ |
| 6 | </a> | 6 | </a> |
| 7 | <span class="text-muted"> » </span> | 7 | <span class="text-muted"> » </span> |
| 8 | @endif | 8 | @endif |
| 9 | - <a href="{{ $chapter->getUrl() }}" class="text-chapter"> | 9 | + <a href="{{ $chapter->getUrl() }}" class="text-chapter entity-list-item-link"> |
| 10 | - <i class="zmdi zmdi-collection-bookmark"></i>{{ $chapter->name }} | 10 | + <i class="zmdi zmdi-collection-bookmark"></i><span class="entity-list-item-name">{{ $chapter->name }}</span> |
| 11 | </a> | 11 | </a> |
| 12 | </h3> | 12 | </h3> |
| 13 | @if(isset($chapter->searchSnippet)) | 13 | @if(isset($chapter->searchSnippet)) | ... | ... |
| ... | @@ -22,15 +22,24 @@ | ... | @@ -22,15 +22,24 @@ |
| 22 | @include('partials/image-manager', ['imageType' => 'gallery', 'uploaded_to' => $page->id]) | 22 | @include('partials/image-manager', ['imageType' => 'gallery', 'uploaded_to' => $page->id]) |
| 23 | 23 | ||
| 24 | <div id="entity-selector-wrap"> | 24 | <div id="entity-selector-wrap"> |
| 25 | - <div class="overlay"> | 25 | + <div class="overlay" entity-link-selector> |
| 26 | <div class="popup-body small flex-child"> | 26 | <div class="popup-body small flex-child"> |
| 27 | <div class="popup-header primary-background"> | 27 | <div class="popup-header primary-background"> |
| 28 | <div class="popup-title">Entity Select</div> | 28 | <div class="popup-title">Entity Select</div> |
| 29 | - <button class="popup-close neg button">x</button> | 29 | + <button type="button" class="corner-button neg button">x</button> |
| 30 | </div> | 30 | </div> |
| 31 | @include('partials/entity-selector', ['name' => 'entity-selector']) | 31 | @include('partials/entity-selector', ['name' => 'entity-selector']) |
| 32 | + <div class="popup-footer"> | ||
| 33 | + <button type="button" disabled="true" class="button entity-link-selector-confirm pos corner-button">Select</button> | ||
| 34 | + </div> | ||
| 32 | </div> | 35 | </div> |
| 33 | </div> | 36 | </div> |
| 34 | </div> | 37 | </div> |
| 35 | 38 | ||
| 39 | + <script> | ||
| 40 | + (function() { | ||
| 41 | + | ||
| 42 | + })(); | ||
| 43 | + </script> | ||
| 44 | + | ||
| 36 | @stop | 45 | @stop |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| 1 | <div class="page {{$page->draft ? 'draft' : ''}} entity-list-item" data-entity-type="page" data-entity-id="{{$page->id}}"> | 1 | <div class="page {{$page->draft ? 'draft' : ''}} entity-list-item" data-entity-type="page" data-entity-id="{{$page->id}}"> |
| 2 | <h3> | 2 | <h3> |
| 3 | - <a href="{{ $page->getUrl() }}" class="text-page"><i class="zmdi zmdi-file-text"></i>{{ $page->name }}</a> | 3 | + <a href="{{ $page->getUrl() }}" class="text-page entity-list-item-link"><i class="zmdi zmdi-file-text"></i><span class="entity-list-item-name">{{ $page->name }}</span></a> |
| 4 | </h3> | 4 | </h3> |
| 5 | 5 | ||
| 6 | @if(isset($page->searchSnippet)) | 6 | @if(isset($page->searchSnippet)) | ... | ... |
-
Please register or sign in to post a comment