Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions plugins/baser-core/src/Service/UtilitiesService.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,23 @@ class UtilitiesService implements UtilitiesServiceInterface
public function verityContentsTree(): bool
{
$contentsTable = TableRegistry::getTableLocator()->get('BaserCore.Contents');
$result = $this->_verify($contentsTable);
return $this->verityTree($contentsTable);
}

/**
* ツリー構造をチェックする
*
* 問題がある場合にはログを出力する
*
* @param Table $table TreeBehavior を利用しているテーブル
* @return bool
* @checked
* @noTodo
* @unitTest
*/
public function verityTree(Table $table): bool
{
$result = $this->_verify($table);
if ($result !== true) {
foreach($result as $value) {
$this->log(implode(', ', $value));
Expand Down Expand Up @@ -97,7 +113,6 @@ protected function _verify(Table $table)
$left = 'lft';
$scope = '1 = 1';
$parent = 'parent_id';
$plugin = 'BaserCore';
if (!$table->find()->applyOptions(['withDeleted'])->where([$scope])->count()) {
return true;
}
Expand Down Expand Up @@ -125,7 +140,7 @@ protected function _verify(Table $table)
}

$table->belongsTo('VerifyParent', [
'className' => $plugin . '.' . $table->getAlias(),
'className' => $table->getRegistryAlias(),
'propertyName' => 'VerifyParent',
'foreignKey' => $parent
]);
Expand Down
14 changes: 14 additions & 0 deletions plugins/baser-core/src/Service/UtilitiesServiceInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use BaserCore\Annotation\UnitTest;
use BaserCore\Annotation\NoTodo;
use BaserCore\Annotation\Checked;
use Cake\ORM\Table;

/**
* UtilitiesServiceInterface
Expand All @@ -31,6 +32,19 @@ interface UtilitiesServiceInterface
*/
public function verityContentsTree(): bool;

/**
* ツリー構造をチェックする
*
* 問題がある場合にはログを出力する
*
* @param Table $table TreeBehavior を利用しているテーブル
* @return bool
* @checked
* @noTodo
* @unitTest
*/
public function verityTree(Table $table): bool;

/**
* コンテンツツリーをリセットし全て同階層にする
*
Expand Down
228 changes: 224 additions & 4 deletions plugins/bc-admin-third/src/bc_blog/js/admin/blog_categories/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,231 @@

$(function () {

var scriptData = $("#AdminBlogCategoriesIndexScript");
var blogContentId = scriptData.attr('data-blogContentId');
var listType = scriptData.attr('data-listType');
var addUrl = scriptData.attr('data-addUrl');

if (listType === '1') {
// ツリー形式
initTree();
$("#GrpChangeTreeOpenClose").show();
} else {
// 表形式:一括処理
$.bcBatch.init({
batchUrl: $.bcUtil.apiAdminBaseUrl + 'bc-blog/blog_categories/batch.json'
});
}

// 表示形式の切り替え(ツリー形式 / 表形式)
$("input[name='ViewSetting[list_type]']").change(function () {
$.bcUtil.showLoader();
var selected = $("input[name='ViewSetting[list_type]']:checked").val();
location.href = $.bcUtil.adminBaseUrl + 'bc-blog/blog_categories/index/' + blogContentId + '?list_type=' + selected;
});

/**
* 一括処理実装
* ノードに紐づくブログカテゴリのデータ(data-jstree)を返す
* @param node
* @returns {object}
*/
$.bcBatch.init({
batchUrl: $.bcUtil.apiAdminBaseUrl + 'bc-blog/blog_categories/batch.json'
});
function nodeData(node) {
return (node && node.data) ? node.data.jstree : {};
}

/**
* ツリー(jstree)の初期化
*/
function initTree() {
var treeDom = $('#BlogCategoryTreeList');
if (!treeDom.length) {
return;
}

treeDom.jstree({
'core': {
'themes': {'name': 'proton', 'stripes': true, 'variant': 'large'},
'multiple': false,
'force_text': true,
// 自分自身の子孫への移動は jstree 側が禁止する。それ以外は任意の親へ移動可。
'check_callback': true
},
'plugins': ['dnd', 'state', 'wholerow', 'contextmenu', 'types'],
'types': {'default': {}},
'state': {'key': 'blog-category-tree-' + blogContentId},
'dnd': {
'large_drop_target': true,
'is_draggable': function () {
return true;
}
},
'contextmenu': {
'show_at_node': false,
'items': buildContextMenu
}
});

var jstreeApi = treeDom.jstree(true);

// 展開・折りたたみ
$("#BtnOpenTree").click(function () {
jstreeApi.open_all();
});
$("#BtnCloseTree").click(function () {
jstreeApi.close_all();
});

// ドラッグ&ドロップによる移動(並び替え・再親付け)
treeDom.on('move_node.jstree', function (e, data) {
orderCategory(jstreeApi, data);
});
}

/**
* ドラッグ&ドロップ完了時に、移動内容をサーバへ保存する
* @param jstreeApi
* @param data move_node.jstree のイベントデータ
*/
function orderCategory(jstreeApi, data) {
var node = data.node;
var origin = nodeData(node);

// 移動先の親カテゴリ(ルートは空)
var targetParentId = '';
if (data.parent !== '#') {
targetParentId = nodeData(jstreeApi.get_node(data.parent)).categoryId;
}
// 移動先で、自分の直後にくる兄弟(=この上に配置する対象)。無ければ末尾。
var parentChildren = jstreeApi.get_node(data.parent).children;
var nextNodeId = parentChildren[data.position + 1];
var targetId = nextNodeId ? nodeData(jstreeApi.get_node(nextNodeId)).categoryId : '';

$.bcToken.check(function () {
return $.ajax({
url: $.bcUtil.apiAdminBaseUrl + 'bc-blog/blog_categories/move.json',
type: 'PATCH',
dataType: 'json',
data: {
origin: {id: origin.categoryId, parentId: origin.parentId},
target: {id: targetId, parentId: targetParentId},
_csrfToken: $.bcToken.key
},
beforeSend: function () {
$.bcUtil.hideMessage();
$.bcUtil.showLoader();
},
success: function () {
// 移動先の親を記憶し、続けての移動に備える
origin.parentId = targetParentId;
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
// サーバ状態は変わっていないため、再読込で元の並びへ戻す
var errorMessage = '';
if (XMLHttpRequest.status === 404) {
errorMessage = '<br>' + bcI18n.commonNotFoundProgramMessage;
} else if (XMLHttpRequest.responseText) {
errorMessage = '<br>' + JSON.parse(XMLHttpRequest.responseText).message;
} else {
errorMessage = '<br>' + errorThrown;
}
$.bcUtil.showAlertMessage(bcI18n.commonBatchExecFailedMessage + '(' + XMLHttpRequest.status + ')' + errorMessage);
location.reload();
},
complete: function () {
$.bcUtil.hideLoader();
}
});
}, {hideLoader: false});
}

/**
* 右クリックメニューを構築する
* @param node
* @returns {object}
*/
function buildContextMenu(node) {
var data = nodeData(node);
var menu = {};

// 確認(フロントのカテゴリ一覧を別タブで開く)
if (data.previewUrl) {
menu.view = {
label: bcI18n.bcTreeCheck,
icon: 'bca-icon--preview',
action: function () {
window.open(data.previewUrl, '_blank');
}
};
}

// 編集
menu.edit = {
label: bcI18n.bcTreeEdit,
icon: 'bca-icon--edit',
action: function () {
location.href = data.editUrl;
}
};

// 子カテゴリを追加
menu.add = {
label: bcI18n.bcTreeAddChild,
icon: 'bca-icon--add',
action: function () {
location.href = addUrl + '?parent_id=' + data.categoryId;
}
};

// 削除
menu.delete = {
label: bcI18n.bcTreeDelete,
icon: 'bca-icon--delete',
action: function () {
deleteCategory(node, data);
}
};

return menu;
}

/**
* カテゴリを削除する
* @param node
* @param data
*/
function deleteCategory(node, data) {
var title = $("#BlogCategoryTreeList").jstree(true).get_text(node);
if (!confirm(bcI18n.blogCategoryConfirmDelete.replace('%s', title))) {
return;
}
$.bcToken.check(function () {
return $.ajax({
url: $.bcUtil.apiAdminBaseUrl + 'bc-blog/blog_categories/delete/' + data.categoryId + '.json',
type: 'POST',
dataType: 'json',
data: {
_csrfToken: $.bcToken.key
},
beforeSend: function () {
$.bcUtil.hideMessage();
$.bcUtil.showLoader();
},
success: function () {
// 削除後はサーバの状態に合わせて再読込する
location.reload();
},
error: function (XMLHttpRequest) {
var errorMessage = '';
if (XMLHttpRequest.responseText) {
errorMessage = '<br>' + JSON.parse(XMLHttpRequest.responseText).message;
}
$.bcUtil.showAlertMessage(bcI18n.blogCategoryDeleteFailed + errorMessage);
},
complete: function () {
$.bcUtil.hideLoader();
}
});
}, {hideLoader: false});
}

});
10 changes: 10 additions & 0 deletions plugins/bc-admin-third/templates/Admin/Utilities/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,16 @@
]) ?>
</div>

<?php
if (method_exists($this, 'dispatchLayerEvent')) {
// EVENT afterUtilitiesIndex
$event = $this->dispatchLayerEvent('afterUtilitiesIndex', [], ['layer' => 'View', 'class' => '', 'plugin' => '']);
if ($event !== false) {
echo ($event->getResult() === null || $event->getResult() === true)? '' : $event->getResult();
}
}
?>

<?php echo $this->BcAdminForm->secure() ?>
<div class="section bca-main__section">
<h2 class="bca-main__heading" data-bca-heading-size="lg"><?php echo __d('baser_core', 'スペシャルサンクスクレジット') ?></h2>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,25 @@
* [ADMIN] ブログカテゴリ 一覧
* @var BcBlog\View\BlogAdminAppView $this
* @var BcBlog\Model\Entity\BlogContent $blogContent
* @var string $template 表示テンプレート(index_list: 表形式 / index_tree: ツリー形式)
* @checked
* @noTodo
* @unitTest
*/
$this->BcAdmin->setTitle(__d('baser_core', '{0}|カテゴリ一覧', $blogContent->content->title));
$this->BcAdmin->setHelp('blog_categories_index');
$this->BcBaser->js('BcBlog.admin/blog_categories/index.bundle', false);
$this->BcBaser->element('BlogCategories/index_setup', ['blogContent' => $blogContent, 'template' => $template]);
$this->BcAdmin->addAdminMainBodyHeaderLinks([
'url' => ['action' => 'add', $blogContent->id],
'title' => __d('baser_core', '新規追加'),
]);
?>


<div id="AlertMessage" class="message" style="display:none"></div>

<?php $this->BcBaser->element('BlogCategories/index_view_setting') ?>

<div class="bca-data-list">
<?php $this->BcBaser->element('BlogCategories/index_list') ?>
<?php $this->BcBaser->element('BlogCategories/' . $template) ?>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
foreach($rowIdTmps as $rowIdTmp) {
$rowGroupId[] = 'row-group-' . $rowIdTmp;
}
$rowGroupClass = ' class="depth-' . $blogCategory->depth . ' ' . implode(' ', $rowGroupId) . '"';
$rowGroupClass = ' class="sortable depth-' . $blogCategory->depth . ' ' . implode(' ', $rowGroupId) . '"';
?>
<?php $currentDepth = $blogCategory->depth ?>
<?php $this->BcBaser->element('BlogCategories/index_row', ['blogCategory' => $blogCategory, 'rowGroupClass' => $rowGroupClass]) ?>
Expand Down
Loading
Loading