]> BookStack Code Mirror - bookstack/commitdiff
Moved all vuejs parts over to angular
authorDan Brown <redacted>
Wed, 30 Dec 2015 18:38:18 +0000 (18:38 +0000)
committerDan Brown <redacted>
Wed, 30 Dec 2015 18:38:18 +0000 (18:38 +0000)
24 files changed:
gulpfile.js
package.json
resources/assets/js/components/drop-zone.html [new file with mode: 0644]
resources/assets/js/components/image-manager.vue [deleted file]
resources/assets/js/components/image-picker.html [new file with mode: 0644]
resources/assets/js/components/image-picker.vue [deleted file]
resources/assets/js/controllers.js [new file with mode: 0644]
resources/assets/js/directives.js
resources/assets/js/global.js
resources/assets/js/jquery-extensions.js [deleted file]
resources/assets/js/pages/book-show.js [deleted file]
resources/assets/js/pages/page-form.js
resources/assets/js/services.js [new file with mode: 0644]
resources/assets/sass/_image-manager.scss
resources/assets/sass/styles.scss
resources/views/base.blade.php
resources/views/books/show.blade.php
resources/views/books/sort.blade.php
resources/views/pages/create.blade.php
resources/views/pages/edit.blade.php
resources/views/pages/page-display.blade.php
resources/views/partials/image-manager.blade.php [new file with mode: 0644]
resources/views/settings/index.blade.php
resources/views/users/edit.blade.php

index 4396187395b41d01f72206bd534c9b7935b4f2e8..e60dffc70571903f504c85797b181e0ff2eb1363 100644 (file)
@@ -21,6 +21,6 @@ elixir.extend('queryVersion', function(inputFiles) {
 elixir(function(mix) {
     mix.sass('styles.scss')
         .sass('print-styles.scss')
-        .browserify(['jquery-extensions.js', 'global.js'], 'public/js/common.js')
+        .browserify('global.js', 'public/js/common.js')
         .queryVersion(['css/styles.css', 'css/print-styles.css', 'js/common.js']);
 });
index acbb6f8facabdecdf8c40f89f305bae9512b8af5..a1fb06b1cd4bd032c73b56b45128409110751120 100644 (file)
@@ -1,21 +1,17 @@
 {
   "private": true,
   "devDependencies": {
-    "gulp": "^3.9.0",
-    "insert-css": "^0.2.0"
+    "gulp": "^3.9.0"
   },
   "dependencies": {
     "angular": "^1.5.0-rc.0",
+    "angular-animate": "^1.5.0-rc.0",
     "angular-resource": "^1.5.0-rc.0",
+    "angular-sanitize": "^1.5.0-rc.0",
     "babel-runtime": "^5.8.29",
     "bootstrap-sass": "^3.0.0",
     "dropzone": "^4.0.1",
     "laravel-elixir": "^3.4.0",
-    "vue": "^1.0.13",
-    "vue-hot-reload-api": "^1.2.1",
-    "vue-resource": "^0.5.1",
-    "vueify": "^5.0.1",
-    "vueify-insert-css": "^1.0.0",
     "zeroclipboard": "^2.2.0"
   }
 }
diff --git a/resources/assets/js/components/drop-zone.html b/resources/assets/js/components/drop-zone.html
new file mode 100644 (file)
index 0000000..26e0ee2
--- /dev/null
@@ -0,0 +1,3 @@
+<div class="dropzone-container">
+    <div class="dz-message">Drop files or click here to upload</div>
+</div>
\ No newline at end of file
diff --git a/resources/assets/js/components/image-manager.vue b/resources/assets/js/components/image-manager.vue
deleted file mode 100644 (file)
index 7574806..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-<template>
-    <div id="image-manager">
-        <div class="overlay" v-el:overlay @click="overlayClick">
-            <div class="image-manager-body">
-                <div class="image-manager-content">
-                    <div class="image-manager-list">
-                        <div v-for="image in images">
-                            <img class="anim fadeIn"
-                                 :class="{selected: (image==selectedImage)}"
-                                 :src="image.thumbs.gallery" :alt="image.title" :title="image.name"
-                                 @click="imageClick(image)"
-                                 :style="{animationDelay: ($index > 26) ? '160ms' : ($index * 25) + 'ms'}">
-                        </div>
-                        <div class="load-more" v-show="hasMore" @click="fetchData">Load More</div>
-                    </div>
-                </div>
-                <button class="neg button image-manager-close" @click="hide">x</button>
-                <div class="image-manager-sidebar">
-                    <h2 v-el:image-title>Images</h2>
-                    <hr class="even">
-                    <div class="dropzone-container" v-el:drop-zone>
-                        <div class="dz-message">Drop files or click here to upload</div>
-                    </div>
-                    <div class="image-manager-details anim fadeIn" v-show="selectedImage">
-                        <hr class="even">
-                        <form @submit="saveImageDetails" v-el:image-form>
-                            <div class="form-group">
-                                <label for="name">Image Name</label>
-                                <input type="text" id="name" name="name" v-model="selectedImage.name">
-                            </div>
-                        </form>
-                        <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.
-                            </p>
-                            <ul class="text-neg">
-                                <li v-for="page in dependantPages">
-                                    <a :href="page.url" target="_blank" class="text-neg">{{ page.name }}</a>
-                                </li>
-                            </ul>
-                        </div>
-
-                        <form @submit="deleteImage" v-el:image-delete-form>
-                            <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" v-show="selectedImage" @click="selectButtonClick"><i
-                                class="zmdi zmdi-square-right"></i>Select Image
-                        </button>
-                    </div>
-                </div>
-            </div>
-        </div>
-    </div>
-</template>
-
-<script>
-
-    var Dropzone = require('dropzone');
-
-    module.exports = {
-        data: function () {
-            return {
-                images: [],
-                hasMore: false,
-                page: 0,
-                cClickTime: 0,
-                selectedImage: false,
-                dependantPages: false,
-                deleteForm: {},
-                token: document.querySelector('meta[name=token]').getAttribute('content'),
-                dataLoaded: false
-            }
-        },
-
-        props: {
-            imageType: {
-                type: String,
-                required: true
-            }
-        },
-
-        created: function () {
-            window.ImageManager = this;
-        },
-
-        ready: function () {
-            // Create dropzone
-            this.setupDropZone();
-        },
-
-        methods: {
-            fetchData: function () {
-                var url = '/images/' + this.imageType + '/all/' + this.page;
-                this.$http.get(url).then((response) => {
-                    this.images = this.images.concat(response.data.images);
-                    this.hasMore = response.data.hasMore;
-                    this.page++;
-                });
-            },
-
-            setupDropZone: function () {
-                var _this = this;
-                var dropZone = new Dropzone(_this.$els.dropZone, {
-                    url: '/images/' + _this.imageType + '/upload',
-                    init: function () {
-                        var dz = this;
-                        dz.on("sending", function (file, xhr, data) {
-                            data.append("_token", _this.token);
-                        });
-                        dz.on("success", function (file, data) {
-                            _this.images.unshift(data);
-                            $(file.previewElement).fadeOut(400, function () {
-                                dz.removeFile(file);
-                            });
-                        });
-                        dz.on('error', function (file, errorMessage, xhr) {
-                            if (errorMessage.file) {
-                                $(file.previewElement).find('[data-dz-errormessage]').text(errorMessage.file[0]);
-                            }
-                            console.log(errorMessage);
-                        });
-                    }
-                });
-            },
-
-            returnCallback: function (image) {
-                this.callback(image);
-            },
-
-            imageClick: function (image) {
-                var dblClickTime = 380;
-                var cTime = (new Date()).getTime();
-                var timeDiff = cTime - this.cClickTime;
-                if (this.cClickTime !== 0 && timeDiff < dblClickTime && this.selectedImage === image) {
-                    // DoubleClick
-                    if (this.callback) {
-                        this.returnCallback(image);
-                    }
-                    this.hide();
-                } else {
-                    this.selectedImage = (this.selectedImage === image) ? false : image;
-                    this.dependantPages = false;
-                }
-                this.cClickTime = cTime;
-            },
-
-            selectButtonClick: function () {
-                if (this.callback) this.returnCallback(this.selectedImage);
-                this.hide();
-            },
-
-            show: function (callback) {
-                this.callback = callback;
-                this.$els.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) {
-                if (e.target.className === 'overlay') {
-                    this.hide();
-                }
-            },
-
-            hide: function () {
-                this.$els.overlay.style.display = 'none';
-            },
-
-            saveImageDetails: function (e) {
-                e.preventDefault();
-                this.selectedImage._token = this.token;
-                var form = $(this.$els.imageForm);
-                var url = '/images/update/' + this.selectedImage.id;
-                this.$http.put(url, this.selectedImage).then((response) => {
-                    form.showSuccess('Image name updated');
-                }, (response) => {
-                    form.showFailure(response.data);
-                });
-            },
-
-            deleteImage: function (e) {
-                e.preventDefault();
-                var _this = this;
-                _this.deleteForm.force = _this.dependantPages !== false;
-                _this.deleteForm._token = _this.token;
-                var url = '/images/' + _this.selectedImage.id;
-                this.$http.delete(url, this.deleteForm).then((response) => {
-                    this.images.splice(this.images.indexOf(this.selectedImage), 1);
-                    this.selectedImage = false;
-                    $(this.$els.imageTitle).showSuccess('Image Deleted');
-                }, (response) => {
-                    // Pages failure
-                    if (response.status === 400) {
-                        _this.dependantPages = response.data;
-                    }
-                });
-            }
-
-        }
-
-    };
-</script>
\ No newline at end of file
diff --git a/resources/assets/js/components/image-picker.html b/resources/assets/js/components/image-picker.html
new file mode 100644 (file)
index 0000000..1a07b92
--- /dev/null
@@ -0,0 +1,15 @@
+
+<div class="image-picker">
+    <div>
+        <img ng-if="image && image !== 'none'" ng-src="{{image}}" ng-class="{{imageClass}}" alt="Image Preview">
+        <img ng-if="image === '' && defaultImage" ng-src="{{defaultImage}}" ng-class="{{imageClass}}" alt="Image Preview">
+    </div>
+    <button class="button" type="button" ng-click="showImageManager()">Select Image</button>
+    <br>
+
+    <button class="text-button" ng-click="reset()" type="button">Reset</button>
+    <span ng-show="showRemove" class="sep">|</span>
+    <button ng-show="showRemove" class="text-button neg" ng-click="remove()" type="button">Remove</button>
+
+    <input type="hidden" ng-attr-name="{{name}}" ng-attr-id="{{name}}" ng-attr-value="{{value}}">
+</div>
\ No newline at end of file
diff --git a/resources/assets/js/components/image-picker.vue b/resources/assets/js/components/image-picker.vue
deleted file mode 100644 (file)
index e3c564e..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-
-<template>
-    <div class="image-picker">
-        <div>
-            <img v-if="image && image !== 'none'" :src="image" :class="imageClass" alt="Image Preview">
-            <img v-if="image === '' && defaultImage" :src="defaultImage" :class="imageClass" alt="Image Preview">
-        </div>
-        <button class="button" type="button" @click="showImageManager">Select Image</button>
-        <br>
-        <button class="text-button" @click="reset" type="button">Reset</button> <span v-show="showRemove" class="sep">|</span> <button v-show="showRemove" class="text-button neg" @click="remove" type="button">Remove</button>
-        <input type="hidden" :name="name" :id="name" v-model="value">
-    </div>
-</template>
-
-<script>
-    module.exports = {
-        props: {
-            currentImage: {
-                required: true,
-                type: String
-            },
-            currentId: {
-                required: false,
-                default: 'false',
-                type: String
-            },
-            name: {
-                required: true,
-                type: String
-            },
-            defaultImage: {
-                required: true,
-                type: String
-            },
-            imageClass: {
-                required: true,
-                type: String
-            },
-            resizeWidth: {
-                type: String
-            },
-            resizeHeight: {
-                type: String
-            },
-            resizeCrop: {
-                type: Boolean
-            },
-            showRemove: {
-                type: Boolean,
-                default: 'true'
-            }
-        },
-        data: function() {
-            return {
-                image: this.currentImage,
-                value: false
-            }
-        },
-        compiled: function() {
-            this.value = this.currentId === 'false' ? this.currentImage : this.currentId;
-        },
-        methods: {
-            setCurrentValue: function(imageModel, imageUrl) {
-                this.image = imageUrl;
-                this.value = this.currentId === 'false' ?  imageUrl : imageModel.id;
-            },
-            showImageManager: function(e) {
-                ImageManager.show((image) => {
-                    this.updateImageFromModel(image);
-                });
-            },
-            reset: function() {
-                this.setCurrentValue({id: 0}, this.defaultImage);
-            },
-            remove: function() {
-                this.image = 'none';
-                this.value = 'none';
-            },
-            updateImageFromModel: function(model) {
-                var isResized = this.resizeWidth && this.resizeHeight;
-
-                if (!isResized) {
-                    this.setCurrentValue(model, model.url);
-                    return;
-                }
-
-                var cropped = this.resizeCrop ? 'true' : 'false';
-                var requestString = '/images/thumb/' + model.id + '/' + this.resizeWidth + '/' + this.resizeHeight + '/' + cropped;
-                this.$http.get(requestString).then((response) => {
-                    this.setCurrentValue(model, response.data.url);
-                });
-            }
-        }
-    };
-</script>
\ No newline at end of file
diff --git a/resources/assets/js/controllers.js b/resources/assets/js/controllers.js
new file mode 100644 (file)
index 0000000..5d2d4bb
--- /dev/null
@@ -0,0 +1,162 @@
+"use strict";
+
+module.exports = function(ngApp) {
+
+    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;
+        var page = 0;
+        var previousClickTime = 0;
+        var dataLoaded = false;
+        var callback = false;
+
+        $scope.getUploadUrl = function() {
+            return '/images/' + $scope.imageType + '/upload';
+        };
+
+        $scope.uploadSuccess = function(file, data) {
+            $scope.$apply(() => {
+                $scope.images.unshift(data);
+            });
+        };
+
+        function callbackAndHide(returnData) {
+            if (callback) callback(returnData);
+            $scope.showing = false;
+        }
+
+        $scope.imageSelect = function (image) {
+            var dblClickTime = 300;
+            var currentTime = Date.now();
+            var timeDiff = currentTime - previousClickTime;
+
+            if (timeDiff < dblClickTime) {
+                // If double click
+                callbackAndHide(image);
+            } else {
+                // If single
+                $scope.selectedImage = image;
+                $scope.dependantPages = false;
+            }
+            previousClickTime = currentTime;
+        };
+
+        $scope.selectButtonClick = function() {
+            callbackAndHide($scope.selectedImage);
+        };
+
+        function show(doneCallback) {
+            callback = doneCallback;
+            $scope.showing = true;
+            // Get initial images if they have not yet been loaded in.
+            if (!dataLoaded) {
+                fetchData();
+                dataLoaded = true;
+            }
+        }
+
+        imageManagerService.show = show;
+        imageManagerService.showExternal = function(doneCallback) {
+            $scope.$apply(() => {
+                show(doneCallback);
+            });
+        };
+        window.ImageManager = imageManagerService;
+
+        $scope.hide = function() {
+            $scope.showing = false;
+        };
+
+        function fetchData() {
+            var url = '/images/' + $scope.imageType + '/all/' + page;
+            $http.get(url).then((response) => {
+                $scope.images = $scope.images.concat(response.data.images);
+                $scope.hasMore = response.data.hasMore;
+                page++;
+            });
+        }
+
+        $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);
+            }, (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);
+            });
+        };
+
+        $scope.deleteImage = function(event) {
+            event.preventDefault();
+            var force = $scope.dependantPages !== false;
+            var url = '/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;
+                $scope.imageDeleteSuccess = true;
+                $timeout(() => {
+                    $scope.imageDeleteSuccess = false;
+                }, 3000);
+            }, (response) => {
+                // Pages failure
+                if (response.status === 400) {
+                    $scope.dependantPages = response.data;
+                }
+            });
+        };
+
+    }]);
+
+
+    ngApp.controller('BookShowController', ['$scope', '$http', '$attrs', function($scope, $http, $attrs) {
+        $scope.searching = false;
+        $scope.searchTerm = '';
+        $scope.searchResults = '';
+
+        $scope.searchBook = function (e) {
+            e.preventDefault();
+            var term = $scope.searchTerm;
+            if (term.length == 0) return;
+            $scope.searching = true;
+            $scope.searchResults = '';
+            var searchUrl = '/search/book/' + $attrs.bookId;
+            searchUrl += '?term=' + encodeURIComponent(term);
+            $http.get(searchUrl).then((response) => {
+                $scope.searchResults = response.data;
+            });
+        };
+
+        $scope.checkSearchForm = function () {
+            if ($scope.searchTerm.length < 1) {
+                $scope.searching = false;
+            }
+        };
+
+        $scope.clearSearch = function() {
+            $scope.searching = false;
+            $scope.searchTerm = '';
+        };
+
+    }]);
+
+
+};
\ No newline at end of file
index a5f45b5894e00a9454135ca961b5ba55054702df..4e936388b51f6840655551b0963d5c3cda74aa71 100644 (file)
@@ -1,11 +1,15 @@
+"use strict";
+var DropZone = require('dropzone');
 
 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) {
 
     /**
      * Toggle Switches
-     * Have basic on/off functionality.
+     * Has basic on/off functionality.
      * Use string values of 'true' & 'false' to dictate the current state.
      */
     ngApp.directive('toggleSwitch', function() {
@@ -29,4 +33,127 @@ module.exports = function(ngApp) {
     });
 
 
+    /**
+     * Image Picker
+     * Is a simple front-end interface that connects to an ImageManager if present.
+     */
+    ngApp.directive('imagePicker', ['$http', 'imageManagerService', function($http, imageManagerService) {
+        return {
+            restrict: 'E',
+            template: imagePickerTemplate,
+            scope: {
+                name: '@',
+                resizeHeight: '@',
+                resizeWidth: '@',
+                resizeCrop: '@',
+                showRemove: '=',
+                currentImage: '@',
+                currentId: '@',
+                defaultImage: '@',
+                imageClass: '@'
+            },
+            link: function(scope, element, attrs) {
+                var usingIds = typeof scope.currentId !== 'undefined' || scope.currentId === 'false';
+                scope.image = scope.currentImage;
+                scope.value = scope.currentImage || '';
+
+                function setImage(imageModel, imageUrl) {
+                    scope.image = imageUrl;
+                    scope.value = usingIds ? imageModel.id : imageUrl;
+                }
+
+                scope.reset = function() {
+                    setImage({id: 0}, scope.defaultImage);
+                };
+
+                scope.remove = function() {
+                    scope.image = 'none';
+                    scope.value = 'none';
+                };
+
+                scope.showImageManager = function() {
+                    imageManagerService.show((image) => {
+                        scope.updateImageFromModel(image);
+                    });
+                };
+
+                scope.updateImageFromModel = function(model) {
+                    var isResized = scope.resizeWidth && scope.resizeHeight;
+
+                    if (!isResized) {
+                        scope.$apply(() => {
+                            setImage(model, model.url);
+                        });
+                        return;
+                    }
+
+                    var cropped = scope.resizeCrop ? 'true' : 'false';
+                    var requestString = '/images/thumb/' + model.id + '/' + scope.resizeWidth + '/' + scope.resizeHeight + '/' + cropped;
+                    $http.get(requestString).then((response) => {
+                        setImage(model, response.data.url);
+                    });
+                };
+
+            }
+        };
+    }]);
+
+    /**
+     * DropZone
+     * Used for uploading images
+     */
+    ngApp.directive('dropZone', [function() {
+        return {
+            restrict: 'E',
+            template: dropZoneTemplate,
+            scope: {
+                uploadUrl: '@',
+                eventSuccess: '=',
+                eventError: '='
+            },
+            link: function(scope, element, attrs) {
+                var dropZone = new DropZone(element[0].querySelector('.dropzone-container'), {
+                    url: scope.uploadUrl,
+                    init: function() {
+                        var dz = this;
+                        dz.on('sending', function(file, xhr, data) {
+                            var token = window.document.querySelector('meta[name=token]').getAttribute('content');
+                            data.append('_token', token);
+                        });
+                        if (typeof scope.eventSuccess !== 'undefined') dz.on('success', scope.eventSuccess);
+                        dz.on('success', function(file, data) {
+                            $(file.previewElement).fadeOut(400, function () {
+                                dz.removeFile(file);
+                            });
+                        });
+                        if (typeof scope.eventError !== 'undefined') dz.on('error', scope.eventError);
+                        dz.on('error', function (file, errorMessage, xhr) {
+                            if (errorMessage.file) {
+                                $(file.previewElement).find('[data-dz-errormessage]').text(errorMessage.file[0]);
+                            }
+                        });
+                    }
+                });
+            }
+        };
+    }]);
+
+
+    ngApp.directive('dropdown', [function() {
+        return {
+            restrict: 'A',
+            link: function(scope, element, attrs) {
+                var menu = element.find('ul');
+                element.find('[dropdown-toggle]').on('click', function() {
+                    menu.show().addClass('anim menuIn');
+                    element.mouseleave(function() {
+                        menu.hide();
+                        menu.removeClass('anim menuIn');
+                    });
+                });
+            }
+        };
+    }]);
+
+
 };
\ No newline at end of file
index 1dfc2b6bb21608474e21979cf09b2c6266039e7a..e740654fd2a5d8d8ef03bea0d569a5aad2717c30 100644 (file)
@@ -6,9 +6,32 @@ window.ZeroClipboard.config({
 
 // AngularJS - Create application and load components
 var angular = require('angular');
-var angularResource = require('angular-resource');
-var app = angular.module('bookStack', ['ngResource']);
-var directives = require('./directives')(app);
+var ngResource = require('angular-resource');
+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 jQuery Config & Extensions
+
+// Smooth scrolling
+jQuery.fn.smoothScrollTo = function() {
+    if(this.length === 0) return;
+    $('body').animate({
+        scrollTop: this.offset().top - 60 // Adjust to change final scroll position top margin
+    }, 800); // Adjust to change animations speed (ms)
+    return this;
+};
+
+// Making contains text expression not worry about casing
+$.expr[":"].contains = $.expr.createPseudo(function(arg) {
+    return function( elem ) {
+        return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
+    };
+});
 
 // Global jQuery Elements
 $(function () {
@@ -18,9 +41,6 @@ $(function () {
         $(this).fadeOut(100);
     });
 
-    // Dropdown toggles
-    $('[data-dropdown]').dropDown();
-
     // Chapter page list toggles
     $('.chapter-toggle').click(function(e) {
         e.preventDefault();
@@ -30,6 +50,11 @@ $(function () {
 
 });
 
+
+function elemExists(selector) {
+    return document.querySelector(selector) !== null;
+}
+
 // TinyMCE editor
 if(elemExists('#html-editor')) {
     var tinyMceOptions = require('./pages/page-form');
diff --git a/resources/assets/js/jquery-extensions.js b/resources/assets/js/jquery-extensions.js
deleted file mode 100644 (file)
index c41a721..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-
-// Smooth scrolling
-jQuery.fn.smoothScrollTo = function() {
-    if(this.length === 0) return;
-    $('body').animate({
-        scrollTop: this.offset().top - 60 // Adjust to change final scroll position top margin
-    }, 800); // Adjust to change animations speed (ms)
-    return this;
-};
-
-// Making contains text expression not worry about casing
-$.expr[":"].contains = $.expr.createPseudo(function(arg) {
-    return function( elem ) {
-        return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
-    };
-});
-
-// Show a success message after the element it's called upon.
-jQuery.fn.showSuccess = function (message) {
-    var elem = $(this);
-    var success = $('<div class="text-pos" style="display:none;"><i class="zmdi zmdi-check-circle"></i>' + message + '</div>');
-    elem.after(success);
-    success.slideDown(400, function () {
-        setTimeout(function () {
-            success.slideUp(400, function () {
-                success.remove();
-            })
-        }, 2000);
-    });
-};
-
-// Show a failure messages from laravel. Searches for the name of the inputs.
-jQuery.fn.showFailure = function (messageMap) {
-    var elem = $(this);
-    $.each(messageMap, function (key, messages) {
-        var input = elem.find('[name="' + key + '"]').last();
-        var fail = $('<div class="text-neg" style="display:none;"><i class="zmdi zmdi-alert-circle"></i>' + messages.join("\n") + '</div>');
-        input.after(fail);
-        fail.slideDown(400, function () {
-            setTimeout(function () {
-                fail.slideUp(400, function () {
-                    fail.remove();
-                })
-            }, 2000);
-        });
-    });
-
-};
-
-// Submit the form that the called upon element sits in.
-jQuery.fn.submitForm = function() {
-    $(this).closest('form').submit();
-};
-
-// Dropdown menu display
-jQuery.fn.dropDown = function() {
-    var container = $(this),
-        menu = container.find('ul');
-        container.find('[data-dropdown-toggle]').on('click', function() {
-        menu.show().addClass('anim menuIn');
-        container.mouseleave(function() {
-            menu.hide();
-            menu.removeClass('anim menuIn');
-        });
-    });
-};
\ No newline at end of file
diff --git a/resources/assets/js/pages/book-show.js b/resources/assets/js/pages/book-show.js
deleted file mode 100644 (file)
index 45159ad..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-
-module.exports = {
-    el: '#book-dashboard',
-    data: {
-        searching: false,
-        searchTerm: '',
-        searchResults: ''
-    },
-    methods: {
-        searchBook: function (e) {
-            e.preventDefault();
-            var term = this.searchTerm;
-            if (term.length == 0) return;
-            this.searching = true;
-            this.searchResults = '';
-            var searchUrl = this.$els.form.getAttribute('action');
-            searchUrl += '?term=' + encodeURIComponent(term);
-            this.$http.get(searchUrl, function (data) {
-                this.$set('searchResults', data);
-            });
-        },
-        checkSearchForm: function (e) {
-            if (this.searchTerm.length < 1) {
-                this.searching = false;
-            }
-        },
-        clearSearch: function(e) {
-            this.searching = false;
-            this.searchTerm = '';
-        }
-    }
-};
\ No newline at end of file
index 2bf7221965965932cc9f2d457c943efb0bbb85ab..cadccb59cfc79cd7772e9f7aaffd8ddff1dc0e4a 100644 (file)
@@ -98,7 +98,7 @@ module.exports = {
             icon: 'image',
             tooltip: 'Insert an image',
             onclick: function() {
-                ImageManager.show(function(image) {
+                window.ImageManager.showExternal(function(image) {
                     var html = '<a href="'+image.url+'" target="_blank">';
                     html += '<img src="'+image.thumbs.display+'" alt="'+image.name+'">';
                     html += '</a>';
@@ -106,6 +106,7 @@ module.exports = {
                 });
             }
         });
+
         // Paste image-uploads
         editor.on('paste', function(e) {
             if(e.clipboardData) {
diff --git a/resources/assets/js/services.js b/resources/assets/js/services.js
new file mode 100644 (file)
index 0000000..684a684
--- /dev/null
@@ -0,0 +1,12 @@
+"use strict";
+
+module.exports = function(ngApp) {
+
+    ngApp.factory('imageManagerService', function() {
+        return {
+            show: false,
+            showExternal: false
+        };
+    });
+
+};
\ No newline at end of file
index 954e10ac08800b7d9109aa65a129eb73cc99ce9a..3b3ce7d9ca67e88e6f811b7d2863606fbb73c506 100644 (file)
@@ -1,7 +1,6 @@
 .overlay {
   background-color: rgba(0, 0, 0, 0.2);
   position: fixed;
-  display: none;
   z-index: 95536;
   width: 100%;
   height: 100%;
index c048aa9fe4268e50c99448bda2b7402f690b6bf5..710bee7eee5b216545e310fcbb3afbda09756f6c 100644 (file)
 
 [v-cloak], [v-show] {display: none;}
 
+[ng\:cloak], [ng-cloak], .ng-cloak {
+  display: none !important;
+}
+
 // Jquery Sortable Styles
 .dragged {
   position: absolute;
index e8958f6296725185eb65f8289e3b860d668cfdb6..8a2e6bc98cedc42acd07ae0fd38f3821cddb341a 100644 (file)
@@ -52,8 +52,8 @@
                             @endif
                         </div>
                         @if($signedIn)
-                            <div class="dropdown-container" data-dropdown>
-                                <span class="user-name" data-dropdown-toggle>
+                            <div class="dropdown-container" dropdown>
+                                <span class="user-name" dropdown-toggle>
                                     <img class="avatar" src="{{$currentUser->getAvatar(30)}}" alt="{{ $currentUser->name }}">
                                     <span class="name">{{ $currentUser->name }}</span> <i class="zmdi zmdi-caret-down"></i>
                                 </span>
index 9a965ccbc8ada02d488594987d311920d9532e68..e6898f3578f6ba94c852d425b5311ac5ee060152 100644 (file)
     </div>
 
 
-    <div class="container" id="book-dashboard">
+    <div class="container" id="book-dashboard" ng-controller="BookShowController" book-id="{{ $book->id }}">
         <div class="row">
             <div class="col-md-7">
 
                 <h1>{{$book->name}}</h1>
-                <div class="book-content anim fadeIn" v-show="!searching">
-                    <p class="text-muted">{{$book->description}}</p>
+                <div class="book-content" ng-show="!searching">
+                    <p class="text-muted" ng-non-bindable>{{$book->description}}</p>
 
-                    <div class="page-list">
+                    <div class="page-list" ng-non-bindable>
                         <hr>
                         @if(count($bookChildren) > 0)
                             @foreach($bookChildren as $childElement)
                         </p>
                     </div>
                 </div>
-                <div class="search-results" v-show="searching">
-                    <h3 class="text-muted">Search Results <a v-if="searching" @click="clearSearch" class="text-small"><i class="zmdi zmdi-close"></i>Clear Search</a></h3>
-                    <div v-if="!searchResults">
+                <div class="search-results" ng-cloak ng-show="searching">
+                    <h3 class="text-muted">Search Results <a ng-if="searching" ng-click="clearSearch()" class="text-small"><i class="zmdi zmdi-close"></i>Clear Search</a></h3>
+                    <div ng-if="!searchResults">
                         @include('partials/loading-icon')
                     </div>
-                    <div v-html="searchResults"></div>
+                    <div ng-bind-html="searchResults"></div>
                 </div>
 
 
             <div class="col-md-4 col-md-offset-1">
                 <div class="margin-top large"></div>
                 <div class="search-box">
-                    <form @submit="searchBook" @input="checkSearchForm" v-el:form action="/search/book/{{ $book->id }}">
-                        {!! csrf_field() !!}
-                        <input v-model="searchTerm" type="text" name="term" placeholder="Search This Book">
+                    <form ng-submit="searchBook($event)">
+                        <input ng-model="searchTerm" ng-change="checkSearchForm()" type="text" name="term" placeholder="Search This Book">
                         <button type="submit"><i class="zmdi zmdi-search"></i></button>
-                        <button v-if="searching" @click="clearSearch" type="button"><i class="zmdi zmdi-close"></i></button>
+                        <button ng-if="searching" ng-click="clearSearch()" type="button"><i class="zmdi zmdi-close"></i></button>
                     </form>
                 </div>
                 <div class="activity anim fadeIn">
index efdc04cf0142001218c8f60a3250b4b1fe705dd3..3ca6a36b614a9c43c8044003449f41598811bc58 100644 (file)
@@ -1,5 +1,9 @@
 @extends('base')
 
+@section('head')
+    <script src="/libs/jquery-sortable/jquery-sortable.min.js"></script>
+@stop
+
 @section('content')
 
     <div class="container">
index 38c2813e25834cfc2f7f3ad6d16c45e07a33acd2..441379eaec9b670029e290d58b6c8e73ea45ebdc 100644 (file)
@@ -16,5 +16,5 @@
             @endif
         </form>
     </div>
-    <image-manager image-type="gallery"></image-manager>
+    @include('partials/image-manager', ['imageType' => 'gallery'])
 @stop
\ No newline at end of file
index 2dca8ee23d61b388f857a611e10eff25095f351e..e0862f92439a8ea1155fe14cdcd0de0686d9d761 100644 (file)
@@ -14,6 +14,6 @@
             @include('pages/form', ['model' => $page])
         </form>
     </div>
-    <image-manager image-type="gallery"></image-manager>
+    @include('partials/image-manager', ['imageType' => 'gallery'])
 
 @stop
\ No newline at end of file
index 13db89d262567913ad21826ce16f9bfb9be4e832..babc4ccfd00b8f4b7309d703101e8604006aeb03 100644 (file)
@@ -1,4 +1,4 @@
-<div v-pre>
+<div ng-non-bindable>
     <h1 id="bkmrk-page-title">{{$page->name}}</h1>
 
     {!! $page->html !!}
diff --git a/resources/views/partials/image-manager.blade.php b/resources/views/partials/image-manager.blade.php
new file mode 100644 (file)
index 0000000..6dc528d
--- /dev/null
@@ -0,0 +1,67 @@
+<div id="image-manager" image-type="{{ $imageType }}" ng-controller="ImageManagerController">
+    <div class="overlay anim-slide" ng-show="showing" ng-cloak ng-click="hide()">
+        <div class="image-manager-body" ng-click="$event.stopPropagation()">
+
+            <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>
+                    <div class="load-more" ng-show="hasMore" ng-click="fetchData()">Load More</div>
+                </div>
+            </div>
+
+            <button class="neg button image-manager-close" ng-click="hide()">x</button>
+
+            <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 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>
+
+                    <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>
+
+                <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
+                    </button>
+                </div>
+
+            </div>
+        </div>
+    </div>
+</div>
\ No newline at end of file
index d1db1ed331490e34339192aef450f0e091b533d6..b5b5d0a4f1ecf4589df977ac953fd94496519e47 100644 (file)
@@ -33,7 +33,7 @@
                 <div class="form-group" id="logo-control">
                     <label for="setting-app-logo">Application Logo</label>
                     <p class="small">This image should be 43px in height. <br>Large images will be scaled down.</p>
-                    <image-picker resize-height="43" resize-width="200" current-image="{{ Setting::get('app-logo', '') }}" default-image="/logo.png" name="setting-app-logo" image-class="logo-image"></image-picker>
+                    <image-picker resize-height="43" show-remove="true" resize-width="200" current-image="{{ Setting::get('app-logo', '') }}" default-image="/logo.png" name="setting-app-logo" image-class="logo-image"></image-picker>
                 </div>
             </div>
         </div>
@@ -86,6 +86,6 @@
 
 </div>
 
-<image-manager image-type="system"></image-manager>
+@include('partials/image-manager', ['imageType' => 'system'])
 
 @stop
index 2a2167279d9c5e1ad87b02224fbc5929b6e47d0d..9de78a4c650d8c63779a58a7726e0b717cdc8a8f 100644 (file)
@@ -33,7 +33,7 @@
                 <div class="form-group" id="logo-control">
                     <label for="user-avatar">User Avatar</label>
                     <p class="small">This image should be approx 256px square.</p>
-                    <image-picker resize-height="512" resize-width="512" current-image="{{ $user->getAvatar(80) }}" current-id="{{ $user->image_id }}" default-image="/user_avatar.png" name="image_id" show-remove="false" image-class="avatar large"></image-picker>
+                    <image-picker resize-height="512" resize-width="512" current-image="{{ $user->getAvatar(80) }}" current-id="{{ $user->image_id }}" default-image="/user_avatar.png" name="image_id" show-remove="false" image-class="['avatar' ,'large']"></image-picker>
                 </div>
             </div>
         </div>
@@ -79,5 +79,5 @@
     </div>
 
     <p class="margin-top large"><br></p>
-    <image-manager image-type="user"></image-manager>
+    @include('partials/image-manager', ['imageType' => 'user'])
 @stop