Updated image controller styling and added preview option
The notification system was also updated so it can be used from JavaScript events such as image manager uploads. Closes #25
This commit is contained in:
		
							parent
							
								
									8e8d582bc6
								
							
						
					
					
						commit
						8296782149
					
				| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
"use strict";
 | 
			
		||||
 | 
			
		||||
module.exports = function (ngApp) {
 | 
			
		||||
module.exports = function (ngApp, events) {
 | 
			
		||||
 | 
			
		||||
    ngApp.controller('ImageManagerController', ['$scope', '$attrs', '$http', '$timeout', 'imageManagerService',
 | 
			
		||||
        function ($scope, $attrs, $http, $timeout, imageManagerService) {
 | 
			
		||||
| 
						 | 
				
			
			@ -17,21 +17,40 @@ module.exports = function (ngApp) {
 | 
			
		|||
            var dataLoaded = false;
 | 
			
		||||
            var callback = false;
 | 
			
		||||
 | 
			
		||||
            /**
 | 
			
		||||
             * Simple returns the appropriate upload url depending on the image type set.
 | 
			
		||||
             * @returns {string}
 | 
			
		||||
             */
 | 
			
		||||
            $scope.getUploadUrl = function () {
 | 
			
		||||
                return '/images/' + $scope.imageType + '/upload';
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            /**
 | 
			
		||||
             * Runs on image upload, Adds an image to local list of images
 | 
			
		||||
             * and shows a success message to the user.
 | 
			
		||||
             * @param file
 | 
			
		||||
             * @param data
 | 
			
		||||
             */
 | 
			
		||||
            $scope.uploadSuccess = function (file, data) {
 | 
			
		||||
                $scope.$apply(() => {
 | 
			
		||||
                    $scope.images.unshift(data);
 | 
			
		||||
                });
 | 
			
		||||
                events.emit('success', 'Image uploaded');
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            /**
 | 
			
		||||
             * Runs the callback and hides the image manager.
 | 
			
		||||
             * @param returnData
 | 
			
		||||
             */
 | 
			
		||||
            function callbackAndHide(returnData) {
 | 
			
		||||
                if (callback) callback(returnData);
 | 
			
		||||
                $scope.showing = false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /**
 | 
			
		||||
             * Image select action. Checks if a double-click was fired.
 | 
			
		||||
             * @param image
 | 
			
		||||
             */
 | 
			
		||||
            $scope.imageSelect = function (image) {
 | 
			
		||||
                var dblClickTime = 300;
 | 
			
		||||
                var currentTime = Date.now();
 | 
			
		||||
| 
						 | 
				
			
			@ -48,10 +67,19 @@ module.exports = function (ngApp) {
 | 
			
		|||
                previousClickTime = currentTime;
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            /**
 | 
			
		||||
             * Action that runs when the 'Select image' button is clicked.
 | 
			
		||||
             * Runs the callback and hides the image manager.
 | 
			
		||||
             */
 | 
			
		||||
            $scope.selectButtonClick = function () {
 | 
			
		||||
                callbackAndHide($scope.selectedImage);
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            /**
 | 
			
		||||
             * Show the image manager.
 | 
			
		||||
             * Takes a callback to execute later on.
 | 
			
		||||
             * @param doneCallback
 | 
			
		||||
             */
 | 
			
		||||
            function show(doneCallback) {
 | 
			
		||||
                callback = doneCallback;
 | 
			
		||||
                $scope.showing = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -62,6 +90,8 @@ module.exports = function (ngApp) {
 | 
			
		|||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Connects up the image manger so it can be used externally
 | 
			
		||||
            // such as from TinyMCE.
 | 
			
		||||
            imageManagerService.show = show;
 | 
			
		||||
            imageManagerService.showExternal = function (doneCallback) {
 | 
			
		||||
                $scope.$apply(() => {
 | 
			
		||||
| 
						 | 
				
			
			@ -70,10 +100,16 @@ module.exports = function (ngApp) {
 | 
			
		|||
            };
 | 
			
		||||
            window.ImageManager = imageManagerService;
 | 
			
		||||
 | 
			
		||||
            /**
 | 
			
		||||
             * Hide the image manager
 | 
			
		||||
             */
 | 
			
		||||
            $scope.hide = function () {
 | 
			
		||||
                $scope.showing = false;
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            /**
 | 
			
		||||
             * Fetch the list image data from the server.
 | 
			
		||||
             */
 | 
			
		||||
            function fetchData() {
 | 
			
		||||
                var url = '/images/' + $scope.imageType + '/all/' + page;
 | 
			
		||||
                $http.get(url).then((response) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -82,28 +118,33 @@ module.exports = function (ngApp) {
 | 
			
		|||
                    page++;
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            $scope.fetchData = fetchData;
 | 
			
		||||
 | 
			
		||||
            /**
 | 
			
		||||
             * Save the details of an image.
 | 
			
		||||
             * @param event
 | 
			
		||||
             */
 | 
			
		||||
            $scope.saveImageDetails = function (event) {
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
                var url = '/images/update/' + $scope.selectedImage.id;
 | 
			
		||||
                $http.put(url, this.selectedImage).then((response) => {
 | 
			
		||||
                    $scope.imageUpdateSuccess = true;
 | 
			
		||||
                    $timeout(() => {
 | 
			
		||||
                        $scope.imageUpdateSuccess = false;
 | 
			
		||||
                    }, 3000);
 | 
			
		||||
                    events.emit('success', 'Image details updated');
 | 
			
		||||
                }, (response) => {
 | 
			
		||||
                    var errors = response.data;
 | 
			
		||||
                    var message = '';
 | 
			
		||||
                    Object.keys(errors).forEach((key) => {
 | 
			
		||||
                        message += errors[key].join('\n');
 | 
			
		||||
                    });
 | 
			
		||||
                    $scope.imageUpdateFailure = message;
 | 
			
		||||
                    $timeout(() => {
 | 
			
		||||
                        $scope.imageUpdateFailure = false;
 | 
			
		||||
                    }, 5000);
 | 
			
		||||
                    events.emit('error', message);
 | 
			
		||||
                });
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            /**
 | 
			
		||||
             * Delete an image from system and notify of success.
 | 
			
		||||
             * Checks if it should force delete when an image
 | 
			
		||||
             * has dependant pages.
 | 
			
		||||
             * @param event
 | 
			
		||||
             */
 | 
			
		||||
            $scope.deleteImage = function (event) {
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
                var force = $scope.dependantPages !== false;
 | 
			
		||||
| 
						 | 
				
			
			@ -112,10 +153,7 @@ module.exports = function (ngApp) {
 | 
			
		|||
                $http.delete(url).then((response) => {
 | 
			
		||||
                    $scope.images.splice($scope.images.indexOf($scope.selectedImage), 1);
 | 
			
		||||
                    $scope.selectedImage = false;
 | 
			
		||||
                    $scope.imageDeleteSuccess = true;
 | 
			
		||||
                    $timeout(() => {
 | 
			
		||||
                        $scope.imageDeleteSuccess = false;
 | 
			
		||||
                    }, 3000);
 | 
			
		||||
                    events.emit('success', 'Image successfully deleted');
 | 
			
		||||
                }, (response) => {
 | 
			
		||||
                    // Pages failure
 | 
			
		||||
                    if (response.status === 400) {
 | 
			
		||||
| 
						 | 
				
			
			@ -124,6 +162,15 @@ module.exports = function (ngApp) {
 | 
			
		|||
                });
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            /**
 | 
			
		||||
             * Simple date creator used to properly format dates.
 | 
			
		||||
             * @param stringDate
 | 
			
		||||
             * @returns {Date}
 | 
			
		||||
             */
 | 
			
		||||
            $scope.getDate = function(stringDate) {
 | 
			
		||||
                return new Date(stringDate);
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
        }]);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,7 @@ var toggleSwitchTemplate = require('./components/toggle-switch.html');
 | 
			
		|||
var imagePickerTemplate = require('./components/image-picker.html');
 | 
			
		||||
var dropZoneTemplate = require('./components/drop-zone.html');
 | 
			
		||||
 | 
			
		||||
module.exports = function (ngApp) {
 | 
			
		||||
module.exports = function (ngApp, events) {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Toggle Switches
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
// AngularJS - Create application and load components
 | 
			
		||||
var angular = require('angular');
 | 
			
		||||
| 
						 | 
				
			
			@ -7,9 +7,31 @@ var ngAnimate = require('angular-animate');
 | 
			
		|||
var ngSanitize = require('angular-sanitize');
 | 
			
		||||
 | 
			
		||||
var ngApp = angular.module('bookStack', ['ngResource', 'ngAnimate', 'ngSanitize']);
 | 
			
		||||
var services = require('./services')(ngApp);
 | 
			
		||||
var directives = require('./directives')(ngApp);
 | 
			
		||||
var controllers = require('./controllers')(ngApp);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Global Event System
 | 
			
		||||
var Events = {
 | 
			
		||||
    listeners: {},
 | 
			
		||||
    emit: function (eventName, eventData) {
 | 
			
		||||
        if (typeof this.listeners[eventName] === 'undefined') return this;
 | 
			
		||||
        var eventsToStart = this.listeners[eventName];
 | 
			
		||||
        for (let i = 0; i < eventsToStart.length; i++) {
 | 
			
		||||
            var event = eventsToStart[i];
 | 
			
		||||
            event(eventData);
 | 
			
		||||
        }
 | 
			
		||||
        return this;
 | 
			
		||||
    },
 | 
			
		||||
    listen: function (eventName, callback) {
 | 
			
		||||
        if (typeof this.listeners[eventName] === 'undefined') this.listeners[eventName] = [];
 | 
			
		||||
        this.listeners[eventName].push(callback);
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
window.Events = Events;
 | 
			
		||||
 | 
			
		||||
var services = require('./services')(ngApp, Events);
 | 
			
		||||
var directives = require('./directives')(ngApp, Events);
 | 
			
		||||
var controllers = require('./controllers')(ngApp, Events);
 | 
			
		||||
 | 
			
		||||
//Global jQuery Config & Extensions
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -32,8 +54,25 @@ $.expr[":"].contains = $.expr.createPseudo(function (arg) {
 | 
			
		|||
// Global jQuery Elements
 | 
			
		||||
$(function () {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    var notifications = $('.notification');
 | 
			
		||||
    var successNotification = notifications.filter('.pos');
 | 
			
		||||
    var errorNotification = notifications.filter('.neg');
 | 
			
		||||
    // Notification Events
 | 
			
		||||
    window.Events.listen('success', function (text) {
 | 
			
		||||
        successNotification.hide();
 | 
			
		||||
        successNotification.find('span').text(text);
 | 
			
		||||
        setTimeout(() => {
 | 
			
		||||
            successNotification.show();
 | 
			
		||||
        }, 1);
 | 
			
		||||
    });
 | 
			
		||||
    window.Events.listen('error', function (text) {
 | 
			
		||||
        errorNotification.find('span').text(text);
 | 
			
		||||
        errorNotification.show();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Notification hiding
 | 
			
		||||
    $('.notification').click(function () {
 | 
			
		||||
    notifications.click(function () {
 | 
			
		||||
        $(this).fadeOut(100);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,6 @@ module.exports = {
 | 
			
		|||
    statusbar: false,
 | 
			
		||||
    menubar: false,
 | 
			
		||||
    paste_data_images: false,
 | 
			
		||||
    //height: 700,
 | 
			
		||||
    extended_valid_elements: 'pre[*]',
 | 
			
		||||
    automatic_uploads: false,
 | 
			
		||||
    valid_children: "-div[p|pre|h1|h2|h3|h4|h5|h6|blockquote]",
 | 
			
		||||
| 
						 | 
				
			
			@ -31,7 +30,7 @@ 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) {
 | 
			
		||||
        ImageManager.show(function (image) {
 | 
			
		||||
        window.ImageManager.showExternal(function (image) {
 | 
			
		||||
            win.document.getElementById(field_name).value = image.url;
 | 
			
		||||
            if ("createEvent" in document) {
 | 
			
		||||
                var evt = document.createEvent("HTMLEvents");
 | 
			
		||||
| 
						 | 
				
			
			@ -40,6 +39,10 @@ module.exports = {
 | 
			
		|||
            } else {
 | 
			
		||||
                win.document.getElementById(field_name).fireEvent("onchange");
 | 
			
		||||
            }
 | 
			
		||||
            var html = '<a href="' + image.url + '" target="_blank">';
 | 
			
		||||
            html += '<img src="' + image.thumbs.display + '" alt="' + image.name + '">';
 | 
			
		||||
            html += '</a>';
 | 
			
		||||
            win.tinyMCE.activeEditor.execCommand('mceInsertContent', false, html);
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
    paste_preprocess: function (plugin, args) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
"use strict";
 | 
			
		||||
 | 
			
		||||
module.exports = function(ngApp) {
 | 
			
		||||
module.exports = function(ngApp, events) {
 | 
			
		||||
 | 
			
		||||
    ngApp.factory('imageManagerService', function() {
 | 
			
		||||
        return {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,6 @@
 | 
			
		|||
  border-radius: 4px;
 | 
			
		||||
  box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.3);
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  max-width: 1340px;
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -44,18 +43,49 @@
 | 
			
		|||
  right: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.image-manager-list img {
 | 
			
		||||
.image-manager-list .image {
 | 
			
		||||
  display: block;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  border-radius: 0;
 | 
			
		||||
  float: left;
 | 
			
		||||
  margin: 0;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  width: (100%/6);
 | 
			
		||||
  height: auto;
 | 
			
		||||
  border: 1px solid #FFF;
 | 
			
		||||
  border: 1px solid #DDD;
 | 
			
		||||
  box-shadow: 0 0 0 0 rgba(0, 0, 0, 0);
 | 
			
		||||
  transition: all cubic-bezier(.4, 0, 1, 1) 160ms;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  &.selected {
 | 
			
		||||
    transform: scale3d(0.92, 0.92, 0.92);
 | 
			
		||||
    border: 1px solid #444;
 | 
			
		||||
    box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.2);
 | 
			
		||||
  }
 | 
			
		||||
  img {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    max-width: 100%;
 | 
			
		||||
    display: block;
 | 
			
		||||
  }
 | 
			
		||||
  .image-meta {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    color: #EEE;
 | 
			
		||||
    background-color: rgba(0, 0, 0, 0.4);
 | 
			
		||||
    font-size: 10px;
 | 
			
		||||
    padding: 3px 4px;
 | 
			
		||||
    span {
 | 
			
		||||
      display: block;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  @include smaller-than($xl) {
 | 
			
		||||
    width: (100%/4);
 | 
			
		||||
  }
 | 
			
		||||
  @include smaller-than($m) {
 | 
			
		||||
    .image-meta {
 | 
			
		||||
      display: none;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,11 +5,14 @@
 | 
			
		|||
            <div class="image-manager-content">
 | 
			
		||||
                <div class="image-manager-list">
 | 
			
		||||
                    <div ng-repeat="image in images">
 | 
			
		||||
                        <img class="anim fadeIn"
 | 
			
		||||
                             ng-class="{selected: (image==selectedImage)}"
 | 
			
		||||
                             ng-src="@{{image.thumbs.gallery}}" ng-attr-alt="@{{image.title}}" ng-attr-title="@{{image.name}}"
 | 
			
		||||
                            ng-click="imageSelect(image)"
 | 
			
		||||
                            ng-style="{animationDelay: ($index > 26) ? '160ms' : ($index * 25) + 'ms'}">
 | 
			
		||||
                        <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>
 | 
			
		||||
| 
						 | 
				
			
			@ -19,18 +22,20 @@
 | 
			
		|||
 | 
			
		||||
            <div class="image-manager-sidebar">
 | 
			
		||||
                <h2>Images</h2>
 | 
			
		||||
                <hr class="even">
 | 
			
		||||
                <drop-zone upload-url="@{{getUploadUrl()}}" 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">
 | 
			
		||||
                            <p class="text-pos text-small" ng-show="imageUpdateSuccess"><i class="fa fa-check"></i> Image name updated</p>
 | 
			
		||||
                            <p class="text-neg text-small" ng-show="imageUpdateFailure"><i class="fa fa-times"></i> <span ng-bind="imageUpdateFailure"></span></p>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </form>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -53,8 +58,6 @@
 | 
			
		|||
                    </form>
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                <p class="text-pos" ng-show="imageDeleteSuccess"><i class="fa fa-check"></i> Image deleted</p>
 | 
			
		||||
 | 
			
		||||
                <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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +1,8 @@
 | 
			
		|||
@if(Session::has('success'))
 | 
			
		||||
    <div class="notification anim pos">
 | 
			
		||||
        <i class="zmdi zmdi-mood"></i> <span>{{ Session::get('success') }}</span>
 | 
			
		||||
    </div>
 | 
			
		||||
@endif
 | 
			
		||||
 | 
			
		||||
@if(Session::has('error'))
 | 
			
		||||
    <div class="notification anim neg stopped">
 | 
			
		||||
<div class="notification anim pos" @if(!Session::has('success')) style="display:none;" @endif>
 | 
			
		||||
    <i class="zmdi zmdi-check-circle"></i> <span>{{ Session::get('success') }}</span>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<div class="notification anim neg stopped" @if(!Session::has('error')) style="display:none;" @endif>
 | 
			
		||||
    <i class="zmdi zmdi-alert-circle"></i> <span>{{ Session::get('error') }}</span>
 | 
			
		||||
    </div>
 | 
			
		||||
@endif
 | 
			
		||||
</div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue