]> BookStack Code Mirror - bookstack/commitdiff
Image uploads now quicker, and image sized reduced with links to originals
authorDan Brown <redacted>
Sun, 18 Oct 2015 17:48:51 +0000 (18:48 +0100)
committerDan Brown <redacted>
Sun, 18 Oct 2015 17:48:51 +0000 (18:48 +0100)
app/Http/Controllers/ImageController.php
bower.json
resources/assets/js/components/image-manager.vue
resources/assets/js/pages/page-form.js

index df4f5543d84f0322f0d4243cf3c8092ea7463a35..3e82bb4c0016547b74d593945bf7bbe9a401bf48 100644 (file)
@@ -39,27 +39,40 @@ class ImageController extends Controller
         $images = $this->image->orderBy('created_at', 'desc')
             ->skip($page * $pageSize)->take($pageSize)->get();
         foreach ($images as $image) {
-            $image->thumbnail = $this->getThumbnail($image, 150, 150);
+            $this->loadSizes($image);
         }
         $hasMore = $this->image->orderBy('created_at', 'desc')
                 ->skip(($page + 1) * $pageSize)->take($pageSize)->count() > 0;
         return response()->json([
-            'images'  => $images,
+            'images' => $images,
             'hasMore' => $hasMore
         ]);
     }
 
+    /**
+     * Loads the standard thumbnail sizes for an image.
+     * @param Image $image
+     */
+    private function loadSizes(Image $image)
+    {
+        $image->thumbnail = $this->getThumbnail($image, 150, 150);
+        $image->display = $this->getThumbnail($image, 840, 0, true);
+    }
+
     /**
      * Get the thumbnail for an image.
-     * @param     $image
-     * @param int $width
-     * @param int $height
+     * If $keepRatio is true only the width will be used.
+     * @param      $image
+     * @param int  $width
+     * @param int  $height
+     * @param bool $keepRatio
      * @return string
      */
-    public function getThumbnail($image, $width = 220, $height = 220)
+    public function getThumbnail($image, $width = 220, $height = 220, $keepRatio = false)
     {
         $explodedPath = explode('/', $image->url);
-        array_splice($explodedPath, 4, 0, ['thumbs-' . $width . '-' . $height]);
+        $dirPrefix = $keepRatio ? 'scaled-' : 'thumbs-';
+        array_splice($explodedPath, 4, 0, [$dirPrefix . $width . '-' . $height]);
         $thumbPath = implode('/', $explodedPath);
         $thumbFilePath = public_path() . $thumbPath;
 
@@ -70,7 +83,14 @@ class ImageController extends Controller
 
         // Otherwise create the thumbnail
         $thumb = ImageTool::make(public_path() . $image->url);
-        $thumb->fit($width, $height);
+        if($keepRatio) {
+            $thumb->resize($width, null, function ($constraint) {
+                $constraint->aspectRatio();
+                $constraint->upsize();
+            });
+        } else {
+            $thumb->fit($width, $height);
+        }
 
         // Create thumbnail folder if it does not exist
         if (!file_exists(dirname($thumbFilePath))) {
@@ -107,7 +127,7 @@ class ImageController extends Controller
         $this->image->created_by = auth()->user()->id;
         $this->image->updated_by = auth()->user()->id;
         $this->image->save();
-        $this->image->thumbnail = $this->getThumbnail($this->image, 150, 150);
+        $this->loadSizes($this->image);
         return response()->json($this->image);
     }
 
@@ -126,6 +146,7 @@ class ImageController extends Controller
         $image = $this->image->findOrFail($imageId);
         $image->fill($request->all());
         $image->save();
+        $this->loadSizes($image);
         return response()->json($this->image);
     }
 
index 06bed0478eff6bbc3627fdf068be44b760fbb376..9ce1401d96ddf2b6f0baa40bb1038bf0405d07b9 100644 (file)
@@ -14,7 +14,7 @@
     "tests"
   ],
   "dependencies": {
-    "tinymce-dist": "~4.2.1",
+    "tinymce-dist": "~4.2.6",
     "bootstrap": "~3.3.5",
     "jquery-sortable": "~0.9.13",
     "material-design-iconic-font": "~2.1.1"
index d489768bf8f2589851185c167b82e956546a9589..f81bf02d1f5acf6ebaaf541658eb41ea8f5dc09a 100644 (file)
@@ -1,6 +1,6 @@
 <template>
     <div id="image-manager">
-        <div class="overlay" v-el="overlay" v-on="click: overlayClick" >
+        <div class="overlay" v-el="overlay" v-on="click: overlayClick">
             <div class="image-manager-body">
                 <div class="image-manager-content">
                     <div class="image-manager-list">
@@ -32,7 +32,8 @@
                         <hr class="even">
                         <div v-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.
+                                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 v-repeat="page: dependantPages">
@@ -46,7 +47,9 @@
                         </form>
                     </div>
                     <div class="image-manager-bottom">
-                        <button class="button pos anim fadeIn" v-show="selectedImage" v-on="click:selectButtonClick"><i class="zmdi zmdi-square-right"></i>Select Image</button>
+                        <button class="button pos anim fadeIn" v-show="selectedImage" v-on="click:selectButtonClick"><i
+                                class="zmdi zmdi-square-right"></i>Select Image
+                        </button>
                     </div>
                 </div>
             </div>
@@ -59,7 +62,7 @@
     var Dropzone = require('dropzone');
 
     module.exports = {
-        data: function(){
+        data: function () {
             return {
                 images: [],
                 hasMore: false,
                 selectedImage: false,
                 dependantPages: false,
                 deleteForm: {},
-                token: document.querySelector('meta[name=token]').getAttribute('content')
+                token: document.querySelector('meta[name=token]').getAttribute('content'),
+                dataLoaded: false
             }
         },
 
         created: function () {
-            // Get initial images
-            this.fetchData(this.page);
             window.ImageManager = this;
         },
 
             show: function (callback) {
                 this.callback = callback;
                 this.$$.overlay.style.display = 'block';
+                // Get initial images if they have not yet been loaded in.
+                if (!this.dataLoaded) {
+                    this.fetchData(this.page);
+                    this.dataLoaded = true;
+                }
             },
 
             overlayClick: function (e) {
                     _this.images.splice(_this.images.indexOf(_this.selectedImage), 1);
                     _this.selectedImage = false;
                     $(_this.$$.imageTitle).showSuccess('Image Deleted');
-                }).fail(function(jqXHR, textStatus) {
+                }).fail(function (jqXHR, textStatus) {
                     // Pages failure
-                    if(jqXHR.status === 400) {
+                    if (jqXHR.status === 400) {
                         _this.dependantPages = jqXHR.responseJSON;
                     }
                 });
index cbebfdd68442688f42e081950875c3674c560dcb..a31220479f3e510b8b2af1b4c235f6e61b46252c 100644 (file)
@@ -15,7 +15,7 @@ module.exports = {
     automatic_uploads: false,
     valid_children: "-div[p|pre|h1|h2|h3|h4|h5|h6|blockquote]",
     plugins: "image table textcolor paste link imagetools fullscreen code hr",
-    toolbar: "undo redo | styleselect | bold italic underline strikethrough superscript subscript | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table image link hr | removeformat code fullscreen",
+    toolbar: "undo redo | styleselect | bold italic underline strikethrough superscript subscript | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table image-insert link hr | removeformat code fullscreen",
     content_style: "body {padding-left: 15px !important; padding-right: 15px !important; margin:0!important; margin-left:auto!important;margin-right:auto!important;}",
     style_formats: [
         {title: "Header 1", format: "h1"},
@@ -51,6 +51,62 @@ module.exports = {
         }
     },
     setup: function(editor) {
+
+        ( function() {
+            var wrap;
+
+            function hasTextContent( node ) {
+                return node && !! ( node.textContent || node.innerText );
+            }
+
+            editor.on( 'dragstart', function() {
+                var node = editor.selection.getNode();
+
+                if ( node.nodeName === 'IMG' ) {
+                    wrap = editor.dom.getParent( node, '.mceTemp' );
+
+                    if ( ! wrap && node.parentNode.nodeName === 'A' && ! hasTextContent( node.parentNode ) ) {
+                        wrap = node.parentNode;
+                    }
+                }
+            } );
+
+            editor.on( 'drop', function( event ) {
+                var dom = editor.dom,
+                    rng = tinymce.dom.RangeUtils.getCaretRangeFromPoint( event.clientX, event.clientY, editor.getDoc() );
+
+                // Don't allow anything to be dropped in a captioned image.
+                if ( dom.getParent( rng.startContainer, '.mceTemp' ) ) {
+                    event.preventDefault();
+                } else if ( wrap ) {
+                    event.preventDefault();
+
+                    editor.undoManager.transact( function() {
+                        editor.selection.setRng( rng );
+                        editor.selection.setNode( wrap );
+                        dom.remove( wrap );
+                    } );
+                }
+
+                wrap = null;
+            } );
+        } )();
+
+        // Image picker button
+        editor.addButton('image-insert', {
+            title: 'My title',
+            icon: 'image',
+            tooltip: 'Insert an image',
+            onclick: function() {
+                ImageManager.show(function(image) {
+                    var html = '<p><a href="'+image.url+'" target="_blank">';
+                    html += '<img src="'+image.display+'" alt="'+image.name+'">';
+                    html += '</a></p>';
+                    console.log(image);
+                    editor.execCommand('mceInsertContent', false, html);
+                });
+            }
+        });
         // Paste image-uploads
         editor.on('paste', function(e) {
             if(e.clipboardData) {