diff --git a/resources/assets/js/components/index.js b/resources/assets/js/components/index.js
index c38e20aa2..43466a0d9 100644
--- a/resources/assets/js/components/index.js
+++ b/resources/assets/js/components/index.js
@@ -21,6 +21,8 @@ for (let i = 0, len = componentNames.length; i < len; i++) {
     if (typeof window.components[name] === "undefined") window.components[name] = [];
     for (let j = 0, jLen = elems.length; j < jLen; j++) {
          let instance = new component(elems[j]);
+         if (typeof elems[j].components === 'undefined') elems[j].components = {};
+         elems[j].components[name] = instance;
          window.components[name].push(instance);
     }
 }
\ No newline at end of file
diff --git a/resources/assets/js/components/notification.js b/resources/assets/js/components/notification.js
index 4b809c935..1a9819702 100644
--- a/resources/assets/js/components/notification.js
+++ b/resources/assets/js/components/notification.js
@@ -7,14 +7,16 @@ class Notification {
         this.textElem = elem.querySelector('span');
         this.autohide = this.elem.hasAttribute('data-autohide');
         window.Events.listen(this.type, text => {
-            console.log('show', text);
             this.show(text);
         });
         elem.addEventListener('click', this.hide.bind(this));
         if (elem.hasAttribute('data-show')) this.show(this.textElem.textContent);
+
+        this.hideCleanup = this.hideCleanup.bind(this);
     }
 
     show(textToShow = '') {
+        this.elem.removeEventListener('transitionend', this.hideCleanup);
         this.textElem.textContent = textToShow;
         this.elem.style.display = 'block';
         setTimeout(() => {
@@ -26,13 +28,12 @@ class Notification {
 
     hide() {
         this.elem.classList.remove('showing');
+        this.elem.addEventListener('transitionend', this.hideCleanup);
+    }
 
-        function transitionEnd() {
-            this.elem.style.display = 'none';
-            this.elem.removeEventListener('transitionend', transitionEnd);
-        }
-
-        this.elem.addEventListener('transitionend', transitionEnd.bind(this));
+    hideCleanup() {
+        this.elem.style.display = 'none';
+        this.elem.removeEventListener('transitionend', this.hideCleanup);
     }
 
 }
diff --git a/resources/assets/js/controllers.js b/resources/assets/js/controllers.js
index 4acb40b35..de3ce81c6 100644
--- a/resources/assets/js/controllers.js
+++ b/resources/assets/js/controllers.js
@@ -8,256 +8,6 @@ moment.locale('en-gb');
 
 module.exports = function (ngApp, events) {
 
-    ngApp.controller('ImageManagerController', ['$scope', '$attrs', '$http', '$timeout', 'imageManagerService',
-        function ($scope, $attrs, $http, $timeout, imageManagerService) {
-
-            $scope.images = [];
-            $scope.imageType = $attrs.imageType;
-            $scope.selectedImage = false;
-            $scope.dependantPages = false;
-            $scope.showing = false;
-            $scope.hasMore = false;
-            $scope.imageUpdateSuccess = false;
-            $scope.imageDeleteSuccess = false;
-            $scope.uploadedTo = $attrs.uploadedTo;
-            $scope.view = 'all';
-
-            $scope.searching = false;
-            $scope.searchTerm = '';
-
-            let page = 0;
-            let previousClickTime = 0;
-            let previousClickImage = 0;
-            let dataLoaded = false;
-            let callback = false;
-
-            let preSearchImages = [];
-            let preSearchHasMore = false;
-
-            /**
-             * Used by dropzone to get the endpoint to upload to.
-             * @returns {string}
-             */
-            $scope.getUploadUrl = function () {
-                return window.baseUrl('/images/' + $scope.imageType + '/upload');
-            };
-
-            /**
-             * Cancel the current search operation.
-             */
-            function cancelSearch() {
-                $scope.searching = false;
-                $scope.searchTerm = '';
-                $scope.images = preSearchImages;
-                $scope.hasMore = preSearchHasMore;
-            }
-            $scope.cancelSearch = cancelSearch;
-
-
-            /**
-             * 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', trans('components.image_upload_success'));
-            };
-
-            /**
-             * Runs the callback and hides the image manager.
-             * @param returnData
-             */
-            function callbackAndHide(returnData) {
-                if (callback) callback(returnData);
-                $scope.hide();
-            }
-
-            /**
-             * Image select action. Checks if a double-click was fired.
-             * @param image
-             */
-            $scope.imageSelect = function (image) {
-                let dblClickTime = 300;
-                let currentTime = Date.now();
-                let timeDiff = currentTime - previousClickTime;
-
-                if (timeDiff < dblClickTime && image.id === previousClickImage) {
-                    // If double click
-                    callbackAndHide(image);
-                } else {
-                    // If single
-                    $scope.selectedImage = image;
-                    $scope.dependantPages = false;
-                }
-                previousClickTime = currentTime;
-                previousClickImage = image.id;
-            };
-
-            /**
-             * 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;
-                $('#image-manager').find('[overlay]').css('display', 'flex').hide().fadeIn(240);
-                // Get initial images if they have not yet been loaded in.
-                if (!dataLoaded) {
-                    fetchData();
-                    dataLoaded = true;
-                }
-            }
-
-            // Connects up the image manger so it can be used externally
-            // such as from TinyMCE.
-            imageManagerService.show = show;
-            imageManagerService.showExternal = function (doneCallback) {
-                $scope.$apply(() => {
-                    show(doneCallback);
-                });
-            };
-            window.ImageManager = imageManagerService;
-
-            /**
-             * Hide the image manager
-             */
-            $scope.hide = function () {
-                $scope.showing = false;
-                $('#image-manager').find('[overlay]').fadeOut(240);
-            };
-
-            let baseUrl = window.baseUrl('/images/' + $scope.imageType + '/all/');
-
-            /**
-             * Fetch the list image data from the server.
-             */
-            function fetchData() {
-                let url = baseUrl + page + '?';
-                let components = {};
-                if ($scope.uploadedTo) components['page_id'] = $scope.uploadedTo;
-                if ($scope.searching) components['term'] = $scope.searchTerm;
-
-
-                url += Object.keys(components).map((key) => {
-                    return key + '=' + encodeURIComponent(components[key]);
-                }).join('&');
-
-                $http.get(url).then((response) => {
-                    $scope.images = $scope.images.concat(response.data.images);
-                    $scope.hasMore = response.data.hasMore;
-                    page++;
-                });
-            }
-            $scope.fetchData = fetchData;
-
-            /**
-             * Start a search operation
-             */
-            $scope.searchImages = function() {
-
-                if ($scope.searchTerm === '') {
-                    cancelSearch();
-                    return;
-                }
-
-                if (!$scope.searching) {
-                    preSearchImages = $scope.images;
-                    preSearchHasMore = $scope.hasMore;
-                }
-
-                $scope.searching = true;
-                $scope.images = [];
-                $scope.hasMore = false;
-                page = 0;
-                baseUrl = window.baseUrl('/images/' + $scope.imageType + '/search/');
-                fetchData();
-            };
-
-            /**
-             * Set the current image listing view.
-             * @param viewName
-             */
-            $scope.setView = function(viewName) {
-                cancelSearch();
-                $scope.images = [];
-                $scope.hasMore = false;
-                page = 0;
-                $scope.view = viewName;
-                baseUrl = window.baseUrl('/images/' + $scope.imageType  + '/' + viewName + '/');
-                fetchData();
-            };
-
-            /**
-             * Save the details of an image.
-             * @param event
-             */
-            $scope.saveImageDetails = function (event) {
-                event.preventDefault();
-                let url = window.baseUrl('/images/update/' + $scope.selectedImage.id);
-                $http.put(url, this.selectedImage).then(response => {
-                    events.emit('success', trans('components.image_update_success'));
-                }, (response) => {
-                    if (response.status === 422) {
-                        let errors = response.data;
-                        let message = '';
-                        Object.keys(errors).forEach((key) => {
-                            message += errors[key].join('\n');
-                        });
-                        events.emit('error', message);
-                    } else if (response.status === 403) {
-                        events.emit('error', response.data.error);
-                    }
-                });
-            };
-
-            /**
-             * 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();
-                let force = $scope.dependantPages !== false;
-                let url = window.baseUrl('/images/' + $scope.selectedImage.id);
-                if (force) url += '?force=true';
-                $http.delete(url).then((response) => {
-                    $scope.images.splice($scope.images.indexOf($scope.selectedImage), 1);
-                    $scope.selectedImage = false;
-                    events.emit('success', trans('components.image_delete_success'));
-                }, (response) => {
-                    // Pages failure
-                    if (response.status === 400) {
-                        $scope.dependantPages = response.data;
-                    } else if (response.status === 403) {
-                        events.emit('error', response.data.error);
-                    }
-                });
-            };
-
-            /**
-             * Simple date creator used to properly format dates.
-             * @param stringDate
-             * @returns {Date}
-             */
-            $scope.getDate = function (stringDate) {
-                return new Date(stringDate);
-            };
-
-        }]);
 
     ngApp.controller('PageEditController', ['$scope', '$http', '$attrs', '$interval', '$timeout', '$sce',
         function ($scope, $http, $attrs, $interval, $timeout, $sce) {
diff --git a/resources/assets/js/directives.js b/resources/assets/js/directives.js
index 522dcacae..a156c961c 100644
--- a/resources/assets/js/directives.js
+++ b/resources/assets/js/directives.js
@@ -383,7 +383,7 @@ module.exports = function (ngApp, events) {
                 // Show the image manager and handle image insertion
                 function showImageManager() {
                     let cursorPos = cm.getCursor('from');
-                    window.ImageManager.showExternal(image => {
+                    window.ImageManager.show(image => {
                         let selectedText = cm.getSelection();
                         let newText = "![" + (selectedText || image.name) + "](" + image.thumbs.display + ")";
                         cm.focus();
diff --git a/resources/assets/js/global.js b/resources/assets/js/global.js
index 3879a4d4f..28d1e3b0c 100644
--- a/resources/assets/js/global.js
+++ b/resources/assets/js/global.js
@@ -67,10 +67,8 @@ require("./vues/vues");
 require("./components");
 
 // Load in angular specific items
-const Services = require('./services');
 const Directives = require('./directives');
 const Controllers = require('./controllers');
-Services(ngApp, window.Events);
 Directives(ngApp, window.Events);
 Controllers(ngApp, window.Events);
 
diff --git a/resources/assets/js/pages/page-form.js b/resources/assets/js/pages/page-form.js
index 4f4c1fbe0..08e4c0c34 100644
--- a/resources/assets/js/pages/page-form.js
+++ b/resources/assets/js/pages/page-form.js
@@ -283,7 +283,7 @@ module.exports = function() {
 
             if (type === 'image') {
                 // Show image manager
-                window.ImageManager.showExternal(function (image) {
+                window.ImageManager.show(function (image) {
 
                     // Set popover link input to image url then fire change event
                     // to ensure the new value sticks
@@ -365,7 +365,7 @@ module.exports = function() {
                 icon: 'image',
                 tooltip: 'Insert an image',
                 onclick: function () {
-                    window.ImageManager.showExternal(function (image) {
+                    window.ImageManager.show(function (image) {
                         let html = `<a href="${image.url}" target="_blank">`;
                         html += `<img src="${image.thumbs.display}" alt="${image.name}">`;
                         html += '</a>';
diff --git a/resources/assets/js/services.js b/resources/assets/js/services.js
deleted file mode 100644
index cd2759c54..000000000
--- a/resources/assets/js/services.js
+++ /dev/null
@@ -1,12 +0,0 @@
-"use strict";
-
-module.exports = function(ngApp, events) {
-
-    ngApp.factory('imageManagerService', function() {
-        return {
-            show: false,
-            showExternal: false
-        };
-    });
-
-};
\ No newline at end of file
diff --git a/resources/assets/js/vues/components/dropzone.js b/resources/assets/js/vues/components/dropzone.js
new file mode 100644
index 000000000..0f31bd579
--- /dev/null
+++ b/resources/assets/js/vues/components/dropzone.js
@@ -0,0 +1,60 @@
+const DropZone = require("dropzone");
+
+const template = `
+    <div class="dropzone-container">
+        <div class="dz-message">{{placeholder}}</div>
+    </div>
+`;
+
+const props = ['placeholder', 'uploadUrl', 'uploadedTo'];
+
+// TODO - Remove jQuery usage
+function mounted() {
+   let container = this.$el;
+   let _this = this;
+   new DropZone(container, {
+        url: function() {
+            return _this.uploadUrl;
+        },
+        init: function () {
+            let dz = this;
+
+            dz.on('sending', function (file, xhr, data) {
+                let token = window.document.querySelector('meta[name=token]').getAttribute('content');
+                data.append('_token', token);
+                let uploadedTo = typeof _this.uploadedTo === 'undefined' ? 0 : _this.uploadedTo;
+                data.append('uploaded_to', uploadedTo);
+            });
+
+            dz.on('success', function (file, data) {
+                _this.$emit('success', {file, data});
+                $(file.previewElement).fadeOut(400, function () {
+                    dz.removeFile(file);
+                });
+            });
+
+            dz.on('error', function (file, errorMessage, xhr) {
+                _this.$emit('error', {file, errorMessage, xhr});
+                console.log(errorMessage);
+                console.log(xhr);
+                function setMessage(message) {
+                    $(file.previewElement).find('[data-dz-errormessage]').text(message);
+                }
+
+                if (xhr.status === 413) setMessage(trans('errors.server_upload_limit'));
+                if (errorMessage.file) setMessage(errorMessage.file[0]);
+            });
+        }
+   });
+}
+
+function data() {
+    return {}
+}
+
+module.exports = {
+    template,
+    props,
+    mounted,
+    data,
+};
\ No newline at end of file
diff --git a/resources/assets/js/vues/image-manager.js b/resources/assets/js/vues/image-manager.js
new file mode 100644
index 000000000..9e3fa013e
--- /dev/null
+++ b/resources/assets/js/vues/image-manager.js
@@ -0,0 +1,182 @@
+const dropzone = require('./components/dropzone');
+
+let page = 0;
+let previousClickTime = 0;
+let previousClickImage = 0;
+let dataLoaded = false;
+let callback = false;
+let baseUrl = '';
+
+let preSearchImages = [];
+let preSearchHasMore = false;
+
+const data = {
+    images: [],
+
+    imageType: false,
+    uploadedTo: false,
+
+    selectedImage: false,
+    dependantPages: false,
+    showing: false,
+    view: 'all',
+    hasMore: false,
+    searching: false,
+    searchTerm: '',
+
+    imageUpdateSuccess: false,
+    imageDeleteSuccess: false,
+};
+
+const methods = {
+
+    show(providedCallback) {
+        callback = providedCallback;
+        this.showing = true;
+        this.$el.children[0].components.overlay.show();
+
+        // Get initial images if they have not yet been loaded in.
+        if (dataLoaded) return;
+        this.fetchData();
+        dataLoaded = true;
+    },
+
+    hide() {
+        this.showing = false;
+        this.$el.children[0].components.overlay.hide();
+    },
+
+    fetchData() {
+        let url = baseUrl + page;
+        let query = {};
+        if (this.uploadedTo !== false) query.page_id = this.uploadedTo;
+        if (this.searching) query.term = this.searchTerm;
+
+        this.$http.get(url, {params: query}).then(response => {
+            this.images = this.images.concat(response.data.images);
+            this.hasMore = response.data.hasMore;
+            page++;
+        });
+    },
+
+    setView(viewName) {
+        this.cancelSearch();
+        this.images = [];
+        this.hasMore = false;
+        page = 0;
+        this.view = viewName;
+        baseUrl = window.baseUrl(`/images/${this.imageType}/${viewName}/`);
+        this.fetchData();
+    },
+
+    searchImages() {
+        if (this.searchTerm === '') return this.cancelSearch();
+
+        // Cache current settings for later
+        if (!this.searching) {
+            preSearchImages = this.images;
+            preSearchHasMore = this.hasMore;
+        }
+
+        this.searching = true;
+        this.images = [];
+        this.hasMore = false;
+        page = 0;
+        baseUrl = window.baseUrl(`/images/${this.imageType}/search/`);
+        this.fetchData();
+    },
+
+    cancelSearch() {
+        this.searching = false;
+        this.searchTerm = '';
+        this.images = preSearchImages;
+        this.hasMore = preSearchHasMore;
+    },
+
+    imageSelect(image) {
+        let dblClickTime = 300;
+        let currentTime = Date.now();
+        let timeDiff = currentTime - previousClickTime;
+        let isDblClick = timeDiff < dblClickTime && image.id === previousClickImage;
+
+        if (isDblClick) {
+            this.callbackAndHide(image);
+        } else {
+            this.selectedImage = image;
+            this.dependantPages = false;
+        }
+
+        previousClickTime = currentTime;
+        previousClickImage = image.id;
+    },
+
+    callbackAndHide(imageResult) {
+        if (callback) callback(imageResult);
+        this.hide();
+    },
+
+    saveImageDetails() {
+        let url = window.baseUrl(`/images/update/${this.selectedImage.id}`);
+        this.$http.put(url, this.selectedImage).then(response => {
+            this.$events.emit('success', trans('components.image_update_success'));
+        }).catch(error => {
+            if (error.response.status === 422) {
+                let errors = error.response.data;
+                let message = '';
+                Object.keys(errors).forEach((key) => {
+                    message += errors[key].join('\n');
+                });
+                this.$events.emit('error', message);
+            } else if (error.response.status === 403) {
+                this.$events.emit('error', error.response.data.error);
+            }
+        });
+    },
+
+    deleteImage() {
+        let force = this.dependantPages !== false;
+        let url = window.baseUrl('/images/' + this.selectedImage.id);
+        if (force) url += '?force=true';
+        this.$http.delete(url).then(response => {
+            this.images.splice(this.images.indexOf(this.selectedImage), 1);
+            this.selectedImage = false;
+            this.$events.emit('success', trans('components.image_delete_success'));
+        }).catch(error=> {
+            if (error.response.status === 400) {
+                this.dependantPages = error.response.data;
+            } else if (error.response.status === 403) {
+                this.$events.emit('error', error.response.data.error);
+            }
+        });
+    },
+
+    getDate(stringDate) {
+        return new Date(stringDate);
+    },
+
+    uploadSuccess(event) {
+        this.images.unshift(event.data);
+        this.$events.emit('success', trans('components.image_upload_success'));
+    },
+};
+
+const computed = {
+    uploadUrl() {
+        return window.baseUrl(`/images/${this.imageType}/upload`);
+    }
+};
+
+function mounted() {
+    window.ImageManager = this;
+    this.imageType = this.$el.getAttribute('image-type');
+    this.uploadedTo = this.$el.getAttribute('uploaded-to');
+    baseUrl = window.baseUrl('/images/' + this.imageType + '/all/')
+}
+
+module.exports = {
+    mounted,
+    methods,
+    data,
+    computed,
+    components: {dropzone},
+};
\ No newline at end of file
diff --git a/resources/assets/js/vues/vues.js b/resources/assets/js/vues/vues.js
index 31d833bfb..e6d4b9f5b 100644
--- a/resources/assets/js/vues/vues.js
+++ b/resources/assets/js/vues/vues.js
@@ -7,7 +7,8 @@ function exists(id) {
 let vueMapping = {
     'search-system': require('./search'),
     'entity-dashboard': require('./entity-search'),
-    'code-editor': require('./code-editor')
+    'code-editor': require('./code-editor'),
+    'image-manager': require('./image-manager'),
 };
 
 window.vues = {};
diff --git a/resources/views/components/image-manager.blade.php b/resources/views/components/image-manager.blade.php
index 05bf09799..a4612a4ac 100644
--- a/resources/views/components/image-manager.blade.php
+++ b/resources/views/components/image-manager.blade.php
@@ -1,6 +1,6 @@
-<div id="image-manager" image-type="{{ $imageType }}" ng-controller="ImageManagerController" uploaded-to="{{ $uploaded_to or 0 }}">
-    <div overlay ng-cloak ng-click="hide()">
-        <div class="popup-body" ng-click="$event.stopPropagation()">
+<div id="image-manager" image-type="{{ $imageType }}" uploaded-to="{{ $uploaded_to or 0 }}">
+    <div overlay v-cloak>
+        <div class="popup-body" @click.stop="">
 
             <div class="popup-header primary-background">
                 <div class="popup-title">{{ trans('components.image_select') }}</div>
@@ -10,82 +10,80 @@
             <div class="flex-fill image-manager-body">
 
                 <div class="image-manager-content">
-                    <div ng-if="imageType === 'gallery'" class="container">
+                    <div v-if="imageType === 'gallery'" class="container">
                         <div class="image-manager-header row faded-small nav-tabs">
-                            <div class="col-xs-4 tab-item" title="{{ trans('components.image_all_title') }}" ng-class="{selected: (view=='all')}" ng-click="setView('all')"><i class="zmdi zmdi-collection-image"></i> {{ trans('components.image_all') }}</div>
-                            <div class="col-xs-4 tab-item" title="{{ trans('components.image_book_title') }}" ng-class="{selected: (view=='book')}" ng-click="setView('book')"><i class="zmdi zmdi-book text-book"></i> {{ trans('entities.book') }}</div>
-                            <div class="col-xs-4 tab-item" title="{{ trans('components.image_page_title') }}" ng-class="{selected: (view=='page')}" ng-click="setView('page')"><i class="zmdi zmdi-file-text text-page"></i> {{ trans('entities.page') }}</div>
+                            <div class="col-xs-4 tab-item" title="{{ trans('components.image_all_title') }}" :class="{selected: (view=='all')}" @click="setView('all')"><i class="zmdi zmdi-collection-image"></i> {{ trans('components.image_all') }}</div>
+                            <div class="col-xs-4 tab-item" title="{{ trans('components.image_book_title') }}" :class="{selected: (view=='book')}" @click="setView('book')"><i class="zmdi zmdi-book text-book"></i> {{ trans('entities.book') }}</div>
+                            <div class="col-xs-4 tab-item" title="{{ trans('components.image_page_title') }}" :class="{selected: (view=='page')}" @click="setView('page')"><i class="zmdi zmdi-file-text text-page"></i> {{ trans('entities.page') }}</div>
                         </div>
                     </div>
-                    <div ng-show="view === 'all'" >
-                        <form ng-submit="searchImages()" class="contained-search-box">
-                            <input type="text" placeholder="{{ trans('components.image_search_hint') }}" ng-model="searchTerm">
-                            <button ng-class="{active: searching}" title="{{ trans('common.search_clear') }}" type="button" ng-click="cancelSearch()" class="text-button cancel"><i class="zmdi zmdi-close-circle-o"></i></button>
-                            <button title="{{ trans('common.search') }}" class="text-button" type="submit"><i class="zmdi zmdi-search"></i></button>
+                    <div v-show="view === 'all'" >
+                        <form @submit="searchImages" class="contained-search-box">
+                            <input placeholder="{{ trans('components.image_search_hint') }}" v-model="searchTerm">
+                            <button :class="{active: searching}" title="{{ trans('common.search_clear') }}" type="button" @click="cancelSearch()" class="text-button cancel"><i class="zmdi zmdi-close-circle-o"></i></button>
+                            <button title="{{ trans('common.search') }}" class="text-button"><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 v-if="images.length > 0" v-for="(image, idx) in images">
+                            <div class="image anim fadeIn" :style="{animationDelay: (idx > 26) ? '160ms' : ((idx * 25) + 'ms')}"
+                                 :class="{selected: (image==selectedImage)}" @click="imageSelect(image)">
+                                <img :src="image.thumbs.gallery" :alt="image.title" :title="image.name">
                                 <div class="image-meta">
-                                    <span class="name" ng-bind="image.name"></span>
+                                    <span class="name" v-text="image.name"></span>
                                     <span class="date">{{ trans('components.image_uploaded', ['uploadedDate' => "{{ getDate(image.created_at) }" . "}"]) }}</span>
                                 </div>
                             </div>
                         </div>
-                        <div class="load-more" ng-show="hasMore" ng-click="fetchData()">{{ trans('components.image_load_more') }}</div>
+                        <div class="load-more" v-show="hasMore" @click="fetchData">{{ trans('components.image_load_more') }}</div>
                     </div>
                 </div>
 
                 <div class="image-manager-sidebar">
                     <div class="inner">
 
-                        <div class="image-manager-details anim fadeIn" ng-show="selectedImage">
+                        <div class="image-manager-details anim fadeIn" v-if="selectedImage">
 
-                            <form ng-submit="saveImageDetails($event)">
+                            <form @submit.prevent="saveImageDetails">
                                 <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 :href="selectedImage.url" target="_blank" style="display: block;">
+                                        <img :src="selectedImage.thumbs.gallery" :alt="selectedImage.title"
+                                             :title="selectedImage.name">
                                     </a>
                                 </div>
                                 <div class="form-group">
                                     <label for="name">{{ trans('components.image_image_name') }}</label>
-                                    <input type="text" id="name" name="name" ng-model="selectedImage.name">
+                                    <input id="name" name="name" v-model="selectedImage.name">
                                 </div>
                             </form>
 
-                            <div ng-show="dependantPages">
+                            <div v-show="dependantPages">
                                 <p class="text-neg text-small">
                                     {{ trans('components.image_delete_confirm') }}
                                 </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 v-for="page in dependantPages">
+                                        <a :href="page.url" target="_blank" class="text-neg" v-text="page.name"></a>
                                     </li>
                                 </ul>
                             </div>
 
                             <div class="clearfix">
-                                <form class="float left" ng-submit="deleteImage($event)">
+                                <form class="float left" @submit.prevent="deleteImage">
                                     <button class="button icon neg"><i class="zmdi zmdi-delete"></i></button>
                                 </form>
-                                <button class="button pos anim fadeIn float right" ng-show="selectedImage" ng-click="selectButtonClick()">
+                                <button class="button pos anim fadeIn float right" v-show="selectedImage" @click="callbackAndHide(selectedImage)">
                                     <i class="zmdi zmdi-square-right"></i>{{ trans('components.image_select_image') }}
                                 </button>
                             </div>
 
                         </div>
 
-                        <drop-zone message="{{ trans('components.image_dropzone') }}" upload-url="@{{getUploadUrl()}}" uploaded-to="@{{uploadedTo}}" event-success="uploadSuccess"></drop-zone>
-
+                        <dropzone placeholder="{{ trans('components.image_dropzone') }}" :upload-url="uploadUrl" :uploaded-to="uploadedTo" @success="uploadSuccess"></dropzone>
 
                     </div>
                 </div>
 
-
-
             </div>
 
         </div>