Last active
December 22, 2015 22:59
-
-
Save seanhess/6544212 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="book_edit"> | |
<!--<pre>{{files}}</pre>--> | |
<div> | |
<!--<label>bookId</label>--> | |
<!--<div><input disabled ng-model="book.bookId"></div>--> | |
<div><a href="/books/{{book.bookId}}" target="_blank">Data</a></div> | |
<br/> | |
<label>productId</label> | |
<div>{{book.bookId | toProductId}}</div> | |
<label>popularity</label> | |
<div>{{book.popularity}}</div> | |
<label>featured</label> | |
<div><input type="checkbox" ng-model="book.featured"/></div> | |
<label>title</label> | |
<div><input ng-model="book.title" placeholder="A Tale of Two Cities"/></div> | |
<label class="cover">cover</label> | |
<div> | |
<div class="cover" dragupload="onDropCoverImage"> | |
<img ng-show="book.imageUrl" ng-src="{{book.imageUrl}}"> | |
<button ng-show="book.imageUrl" class="clear" ng-click="clearImage()">clear</button> | |
</div> | |
</div> | |
<label>author</label> | |
<div><input ng-model="book.author" placeholder="Charles Dickens"/></div> | |
<label>genre</label> | |
<div ng-hide="editingNewGenre" class="genre"> | |
<select | |
ng-model="book.genre" | |
ng-options="genre.name as genre.name for genre in genres"> | |
</select> | |
<a ng-click="toggleEditNewGenre()">New Genre</a> | |
</div> | |
<div ng-show="editingNewGenre" class="genre"> | |
<input ng-model="book.genre" placeholder="Comedy"> | |
<a ng-click="toggleEditNewGenre()">Cancel</a> | |
</div> | |
<label>description</label> | |
<div><textarea ng-model="book.description" placeholder="This book is awesome"></textarea></div> | |
<label>{{book.textFiles}} text files</label> | |
<label>{{book.audioFiles}} audio files</label> | |
<div class="files" dragupload="onDrop"> | |
<div class="instructions">Drop files here (.mp3 or .html)</div> | |
<div class="file" ng-class="{loading: isLoading(file), active: isFileUploadActive(file)}" ng-repeat="file in book.files | orderBy:'name'"> | |
<div ng-hide="isEditing(file)"> | |
<small><button class="remove" ng-click="removeFile(file)">x</button> </small> | |
<small><button class="rename" ng-click="editFile(file)">rename</button></small> | |
<a href="{{file.url}}" target="_blank">{{file.name}}.{{file.ext}}</a> | |
<!--<a class="external_link" href="{{file.url}}"></a>--> | |
</div> | |
<form ng-show="isEditing(file)"> | |
<input ng-model="editing.name"> | |
<button ng-click="updateFile(file)">Save</button> | |
<a ng-click="cancelEdit()">Cancel</a> | |
</form> | |
</div> | |
</div> | |
<p> | |
<input type="submit" ng-disabled="!isBookValid()" ng-click="save()" value="Save"></input> | |
<button ng-disabled="!book" ng-click="remove()">Remove</button> | |
</p> | |
</div> | |
</div> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
///<reference path="../def/angular.d.ts"/> | |
///<reference path="../def/underscore.d.ts"/> | |
///<reference path="../types.ts"/> | |
///<reference path="../services/Books"/> | |
///<reference path="../services/Files.ts"/> | |
interface BookParams extends ng.IRouteParamsService { | |
bookId: string; | |
} | |
function BookCtrl($scope, Books:IBookService, Files:IFileService, $routeParams: BookParams, $location:ng.ILocationService, $http:ng.IHttpService) { | |
var bookId = $scope.bookId = $routeParams.bookId | |
$scope.book = Books.get({bookId:bookId}) | |
$scope.fileStatus = {} | |
$http.get("/genres/").success(function(genres) { | |
$scope.genres = genres | |
}) | |
function calculateNumFiles() { | |
$scope.book.audioFiles = Files.audioFiles($scope.book.files).length | |
$scope.book.textFiles = Files.textFiles($scope.book.files).length | |
} | |
function back() { | |
$location.path("/admin") | |
} | |
function bookValid(book:IBook) { | |
if (!book) return false | |
if (!book.files) return false | |
var validFiles = book.files.filter(fileValid) | |
if (validFiles.length < book.files.length) return false | |
return true | |
} | |
function fileValid(file:IFile) { | |
if (!file.url) return false | |
if (!file.fileId) return false | |
if (!file.name) return false | |
if (!file.ext) return false | |
return true | |
} | |
$scope.isBookValid = function() { | |
return bookValid($scope.book) | |
} | |
$scope.toggleEditNewGenre = function() { | |
$scope.editingNewGenre = !$scope.editingNewGenre | |
} | |
$scope.save = function(book) { | |
Books.update($scope.book).then(back) | |
} | |
$scope.remove = function() { | |
Books.remove({bookId: bookId}, back) | |
} | |
$scope.removeFile = function(file:IFile) { | |
$scope.book.files = _.without($scope.book.files, file) | |
calculateNumFiles() | |
} | |
$scope.isEditing = function(file) { | |
return $scope.editing && $scope.editing.fileId == file.fileId | |
} | |
$scope.editFile = function(file:IFile) { | |
$scope.editing = _.clone(file) | |
} | |
$scope.cancelEdit = function() { | |
delete $scope.editing | |
} | |
$scope.updateFile = function(file) { | |
file.name = $scope.editing.name | |
$scope.cancelEdit() | |
$http.put('/files/' + file.fileId, file).success(function() { | |
//loadFiles() | |
}) | |
} | |
$scope.onDrop = function(files:IHTMLFile[]) { | |
files.forEach(addFile) | |
} | |
$scope.onDropCoverImage = function(files:IHTMLFile[]) { | |
Files.upload(files[0]) | |
.then(function(file:IFile) { | |
$scope.book.imageUrl = file.url | |
}) | |
} | |
$scope.clearImage = function() { | |
delete $scope.book.imageUrl | |
} | |
$scope.isLoading = function(file:IFile) { | |
return (file.fileId === undefined || file.fileId === null) | |
} | |
$scope.isFileUploadActive = function(file:IFile) { | |
var op = $scope.fileStatus[file.name] | |
if (!op) return false | |
return op.active | |
} | |
function filesOfType(files:IFile[], ext:string):IFile[] { | |
return files.filter(function(file:IFile) { | |
return (file.ext == ext) | |
}) | |
} | |
function toPendingFile(htmlFile:IHTMLFile):IFile { | |
var ext = htmlFile.name.match(/\.(\w+)$/)[1] | |
var name = htmlFile.name.replace("." + ext, "") | |
// you can tell it's pending because it doesn't have url, fileId, bookId | |
return { | |
name:name, | |
ext:ext, | |
url:undefined, | |
fileId:undefined, | |
bookId:undefined, | |
} | |
} | |
function addFile(file:IHTMLFile) { | |
var pendingFile = toPendingFile(file) | |
$scope.book.files.push(pendingFile) | |
var op = Files.queueUpload(file, function(file:IFile) { | |
_.extend(pendingFile, file) | |
delete $scope.fileStatus[file.name] | |
calculateNumFiles() | |
}) | |
$scope.fileStatus[pendingFile.name] = op | |
} | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
///<reference path="../def/angular.d.ts"/> | |
///<reference path="../def/jquery.d.ts"/> | |
// prevents drops from changing the page | |
function dragIgnore($parse:ng.IParseService) { | |
return function(scope:ng.IScope, element:JQuery, attrs) { | |
var target = document | |
target.addEventListener("dragover", function(e) { | |
e.preventDefault() | |
return false | |
}) | |
target.addEventListener("drop", function(e) { | |
e.preventDefault() | |
return false | |
}) | |
} | |
} | |
// dragupload="onDropFiles" will call scope.onDropFiles(files) | |
function dragUpload($parse:ng.IParseService) { | |
return function(scope:ng.IScope, element:JQuery, attrs) { | |
var target = element.get(0) | |
//var onDrop = $parse(attrs.dragupload) | |
var onDrop = scope[attrs.dragupload] | |
//var onDrop = $parse(attrs.dragupload) | |
//function shouldAccept(e) { | |
//return (e.dataTransfer.files && e.dataTransfer.files.length && e.dataTransfer.files[0].type.match("text/plain")) | |
//} | |
target.addEventListener("dragenter", function(e) { | |
element.addClass("drag") | |
}) | |
target.addEventListener("dragleave", function(e) { | |
element.removeClass("drag") | |
}) | |
target.addEventListener("dragover", function(e) { | |
e.stopPropagation() | |
e.preventDefault() | |
var ok = e.dataTransfer && e.dataTransfer.types && e.dataTransfer.types.indexOf('Files') >= 0 | |
return false | |
}) | |
target.addEventListener("drop", function(e) { | |
// dropped! Check out e.dataTransfer | |
e.stopPropagation() | |
e.preventDefault() | |
element.removeClass("drag") | |
//if (!shouldAccept(e)) return | |
// convert files to array | |
var files = Array.prototype.slice.call(e.dataTransfer.files, 0) | |
scope.$apply(function() { | |
onDrop(files) | |
}) | |
}) | |
} | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <reference path="../types.ts"/> | |
/// <reference path="../def/angular.d.ts" /> | |
/// <reference path="../controls/Book.ts" /> | |
interface IFileCb { | |
(file:IFile); | |
} | |
interface IFileService extends ng.resource.IResourceClass { | |
upload(file:IHTMLFile):ng.IPromise<IFile>; | |
queueUpload(file:IHTMLFile, cb:IFileCb):FileServiceUploadOperation; | |
audioFiles(files:IFile[]):IFile[]; | |
textFiles(files:IFile[]):IFile[]; | |
} | |
interface FileServiceUploadOperation { | |
file:IHTMLFile; | |
active:boolean; | |
cb(file:IFile); | |
} | |
// TODO: turn this into a queue | |
function Files($http: ng.IHttpService):IFileService { | |
function not(f:Function) { | |
return function(...args:any[]) { | |
return !f.apply(null, args) | |
} | |
} | |
function isAudio(file:IFile) { | |
return file.ext == "mp3" | |
} | |
var queue:FileServiceUploadOperation[] = [] | |
var currentOp:FileServiceUploadOperation; | |
function nextUpload() { | |
currentOp = queue.pop() | |
currentOp.active = true | |
Service.upload(currentOp.file) | |
.then((file:IFile) => currentOp.cb(file)) | |
.then(function() { | |
currentOp = null | |
if (queue.length) nextUpload() | |
}) | |
} | |
// this can return a promise object thing | |
// should be thenable, for when it finishes | |
// but also have a progress | |
var Service:IFileService = <any> {} | |
Service.queueUpload = function(file:IHTMLFile, cb:IFileCb) { | |
var op:FileServiceUploadOperation = {file:file, cb:cb, active:false} | |
queue.push(op) | |
// if not started, start now | |
if (!currentOp) nextUpload() | |
return op | |
} | |
Service.upload = function(file:IHTMLFile) { | |
console.log("UPLOAD", file.name, file.size) | |
// must be a file from the web browser | |
var formData = new FormData() | |
formData.append('file', file) | |
return $http({ | |
method: 'POST', | |
url: '/files', | |
data: formData, | |
// no idea why you need both of these, but you do | |
transformRequest: angular.identity, | |
headers: {'Content-Type': undefined}, | |
}) | |
.then((rs) => rs.data) | |
} | |
Service.audioFiles = function(files:IFile[]) { | |
return files.filter(isAudio) | |
} | |
Service.textFiles = function(files:IFile[]) { | |
return files.filter(not(isAudio)) | |
} | |
// simple queueing method for uploading? | |
return Service | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment