Skip to content

Commit

Permalink
Page Attachments - Improved UI, Now initially complete
Browse files Browse the repository at this point in the history
Closes #62
  • Loading branch information
ssddanbrown committed Oct 23, 2016
1 parent 9122023 commit 3045840
Show file tree
Hide file tree
Showing 11 changed files with 222 additions and 69 deletions.
2 changes: 1 addition & 1 deletion app/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public function page()
*/
public function getUrl()
{
return '/files/' . $this->id;
return baseUrl('/files/' . $this->id);
}

}
22 changes: 19 additions & 3 deletions app/Http/Controllers/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
namespace BookStack\Http\Controllers;

use BookStack\Ownable;
use HttpRequestException;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Http\Exception\HttpResponseException;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;
use BookStack\User;

abstract class Controller extends BaseController
Expand Down Expand Up @@ -130,4 +128,22 @@ protected function jsonError($messageText = "", $statusCode = 500)
return response()->json(['message' => $messageText], $statusCode);
}

/**
* Create the response for when a request fails validation.
*
* @param \Illuminate\Http\Request $request
* @param array $errors
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function buildFailedValidationResponse(Request $request, array $errors)
{
if ($request->expectsJson()) {
return response()->json(['validation' => $errors], 422);
}

return redirect()->to($this->getRedirectUrl())
->withInput($request->input())
->withErrors($errors, $this->errorBag());
}

}
8 changes: 4 additions & 4 deletions app/Http/Controllers/FileController.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ public function update($fileId, Request $request)
{
$this->validate($request, [
'uploaded_to' => 'required|integer|exists:pages,id',
'name' => 'string|max:255',
'link' => 'url'
'name' => 'required|string|min:1|max:255',
'link' => 'url|min:1|max:255'
]);

$pageId = $request->get('uploaded_to');
Expand All @@ -129,8 +129,8 @@ public function attachLink(Request $request)
{
$this->validate($request, [
'uploaded_to' => 'required|integer|exists:pages,id',
'name' => 'string|max:255',
'link' => 'url|max:255'
'name' => 'required|string|min:1|max:255',
'link' => 'required|url|min:1|max:255'
]);

$pageId = $request->get('uploaded_to');
Expand Down
51 changes: 37 additions & 14 deletions resources/assets/js/controllers.js
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,10 @@ module.exports = function (ngApp, events) {
$scope.files = [];
$scope.editFile = false;
$scope.file = getCleanFile();
$scope.errors = {
link: {},
edit: {}
};

function getCleanFile() {
return {
Expand Down Expand Up @@ -567,7 +571,7 @@ module.exports = function (ngApp, events) {
currentOrder = newOrder;
$http.put(`/files/sort/page/${pageId}`, {files: $scope.files}).then(resp => {
events.emit('success', resp.data.message);
}, checkError);
}, checkError('sort'));
}

/**
Expand All @@ -587,7 +591,7 @@ module.exports = function (ngApp, events) {
$http.get(url).then(resp => {
$scope.files = resp.data;
currentOrder = resp.data.map(file => {return file.id}).join(':');
}, checkError);
}, checkError('get'));
}
getFiles();

Expand All @@ -599,7 +603,7 @@ module.exports = function (ngApp, events) {
*/
$scope.uploadSuccess = function (file, data) {
$scope.$apply(() => {
$scope.files.unshift(data);
$scope.files.push(data);
});
events.emit('success', 'File uploaded');
};
Expand All @@ -612,10 +616,10 @@ module.exports = function (ngApp, events) {
$scope.uploadSuccessUpdate = function (file, data) {
$scope.$apply(() => {
let search = filesIndexOf(data);
if (search !== -1) $scope.files[search] = file;
if (search !== -1) $scope.files[search] = data;

if ($scope.editFile) {
$scope.editFile = data;
$scope.editFile = angular.copy(data);
data.link = '';
}
});
Expand All @@ -627,10 +631,14 @@ module.exports = function (ngApp, events) {
* @param file
*/
$scope.deleteFile = function(file) {
if (!file.deleting) {
file.deleting = true;
return;
}
$http.delete(`/files/${file.id}`).then(resp => {
events.emit('success', resp.data.message);
$scope.files.splice($scope.files.indexOf(file), 1);
}, checkError);
}, checkError('delete'));
};

/**
Expand All @@ -641,19 +649,20 @@ module.exports = function (ngApp, events) {
$scope.attachLinkSubmit = function(file) {
file.uploaded_to = pageId;
$http.post('/files/link', file).then(resp => {
$scope.files.unshift(resp.data);
$scope.files.push(resp.data);
events.emit('success', 'Link attached');
$scope.file = getCleanFile();
}, checkError);
}, checkError('link'));
};

/**
* Start the edit mode for a file.
* @param fileId
*/
$scope.startEdit = function(file) {
console.log(file);
$scope.editFile = angular.copy(file);
if (!file.external) $scope.editFile.link = '';
$scope.editFile.link = (file.external) ? file.path : '';
};

/**
Expand All @@ -670,16 +679,23 @@ module.exports = function (ngApp, events) {
$scope.updateFile = function(file) {
$http.put(`/files/${file.id}`, file).then(resp => {
let search = filesIndexOf(resp.data);
if (search !== -1) $scope.files[search] = file;
if (search !== -1) $scope.files[search] = resp.data;

if ($scope.editFile && !file.external) {
$scope.editFile.link = '';
}
$scope.editFile = false;
events.emit('success', 'Attachment details updated');
});
}, checkError('edit'));
};

/**
* Get the url of a file.
*/
$scope.getFileUrl = function(file) {
return window.baseUrl('/files/' + file.id);
}

/**
* Search the local files via another file object.
* Used to search via object copies.
Expand All @@ -697,9 +713,16 @@ module.exports = function (ngApp, events) {
* Check for an error response in a ajax request.
* @param response
*/
function checkError(response) {
if (typeof response.data !== 'undefined' && typeof response.data.error !== 'undefined') {
events.emit('error', response.data.error);
function checkError(errorGroupName) {
$scope.errors[errorGroupName] = {};
return function(response) {
if (typeof response.data !== 'undefined' && typeof response.data.error !== 'undefined') {
events.emit('error', response.data.error);
}
if (typeof response.data !== 'undefined' && typeof response.data.validation !== 'undefined') {
$scope.errors[errorGroupName] = response.data.validation;
console.log($scope.errors[errorGroupName])
}
}
}

Expand Down
65 changes: 59 additions & 6 deletions resources/assets/js/directives.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,59 @@ module.exports = function (ngApp, events) {
};
});

/**
* Common tab controls using simple jQuery functions.
*/
ngApp.directive('tabContainer', function() {
return {
restrict: 'A',
link: function (scope, element, attrs) {
const $content = element.find('[tab-content]');
const $buttons = element.find('[tab-button]');

if (attrs.tabContainer) {
let initial = attrs.tabContainer;
$buttons.filter(`[tab-button="${initial}"]`).addClass('selected');
$content.hide().filter(`[tab-content="${initial}"]`).show();
} else {
$content.hide().first().show();
$buttons.first().addClass('selected');
}

$buttons.click(function() {
let clickedTab = $(this);
$buttons.removeClass('selected');
$content.hide();
let name = clickedTab.addClass('selected').attr('tab-button');
$content.filter(`[tab-content="${name}"]`).show();
});
}
};
});

/**
* Sub form component to allow inner-form sections to act like thier own forms.
*/
ngApp.directive('subForm', function() {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.on('keypress', e => {
if (e.keyCode === 13) {
submitEvent(e);
}
});

element.find('button[type="submit"]').click(submitEvent);

function submitEvent(e) {
e.preventDefault()
if (attrs.subForm) scope.$eval(attrs.subForm);
}
}
};
});


/**
* Image Picker
Expand Down Expand Up @@ -489,8 +542,8 @@ module.exports = function (ngApp, events) {
link: function (scope, elem, attrs) {

// Get common elements
const $buttons = elem.find('[tab-button]');
const $content = elem.find('[tab-content]');
const $buttons = elem.find('[toolbox-tab-button]');
const $content = elem.find('[toolbox-tab-content]');
const $toggle = elem.find('[toolbox-toggle]');

// Handle toolbox toggle click
Expand All @@ -502,17 +555,17 @@ module.exports = function (ngApp, events) {
function setActive(tabName, openToolbox) {
$buttons.removeClass('active');
$content.hide();
$buttons.filter(`[tab-button="${tabName}"]`).addClass('active');
$content.filter(`[tab-content="${tabName}"]`).show();
$buttons.filter(`[toolbox-tab-button="${tabName}"]`).addClass('active');
$content.filter(`[toolbox-tab-content="${tabName}"]`).show();
if (openToolbox) elem.addClass('open');
}

// Set the first tab content active on load
setActive($content.first().attr('tab-content'), false);
setActive($content.first().attr('toolbox-tab-content'), false);

// Handle tab button click
$buttons.click(function (e) {
let name = $(this).attr('tab-button');
let name = $(this).attr('toolbox-tab-button');
setActive(name, true);
});
}
Expand Down
14 changes: 14 additions & 0 deletions resources/assets/sass/_components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -452,3 +452,17 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
border-right: 6px solid transparent;
border-bottom: 6px solid $negative;
}


[tab-container] .nav-tabs {
text-align: left;
border-bottom: 1px solid #DDD;
margin-bottom: $-m;
.tab-item {
padding: $-s;
color: #666;
&.selected {
border-bottom-width: 3px;
}
}
}
7 changes: 3 additions & 4 deletions resources/assets/sass/_pages.scss
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@
background-color: #FFF;
border: 1px solid #DDD;
right: $-xl*2;
z-index: 99;
width: 48px;
overflow: hidden;
align-items: stretch;
Expand Down Expand Up @@ -201,15 +200,15 @@
color: #444;
background-color: rgba(0, 0, 0, 0.1);
}
div[tab-content] {
div[toolbox-tab-content] {
padding-bottom: 45px;
display: flex;
flex: 1;
flex-direction: column;
min-height: 0px;
overflow-y: scroll;
}
div[tab-content] .padded {
div[toolbox-tab-content] .padded {
flex: 1;
padding-top: 0;
}
Expand Down Expand Up @@ -241,7 +240,7 @@
}
}

[tab-content] {
[toolbox-tab-content] {
display: none;
}

Expand Down
10 changes: 10 additions & 0 deletions resources/assets/sass/_tables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,14 @@ table.list-table {
vertical-align: middle;
padding: $-xs;
}
}

table.file-table {
@extend .no-style;
td {
padding: $-xs;
}
.ui-sortable-helper {
display: table;
}
}
Loading

0 comments on commit 3045840

Please sign in to comment.