mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-11-23 11:22:33 +01:00
Started the page attributes interface
This commit is contained in:
parent
fcfb9470c9
commit
1fa079b466
@ -6,7 +6,7 @@
|
||||
*/
|
||||
class Attribute extends Model
|
||||
{
|
||||
protected $fillable = ['name', 'value'];
|
||||
protected $fillable = ['name', 'value', 'order'];
|
||||
|
||||
/**
|
||||
* Get the entity that this attribute belongs to
|
||||
|
@ -38,18 +38,15 @@ class AttributeController extends Controller
|
||||
*/
|
||||
public function updateForEntity($entityType, $entityId, Request $request)
|
||||
{
|
||||
|
||||
$this->validate($request, [
|
||||
'attributes.*.name' => 'required|min:3|max:250',
|
||||
'attributes.*.value' => 'max:250'
|
||||
]);
|
||||
|
||||
$entity = $this->attributeRepo->getEntity($entityType, $entityId, 'update');
|
||||
if ($entity === null) return $this->jsonError("Entity not found", 404);
|
||||
|
||||
$inputAttributes = $request->input('attributes');
|
||||
$attributes = $this->attributeRepo->saveAttributesToEntity($entity, $inputAttributes);
|
||||
return response()->json($attributes);
|
||||
return response()->json([
|
||||
'attributes' => $attributes,
|
||||
'message' => 'Attributes successfully updated'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,7 +72,7 @@ class PageController extends Controller
|
||||
$this->checkOwnablePermission('page-create', $book);
|
||||
$this->setPageTitle('Edit Page Draft');
|
||||
|
||||
return view('pages/create', ['draft' => $draft, 'book' => $book]);
|
||||
return view('pages/edit', ['page' => $draft, 'book' => $book, 'isDraft' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -80,6 +80,7 @@ class AttributeRepo
|
||||
$entity->attributes()->delete();
|
||||
$newAttributes = [];
|
||||
foreach ($attributes as $attribute) {
|
||||
if (trim($attribute['name']) === '') continue;
|
||||
$newAttributes[] = $this->newInstanceFromInput($attribute);
|
||||
}
|
||||
|
||||
|
@ -18,10 +18,12 @@ class CreateAttributesTable extends Migration
|
||||
$table->string('entity_type', 100);
|
||||
$table->string('name');
|
||||
$table->string('value');
|
||||
$table->integer('order');
|
||||
$table->timestamps();
|
||||
|
||||
$table->index('name');
|
||||
$table->index('value');
|
||||
$table->index('order');
|
||||
$table->index(['entity_id', 'entity_type']);
|
||||
});
|
||||
}
|
||||
|
@ -400,4 +400,96 @@ module.exports = function (ngApp, events) {
|
||||
|
||||
}]);
|
||||
|
||||
};
|
||||
ngApp.controller('PageAttributeController', ['$scope', '$http', '$attrs',
|
||||
function ($scope, $http, $attrs) {
|
||||
|
||||
const pageId = Number($attrs.pageId);
|
||||
$scope.attributes = [];
|
||||
|
||||
/**
|
||||
* Push an empty attribute to the end of the scope attributes.
|
||||
*/
|
||||
function addEmptyAttribute() {
|
||||
$scope.attributes.push({
|
||||
name: '',
|
||||
value: ''
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all attributes for the current book and add into scope.
|
||||
*/
|
||||
function getAttributes() {
|
||||
$http.get('/ajax/attributes/get/page/' + pageId).then((responseData) => {
|
||||
$scope.attributes = responseData.data;
|
||||
addEmptyAttribute();
|
||||
});
|
||||
}
|
||||
getAttributes();
|
||||
|
||||
/**
|
||||
* Set the order property on all attributes.
|
||||
*/
|
||||
function setAttributeOrder() {
|
||||
for (let i = 0; i < $scope.attributes.length; i++) {
|
||||
$scope.attributes[i].order = i;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When an attribute changes check if another empty editable
|
||||
* field needs to be added onto the end.
|
||||
* @param attribute
|
||||
*/
|
||||
$scope.attributeChange = function(attribute) {
|
||||
let cPos = $scope.attributes.indexOf(attribute);
|
||||
if (cPos !== $scope.attributes.length-1) return;
|
||||
|
||||
if (attribute.name !== '' || attribute.value !== '') {
|
||||
addEmptyAttribute();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* When an attribute field loses focus check the attribute to see if its
|
||||
* empty and therefore could be removed from the list.
|
||||
* @param attribute
|
||||
*/
|
||||
$scope.attributeBlur = function(attribute) {
|
||||
let isLast = $scope.attributes.length - 1 === $scope.attributes.indexOf(attribute);
|
||||
if (attribute.name === '' && attribute.value === '' && !isLast) {
|
||||
let cPos = $scope.attributes.indexOf(attribute);
|
||||
$scope.attributes.splice(cPos, 1);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.saveAttributes = function() {
|
||||
setAttributeOrder();
|
||||
let postData = {attributes: $scope.attributes};
|
||||
$http.post('/ajax/attributes/update/page/' + pageId, postData).then((responseData) => {
|
||||
$scope.attributes = responseData.data.attributes;
|
||||
addEmptyAttribute();
|
||||
events.emit('success', responseData.data.message);
|
||||
})
|
||||
};
|
||||
|
||||
}]);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -201,4 +201,18 @@ $btt-size: 40px;
|
||||
background-color: $negative;
|
||||
color: #EEE;
|
||||
}
|
||||
}
|
||||
|
||||
// Attribute form
|
||||
.floating-toolbox {
|
||||
background-color: #FFF;
|
||||
border: 1px solid #BBB;
|
||||
border-radius: 3px;
|
||||
padding: $-l;
|
||||
position: fixed;
|
||||
right: $-xl*2;
|
||||
top: 100px;
|
||||
z-index: 99;
|
||||
height: 800px;
|
||||
overflow-y: scroll;
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
@extends('base')
|
||||
|
||||
@section('head')
|
||||
<script src="/libs/tinymce/tinymce.min.js?ver=4.3.7"></script>
|
||||
@stop
|
||||
|
||||
@section('body-class', 'flexbox')
|
||||
|
||||
@section('content')
|
||||
|
||||
<div class="flex-fill flex">
|
||||
<form action="{{$book->getUrl() . '/page/' . $draft->id}}" method="POST" class="flex flex-fill">
|
||||
@include('pages/form', ['model' => $draft])
|
||||
</form>
|
||||
</div>
|
||||
@include('partials/image-manager', ['imageType' => 'gallery', 'uploaded_to' => $draft->id])
|
||||
@stop
|
@ -10,9 +10,24 @@
|
||||
|
||||
<div class="flex-fill flex">
|
||||
<form action="{{$page->getUrl()}}" data-page-id="{{ $page->id }}" method="POST" class="flex flex-fill">
|
||||
<input type="hidden" name="_method" value="PUT">
|
||||
@if(!isset($isDraft))
|
||||
<input type="hidden" name="_method" value="PUT">
|
||||
@endif
|
||||
@include('pages/form', ['model' => $page])
|
||||
</form>
|
||||
|
||||
<div class="floating-toolbox" ng-controller="PageAttributeController" page-id="{{ $page->id or 0 }}">
|
||||
<form ng-submit="saveAttributes()">
|
||||
<table>
|
||||
<tr ng-repeat="attribute in attributes">
|
||||
<td><input type="text" ng-model="attribute.name" ng-change="attributeChange(attribute)" ng-blur="attributeBlur(attribute)" placeholder="Attribute Name"></td>
|
||||
<td><input type="text" ng-model="attribute.value" ng-change="attributeChange(attribute)" ng-blur="attributeBlur(attribute)" placeholder="Value"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<button class="button pos" type="submit">Save attributes</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@include('partials/image-manager', ['imageType' => 'gallery', 'uploaded_to' => $page->id])
|
||||
|
||||
|
@ -41,6 +41,7 @@
|
||||
@include('form/text', ['name' => 'name', 'placeholder' => 'Page Title'])
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="edit-area flex-fill flex">
|
||||
@if(setting('app-editor') === 'wysiwyg')
|
||||
<textarea id="html-editor" tinymce="editorOptions" mce-change="editorChange" mce-model="editContent" name="html" rows="5"
|
||||
|
@ -97,19 +97,32 @@ class AttributeTests extends \TestCase
|
||||
['name' => 'country', 'value' => 'England'],
|
||||
];
|
||||
|
||||
// Do update request
|
||||
$this->asAdmin()->json("POST", "/ajax/attributes/update/page/" . $page->id, ['attributes' => $testJsonData]);
|
||||
$this->asAdmin()->get("/ajax/attributes/get/page/" . $page->id);
|
||||
$jsonData = json_decode($this->response->getContent());
|
||||
// Check counts
|
||||
$this->assertTrue(count($jsonData) === count($testJsonData), "The received attribute count is incorrect");
|
||||
$updateData = json_decode($this->response->getContent());
|
||||
// Check data is correct
|
||||
$testDataCorrect = true;
|
||||
foreach ($jsonData as $data) {
|
||||
foreach ($updateData->attributes as $data) {
|
||||
$testItem = ['name' => $data->name, 'value' => $data->value];
|
||||
if (!in_array($testItem, $testResponseJsonData)) $testDataCorrect = false;
|
||||
}
|
||||
$testMessage = "Expected data was not found in the response.\nExpected Data: %s\nRecieved Data: %s";
|
||||
$this->assertTrue($testDataCorrect, sprintf($testMessage, json_encode($testResponseJsonData), json_encode($jsonData)));
|
||||
$this->assertTrue($testDataCorrect, sprintf($testMessage, json_encode($testResponseJsonData), json_encode($updateData)));
|
||||
$this->assertTrue(isset($updateData->message), "No message returned in attribute update response");
|
||||
|
||||
// Do get request
|
||||
$this->asAdmin()->get("/ajax/attributes/get/page/" . $page->id);
|
||||
$getResponseData = json_decode($this->response->getContent());
|
||||
// Check counts
|
||||
$this->assertTrue(count($getResponseData) === count($testJsonData), "The received attribute count is incorrect");
|
||||
// Check data is correct
|
||||
$testDataCorrect = true;
|
||||
foreach ($getResponseData as $data) {
|
||||
$testItem = ['name' => $data->name, 'value' => $data->value];
|
||||
if (!in_array($testItem, $testResponseJsonData)) $testDataCorrect = false;
|
||||
}
|
||||
$testMessage = "Expected data was not found in the response.\nExpected Data: %s\nRecieved Data: %s";
|
||||
$this->assertTrue($testDataCorrect, sprintf($testMessage, json_encode($testResponseJsonData), json_encode($getResponseData)));
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user