【JQuery】エクスプローラーのようなフォルダーツリーを作ってみる(その2)

2019年7月6日Javascript,開発

おはようございます。

少し間が空きましたが、引き続きエクスプローラー風ツリーのサンプルです。

今回はドラッグアンドドロップでフォルダ移動できるようにしてみました。

スポンサーリンク

画面の修正

基本的に大した修正はしていません。

  • 説明文の変更
  • JQuery-UIの読み込み
  • CSSスタイルの追加

といった感じ。

CSS

css/style.css

次のスタイルを追加

/**
 * ドラッグヘルパー
 */
.helper {
	border : 2px solid gray;
	opacity : 1;
	background-color: #FFFFFF;
	margin: 15px;
}
.helper > i.fa-check {
	color: green;
}

html

sampleTree.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta http-equiv="content-type" content="text/html; charset=UTF-8">
	<title>サンプルツリー</title>
	<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
	<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.1/css/all.css">
	<link rel="stylesheet" href="css/style.css">
</head>
<body class="hold-transition fixed skin-blue-light sidebar-mini ">
<div class="wrapper" >
<div style="margin: 20px;">
<pre>
ツリーのサンプル

矢印をシングルクリックでフォルダの開閉、その他の部分はダブルクリックで開閉します。

フォルダをドラッグアンドドロップで移動できます。
</pre>
</div>
	<div>
		<ul class="tree" data-widget="tree">
			<li>
				<div>
					<span><i class="fa-none"></i></span>
					<span class="tree-icon-arrow"><i class="fas fa-angle-right"></i></span>
					<span class="tree-icon-folder"><i class="far fa-folder"></i></span>
					<span class="tree-title">フォルダー1</span>
				</div>
				<ul style="display:none;">
					<li>
						<div class="selected">
							<span><i class="fa-none"></i></span>
							<span><i class="fa-none"></i></span>
							<span class="tree-icon-arrow"><i class="fa-none"></i></span>
							<span class="tree-icon-folder"><i class="far fa-folder"></i></span>
							<span class="tree-title">サブフォルダー1-1</span>
						</div>
					</li>
					<li>
						<div>
							<span><i class="fa-none"></i></span>
							<span><i class="fa-none"></i></span>
							<span class="tree-icon-arrow"><i class="fas fa-angle-right"></i></span>
							<span class="tree-icon-folder"><i class="far fa-folder"></i></span>
							<span class="tree-title">サブフォルダー1-2</span>
						</div>
						<ul style="display:none;">
							<li>
								<div class="selected">
									<span><i class="fa-none"></i></span>
									<span><i class="fa-none"></i></span>
									<span><i class="fa-none"></i></span>
									<span class="tree-icon-arrow"><i class="fa-none"></i></span>
									<span class="tree-icon-folder"><i class="far fa-folder"></i></span>
									<span class="tree-title">サブフォルダー1-2-1</span>
								</div>
							</li>
							<li>
								<div>
									<span><i class="fa-none"></i></span>
									<span><i class="fa-none"></i></span>
									<span><i class="fa-none"></i></span>
									<span class="tree-icon-arrow"><i class="fa-none"></i></span>
									<span class="tree-icon-folder"><i class="far fa-folder"></i></span>
									<span class="tree-title">サブフォルダー1-2-2</span>
								</div>
							</li>
						</ul>
					</li>
				</ul>
			</li>
			<li>
				<div>
					<span><i class="fa-none"></i></span>
					<span class="tree-icon-arrow"><i class="fas fa-angle-right"></i></span>
					<span class="tree-icon-folder"><i class="far fa-folder"></i></span>
					<span class="tree-title">フォルダー2</span>
				</div>
				<ul style="display:none;">
					<li>
						<div class="selected">
							<span><i class="fa-none"></i></span>
							<span><i class="fa-none"></i></span>
							<span class="tree-icon-arrow"><i class="fa-none"></i></span>
							<span class="tree-icon-folder"><i class="far fa-folder"></i></span>
							<span class="tree-title">サブフォルダー2-1</span>
						</div>
					</li>
					<li>
						<div>
							<span><i class="fa-none"></i></span>
							<span><i class="fa-none"></i></span>
							<span class="tree-icon-arrow"><i class="fa-none"></i></span>
							<span class="tree-icon-folder"><i class="far fa-folder"></i></span>
							<span class="tree-title">サブフォルダー2-2</span>
						</div>
					</li>
					<li>
						<div>
							<span><i class="fa-none"></i></span>
							<span><i class="fa-none"></i></span>
							<span class="tree-icon-arrow"><i class="fa-none"></i></span>
							<span class="tree-icon-folder"><i class="far fa-folder"></i></span>
							<span class="tree-title">サブフォルダー2-3</span>
						</div>
					</li>
					<li>
						<div>
							<span><i class="fa-none"></i></span>
							<span><i class="fa-none"></i></span>
							<span class="tree-icon-arrow"><i class="fa-none"></i></span>
							<span class="tree-icon-folder"><i class="far fa-folder"></i></span>
							<span class="tree-title">サブフォルダー2-4</span>
						</div>
					</li>
				</ul>
			</li>
			<li>
				<div>
					<span><i class="fa-none"></i></span>
					<span class="tree-icon-arrow"><i class="fa-none"></i></span>
					<span class="tree-icon-folder"><i class="far fa-folder"></i></span>
					<span class="tree-title">フォルダー3</span>
				</div>
			</li>
			<li>
				<div>
					<span><i class="fa-none"></i></span>
					<span class="tree-icon-arrow"><i class="fa-none"></i></span>
					<span class="tree-icon-folder"><i class="far fa-folder"></i></span>
					<span class="tree-title">フォルダー4</span>
				</div>
			</li>
		</ul>
	
	</div>
</div>
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script src="js/sampleTree.js"></script>
</body>
</html>

スクリプト

javascript

script/sampleTree.js

次の処理を追加。

	// フォルダーをドラッグ可能に
	var dragable = $(".tree div").draggable({ 
		axis: "auto"
		, opacity: 1
		, cursor: "move"
		, cursorAt: { top: 10, left: 50 }
		, helper: function( event ) { 
			var target = $(event.currentTarget).find(".tree-title").text();
			return $( "<div class='helper' style='padding:5px 10px;'><i class='fa fa-check'></i>" + target +  "</div>" );
		}
	});
	
	// ドロップ可能エリアの指定
	$(".tree div").droppable({
		accept: ".tree div",
		drop: function( event, ui ) {
			var target = ui.draggable.parent("li");
			var parentDir = target.parent("ul");
			var dest = $(event.target).parent("li");
			var subDir = $(event.target).next();
			
			var from_hierarchy = ui.draggable.parents("ul").length;
			var to_hierarchy = $(event.target).parents("ul").length + 1;
			
			// インデントの調整
			if (from_hierarchy < to_hierarchy) {
				// 下階層への移動
				target.find("div").each(function(index, element) {
					for (let i = 0; i < (to_hierarchy - from_hierarchy); i++) {
						$(this).prepend("<span><i class='fa-none'></i></span>");
					}
				});
			} else {
				// 上階層への移動
				target.find("div").each(function(index, element) {
					for (let i = 0; i < (from_hierarchy - to_hierarchy); i++) {
						if ($(this).find("span").length > 0) {
							$(this).find("span").get(0).remove();
						}
					}
				});
			}
			
			// フォルダ移動
			if (subDir.length > 0) {
				// サブフォルダが存在する場合はそのまま追加
				subDir.append(target);
			} else {
				// サブフォルダが存在しない場合は要素を追加
				dest.find(".tree-icon-arrow").children("i").toggleClass("fas fa-angle-down fa-none");
				dest.find(".tree-icon-folder").children("i").toggleClass("fa-folder fa-folder-open");
				dest.append(target);
				target.wrap("<ul></ul>")
			}
			
			// 移動元のフォルダが空になった場合
			if (parentDir.children("li").length == 0) {
				var div = parentDir.prev();
				div.find(".tree-icon-arrow").children("i").toggleClass("fas fa-angle-down fa-none");
				div.find(".tree-icon-folder").children("i").toggleClass("fa-folder fa-folder-open")
				parentDir.remove();
			}
			
		}
	});

サンプルイメージ

フォルダー3の移動

フォルダー3をドラッグしているところ。

フォルダー4へ移動完了

フォルダー4へ、フォルダー3が移動しました。

元々サブフォルダーがないフォルダーでしたが、フォルダーイメージと展開しているアイコンもちゃんとなってます。

サブフォルダがあるフォルダの移動

サブフォルダーありフォルダーの移動。

移動完了

問題なく移動できました。

まとめ

今回は JQuery-UI の Draggable、Droppable 機能を利用しました。

JQuery便利ですね。

これを自力で実装しようと思ったらなかなかに大変だと思います。

次回はもしかしたら、移動できるフォルダかどうかの判定なんかをやってみようかなと。

何かのお役に立てれば。

ではでは。

 

スポンサーリンク


関連するコンテンツ

2019年7月6日Javascript,開発Bootstrap,JQuery,JQueryプラグイン,サンプルプログラム

Posted by doradora