mirror of
https://github.com/Poniverse/Pony.fm.git
synced 2024-11-25 06:27:59 +01:00
Image things
This commit is contained in:
parent
c56568b6f5
commit
3b291f3b8f
12 changed files with 210 additions and 22 deletions
29
app/controllers/Api/Web/ImagesController.php
Normal file
29
app/controllers/Api/Web/ImagesController.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Api\Web;
|
||||
|
||||
use Commands\DeleteTrackCommand;
|
||||
use Commands\EditTrackCommand;
|
||||
use Commands\UploadTrackCommand;
|
||||
use Cover;
|
||||
use Entities\Image;
|
||||
use Entities\Track;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
|
||||
class ImagesController extends \ApiControllerBase {
|
||||
public function getOwned() {
|
||||
$query = Image::where('uploaded_by', \Auth::user()->id);
|
||||
$images = [];
|
||||
foreach ($query->get() as $image) {
|
||||
$images[] = [
|
||||
'id' => $image->id,
|
||||
'url' => $image->getUrl(Image::SMALL),
|
||||
'filename' => $image->filename
|
||||
];
|
||||
}
|
||||
|
||||
return Response::json($images, 200);
|
||||
}
|
||||
}
|
|
@ -92,7 +92,8 @@
|
|||
'description' => $track->description,
|
||||
'lyrics' => $track->lyrics,
|
||||
'released_at' => $track->released_at,
|
||||
'cover_url' => $track->hasCover() ? $track->getCoverUrl(Image::NORMAL) : null
|
||||
'cover_url' => $track->hasCover() ? $track->getCoverUrl(Image::NORMAL) : null,
|
||||
'real_cover_url' => $track->getCoverUrl(Image::NORMAL)
|
||||
], 200);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,17 @@
|
|||
if (!$image)
|
||||
App::abort(404);
|
||||
|
||||
return File::inline($image->getFile($coverType['id']), $image->mime, $image->filename);
|
||||
$filename = $image->getFile($coverType['id']);
|
||||
$lastModified = filemtime($filename);
|
||||
|
||||
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $lastModified == $_SERVER['HTTP_IF_MODIFIED_SINCE']) {
|
||||
header('HTTP/1.0 304 Not Modified');
|
||||
exit();
|
||||
}
|
||||
|
||||
header('Last-Modified: ' . $lastModified);
|
||||
header('Cache-Control: max-age=' . (60 * 60 * 24 * 7));
|
||||
|
||||
return File::inline($filename, $image->mime, $image->filename);
|
||||
}
|
||||
}
|
|
@ -42,7 +42,8 @@
|
|||
'genre_id' => 'required|exists:genres,id',
|
||||
'cover' => 'image|mimes:png|min_width:350|min_height:350',
|
||||
'track_type_id' => 'required|exists:track_types,id',
|
||||
'songs' => 'required_when:track_type,2|exists:songs,id'
|
||||
'songs' => 'required_when:track_type,2|exists:songs,id',
|
||||
'cover_id' => 'exists:images,id'
|
||||
]);
|
||||
|
||||
if ($validator->fails())
|
||||
|
@ -64,10 +65,13 @@
|
|||
$track->published_at = new \DateTime();
|
||||
}
|
||||
|
||||
if (isset($this->_input['cover'])) {
|
||||
if (isset($this->_input['cover_id'])) {
|
||||
$track->cover_id = $this->_input['cover_id'];
|
||||
}
|
||||
else if (isset($this->_input['cover'])) {
|
||||
$cover = $this->_input['cover'];
|
||||
$track->cover_id = Image::Upload($cover, Auth::user())->id;
|
||||
} else
|
||||
} else if ($this->_input['remove_cover'] == 'true')
|
||||
$track->cover_id = null;
|
||||
|
||||
$track->save();
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
});
|
||||
|
||||
Route::group(['before' => 'auth'], function() {
|
||||
Route::get('/images/owned', 'Api\Web\ImagesController@getOwned');
|
||||
Route::get('/tracks/owned', 'Api\Web\TracksController@getOwned');
|
||||
Route::get('/tracks/edit/{id}', 'Api\Web\TracksController@getEdit');
|
||||
});
|
||||
|
|
|
@ -8,6 +8,7 @@ angular.module('ponyfm').controller "account-content-tracks", [
|
|||
$scope.isCoverLoaded = false
|
||||
$scope.selectedTrack = null
|
||||
$scope.isDirty = false
|
||||
$scope.isSaving = false
|
||||
$scope.taxonomies =
|
||||
trackTypes: taxonomies.trackTypes
|
||||
licenses: taxonomies.licenses
|
||||
|
@ -18,11 +19,22 @@ angular.module('ponyfm').controller "account-content-tracks", [
|
|||
|
||||
$scope.previewCover = () ->
|
||||
return if !$scope.edit.cover
|
||||
if typeof($scope.edit.cover) == 'object'
|
||||
lightbox.openDataUrl $('#coverPreview').attr 'src'
|
||||
else
|
||||
lightbox.openImageUrl $scope.edit.cover
|
||||
|
||||
$scope.selectGalleryImage = (image) ->
|
||||
$('#coverPreview').attr 'src', image.url
|
||||
$scope.edit.cover_id = image.id
|
||||
$scope.edit.remove_cover = false
|
||||
$scope.edit.cover = null
|
||||
$scope.isDirty = true
|
||||
|
||||
$scope.updateTrack = (track) ->
|
||||
xhr = new XMLHttpRequest()
|
||||
xhr.onload = -> $scope.$apply ->
|
||||
$scope.isSaving = false
|
||||
if xhr.status != 200
|
||||
errors =
|
||||
if xhr.getResponseHeader('content-type') == 'application/json'
|
||||
|
@ -40,12 +52,15 @@ angular.module('ponyfm').controller "account-content-tracks", [
|
|||
formData = new FormData();
|
||||
_.each $scope.edit, (value, name) ->
|
||||
if name == 'cover'
|
||||
return if value == null
|
||||
if typeof(value) == 'object'
|
||||
formData.append name, value, value.name
|
||||
else
|
||||
formData.append name, value
|
||||
|
||||
xhr.open 'POST', '/api/web/tracks/edit/' + $scope.edit.id, true
|
||||
xhr.setRequestHeader 'X-Token', pfm.token
|
||||
$scope.isSaving = true
|
||||
xhr.send formData
|
||||
|
||||
$scope.uploadTrackCover = () ->
|
||||
|
@ -53,6 +68,7 @@ angular.module('ponyfm').controller "account-content-tracks", [
|
|||
|
||||
$scope.setCoverImage = (input) ->
|
||||
$scope.$apply ->
|
||||
delete $scope.edit.cover_id
|
||||
previewElement = $('#coverPreview')[0]
|
||||
file = input.files[0]
|
||||
|
||||
|
@ -71,6 +87,9 @@ angular.module('ponyfm').controller "account-content-tracks", [
|
|||
|
||||
$scope.clearTrackCover = () ->
|
||||
$scope.isCoverLoaded = false
|
||||
$scope.isDirty = true
|
||||
$scope.edit.remove_cover = true
|
||||
delete $scope.edit.cover_id
|
||||
delete $scope.edit.cover
|
||||
|
||||
$scope.filters =
|
||||
|
@ -162,6 +181,20 @@ angular.module('ponyfm').controller "account-content-tracks", [
|
|||
genre_id: track.genre_id
|
||||
track_type_id: track.track_type_id
|
||||
released_at: if track.released_at then track.released_at.date else ''
|
||||
remove_cover: false
|
||||
cover: track.cover_url
|
||||
|
||||
trackDbItem = tracksDb[t.id]
|
||||
trackDbItem.title = track.title
|
||||
trackDbItem.is_explicit = track.is_explicit
|
||||
trackDbItem.is_vocal = track.is_vocal
|
||||
trackDbItem.genre_id = track.genre_id
|
||||
trackDbItem.is_published = track.is_published
|
||||
trackDbItem.cover_url = track.real_cover_url
|
||||
|
||||
if track.cover_url
|
||||
$('#coverPreview').attr 'src', track.cover_url
|
||||
$scope.isCoverLoaded = true
|
||||
|
||||
$scope.touchModel = -> $scope.isDirty = true
|
||||
|
||||
|
|
10
public/scripts/app/controllers/account-image-select.coffee
Normal file
10
public/scripts/app/controllers/account-image-select.coffee
Normal file
|
@ -0,0 +1,10 @@
|
|||
angular.module('ponyfm').controller "account-image-select", [
|
||||
'$scope'
|
||||
($scope) ->
|
||||
$scope.images = []
|
||||
$scope.isLoading = true
|
||||
|
||||
$.getJSON('/api/web/images/owned').done (images) -> $scope.$apply ->
|
||||
$scope.images = images
|
||||
$scope.isLoading = false
|
||||
]
|
36
public/scripts/app/directives/popup.coffee
Normal file
36
public/scripts/app/directives/popup.coffee
Normal file
|
@ -0,0 +1,36 @@
|
|||
angular.module('ponyfm').directive 'pfmPopup', () ->
|
||||
(scope, element, attrs) ->
|
||||
$popup = $ '#' + attrs.pfmPopup
|
||||
$element = $ element
|
||||
$popup.remove()
|
||||
open = false
|
||||
|
||||
documentClickHandler = () ->
|
||||
return if !open
|
||||
$popup.removeClass 'open'
|
||||
open = false
|
||||
|
||||
$(document.body).bind 'click', documentClickHandler
|
||||
|
||||
$(document.body).append $popup
|
||||
|
||||
$(element).click (e) ->
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
||||
if open
|
||||
open = false
|
||||
$popup.removeClass 'open'
|
||||
return
|
||||
|
||||
position = $element.offset()
|
||||
$popup.addClass 'open'
|
||||
$popup.css
|
||||
top: position.top + $element.height() + 10
|
||||
left: position.left
|
||||
|
||||
open = true
|
||||
|
||||
scope.$on '$destroy', () ->
|
||||
$(document.body).unbind 'click', documentClickHandler
|
||||
$popup.remove()
|
|
@ -4,5 +4,10 @@ angular.module('ponyfm').factory('lightbox', [
|
|||
$.colorbox
|
||||
html: '<img src="' + src + '" />'
|
||||
transition: 'none'
|
||||
|
||||
openImageUrl: (src) ->
|
||||
$.colorbox
|
||||
href: src
|
||||
transition: 'none'
|
||||
])
|
||||
|
||||
|
|
|
@ -15,6 +15,38 @@
|
|||
}
|
||||
}
|
||||
|
||||
.image-selector {
|
||||
width: 500px;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
|
||||
li {
|
||||
margin: 0px;
|
||||
float: left;
|
||||
width: 20%;
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
.transition(all 400ms);
|
||||
display: block;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
img {
|
||||
opacity: .8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.account-tracks-listing {
|
||||
overflow-y: auto;
|
||||
margin: 0px;
|
||||
|
|
|
@ -81,3 +81,15 @@ html body {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pfm-popup {
|
||||
.box-shadow(0 5px 10px rgba(0, 0, 0, 0.2));
|
||||
position: absolute;
|
||||
display: none;
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
background: #fff;
|
||||
|
||||
&.open {
|
||||
display: block;
|
||||
}
|
||||
}
|
|
@ -58,42 +58,48 @@
|
|||
<form novalidate ng-submit="updateTrack(edit)">
|
||||
<ul class="toolbar">
|
||||
<li>
|
||||
<button type="submit" class="btn" ng-class="{disabled: selectedTrack.is_published && !isDirty, 'btn-primary': !selectedTrack.is_published || isDirty}">
|
||||
<span ng-show="selectedTrack.is_published">Save Changes</span>
|
||||
<span ng-hide="selectedTrack.is_published">Publish Track</span>
|
||||
<button type="submit" class="btn" ng-class="{disabled: (selectedTrack.is_published && !isDirty) || isSaving, 'btn-primary': !selectedTrack.is_published || isDirty}">
|
||||
<span ng-show="selectedTrack.is_published">
|
||||
Save Changes
|
||||
<i ng-show="isSaving" class="icon-cog icon-spin icon-large"></i>
|
||||
</span>
|
||||
<span ng-hide="selectedTrack.is_published">
|
||||
Publish Track
|
||||
<i ng-show="isSaving" class="icon-cog icon-spin icon-large"></i>
|
||||
</span>
|
||||
</button>
|
||||
</li>
|
||||
<li class="delete"><a class="btn btn-danger" href="#" ng-click="deleteTrack(selectedTrack)" pfm-eat-click>Delete Track</a></li>
|
||||
<li class="delete"><a ng-class="{disabled: isSaving}" class="btn btn-danger" href="#" ng-click="deleteTrack(selectedTrack)" pfm-eat-click>Delete Track</a></li>
|
||||
</ul>
|
||||
<div class="strech-to-bottom">
|
||||
<div class="form-row" ng-class="{'has-error': errors.title != null}">
|
||||
<label for="title" class="strong">Title:</label>
|
||||
<input required ng-change="touchModel()" placeholder="Track Title" type="text" id="title" ng-model="edit.title" />
|
||||
<input ng-disabled="isSaving" ng-change="touchModel()" placeholder="Track Title" type="text" id="title" ng-model="edit.title" />
|
||||
<div class="error">{{errors.title}}</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span6 form-row" ng-class="{'has-error': errors.description != null}">
|
||||
<label for="description" class="strong">Description:</label>
|
||||
<textarea ng-change="touchModel()" placeholder="Description (optional)" id="description" ng-model="edit.description"></textarea>
|
||||
<textarea ng-disabled="isSaving" ng-change="touchModel()" placeholder="Description (optional)" id="description" ng-model="edit.description"></textarea>
|
||||
<div class="error">{{errors.description}}</div>
|
||||
</div>
|
||||
<div class="span6 form-row" ng-class="{'has-error': errors.lyrics != null}">
|
||||
<label for="is_vocal" class="strong"><input ng-change="touchModel(); updateIsVocal()" id="is_vocal" type="checkbox" ng-model="edit.is_vocal" /> Is Vocal</label>
|
||||
<textarea ng-change="touchModel()" ng-show="edit.is_vocal" ng-animate="'fade'" placeholder="Lyrics (required)" id="lyrics" ng-model="edit.lyrics"></textarea>
|
||||
<label for="is_vocal" class="strong"><input ng-disabled="isSaving" ng-change="touchModel(); updateIsVocal()" id="is_vocal" type="checkbox" ng-model="edit.is_vocal" /> Is Vocal</label>
|
||||
<textarea ng-disabled="isSaving" ng-change="touchModel()" ng-show="edit.is_vocal" ng-animate="'fade'" placeholder="Lyrics (required)" id="lyrics" ng-model="edit.lyrics"></textarea>
|
||||
<div class="error">{{errors.lyrics}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="form-row span6" ng-class="{'has-error': errors.track_type_id != null}">
|
||||
<label for="track_type" class="strong">This track is...</label>
|
||||
<select required id="track_type" ng-change="touchModel()" ng-model="edit.track_type_id" ng-options="type.id as type.editor_title for type in taxonomies.trackTypes">
|
||||
<select ng-disabled="isSaving" id="track_type" ng-change="touchModel()" ng-model="edit.track_type_id" ng-options="type.id as type.editor_title for type in taxonomies.trackTypes">
|
||||
<option value="">Please select a type...</option>
|
||||
</select>
|
||||
<div class="error">{{errors.track_type_id}}</div>
|
||||
</div>
|
||||
<div class="form-row span6" ng-class="{'has-error': errors.genre_id != null}">
|
||||
<label for="genre" class="strong">Genre:</label>
|
||||
<select required id="genre" ng-change="touchModel()" ng-model="edit.genre_id" ng-options="genre.id as genre.name for genre in taxonomies.genres">
|
||||
<select ng-disabled="isSaving" id="genre" ng-change="touchModel()" ng-model="edit.genre_id" ng-options="genre.id as genre.name for genre in taxonomies.genres">
|
||||
<option value="">Please select a genre...</option>
|
||||
</select>
|
||||
<div class="error">{{errors.genre_id}}</div>
|
||||
|
@ -109,24 +115,32 @@
|
|||
<input type="file" id="coverImage" onchange="angular.element(this).scope().setCoverImage(this)" />
|
||||
</p>
|
||||
<div class="btn-group">
|
||||
<a href="#" pfm-popup="image-selector" class="btn btn-small"><i class="icon-picture"></i> Gallery</a>
|
||||
<a href="#" pfm-eat-click ng-click="uploadTrackCover()" class="btn btn-info btn-small"><i class="icon-upload"></i> Upload</a>
|
||||
<a href="#" pfm-eat-click ng-click="clearTrackCover()" class="btn btn-danger btn-small" ng-show="edit.cover"><i class="icon-remove"></i></a>
|
||||
<a href="#" pfm-eat-click ng-click="clearTrackCover()" class="btn btn-danger btn-small" ng-show="edit.cover || edit.cover_id"><i class="icon-remove"></i></a>
|
||||
</div>
|
||||
<div id="image-selector" class="pfm-popup image-selector" ng-controller="account-image-select">
|
||||
<ul>
|
||||
<li ng-repeat="image in images" ng-click="selectGalleryImage(image)">
|
||||
<img src="{{image.url}}" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="error">{{errors.cover}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row span6" ng-class="{'has-error': errors.released_at != null}">
|
||||
<label for="released_at" class="strong">Release Date:</label>
|
||||
<input type="text" id="released_at" ui-date ng-model="edit.released_at" ng-change="touchModel()" ui-date-format="yy-mm-dd" />
|
||||
<input ng-disabled="isSaving" type="text" id="released_at" ui-date ng-model="edit.released_at" ng-change="touchModel()" ui-date-format="yy-mm-dd" />
|
||||
<div class="error">{{errors.released_at}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span6 form-row">
|
||||
<label for="is_explicit"><input ng-change="touchModel()" id="is_explicit" type="checkbox" ng-model="edit.is_explicit" /> Contains Explicit Content</label>
|
||||
<label for="is_explicit"><input ng-disabled="isSaving" ng-change="touchModel()" id="is_explicit" type="checkbox" ng-model="edit.is_explicit" /> Contains Explicit Content</label>
|
||||
</div>
|
||||
<div class="span6 form-row">
|
||||
<label for="is_downloadable"><input ng-change="touchModel()" id="is_downloadable" type="checkbox" ng-model="edit.is_downloadable" /> Is Downloadable</label>
|
||||
<label for="is_downloadable"><input ng-disabled="isSaving" ng-change="touchModel()" id="is_downloadable" type="checkbox" ng-model="edit.is_downloadable" /> Is Downloadable</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
|
@ -136,7 +150,7 @@
|
|||
<div ng-click="edit.license_id = license.id; touchModel()">
|
||||
<strong>{{license.title}}</strong>
|
||||
<p>{{license.description}}</p>
|
||||
<a href="#" pfm-eat-click class="btn" ng-class="{'btn-primary': edit.license_id == license.id}">
|
||||
<a href="#" pfm-eat-click class="btn" ng-class="{'btn-primary': edit.license_id == license.id, 'disabled': isSaving}">
|
||||
<span ng-hide="edit.license_id == license.id">Select</span>
|
||||
<span ng-show="edit.license_id == license.id">Selected</span>
|
||||
</a>
|
||||
|
|
Loading…
Reference in a new issue