mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Started vueifying tag system
This commit is contained in:
parent
ab07f7df6c
commit
f338dbe3f8
@ -40,7 +40,8 @@
|
|||||||
"markdown-it": "^8.3.1",
|
"markdown-it": "^8.3.1",
|
||||||
"markdown-it-task-lists": "^2.0.0",
|
"markdown-it-task-lists": "^2.0.0",
|
||||||
"moment": "^2.12.0",
|
"moment": "^2.12.0",
|
||||||
"vue": "^2.2.6"
|
"vue": "^2.2.6",
|
||||||
|
"vuedraggable": "^2.14.1"
|
||||||
},
|
},
|
||||||
"browser": {
|
"browser": {
|
||||||
"vue": "vue/dist/vue.common.js"
|
"vue": "vue/dist/vue.common.js"
|
||||||
|
@ -157,74 +157,7 @@ module.exports = function (ngApp, events) {
|
|||||||
containment: "parent",
|
containment: "parent",
|
||||||
axis: "y"
|
axis: "y"
|
||||||
};
|
};
|
||||||
|
// TODO - Delete
|
||||||
/**
|
|
||||||
* Push an empty tag to the end of the scope tags.
|
|
||||||
*/
|
|
||||||
function addEmptyTag() {
|
|
||||||
$scope.tags.push({
|
|
||||||
name: '',
|
|
||||||
value: ''
|
|
||||||
});
|
|
||||||
}
|
|
||||||
$scope.addEmptyTag = addEmptyTag;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all tags for the current book and add into scope.
|
|
||||||
*/
|
|
||||||
function getTags() {
|
|
||||||
let url = window.baseUrl(`/ajax/tags/get/page/${pageId}`);
|
|
||||||
$http.get(url).then((responseData) => {
|
|
||||||
$scope.tags = responseData.data;
|
|
||||||
addEmptyTag();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
getTags();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the order property on all tags.
|
|
||||||
*/
|
|
||||||
function setTagOrder() {
|
|
||||||
for (let i = 0; i < $scope.tags.length; i++) {
|
|
||||||
$scope.tags[i].order = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When an tag changes check if another empty editable
|
|
||||||
* field needs to be added onto the end.
|
|
||||||
* @param tag
|
|
||||||
*/
|
|
||||||
$scope.tagChange = function(tag) {
|
|
||||||
let cPos = $scope.tags.indexOf(tag);
|
|
||||||
if (cPos !== $scope.tags.length-1) return;
|
|
||||||
|
|
||||||
if (tag.name !== '' || tag.value !== '') {
|
|
||||||
addEmptyTag();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When an tag field loses focus check the tag to see if its
|
|
||||||
* empty and therefore could be removed from the list.
|
|
||||||
* @param tag
|
|
||||||
*/
|
|
||||||
$scope.tagBlur = function(tag) {
|
|
||||||
let isLast = $scope.tags.length - 1 === $scope.tags.indexOf(tag);
|
|
||||||
if (tag.name === '' && tag.value === '' && !isLast) {
|
|
||||||
let cPos = $scope.tags.indexOf(tag);
|
|
||||||
$scope.tags.splice(cPos, 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a tag from the current list.
|
|
||||||
* @param tag
|
|
||||||
*/
|
|
||||||
$scope.removeTag = function(tag) {
|
|
||||||
let cIndex = $scope.tags.indexOf(tag);
|
|
||||||
$scope.tags.splice(cIndex, 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
|
65
resources/assets/js/vues/tag-manager.js
Normal file
65
resources/assets/js/vues/tag-manager.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
const draggable = require('vuedraggable');
|
||||||
|
|
||||||
|
let data = {
|
||||||
|
pageId: false,
|
||||||
|
tags: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const components = {draggable};
|
||||||
|
|
||||||
|
let computed = {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
let methods = {
|
||||||
|
|
||||||
|
addEmptyTag() {
|
||||||
|
this.tags.push({name: '', value: '', key: Math.random().toString(36).substring(7)});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When an tag changes check if another empty editable field needs to be added onto the end.
|
||||||
|
* @param tag
|
||||||
|
*/
|
||||||
|
tagChange(tag) {
|
||||||
|
let tagPos = this.tags.indexOf(tag);
|
||||||
|
if (tagPos !== this.tags.length-1 || tag.name !== '' || tag.value !== '') return;
|
||||||
|
this.addEmptyTag();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When an tag field loses focus check the tag to see if its
|
||||||
|
* empty and therefore could be removed from the list.
|
||||||
|
* @param tag
|
||||||
|
*/
|
||||||
|
tagBlur(tag) {
|
||||||
|
let isLast = (this.tags.indexOf(tag) === this.tags.length-1);
|
||||||
|
if (tag.name !== '' || tag.value !== '' || isLast) return;
|
||||||
|
let cPos = this.tags.indexOf(tag);
|
||||||
|
this.tags.splice(cPos, 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeTag(tag) {
|
||||||
|
let tagPos = this.tags.indexOf(tag);
|
||||||
|
if (tagPos === -1) return;
|
||||||
|
this.tags.splice(tagPos, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function mounted() {
|
||||||
|
this.pageId = Number(this.$el.getAttribute('page-id'));
|
||||||
|
|
||||||
|
let url = window.baseUrl(`/ajax/tags/get/page/${this.pageId}`);
|
||||||
|
this.$http.get(url).then(response => {
|
||||||
|
let tags = response.data;
|
||||||
|
for (let i = 0, len = tags.length; i < len; i++) {
|
||||||
|
tags[i].key = Math.random().toString(36).substring(7);
|
||||||
|
}
|
||||||
|
this.tags = tags;
|
||||||
|
this.addEmptyTag();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
data, computed, methods, mounted, components
|
||||||
|
};
|
@ -9,6 +9,7 @@ let vueMapping = {
|
|||||||
'entity-dashboard': require('./entity-search'),
|
'entity-dashboard': require('./entity-search'),
|
||||||
'code-editor': require('./code-editor'),
|
'code-editor': require('./code-editor'),
|
||||||
'image-manager': require('./image-manager'),
|
'image-manager': require('./image-manager'),
|
||||||
|
'tag-manager': require('./tag-manager'),
|
||||||
};
|
};
|
||||||
|
|
||||||
window.vues = {};
|
window.vues = {};
|
||||||
|
@ -226,7 +226,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
min-width: 50px;
|
min-width: 50px;
|
||||||
}
|
}
|
||||||
.tags td {
|
.tags td, .tag-table > div > div > div {
|
||||||
padding-right: $-s;
|
padding-right: $-s;
|
||||||
padding-top: $-s;
|
padding-top: $-s;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -68,3 +68,16 @@ table.file-table {
|
|||||||
display: table;
|
display: table;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fake-table {
|
||||||
|
display: table;
|
||||||
|
> div {
|
||||||
|
display: table-row-group;
|
||||||
|
}
|
||||||
|
> div > div {
|
||||||
|
display: table-row;
|
||||||
|
}
|
||||||
|
> div > div > div {
|
||||||
|
display: table-cell;
|
||||||
|
}
|
||||||
|
}
|
@ -9,31 +9,36 @@
|
|||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div toolbox-tab-content="tags" ng-controller="PageTagController" page-id="{{ $page->id or 0 }}">
|
<div toolbox-tab-content="tags" id="tag-manager" page-id="{{ $page->id or 0 }}">
|
||||||
<h4>{{ trans('entities.page_tags') }}</h4>
|
<h4>{{ trans('entities.page_tags') }}</h4>
|
||||||
<div class="padded tags">
|
<div class="padded tags">
|
||||||
<p class="muted small">{!! nl2br(e(trans('entities.tags_explain'))) !!}</p>
|
<p class="muted small">{!! nl2br(e(trans('entities.tags_explain'))) !!}</p>
|
||||||
<table class="no-style" tag-autosuggestions style="width: 100%;">
|
|
||||||
<tbody ui-sortable="sortOptions" ng-model="tags" >
|
<draggable class="fake-table no-style tag-table" :options="{handle: '.handle'}" :list="tags" element="div" style="width: 100%;">
|
||||||
<tr ng-repeat="tag in tags track by $index">
|
<transition-group name="test" tag="div">
|
||||||
<td width="20" ><i class="handle zmdi zmdi-menu"></i></td>
|
<div v-for="(tag, i) in tags" :key="tag.key">
|
||||||
<td><input autosuggest="{{ baseUrl('/ajax/tags/suggest/names') }}" autosuggest-type="name" class="outline" ng-attr-name="tags[@{{$index}}][name]" type="text" ng-model="tag.name" ng-change="tagChange(tag)" ng-blur="tagBlur(tag)" placeholder="{{ trans('entities.tag') }}"></td>
|
<div width="20" class="handle" ><i class="zmdi zmdi-menu"></i></div>
|
||||||
<td><input autosuggest="{{ baseUrl('/ajax/tags/suggest/values') }}" autosuggest-type="value" class="outline" ng-attr-name="tags[@{{$index}}][value]" type="text" ng-model="tag.value" ng-change="tagChange(tag)" ng-blur="tagBlur(tag)" placeholder="{{ trans('entities.tag_value') }}"></td>
|
<div><input autosuggest="{{ baseUrl('/ajax/tags/suggest/names') }}" autosuggest-type="name" class="outline" :name="tags[i].name"
|
||||||
<td width="10" ng-show="tags.length != 1" class="text-center text-neg" style="padding: 0;" ng-click="removeTag(tag)"><i class="zmdi zmdi-close"></i></td>
|
v-model="tag.name" @change="tagChange(tag)" @blur="tagBlur(tag)" placeholder="{{ trans('entities.tag') }}"></div>
|
||||||
</tr>
|
<div><input autosuggest="{{ baseUrl('/ajax/tags/suggest/values') }}" autosuggest-type="value" class="outline" :name="tags[i].value"
|
||||||
</tbody>
|
v-model="tag.value" @change="tagChange(tag)" @blur="tagBlur(tag)" placeholder="{{ trans('entities.tag_value') }}"></div>
|
||||||
</table>
|
<div width="10" v-show="tags.length !== 1" class="text-center text-neg" style="padding: 0;" @click="removeTag(tag)"><i class="zmdi zmdi-close"></i></div>
|
||||||
|
</div>
|
||||||
|
</transition-group>
|
||||||
|
</draggable>
|
||||||
|
|
||||||
<table class="no-style" style="width: 100%;">
|
<table class="no-style" style="width: 100%;">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr class="unsortable">
|
<tr class="unsortable">
|
||||||
<td width="34"></td>
|
<td width="34"></td>
|
||||||
<td ng-click="addEmptyTag()">
|
<td @click="addEmptyTag">
|
||||||
<button type="button" class="text-button">{{ trans('entities.tags_add') }}</button>
|
<button type="button" class="text-button">{{ trans('entities.tags_add') }}</button>
|
||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user