Created
November 24, 2017 20:04
-
-
Save ryosukemori/671a1c155c43db76941dfef23d6f3d71 to your computer and use it in GitHub Desktop.
JqueryUI依存の交換型並び替え機能 アップロード付き .js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* class SortBox | |
* 要素の並び替えやアイテム追加・アップロードのできるボックスを実現する | |
* | |
* 依存: jquery-ui | |
* @author Nickel Lab. Ryosuke Mori | |
* @version 0.1.0 | |
*/ | |
(function(){ | |
/** | |
* @constructor | |
*/ | |
function SortBox() | |
{ | |
/* Options */ | |
this.options = { | |
//並び替え機能 | |
sort: true, | |
//並び替え対象子要素 | |
childrenTag: 'li', | |
//並び替え生成時のflex付与有無 | |
flex: true, | |
//要素移動のアニメーションスピード | |
sortDuration: 'fast', | |
//アップロード機能 | |
upload: true, | |
//アップロード先 | |
uploadAction: location.href.split('?')[0] + '/upload', | |
//アップロード値 | |
uploadData: {}, | |
//アップロードファイルタイプ | |
fileType: 'image', | |
//許容ファイルサイズ(Byte) | |
allowFileSize: 1000000, | |
//アップロード完了後処理クロージャ | |
success: this.uploadSuccess, | |
//アップロード完了後処理終了時に追加処理を行う | |
successAfter: function(){}, | |
//アップロード失敗後処理クロージャ | |
fail: this.uploadFail, | |
//ソート情報を保存する形式 | |
sortSaveType: 'hidden', | |
//ソート情報を保存する名前 | |
sortSaveName: 'sort_box_data', | |
//この機能を適用するボックスのセレクタ | |
boxSelector: '#sort-box', | |
//ファイルインプットのname属性 | |
fileInputName: 'sort_box_file', | |
//ファイルインプットをクリックさせる要素のセレクタ | |
fileInputWrapper: '#sort-box [data-sort-box=file-wrapper]', | |
/* Draggable Options */ | |
revertDuration: '200', | |
scroll: false, | |
opacity: 0.8, | |
zindex: 10, | |
} | |
/* val */ | |
//ソート情報 | |
this.sortData = new Array(); | |
//ドラッグ中オブジェクト | |
this.$draggedObj = null; | |
//ドラッグ中オブジェクトの手前のオブジェクト | |
this.$prevObj = null; | |
//ドラッグ中オブジェクトの元座標 | |
this.draggedDefPosition = null; | |
//元に戻すフラグ | |
this.revert = true; | |
} | |
/** | |
* 初期化 | |
*/ | |
SortBox.prototype.init = function(boxSelector,options) | |
{ | |
//セレクタが指定されていれば設定する | |
if( typeof boxSelector === 'string' ){ | |
this.options.boxSelector = boxSelector; | |
this.options.fileInputWrapper = boxSelector + ' [data-sort-box=file-wrapper]'; | |
} | |
//子要素を予め想定して設定 | |
var boxTag = $(this.options.boxSelector)[0].tagName; | |
switch( boxTag ){ | |
case 'UL': | |
this.options.childrenTag = 'li'; | |
break; | |
case 'DIV': | |
this.options.childrenTag = 'div'; | |
break; | |
case 'OL': | |
this.options.childrenTag = 'li'; | |
break; | |
case 'DL': | |
this.options.childrenTag = 'dd'; | |
break; | |
case 'TR': | |
this.options.childrenTag = 'td'; | |
break; | |
case 'FORM': | |
this.options.childrenTag = 'input'; | |
break; | |
case 'MENU': | |
this.options.childrenTag = 'button'; | |
break; | |
} | |
//オプションがあれば設定する | |
if( typeof options === 'object' ){ | |
if( 'sort' in options ){ | |
this.options.sort = options.sort; | |
} | |
if( 'childrenTag' in options ){ | |
this.options.childrenTag = options.childrenTag; | |
} | |
if( 'flex' in options ){ | |
this.options.flex = options.flex; | |
} | |
if( 'sortDuration' in options ){ | |
this.options.sortDuration = options.sortDuration; | |
} | |
if( 'upload' in options ){ | |
this.options.upload = options.upload; | |
} | |
if( 'uploadAction' in options ){ | |
this.options.uploadAction = options.uploadAction; | |
} | |
if( 'uploadData' in options ){ | |
this.options.uploadData = options.uploadData; | |
} | |
if( 'fileType' in options ){ | |
this.options.fileType = options.fileType; | |
} | |
if( 'allowFileSize' in options ){ | |
this.options.allowFileSize = options.allowFileSize; | |
} | |
if( 'success' in options ){ | |
this.options.success = options.success; | |
} | |
if( 'successAfter' in options ){ | |
this.options.successAfter = options.successAfter; | |
} | |
if( 'fail' in options ){ | |
this.options.fail = options.fail; | |
} | |
if( 'sortSaveType' in options ){ | |
this.options.sortSaveType = options.sortSaveType; | |
} | |
if( 'sortSaveName' in options ){ | |
this.options.sortSaveName = options.sortSaveName; | |
} | |
if( 'fileInputName' in options ){ | |
this.options.fileInputName = options.fileInputName; | |
} | |
if( 'fileInputWrapper' in options ){ | |
this.options.fileInputWrapper = options.fileInputWrapper; | |
} | |
// Draggable Options | |
if( 'revertDuration' in options ){ | |
this.options.revertDuration = options.revertDuration; | |
} | |
if( 'scroll' in options ){ | |
this.options.scroll = options.scroll; | |
} | |
if( 'opacity' in options ){ | |
this.options.opacity = options.opacity; | |
} | |
if( 'zindex' in options ){ | |
this.options.zindex = options.zindex; | |
} | |
} | |
//複数箇所対応でクローン | |
var SortBox = $.extend(true, {}, this); | |
var $box = $(SortBox.options.boxSelector); | |
//ソート機能 | |
SortBox.addSorter($box); | |
//アップローダ機能 | |
SortBox.addUploader($box); | |
} | |
/** | |
* ドラック&ドロップでの並び替え機能をセットする | |
* @param {Jquery Object} $box 対象リストのボックス要素 | |
*/ | |
SortBox.prototype.addSorter = function($box) | |
{ | |
var _self = this; | |
//オプションが有効な場合に追加する | |
if( !this.options.sort ){ | |
return false; | |
} | |
//対象子要素 | |
var $children = $box.children(this.options.childrenTag + '[data-id]'); | |
if( $children.length < 1 ){ | |
console.log('子要素を取得できませんでした。対象の子要素に data-id 属性はありますか?'); | |
return false; | |
} | |
//cssの適用 | |
if( this.options.flex == true ){ | |
$box.css('display','flex'); | |
$children.css({ | |
'cursor':'pointer', | |
'position':'relative', | |
}); | |
} | |
//ドラッグ機能をセットする | |
$children.draggable({ | |
containment: this.options.boxSelector, | |
scroll: this.options.scroll, | |
opacity: this.options.opacity, | |
zIndex: this.options.zindex, | |
revertDuration: this.options.revertDuration, | |
start: function(){ | |
_self.draggableStart($(this)); | |
}, | |
stop: function(){ | |
_self.draggableStop($(this)); | |
}, | |
revert: function(){ | |
return _self.draggableRevert($(this)); | |
}, | |
cancel: $(_self.options.fileInputWrapper) | |
}); | |
//ドロップ機能をセットする | |
$children.droppable({ | |
drop: function(){ | |
_self.droppableDrop($(this),$box,$children); | |
}, | |
}); | |
} | |
/** | |
* ドラッグ開始時の処理 | |
* @param {Jquery Object} $e トリガー元オブジェクト | |
*/ | |
SortBox.prototype.draggableStart = function($e) | |
{ | |
this.$draggedObj = $e; | |
this.$prevObj = $e.prev(); | |
this.draggedDefPosition = $e.position(); | |
this.revert = true; | |
} | |
/** | |
* ドラッグ終了時の処理 | |
* @param {Jquery Object} $e トリガー元オブジェクト | |
*/ | |
SortBox.prototype.draggableStop = function($e) | |
{ | |
$e.draggable('enable'); | |
} | |
/** | |
* 元の位置に戻る処理の有無を返す | |
* @param {Jquery Object} $e トリガー元オブジェクト | |
*/ | |
SortBox.prototype.draggableRevert = function($e) | |
{ | |
return this.revert; | |
} | |
/** | |
* ドロップ時の処理 | |
* @param {Jquery Object} $e トリガー元オブジェクト | |
* @param {Jquery Object} $box クラス適用コンテナボックス | |
* @param {Array<Jquery Object>} $children 適用対象子要素配列 | |
*/ | |
SortBox.prototype.droppableDrop = function($e,$box,$children) | |
{ | |
var _self = this; | |
$children.draggable('disable'); | |
this.revert = false; | |
this.$draggedObj.animate({ | |
top: $e.position().top - this.draggedDefPosition.top, | |
left: $e.position().left - this.draggedDefPosition.left, | |
},this.options.sortDuration, | |
function(){ | |
//ドロップアニメーション後 | |
$e.animate({ | |
top: _self.draggedDefPosition.top - $e.position().top, | |
left: _self.draggedDefPosition.left - $e.position().left, | |
},_self.options.sortDuration, | |
function(){ | |
//要素の入れ替え | |
$e.before(_self.$draggedObj); | |
_self.$draggedObj.css({'top':0,'left':0}); | |
if( _self.$prevObj.length != 0 ){ | |
_self.$prevObj.after($e); | |
} | |
else{ | |
$box.prepend($e); | |
} | |
$e.css({'top':0,'left':0}); | |
//ソート状態の保存 | |
_self.saveSortState($box); | |
//ソート状態をhtml出力 | |
_self.outputSortState($box); | |
//ドラッグの有効化 | |
$children.draggable('enable'); | |
}); | |
}); | |
} | |
/** | |
* ソート情報を保存する | |
* @param {Jquery Object} $box クラス適用コンテナボックス | |
*/ | |
SortBox.prototype.saveSortState = function($box) | |
{ | |
var ids = $box.children('[data-id]').map(function(){ return $(this).attr('data-id') }).get(); | |
this.sortData = ids; | |
return ids; | |
} | |
/** | |
* ソート情報をHTML出力する | |
* タイプは hidden, sameText, | |
* @param {Jquery Object} $box クラス適用コンテナボックス | |
* @return {Jquery Object} $sortData 生成した要素 | |
*/ | |
SortBox.prototype.outputSortState = function($box) | |
{ | |
switch( this.options.sortSaveType ){ | |
case 'hidden': | |
//Hiddenインプットを生成してボックス内に配置 | |
var $sortData = $('<input>',{ | |
'type': 'hidden', | |
'name': this.options.sortSaveName, | |
'class': 'sort-box-output', | |
'value': this.sortData.join(','), | |
}); | |
break; | |
case 'childTagText': | |
//コンテナ内子要素と同じタグでテキスト出力する | |
var $sortData = $('<'+ this.options.childrenTag +'>',{ | |
'class': 'sort-box-output', | |
}); | |
$sortData.text(this.sortData.join(',')); | |
break; | |
case 'childTagAttribute': | |
//コンテナ内子要素と同じタグで属性に出力する | |
var $sortdata = $('<'+ this.options.childrenTag +'>',{ | |
'class': 'sort-box-output', | |
'sort-box-data': this.sortData.join(''), | |
}); | |
break; | |
case 'none': | |
default: | |
//html出力をしない | |
return $(''); | |
break; | |
} | |
if( $box.children('.sort-box-output').length > 0 ){ | |
$box.children('.sort-box-output').replaceWith($sortData); | |
} | |
else{ | |
$box.append($sortData); | |
} | |
return $sortData; | |
} | |
/** | |
* アップローダ機能をセットする | |
* @param {Jquery Object} $box クラス適用要素 | |
*/ | |
SortBox.prototype.addUploader = function($box) | |
{ | |
var _self = this; | |
//オプションが有効な場合に追加する | |
if( !this.options.upload ){ | |
return false; | |
} | |
//Input[type=file]を設置する | |
var $fileInput = $box.children('input[type=file]'); | |
if( $fileInput.length < 1 ){ | |
$fileInput = $('<input>',{ | |
'type': 'file', | |
'name': this.options.fileInputName, | |
'style': 'display:none', | |
}); | |
$box.append($fileInput); | |
} | |
//Input[type=file]をクリックする要素をセットする | |
var $wrapper = $( this.options.fileInputWrapper ); | |
$wrapper.on('click',function(){ | |
$fileInput.click(); | |
}); | |
//Input[type=file]のチェンジ後処理をセットする | |
$fileInput.on('change',function(){ | |
_self.onChangeFileInput($(this)); | |
}); | |
} | |
/** | |
* アップローダ機能のファイルインプットの値変更時 | |
* @param {Jquery Object} $e 呼び出し元要素 | |
*/ | |
SortBox.prototype.onChangeFileInput = function($e) | |
{ | |
var _self = this; | |
var $fd = new FormData(); | |
if( $e.val() == '' ){ | |
console.log('アップロードファイルが存在しません。'); | |
return false; | |
} | |
//Validation | |
var file = $e.prop('files')[0]; | |
//ファイルサイズ | |
if( file.size >= this.options.allowFileSize ){ | |
alert('ファイルサイズが'+ this.options.allowFileSize +'バイトを超えています'); | |
return false; | |
} | |
//ファイルタイプ | |
if( file.type.indexOf(this.options.fileType) < 0 ){ | |
alert('ファイルの種類が対象外です。'); | |
return false; | |
} | |
//必要項目をフォームに追加 | |
$fd.append("file",$e.prop("files")[0] ); | |
$.each(this.options.uploadData,function(index,value){ | |
$fd.append(index, value ); | |
}); | |
$.post({ | |
url: this.options.uploadAction, | |
dataType: 'json', | |
data: $fd, | |
processData: false, | |
contentType: false, | |
},function(response){ | |
//クロージャ def: this.uploadSuccess() | |
_self.options.success.call(_self,response,file); | |
}) | |
.fail(function(response){ | |
_self.options.fail.call(_self,response,file); | |
}); | |
} | |
SortBox.prototype.uploadSuccess = function(response,file) | |
{ | |
var _self = this; | |
var $box = $(this.options.boxSelector); | |
var fileReader = new FileReader(); | |
//ファイル読み込完了時 | |
fileReader.onload = function(fileData){ | |
if( file.type.indexOf(_self.options.fileType) >= 0 ){ | |
var $data = $('<img>',{ | |
'src': fileData.target.result, | |
'title': file.name, | |
}); | |
} | |
//TODO: text対応 | |
//読み込みデータを表示 | |
var $child = $('<'+ _self.options.childrenTag + '>',{ | |
'class': 'sort-box-add', | |
'data-id': 'new', | |
}); | |
$child.append($data); | |
$box.children('[data-id]:last').after($child); | |
_self.addSorter($box); | |
//ソート情報を更新 | |
_self.saveSortState($box); | |
//ソート情報をHTMLに書き込み | |
_self.outputSortState($box); | |
//成功処理後に追加の処理 | |
_self.options.successAfter.call(_self,response,file); | |
} | |
fileReader.readAsDataURL(file); | |
} | |
SortBox.prototype.uploadFail = function(response,file) | |
{ | |
alert('アップロードに失敗しました。'); | |
} | |
window.SortBox = SortBox; | |
}(window)); | |
var SortBox = new SortBox(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment