diff --git a/resources/assets/js/controllers.js b/resources/assets/js/controllers.js index 9067f6ca4..beb2fe93e 100644 --- a/resources/assets/js/controllers.js +++ b/resources/assets/js/controllers.js @@ -69,7 +69,7 @@ module.exports = function (ngApp, events) { */ function callbackAndHide(returnData) { if (callback) callback(returnData); - $scope.showing = false; + $scope.hide(); } /** @@ -109,6 +109,7 @@ module.exports = function (ngApp, events) { function show(doneCallback) { callback = doneCallback; $scope.showing = true; + $('#image-manager').find('.overlay').css('display', 'flex').hide().fadeIn(240); // Get initial images if they have not yet been loaded in. if (!dataLoaded) { fetchData(); @@ -131,6 +132,7 @@ module.exports = function (ngApp, events) { */ $scope.hide = function () { $scope.showing = false; + $('#image-manager').find('.overlay').fadeOut(240); }; var baseUrl = window.baseUrl('/images/' + $scope.imageType + '/all/'); diff --git a/resources/assets/js/global.js b/resources/assets/js/global.js index 3a107afa8..cc868a0ea 100644 --- a/resources/assets/js/global.js +++ b/resources/assets/js/global.js @@ -18,7 +18,7 @@ window.baseUrl = function(path) { var ngApp = angular.module('bookStack', ['ngResource', 'ngAnimate', 'ngSanitize', 'ui.sortable']); // Global Event System -class Events { +class EventManager { constructor() { this.listeners = {}; } @@ -39,12 +39,12 @@ class Events { return this; } }; -window.Events = new Events(); +window.Events = new EventManager(); -var services = require('./services')(ngApp, Events); -var directives = require('./directives')(ngApp, Events); -var controllers = require('./controllers')(ngApp, Events); +var services = require('./services')(ngApp, window.Events); +var directives = require('./directives')(ngApp, window.Events); +var controllers = require('./controllers')(ngApp, window.Events); //Global jQuery Config & Extensions @@ -130,6 +130,10 @@ $(function () { $('.entity-list.compact').find('p').not('.empty-text').slideToggle(240); }); + // Popup close + $('.popup-close').click(function() { + $(this).closest('.overlay').fadeOut(240); + }); }); diff --git a/resources/assets/js/pages/page-form.js b/resources/assets/js/pages/page-form.js index 86678a1ba..b733494fa 100644 --- a/resources/assets/js/pages/page-form.js +++ b/resources/assets/js/pages/page-form.js @@ -95,7 +95,12 @@ var mceOptions = module.exports = { alignright: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-right'}, }, file_browser_callback: function (field_name, url, type, win) { + + // Show image manager window.ImageManager.showExternal(function (image) { + + // Set popover link input to image url then fire change event + // to ensure the new value sticks win.document.getElementById(field_name).value = image.url; if ("createEvent" in document) { var evt = document.createEvent("HTMLEvents"); @@ -104,6 +109,8 @@ var mceOptions = module.exports = { } else { win.document.getElementById(field_name).fireEvent("onchange"); } + + // Replace the actively selected content with the linked image var html = '<a href="' + image.url + '" target="_blank">'; html += '<img src="' + image.thumbs.display + '" alt="' + image.name + '">'; html += '</a>'; @@ -119,6 +126,8 @@ var mceOptions = module.exports = { extraSetups: [], setup: function (editor) { + // Run additional setup actions + // Used by the angular side of things for (var i = 0; i < mceOptions.extraSetups.length; i++) { mceOptions.extraSetups[i](editor); } diff --git a/resources/assets/sass/_image-manager.scss b/resources/assets/sass/_components.scss similarity index 89% rename from resources/assets/sass/_image-manager.scss rename to resources/assets/sass/_components.scss index 73b3b59d6..a41277e6f 100644 --- a/resources/assets/sass/_image-manager.scss +++ b/resources/assets/sass/_components.scss @@ -1,5 +1,5 @@ .overlay { - background-color: rgba(0, 0, 0, 0.2); + background-color: rgba(0, 0, 0, 0.333); position: fixed; z-index: 95536; width: 100%; @@ -10,26 +10,56 @@ left: 0; right: 0; bottom: 0; + display: flex; + align-items: center; + justify-content: center; + display: none; } -.image-manager-body { +.popup-body { background-color: #FFF; max-height: 90%; - width: 90%; - height: 90%; + width: 1200px; + height: auto; margin: 2% 5%; border-radius: 4px; box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.3); overflow: hidden; - position: fixed; - top: 0; - bottom: 0; - left: 0; z-index: 999; display: flex; - h1, h2, h3 { - font-weight: 300; + flex-direction: column; + &.small { + margin: 2% auto; + width: 800px; + max-width: 90%; } + &:before { + display: flex; + align-self: flex-start; + } +} + +.popup-header { + display: block; + position: relative; + height: 40px; + .popup-close { + position: absolute; + top: 0; + right: 0; + margin: 0; + height: 40px; + border-radius: 0; + box-shadow: none; + } + .popup-title { + color: #FFF; + padding: 8px $-m; + } +} + +.image-manager-body { + min-height: 60vh; } #image-manager .dropzone-container { @@ -37,12 +67,6 @@ border: 3px dashed #DDD; } -.image-manager-bottom { - position: absolute; - bottom: 0; - right: 0; -} - .image-manager-list .image { display: block; position: relative; @@ -103,18 +127,13 @@ .image-manager-sidebar { width: 300px; - height: 100%; margin-left: 1px; - padding: 0 $-l; + padding: $-m $-l; + overflow-y: auto; border-left: 1px solid #DDD; -} - -.image-manager-close { - position: absolute; - top: 0; - right: 0; - margin: 0; - border-radius: 0; + .dropzone-container { + margin-top: $-m; + } } .image-manager-list { @@ -125,7 +144,6 @@ .image-manager-content { display: flex; flex-direction: column; - height: 100%; flex: 1; .container { width: 100%; @@ -141,12 +159,13 @@ * Copyright (c) 2012 Matias Meno <m@tias.me> */ .dz-message { - font-size: 1.4em; + font-size: 1.2em; + line-height: 1.1; font-style: italic; color: #aaa; text-align: center; cursor: pointer; - padding: $-xl $-m; + padding: $-l $-m; transition: all ease-in-out 120ms; } diff --git a/resources/assets/sass/_grid.scss b/resources/assets/sass/_grid.scss index 1a1321e58..26cfc25ff 100644 --- a/resources/assets/sass/_grid.scss +++ b/resources/assets/sass/_grid.scss @@ -25,6 +25,10 @@ body.flexbox { } } +.flex-child > div { + flex: 1; +} + /** Rules for all columns */ div[class^="col-"] img { max-width: 100%; diff --git a/resources/assets/sass/styles.scss b/resources/assets/sass/styles.scss index a6c364018..90b452a8e 100644 --- a/resources/assets/sass/styles.scss +++ b/resources/assets/sass/styles.scss @@ -12,7 +12,7 @@ @import "animations"; @import "tinymce"; @import "highlightjs"; -@import "image-manager"; +@import "components"; @import "header"; @import "lists"; @import "pages"; diff --git a/resources/views/pages/edit.blade.php b/resources/views/pages/edit.blade.php index 9fe6a6a19..f470d8d80 100644 --- a/resources/views/pages/edit.blade.php +++ b/resources/views/pages/edit.blade.php @@ -21,4 +21,16 @@ </div> @include('partials/image-manager', ['imageType' => 'gallery', 'uploaded_to' => $page->id]) + <div id="entity-selector-wrap"> + <div class="overlay"> + <div class="popup-body small flex-child"> + <div class="popup-header primary-background"> + <div class="popup-title">Entity Select</div> + <button class="popup-close neg button">x</button> + </div> + @include('partials/entity-selector', ['name' => 'entity-selector']) + </div> + </div> + </div> + @stop \ No newline at end of file diff --git a/resources/views/partials/image-manager.blade.php b/resources/views/partials/image-manager.blade.php index 69928e119..1b3fb0cfb 100644 --- a/resources/views/partials/image-manager.blade.php +++ b/resources/views/partials/image-manager.blade.php @@ -1,84 +1,94 @@ <div id="image-manager" image-type="{{ $imageType }}" ng-controller="ImageManagerController" uploaded-to="{{ $uploaded_to or 0 }}"> - <div class="overlay anim-slide" ng-show="showing" ng-cloak ng-click="hide()"> - <div class="image-manager-body" ng-click="$event.stopPropagation()"> + <div class="overlay" ng-cloak ng-click="hide()"> + <div class="popup-body" ng-click="$event.stopPropagation()"> - <div class="image-manager-content"> - <div ng-if="imageType === 'gallery'" class="container"> - <div class="image-manager-header row faded-small nav-tabs"> - <div class="col-xs-4 tab-item" title="View all images" ng-class="{selected: (view=='all')}" ng-click="setView('all')"><i class="zmdi zmdi-collection-image"></i> All</div> - <div class="col-xs-4 tab-item" title="View images uploaded to this book" ng-class="{selected: (view=='book')}" ng-click="setView('book')"><i class="zmdi zmdi-book text-book"></i> Book</div> - <div class="col-xs-4 tab-item" title="View images uploaded to this page" ng-class="{selected: (view=='page')}" ng-click="setView('page')"><i class="zmdi zmdi-file-text text-page"></i> Page</div> + <div class="popup-header primary-background"> + <div class="popup-title">Image Select</div> + <button class="popup-close neg button">x</button> + </div> + + <div class="flex-fill image-manager-body"> + + <div class="image-manager-content"> + <div ng-if="imageType === 'gallery'" class="container"> + <div class="image-manager-header row faded-small nav-tabs"> + <div class="col-xs-4 tab-item" title="View all images" ng-class="{selected: (view=='all')}" ng-click="setView('all')"><i class="zmdi zmdi-collection-image"></i> All</div> + <div class="col-xs-4 tab-item" title="View images uploaded to this book" ng-class="{selected: (view=='book')}" ng-click="setView('book')"><i class="zmdi zmdi-book text-book"></i> Book</div> + <div class="col-xs-4 tab-item" title="View images uploaded to this page" ng-class="{selected: (view=='page')}" ng-click="setView('page')"><i class="zmdi zmdi-file-text text-page"></i> Page</div> + </div> </div> - </div> - <div ng-show="view === 'all'" > - <form ng-submit="searchImages()" class="contained-search-box"> - <input type="text" placeholder="Search by image name" ng-model="searchTerm"> - <button ng-class="{active: searching}" title="Clear Search" type="button" ng-click="cancelSearch()" class="text-button cancel"><i class="zmdi zmdi-close-circle-o"></i></button> - <button title="Search" class="text-button" type="submit"><i class="zmdi zmdi-search"></i></button> - </form> - </div> - <div class="image-manager-list"> - <div ng-repeat="image in images"> - <div class="image anim fadeIn" ng-style="{animationDelay: ($index > 26) ? '160ms' : ($index * 25) + 'ms'}" - ng-class="{selected: (image==selectedImage)}" ng-click="imageSelect(image)"> - <img ng-src="@{{image.thumbs.gallery}}" ng-attr-alt="@{{image.title}}" ng-attr-title="@{{image.name}}"> - <div class="image-meta"> - <span class="name" ng-bind="image.name"></span> - <span class="date">Uploaded @{{ getDate(image.created_at) | date:'mediumDate' }}</span> + <div ng-show="view === 'all'" > + <form ng-submit="searchImages()" class="contained-search-box"> + <input type="text" placeholder="Search by image name" ng-model="searchTerm"> + <button ng-class="{active: searching}" title="Clear Search" type="button" ng-click="cancelSearch()" class="text-button cancel"><i class="zmdi zmdi-close-circle-o"></i></button> + <button title="Search" class="text-button" type="submit"><i class="zmdi zmdi-search"></i></button> + </form> + </div> + <div class="image-manager-list"> + <div ng-repeat="image in images"> + <div class="image anim fadeIn" ng-style="{animationDelay: ($index > 26) ? '160ms' : ($index * 25) + 'ms'}" + ng-class="{selected: (image==selectedImage)}" ng-click="imageSelect(image)"> + <img ng-src="@{{image.thumbs.gallery}}" ng-attr-alt="@{{image.title}}" ng-attr-title="@{{image.name}}"> + <div class="image-meta"> + <span class="name" ng-bind="image.name"></span> + <span class="date">Uploaded @{{ getDate(image.created_at) | date:'mediumDate' }}</span> + </div> </div> </div> + <div class="load-more" ng-show="hasMore" ng-click="fetchData()">Load More</div> </div> - <div class="load-more" ng-show="hasMore" ng-click="fetchData()">Load More</div> </div> + + <div class="image-manager-sidebar"> + <div class="inner"> + + <div class="image-manager-details anim fadeIn" ng-show="selectedImage"> + + <form ng-submit="saveImageDetails($event)"> + <div> + <a ng-href="@{{selectedImage.url}}" target="_blank" style="display: block;"> + <img ng-src="@{{selectedImage.thumbs.gallery}}" ng-attr-alt="@{{selectedImage.title}}" ng-attr-title="@{{selectedImage.name}}"> + </a> + </div> + <div class="form-group"> + <label for="name">Image Name</label> + <input type="text" id="name" name="name" ng-model="selectedImage.name"> + </div> + </form> + + <div ng-show="dependantPages"> + <p class="text-neg text-small"> + This image is used in the pages below, Click delete again to confirm you want to delete + this image. + </p> + <ul class="text-neg"> + <li ng-repeat="page in dependantPages"> + <a ng-href="@{{ page.url }}" target="_blank" class="text-neg" ng-bind="page.name"></a> + </li> + </ul> + </div> + + <div class="clearfix"> + <form class="float left" ng-submit="deleteImage($event)"> + <button class="button neg"><i class="zmdi zmdi-delete"></i></button> + </form> + <button class="button pos anim fadeIn float right" ng-show="selectedImage" ng-click="selectButtonClick()"> + <i class="zmdi zmdi-square-right"></i>Select Image + </button> + </div> + + </div> + + <drop-zone upload-url="@{{getUploadUrl()}}" uploaded-to="@{{uploadedTo}}" event-success="uploadSuccess"></drop-zone> + + + </div> + </div> + + + </div> - <button class="neg button image-manager-close" ng-click="hide()">x</button> - - <div class="image-manager-sidebar"> - <h2>Images</h2> - <drop-zone upload-url="@{{getUploadUrl()}}" uploaded-to="@{{uploadedTo}}" event-success="uploadSuccess"></drop-zone> - <div class="image-manager-details anim fadeIn" ng-show="selectedImage"> - - <hr class="even"> - - <form ng-submit="saveImageDetails($event)"> - <div> - <a ng-href="@{{selectedImage.url}}" target="_blank" style="display: block;"> - <img ng-src="@{{selectedImage.thumbs.gallery}}" ng-attr-alt="@{{selectedImage.title}}" ng-attr-title="@{{selectedImage.name}}"> - </a> - </div> - <div class="form-group"> - <label for="name">Image Name</label> - <input type="text" id="name" name="name" ng-model="selectedImage.name"> - </div> - </form> - - <hr class="even"> - - <div ng-show="dependantPages"> - <p class="text-neg text-small"> - This image is used in the pages below, Click delete again to confirm you want to delete - this image. - </p> - <ul class="text-neg"> - <li ng-repeat="page in dependantPages"> - <a ng-href="@{{ page.url }}" target="_blank" class="text-neg" ng-bind="page.name"></a> - </li> - </ul> - </div> - - <form ng-submit="deleteImage($event)"> - <button class="button neg"><i class="zmdi zmdi-delete"></i>Delete Image</button> - </form> - </div> - - <div class="image-manager-bottom"> - <button class="button pos anim fadeIn" ng-show="selectedImage" ng-click="selectButtonClick()"> - <i class="zmdi zmdi-square-right"></i>Select Image - </button> - </div> - - </div> </div> </div> </div> \ No newline at end of file