*/
class Attribute extends Model
{
- protected $fillable = ['name', 'value'];
+ protected $fillable = ['name', 'value', 'order'];
/**
* Get the entity that this attribute belongs to
*/
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'
+ ]);
}
/**
$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]);
}
/**
$entity->attributes()->delete();
$newAttributes = [];
foreach ($attributes as $attribute) {
+ if (trim($attribute['name']) === '') continue;
$newAttributes[] = $this->newInstanceFromInput($attribute);
}
$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']);
});
}
}]);
-};
\ No newline at end of file
+ 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);
+ })
+ };
+
+ }]);
+
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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;
}
\ No newline at end of file
+++ /dev/null
-@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
\ No newline at end of file
<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])
@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"
['name' => 'country', 'value' => 'England'],
];
+ // Do update request
$this->asAdmin()->json("POST", "/ajax/attributes/update/page/" . $page->id, ['attributes' => $testJsonData]);
+ $updateData = json_decode($this->response->getContent());
+ // Check data is correct
+ $testDataCorrect = true;
+ 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($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);
- $jsonData = json_decode($this->response->getContent());
+ $getResponseData = json_decode($this->response->getContent());
// Check counts
- $this->assertTrue(count($jsonData) === count($testJsonData), "The received attribute count is incorrect");
+ $this->assertTrue(count($getResponseData) === count($testJsonData), "The received attribute count is incorrect");
// Check data is correct
$testDataCorrect = true;
- foreach ($jsonData as $data) {
+ 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($jsonData)));
+ $this->assertTrue($testDataCorrect, sprintf($testMessage, json_encode($testResponseJsonData), json_encode($getResponseData)));
}
}