"tests"
],
"dependencies": {
- "dropzone": "~4.0.1",
"tinymce-dist": "~4.2.1",
"bootstrap": "~3.3.5",
"jquery-sortable": "~0.9.13",
- "material-design-iconic-font": "~2.1.1",
- "vue": "~0.12.10",
- "vue-resource": "~0.1.15"
+ "material-design-iconic-font": "~2.1.1"
}
}
var elixir = require('laravel-elixir');
+elixir.config.js.browserify.transformers.push({
+ name: 'vueify',
+ options: {}
+});
elixir(function(mix) {
mix.sass('styles.scss');
- mix.scripts('image-manager.js', 'public/js/image-manager.js');
- mix.browserify(['jquery-extensions.js', 'pages/book-show.js' ,'global.js'], 'public/js/common.js');
+ mix.browserify(['jquery-extensions.js', 'global.js'], 'public/js/common.js');
});
"devDependencies": {
"gulp": "^3.8.8",
"insert-css": "^0.2.0",
- "laravel-elixir-livereload": "1.1.3"
+ "laravel-elixir-livereload": "1.1.3",
+ "vueify": "^1.1.5"
},
"dependencies": {
"bootstrap-sass": "^3.0.0",
+ "dropzone": "^4.0.1",
"laravel-elixir": "^3.3.1",
- "vue": "^0.12.16"
+ "vue": "^0.12.16",
+ "vue-resource": "^0.1.16"
}
}
--- /dev/null
+<template>
+ <div id="image-manager">
+ <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">
+ <div v-repeat="image: images">
+ <img class="anim fadeIn"
+ v-class="selected: (image==selectedImage)"
+ v-attr="src: image.thumbnail, alt: image.name, title: image.name"
+ v-on="click: imageClick(image)"
+ v-style="animation-delay: ($index > 26) ? '160ms' : ($index * 25) + 'ms'">
+ </div>
+ <div class="load-more" v-show="hasMore" v-on="click: fetchData">Load More</div>
+ </div>
+ </div>
+ <button class="neg button image-manager-close" v-on="click: hide()">x</button>
+ <div class="image-manager-sidebar">
+ <h2 v-el="imageTitle">Images</h2>
+ <hr class="even">
+ <div class="dropzone-container" v-el="dropZone">
+ <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 v-on="submit: saveImageDetails" v-el="imageForm">
+ <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-repeat="page: dependantPages">
+ <a v-attr="href: page.url" target="_blank" class="text-neg">@{{ page.name }}</a>
+ </li>
+ </ul>
+ </div>
+
+ <form v-on="submit: deleteImage" v-el="imageDeleteForm">
+ <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" v-on="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')
+ }
+ },
+
+ created: function () {
+ // Get initial images
+ this.fetchData(this.page);
+ window.ImageManager = this;
+ },
+
+ ready: function () {
+ // Create dropzone
+ this.setupDropZone();
+ },
+
+ methods: {
+ fetchData: function () {
+ var _this = this;
+ this.$http.get('/images/all/' + _this.page, function (data) {
+ _this.images = _this.images.concat(data.images);
+ _this.hasMore = data.hasMore;
+ _this.page++;
+ });
+ },
+
+ setupDropZone: function () {
+ var _this = this;
+ var dropZone = new Dropzone(_this.$$.dropZone, {
+ url: '/upload/image',
+ init: function () {
+ var dz = this;
+ this.on("sending", function (file, xhr, data) {
+ data.append("_token", _this.token);
+ });
+ this.on("success", function (file, data) {
+ _this.images.unshift(data);
+ $(file.previewElement).fadeOut(400, function () {
+ dz.removeFile(file);
+ });
+ });
+ }
+ });
+ },
+
+ 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.callback(image);
+ }
+ this.hide();
+ } else {
+ this.selectedImage = (this.selectedImage === image) ? false : image;
+ this.dependantPages = false;
+ }
+ this.cClickTime = cTime;
+ },
+
+ selectButtonClick: function () {
+ if (this.callback) {
+ this.callback(this.selectedImage);
+ }
+ this.hide();
+ },
+
+ show: function (callback) {
+ this.callback = callback;
+ this.$$.overlay.style.display = 'block';
+ },
+
+ overlayClick: function (e) {
+ if (e.target.className === 'overlay') {
+ this.hide();
+ }
+ },
+
+ hide: function () {
+ this.$$.overlay.style.display = 'none';
+ },
+
+ saveImageDetails: function (e) {
+ e.preventDefault();
+ var _this = this;
+ _this.selectedImage._token = _this.token;
+ var form = $(_this.$$.imageForm);
+ $.ajax('/images/update/' + _this.selectedImage.id, {
+ method: 'PUT',
+ data: _this.selectedImage
+ }).done(function () {
+ form.showSuccess('Image name updated');
+ }).fail(function (jqXHR) {
+ form.showFailure(jqXHR.responseJSON);
+ })
+ },
+
+ deleteImage: function (e) {
+ e.preventDefault();
+ var _this = this;
+ _this.deleteForm.force = _this.dependantPages !== false;
+ _this.deleteForm._token = _this.token;
+ $.ajax('/images/' + _this.selectedImage.id, {
+ method: 'DELETE',
+ data: _this.deleteForm
+ }).done(function () {
+ _this.images.splice(_this.images.indexOf(_this.selectedImage), 1);
+ _this.selectedImage = false;
+ $(_this.$$.imageTitle).showSuccess('Image Deleted');
+ }).fail(function(jqXHR, textStatus) {
+ // Pages failure
+ if(jqXHR.status === 400) {
+ _this.dependantPages = jqXHR.responseJSON;
+ }
+ });
+ }
+
+ }
+
+ };
+</script>
\ No newline at end of file
--- /dev/null
+
+<template>
+ <div class="image-picker">
+ <div>
+ <img v-if="image && image !== 'none'" v-attr="src: image, class: imageClass" alt="Image Preview">
+ </div>
+ <button class="button" type="button" v-on="click: showImageManager">Select Image</button>
+ <br>
+ <button class="text-button" v-on="click: reset" type="button">Reset</button> <span class="sep">|</span> <button class="text-button neg" v-on="click: remove" type="button">Remove</button>
+ <input type="hidden" v-attr="name: name, id: name" v-model="image">
+ </div>
+</template>
+
+<script>
+ module.exports = {
+ props: ['currentImage', 'name', 'imageClass'],
+ data: function() {
+ return {
+ image: this.currentImage
+ }
+ },
+ methods: {
+ showImageManager: function(e) {
+ var _this = this;
+ ImageManager.show(function(image) {
+ _this.image = image.url;
+ });
+ },
+ reset: function() {
+ this.image = '';
+ },
+ remove: function() {
+ this.image = 'none';
+ }
+ }
+ }
+</script>
\ No newline at end of file
+
+// Global jQuery Elements
$(function () {
// Notification hiding
$('.notification').click(function () {
$(this).fadeOut(100);
-
});
// Dropdown toggles
});
+function elemExists(selector) {
+ return document.querySelector(selector) !== null;
+}
+
+// Vue JS elements
+var Vue = require('vue');
+Vue.use(require('vue-resource'));
// Vue Components
+Vue.component('image-manager', require('./components/image-manager.vue'));
+Vue.component('image-picker', require('./components/image-picker.vue'));
-Vue.component('image-picker', {
- template: require('./templates/image-picker.html'),
- props: ['currentImage', 'name', 'imageClass'],
- data: function() {
- return {
- image: this.currentImage
- }
- },
- methods: {
- showImageManager: function(e) {
- var _this = this;
- ImageManager.show(function(image) {
- _this.image = image.url;
- });
- },
- reset: function() {
- this.image = '';
- },
- remove: function() {
- this.image = 'none';
- }
- }
-});
+// Vue Controllers
+if(elemExists('#book-dashboard')) {
+ new Vue(require('./pages/book-show'));
+}
// Global Vue Instance
+// Needs to be loaded after all components we want to use.
var app = new Vue({
el: '#app'
});
\ No newline at end of file
+++ /dev/null
-
-
-window.ImageManager = new Vue({
-
- el: '#image-manager',
-
- data: {
- images: [],
- hasMore: false,
- page: 0,
- cClickTime: 0,
- selectedImage: false,
- dependantPages: false,
- deleteForm: {}
- },
-
- created: function () {
- // Get initial images
- this.fetchData(this.page);
- },
-
- ready: function () {
- // Create dropzone
- this.setupDropZone();
- },
-
- methods: {
- fetchData: function () {
- var _this = this;
- this.$http.get('/images/all/' + _this.page, function (data) {
- _this.images = _this.images.concat(data.images);
- _this.hasMore = data.hasMore;
- _this.page++;
- });
- },
-
- setupDropZone: function () {
- var _this = this;
- var dropZone = new Dropzone(_this.$$.dropZone, {
- url: '/upload/image',
- init: function () {
- var dz = this;
- this.on("sending", function (file, xhr, data) {
- data.append("_token", document.querySelector('meta[name=token]').getAttribute('content'));
- });
- this.on("success", function (file, data) {
- _this.images.unshift(data);
- $(file.previewElement).fadeOut(400, function () {
- dz.removeFile(file);
- });
- });
- }
- });
- },
-
- 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.callback(image);
- }
- this.hide();
- } else {
- this.selectedImage = (this.selectedImage === image) ? false : image;
- this.dependantPages = false;
- }
- this.cClickTime = cTime;
- },
-
- selectButtonClick: function () {
- if (this.callback) {
- this.callback(this.selectedImage);
- }
- this.hide();
- },
-
- show: function (callback) {
- this.callback = callback;
- this.$$.overlay.style.display = 'block';
- },
-
- overlayClick: function (e) {
- if (e.target.className === 'overlay') {
- this.hide();
- }
- },
-
- hide: function () {
- this.$$.overlay.style.display = 'none';
- },
-
- saveImageDetails: function (e) {
- e.preventDefault();
- var _this = this;
- var form = $(_this.$$.imageForm);
- $.ajax('/images/update/' + _this.selectedImage.id, {
- method: 'PUT',
- data: form.serialize()
- }).done(function () {
- form.showSuccess('Image name updated');
- }).fail(function (jqXHR) {
- form.showFailure(jqXHR.responseJSON);
- })
- },
-
- deleteImage: function (e) {
- e.preventDefault();
- var _this = this;
- _this.deleteForm.force = _this.dependantPages !== false;
- $.ajax('/images/' + _this.selectedImage.id, {
- method: 'DELETE',
- data: _this.deleteForm
- }).done(function () {
- _this.images.splice(_this.images.indexOf(_this.selectedImage), 1);
- _this.selectedImage = false;
- $(_this.$$.imageTitle).showSuccess('Image Deleted');
- }).fail(function(jqXHR, textStatus) {
- // Pages failure
- if(jqXHR.status === 400) {
- _this.dependantPages = jqXHR.responseJSON;
- }
- });
- }
-
- }
-
-});
jQuery.fn.dropDown = function() {
var container = $(this),
menu = container.find('ul');
- container.find('[data-dropdown-toggle]').on('click', function() {
+ container.find('[data-dropdown-toggle]').on('click', function() {
menu.show().addClass('anim menuIn');
container.mouseleave(function() {
menu.hide();
-new Vue({
+module.exports = {
el: '#book-dashboard',
data: {
searching: false,
this.searchTerm = '';
}
}
-});
\ No newline at end of file
+};
\ No newline at end of file
+++ /dev/null
-
-<div class="image-picker">
- <div>
- <img v-if="image && image !== 'none'" v-attr="src: image, class: imageClass" alt="Image Preview">
- </div>
- <button class="button" type="button" v-on="click: showImageManager">Select Image</button>
- <br>
- <button class="text-button" v-on="click: reset" type="button">Reset</button> <span class="sep">|</span> <button class="text-button neg" v-on="click: remove" type="button">Remove</button>
- <input type="hidden" v-attr="name: name, id: name" v-model="image">
-</div>
\ No newline at end of file
right: 0;
margin: $-m 0;
background-color: #FFFFFF;
- list-style: none;
box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.1);
border-radius: 1px;
border: 1px solid #EEE;
@import "lists";
@import "pages";
+[v-cloak] {display: none;}
+
// Jquery Sortable Styles
.dragged {
position: absolute;
<meta name="token" content="{{ csrf_token() }}">
<!-- Styles and Fonts -->
- <link rel="stylesheet" href="/css/app.css">
+ <link rel="stylesheet" href="/css/styles.css">
<link href='//fonts.googleapis.com/css?family=Roboto:400,400italic,500,500italic,700,700italic,300italic,100,300' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="/bower/material-design-iconic-font/dist/css/material-design-iconic-font.min.css">
<!-- Scripts -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="/bower/jquery-sortable/source/js/jquery-sortable.js"></script>
- <script src="/bower/dropzone/dist/min/dropzone.min.js"></script>
- <script src="/bower/vue/dist/vue.min.js"></script>
- <script src="/bower/vue-resource/dist/vue-resource.min.js"></script>
@yield('head')
</head>
</form>
</div>
-@stop
-
-@section('bottom')
- @include('pages/image-manager')
@stop
\ No newline at end of file
</form>
</div>
-@stop
-
-@section('bottom')
- @include('pages/image-manager')
@stop
\ No newline at end of file
@endif
</form>
</div>
-@stop
-
-@section('bottom')
- @include('pages/image-manager')
- <script src="/js/image-manager.js"></script>
@stop
\ No newline at end of file
</form>
</div>
-@stop
-
-@section('bottom')
- @include('pages/image-manager')
@stop
\ No newline at end of file
</form>
</div>
-@stop
-
-@section('bottom')
- @include('pages/image-manager')
- <script src="/js/image-manager.js"></script>
@stop
\ No newline at end of file
});
-</script>
\ No newline at end of file
+</script>
+
+<image-manager></image-manager>
\ No newline at end of file
+++ /dev/null
-
-<div id="image-manager">
- <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">
- <div v-repeat="image: images">
- <img class="anim fadeIn"
- v-class="selected: (image==selectedImage)"
- v-attr="src: image.thumbnail, alt: image.name, title: image.name"
- v-on="click: imageClick(image)"
- v-style="animation-delay: ($index > 26) ? '160ms' : ($index * 25) + 'ms'">
- </div>
- <div class="load-more" v-show="hasMore" v-on="click: fetchData">Load More</div>
- </div>
- </div>
- <button class="neg button image-manager-close" v-on="click: hide()">x</button>
- <div class="image-manager-sidebar">
- <h2 v-el="imageTitle">Images</h2>
- <hr class="even">
- <div class="dropzone-container" v-el="dropZone">
- <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 v-on="submit: saveImageDetails" v-el="imageForm">
- {{ csrf_field() }}
- <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-repeat="page: dependantPages">
- <a v-attr="href: page.url" target="_blank" class="text-neg">@{{ page.name }}</a>
- </li>
- </ul>
- </div>
-
- <form v-on="submit: deleteImage" v-el="imageDeleteForm">
- <input type="hidden" v-model="deleteForm._token" value="{{ csrf_token() }}">
- <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" v-on="click:selectButtonClick"><i class="zmdi zmdi-square-right"></i>Select Image</button>
- </div>
- </div>
- </div>
- </div>
-</div>
</div>
-@stop
+<image-manager></image-manager>
-@section('bottom')
- @include('pages/image-manager')
- <script src="/js/image-manager.js"></script>
-@stop
\ No newline at end of file
+@stop