Toggle navigation
Toggle navigation
This project
Loading...
Sign in
Зуев Егор
/
wiki.dev
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
Authored by
Dan Brown
2015-08-12 23:42:42 +0100
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
Commit
83c653fc3225cab9e47053348edc84807b5d248f
83c653fc
1 parent
8d72883d
Got react image manager working
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
210 additions
and
259 deletions
.gitignore
app/Http/Controllers/ImageController.php
gulpfile.js
public/js/image-manager.js
resources/assets/js/image-manager.js
resources/assets/sass/image-manager.scss
resources/assets/sass/styles.scss
resources/views/base.blade.php
resources/views/pages/edit.blade.php
resources/views/pages/form.blade.php
.gitignore
View file @
83c653f
...
...
@@ -6,6 +6,7 @@ Homestead.yaml
.idea
/public/plugins
/public/css
/public/js/all*
/public/js
/public/uploads
/public/bower
/storage/images
\ No newline at end of file
...
...
app/Http/Controllers/ImageController.php
View file @
83c653f
...
...
@@ -71,7 +71,7 @@ class ImageController extends Controller
*/
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
)
{
...
...
@@ -95,9 +95,9 @@ class ImageController extends Controller
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
))
{
...
...
@@ -105,7 +105,7 @@ class ImageController extends Controller
}
// 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
...
...
@@ -127,17 +127,18 @@ class ImageController extends Controller
{
$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
)
.
$n
ame
;
$fullPath
=
$storagePath
.
$
n
ame
;
$
storageName
=
substr
(
sha1
(
rand
()),
0
,
3
)
.
$storageN
ame
;
$fullPath
=
$storagePath
.
$
storageN
ame
;
}
$imageUpload
->
move
(
$storagePath
,
$
n
ame
);
$imageUpload
->
move
(
$storagePath
,
$
storageN
ame
);
// Create and save image object
$this
->
image
->
name
=
$name
;
$this
->
image
->
url
=
$imagePath
.
$
n
ame
;
$this
->
image
->
url
=
$imagePath
.
$
storageN
ame
;
$this
->
image
->
created_by
=
Auth
::
user
()
->
id
;
$this
->
image
->
updated_by
=
Auth
::
user
()
->
id
;
$this
->
image
->
save
();
...
...
gulpfile.js
View file @
83c653f
...
...
@@ -13,5 +13,5 @@ var elixir = require('laravel-elixir');
elixir
(
function
(
mix
)
{
mix
.
sass
(
'styles.scss'
);
mix
.
babel
(
'image-manager.js'
);
mix
.
babel
(
'image-manager.js'
,
'public/js/image-manager.js'
);
});
...
...
public/js/image-manager.js
deleted
100644 → 0
View file @
8d72883
// 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
resources/assets/js/image-manager.js
View file @
83c653f
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
})();
...
...
resources/assets/sass/image-manager.scss
View file @
83c653f
...
...
@@ -9,46 +9,29 @@
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
;
...
...
@@ -62,32 +45,54 @@
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
* Copyright (c) 2012 Matias Meno <m@tias.me>
*/
.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
;
...
...
@@ -128,30 +133,13 @@
.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
:
1
6
px
;
min-height
:
10
0px
;
}
margin
:
1
2
px
;
min-height
:
8
0px
;
}
.dz-preview
:hover
{
z-index
:
1000
;
}
.dz-preview
:hover
.dz-details
{
...
...
@@ -186,16 +174,16 @@
top
:
0
;
left
:
0
;
opacity
:
0
;
font-size
:
1
3
px
;
font-size
:
1
0
px
;
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
:
1
em
;
font-size
:
1
6
px
;
}
margin-bottom
:
0
.5
em
;
font-size
:
1
2
px
;
}
.dz-preview
.dz-details
.dz-filename
{
white-space
:
nowrap
;
}
.dz-preview
.dz-details
.dz-filename
:hover
span
{
...
...
@@ -221,8 +209,8 @@
.dz-preview
.dz-image
{
border-radius
:
4px
;
overflow
:
hidden
;
width
:
12
0px
;
height
:
12
0px
;
width
:
8
0px
;
height
:
8
0px
;
position
:
relative
;
display
:
block
;
z-index
:
10
;
}
...
...
resources/assets/sass/styles.scss
View file @
83c653f
...
...
@@ -182,7 +182,7 @@ ul.menu {
.overlay
{
background-color
:
rgba
(
0
,
0
,
0
,
0
.2
);
position
:
fixed
;
display
:
block
;
display
:
none
;
z-index
:
95536
;
width
:
100%
;
height
:
100%
;
...
...
@@ -355,7 +355,8 @@ body.dragging, body.dragging * {
width
:
100%
;
height
:
100%
;
z-index
:
-1
;
.overlay
{
&
:after
{
content
:
''
;
position
:
absolute
;
top
:
0
;
left
:
0
;
...
...
@@ -363,6 +364,7 @@ body.dragging, body.dragging * {
height
:
100%
;
z-index
:
-1
;
background-color
:
rgba
(
0
,
0
,
0
,
0
.7
);
display
:
block
;
}
}
...
...
resources/views/base.blade.php
View file @
83c653f
...
...
@@ -3,6 +3,7 @@
<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"
>
--}}
...
...
@@ -10,6 +11,7 @@
<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
()
{
...
...
@@ -63,7 +65,5 @@
</section>
@yield('bottom')
<script
src=
"/js/all.js"
></script>
</body>
</html>
...
...
resources/views/pages/edit.blade.php
View file @
83c653f
...
...
@@ -2,8 +2,6 @@
@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')
...
...
@@ -16,5 +14,6 @@
@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
...
...
resources/views/pages/form.blade.php
View file @
83c653f
...
...
@@ -41,7 +41,7 @@
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"
);
...
...
Please
register
or
sign in
to post a comment