.idea
/public/plugins
/public/css
-/public/js/all*
+/public/js
+/public/uploads
/public/bower
/storage/images
\ No newline at end of file
*/
public function getAll($page = 0)
{
- $pageSize = 13;
+ $pageSize = 25;
$images = DB::table('images')->orderBy('created_at', 'desc')
->skip($page*$pageSize)->take($pageSize)->get();
foreach($images as $image) {
public function getThumbnail($image, $width = 220, $height = 220)
{
$explodedPath = explode('/', $image->url);
- array_splice($explodedPath, 3, 0, ['thumbs-' . $width . '-' . $height]);
+ array_splice($explodedPath, 4, 0, ['thumbs-' . $width . '-' . $height]);
$thumbPath = implode('/', $explodedPath);
- $thumbFilePath = storage_path() . $thumbPath;
+ $thumbFilePath = public_path() . $thumbPath;
// Return the thumbnail url path if already exists
if(file_exists($thumbFilePath)) {
}
// Otherwise create the thumbnail
- $thumb = ImageTool::make(storage_path() . $image->url);
+ $thumb = ImageTool::make(public_path() . $image->url);
$thumb->fit($width, $height);
// Create thumbnail folder if it does not exist
{
$imageUpload = $request->file('file');
$name = str_replace(' ', '-', $imageUpload->getClientOriginalName());
- $imagePath = '/images/' . Date('Y-m-M') . '/';
- $storagePath = storage_path(). $imagePath;
- $fullPath = $storagePath . $name;
+ $storageName = substr(sha1(time()), 0, 10) . '-' . $name;
+ $imagePath = '/uploads/images/'.Date('Y-m-M').'/';
+ $storagePath = public_path(). $imagePath;
+ $fullPath = $storagePath . $storageName;
while(file_exists($fullPath)) {
- $name = substr(sha1(rand()), 0, 3) . $name;
- $fullPath = $storagePath . $name;
+ $storageName = substr(sha1(rand()), 0, 3) . $storageName;
+ $fullPath = $storagePath . $storageName;
}
- $imageUpload->move($storagePath, $name);
+ $imageUpload->move($storagePath, $storageName);
// Create and save image object
$this->image->name = $name;
- $this->image->url = $imagePath . $name;
+ $this->image->url = $imagePath . $storageName;
$this->image->created_by = Auth::user()->id;
$this->image->updated_by = Auth::user()->id;
$this->image->save();
elixir(function(mix) {
mix.sass('styles.scss');
- mix.babel('image-manager.js');
+ mix.babel('image-manager.js', 'public/js/image-manager.js');
});
+++ /dev/null
-
-// Dropzone config
-Dropzone.options.imageUploadDropzone = {
- uploadMultiple: false,
- previewsContainer: '.image-manager-display .uploads',
- init: function() {
- this.on('success', function(event, image) {
- $('.image-manager-display .uploads').empty();
- var newImage = $('<img />').attr('data-image-id', image.id);
- newImage.attr('title', image.name).attr('src', image.thumbnail);
- newImage.data('imageData', image);
- $('.image-manager-display .uploads').after(newImage);
- });
- }
-};
-
-(function() {
-
- var isInit = false;
- var elem;
- var overlay;
- var display;
- var imageIndexUrl = '/images/all';
- var pageIndex = 0;
- var hasMore = true;
- var isGettingImages = true;
-
- var ImageManager = {};
- var action = false;
-
- ImageManager.show = function(selector, callback) {
- if(isInit) {
- showWindow();
- } else {
- this.init(selector)
- showWindow();
- }
-
- action = (typeof callback !== 'undefined') ? callback : false;
- };
-
- ImageManager.init = function(selector) {
- elem = $(selector);
- overlay = elem.closest('.overlay');
- display = elem.find('.image-manager-display').first();
- var uploads = display.find('.uploads');
- var images = display.find('images');
- var loadMore = display.find('.load-more');
- // Get recent images and show
- $.getJSON(imageIndexUrl, showImages);
- function showImages(data) {
- var images = data.images;
- hasMore = data.hasMore;
- pageIndex++;
- isGettingImages = false;
- for(var i = 0; i < images.length; i++) {
- var image = images[i];
- var newImage = $('<img />').attr('data-image-id', image.id);
- newImage.attr('title', image.name).attr('src', image.thumbnail);
- loadMore.before(newImage);
- newImage.data('imageData', image);
- }
- if(hasMore) loadMore.show();
- }
-
- loadMore.click(function() {
- loadMore.hide();
- if(isGettingImages === false) {
- isGettingImages = true;
- $.getJSON(imageIndexUrl + '/' + pageIndex, showImages);
- }
- });
-
- // Image grabbing on scroll
- display.on('scroll', function() {
- var displayBottom = display.scrollTop() + display.height();
- var elemTop = loadMore.offset().top;
- if(elemTop < displayBottom && hasMore && isGettingImages === false) {
- isGettingImages = true;
- loadMore.hide();
- $.getJSON(imageIndexUrl + '/' + pageIndex, showImages);
- }
- });
-
- elem.on('dblclick', '.image-manager-display img', function() {
- var imageElem = $(this);
- var imageData = imageElem.data('imageData');
- closeWindow();
- if(action) {
- action(imageData);
- }
- });
-
- elem.find('button[data-action="close"]').click(function() {
- closeWindow();
- });
-
- // Set up dropzone
- elem.find('.image-manager-dropzone').first().dropzone({
- uploadMultiple: false
- });
-
- isInit = true;
- };
-
- function showWindow() {
- overlay.closest('body').css('overflow', 'hidden');
- overlay.show();
- }
-
- function closeWindow() {
- overlay.hide();
- overlay.closest('body').css('overflow', 'auto');
- }
-
- window.ImageManager = ImageManager;
-})();
\ No newline at end of file
-class ImageList extends React.Component {
-
- constructor(props) {
- super(props);
- this.state = {
- images: [],
- hasMore: false,
- page: 0
- };
- }
+(function() {
+
+
+ class ImageManager extends React.Component {
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ images: [],
+ hasMore: false,
+ page: 0
+ };
+ }
+
+ show(callback) {
+ $(React.findDOMNode(this)).show();
+ this.callback = callback;
+ }
+
+ hide() {
+ $(React.findDOMNode(this)).hide();
+ }
+
+ selectImage(image) {
+ if(this.callback) {
+ this.callback(image);
+ }
+ this.hide();
+ }
- componentDidMount() {
- $.getJSON('/images/all', data => {
- this.setState({
- images: data.images,
- hasMore: data.hasMore
+ componentDidMount() {
+ var _this = this;
+ // Set initial images
+ $.getJSON('/images/all', data => {
+ this.setState({
+ images: data.images,
+ hasMore: data.hasMore
+ });
});
- });
- }
+ // Create dropzone
+ this.dropZone = new Dropzone(React.findDOMNode(this.refs.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.state.images.unshift(data);
+ _this.setState({
+ images: _this.state.images
+ });
+ //$(file.previewElement).fadeOut(400, function() {
+ // dz.removeFile(file);
+ //})
+ });
+ }
+ });
+ }
- loadMore() {
- this.state.page++;
- $.getJSON('/images/all/' + this.state.page, data => {
- this.setState({
- images: this.state.images.concat(data.images),
- hasMore: data.hasMore
+ loadMore() {
+ this.state.page++;
+ $.getJSON('/images/all/' + this.state.page, data => {
+ this.setState({
+ images: this.state.images.concat(data.images),
+ hasMore: data.hasMore
+ });
});
- });
+ }
+
+ render() {
+ var loadMore = this.loadMore.bind(this);
+ var selectImage = this.selectImage.bind(this);
+ return (
+ <div className="overlay">
+ <div id="image-manager">
+ <div className="image-manager-content">
+ <div className="dropzone-container" ref="dropZone">
+ <div className="dz-message">Drop files or click here to upload</div>
+ </div>
+ <ImageList data={this.state.images} loadMore={loadMore} selectImage={selectImage} hasMore={this.state.hasMore}/>
+ </div>
+ <div className="image-manager-sidebar">
+ <h2>Images</h2>
+ </div>
+ </div>
+ </div>
+ );
+ }
+
}
+ window.ImageManager = new ImageManager();
- render() {
- var images = this.state.images.map(function(image) {
+ class ImageList extends React.Component {
+
+ render() {
+ var selectImage = this.props.selectImage;
+ var images = this.props.data.map(function(image) {
+ return (
+ <Image key={image.id} image={image} selectImage={selectImage} />
+ );
+ });
return (
- <div key={image.id}>
- <img src={image.thumbnail}/>
+ <div className="image-manager-list clearfix">
+ {images}
+ { this.props.hasMore ? <div className="load-more" onClick={this.props.loadMore}>Load More</div> : null }
</div>
);
- });
- return (
- <div className="image-list">
- {images}
- <div className="load-more" onClick={this.loadMore}>Load More</div>
- </div>
- );
+ }
+
}
-}
+ class Image extends React.Component {
-class ImageManager extends React.Component {
- render() {
- return (
- <div id="image-manager">
- <ImageList/>
- </div>
+ setImage() {
+ this.props.selectImage(this.props.image);
+ }
+
+ render() {
+ var setImage = this.setImage.bind(this);
+ return (
+ <div>
+ <img onDoubleClick={setImage} src={this.props.image.thumbnail}/>
+ </div>
+ );
+ }
+
+ }
+
+ if(document.getElementById('image-manager-container')) {
+ window.ImageManager = React.render(
+ <ImageManager />,
+ document.getElementById('image-manager-container')
);
}
-}
-React.render(
- <ImageManager />,
- document.getElementById('container')
-);
\ No newline at end of file
+})();
+
+
border-radius: 4px;
box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.3);
overflow: hidden;
- .image-list img {
+ .image-manager-list img {
border-radius: 0;
float: left;
margin: 1px;
cursor: pointer;
}
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 999;
+ display: flex;
}
-#image-manager .dropzone {
- display: table;
- position: absolute;
- top: 10px;
- left: 300px;
- width: 480px;
- height: 60px;
- border: 4px dashed $primary;
- text-align: center;
- z-index: 900;
- .dz-message {
- display: table-cell;
- vertical-align: middle;
- color: $primary;
- font-size: 1.2em;
- }
- * {
- pointer-events: none;
- }
-}
-.image-manager-display-wrap {
- height: 100%;
- padding-top: 87px;
- position: absolute;
- top: 0;width: 100%;
+#image-manager .dropzone-container {
+ height: 100px;
+ position: relative;
}
-.image-manager-display {
- height: 100%;
- width: 100%;
- text-align: left;
- overflow-y: scroll;
+
+#container {
+ height: 90vh;
}
+
#image-manager .load-more {
width: 150px;
height: 150px;
font-size: 20px;
cursor: pointer;
}
-.image-manager-title {
- font-size: 2em;
- text-align: left;
- margin: 0 $-m;
- padding: $-xl $-m;
- color: #666;
- border-bottom: 1px solid #DDD;
+
+.image-manager-sidebar {
+ width: 300px;
+ height: 100%;
+ margin-left: 1px;
+ padding: 0 $-l;
+ border-left: 1px solid #DDD;
}
-.image-manager-dropzone {
- background-color: lighten($primary, 40%);
- height: 25%;
- text-align: center;
- font-size: 2em;
- line-height: 2em;
- padding-top: $-xl*1.2;
- color: #666;
- border-top: 2px solid $primary;
+.image-manager-list {
+ overflow-y: scroll;
+ flex: 1;
}
+.image-manager-content {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ flex: 1;
+}
+
+
+
+
// Dropzone
/*
* The MIT License
*/
-
+.dz-message {
+ font-size: 1.6em;
+ font-style: italic;
+ color: #aaa;
+ text-align: center;
+ line-height: 90px;
+ cursor: pointer;
+ transition: all ease-in-out 120ms;
+ position: absolute;
+ top: 0;
+ left: 50%;
+ max-width: 400px;
+ width: 400px;
+ margin-left: -200px;
+}
+.dz-drag-hover .dz-message {
+ background-color: rgb(16, 126, 210);
+ color: #EEE;
+}
@keyframes passing-through {
0% {
opacity: 0;
.dropzone, .dropzone * {
box-sizing: border-box; }
-.dropzone {
- background: white;
- padding: 20px 20px; }
-.dropzone.dz-clickable {
- cursor: pointer; }
-.dropzone.dz-clickable * {
- cursor: default; }
-.dropzone.dz-clickable .dz-message, .dropzone.dz-clickable .dz-message * {
- cursor: pointer; }
-.dropzone.dz-started .dz-message {
- display: none; }
-.dropzone.dz-drag-hover {
- border-style: solid; }
-.dropzone.dz-drag-hover .dz-message {
- opacity: 0.5; }
-.dropzone .dz-message {
- text-align: center;
- margin: 2em 0; }
+
.dz-preview {
position: relative;
display: inline-block;
vertical-align: top;
- margin: 16px;
- min-height: 100px; }
+ margin: 12px;
+ min-height: 80px; }
.dz-preview:hover {
z-index: 1000; }
.dz-preview:hover .dz-details {
top: 0;
left: 0;
opacity: 0;
- font-size: 13px;
+ font-size: 10px;
min-width: 100%;
max-width: 100%;
- padding: 2em 1em;
+ padding: 6px 3px;
text-align: center;
color: rgba(0, 0, 0, 0.9);
line-height: 150%; }
.dz-preview .dz-details .dz-size {
- margin-bottom: 1em;
- font-size: 16px; }
+ margin-bottom: 0.5em;
+ font-size: 12px; }
.dz-preview .dz-details .dz-filename {
white-space: nowrap; }
.dz-preview .dz-details .dz-filename:hover span {
.dz-preview .dz-image {
border-radius: 4px;
overflow: hidden;
- width: 120px;
- height: 120px;
+ width: 80px;
+ height: 80px;
position: relative;
display: block;
z-index: 10; }
.overlay {
background-color: rgba(0, 0, 0, 0.2);
position: fixed;
- display: block;
+ display: none;
z-index: 95536;
width: 100%;
height: 100%;
width: 100%;
height: 100%;
z-index: -1;
- .overlay {
+ &:after{
+ content: '';
position: absolute;
top: 0;
left: 0;
height: 100%;
z-index: -1;
background-color: rgba(0,0,0,0.7);
+ display: block;
}
}
<head>
<title>BookStack</title>
<meta name="viewport" content="width=device-width">
+ <meta name="token" content="{{ csrf_token() }}">
<link rel="stylesheet" href="/css/app.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="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">--}}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="/bower/bootstrap/dist/js/bootstrap.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="https://fb.me/react-0.13.3.js"></script>
<script>
$.fn.smoothScrollTo = function() {
</section>
@yield('bottom')
-
- <script src="/js/all.js"></script>
</body>
</html>
@section('head')
<script src="/bower/tinymce-dist/tinymce.jquery.min.js"></script>
- <script src="/bower/dropzone/dist/min/dropzone.min.js"></script>
- <script src="/js/image-manager.js"></script>
@stop
@section('content')
@stop
@section('bottom')
- @include('pages/image-manager')
+ <div id="image-manager-container"></div>
+ <script src="/js/image-manager.js"></script>
@stop
\ No newline at end of file
toolbar: "undo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table image link | fontsizeselect fullscreen",
content_style: "body {padding-left: 15px !important; padding-right: 15px !important; margin:0!important; margin-left:auto!important;margin-right:auto!important;}",
file_browser_callback: function(field_name, url, type, win) {
- ImageManager.show('#image-manager', function(image) {
+ ImageManager.show(function(image) {
win.document.getElementById(field_name).value = image.url;
if ("createEvent" in document) {
var evt = document.createEvent("HTMLEvents");