/**
* @name CeL function for drag-and-drop
* @fileoverview
* 本檔案包含了 web 物件的滑鼠拖曳 functions。
* @since
*/
/*
http://www.w3.org/TR/html5/dnd.html#dnd
http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html
https://developer.mozilla.org/en/Using_files_from_web_applications
http://html5demos.com/drag
http://d.hatena.ne.jp/ksy_dev/20100731/p1?sid=810f738005e991c6
*/
'use strict';
if (typeof CeL === 'function')
CeL.run(
{
name:'interact.DnD',
require : 'interact.DOM.is_HTML_element|interact.DOM.get_element|interact.DOM.add_listener|interact.DOM.stop_event|interact.DOM.set_text|data.swap_key_value',
code : function(library_namespace) {
// requiring
var is_HTML_element = this.r('is_HTML_element'), get_element = this.r('get_element'), add_listener = this.r('add_listener'), stop_event = this.r('stop_event'), set_text = this.r('set_text'), swap_key_value = this.r('swap_key_value');
/**
* null module constructor
* @class web drag_and_drop 的 functions
*/
var _// JSDT:_module_
= function() {
// null module constructor
};
/**
* for JSDT: 有 prototype 才會將之當作 Class
*/
_// JSDT:_module_
.prototype = {
};
_// JSDT:_module_
.
move_element = function(element, target) {
target.appendChild(element.parentNode.removeChild(element));
};
function set_drop_target(element, drop_handler, drag_in_handler) {
if (!is_HTML_element(element)
&& !is_HTML_element(element = get_element(element)))
return;
//if(element.id) library_namespace.debug(element.id, 0, 'set_drop_target');
add_listener( {
// 拖進 target。
// 阻止 dragover 預定動作方能觸發 ondrop。
// http://fillano.blog.ithome.com.tw/post/257/81723
dragover : stop_event,
// 在 target 上拖動。
dragenter : stop_event,
// 在 target 上拖完放開滑鼠。
drop : function(event) {
// 處理 types: 將所有設定的 type 一一列出。IE9 沒有 dataTransfer.types。
var i = 0, list = event.dataTransfer.types || ['text', 'url'], l = list.length, data, type;
for (; i < l; i++) {
try {
// IE10 中拖拉外部檔案時,dataTransfer.getData(list[i]) 可能會 throw "Invalid argument."
data = event.dataTransfer.getData(list[i]);
type = typeof data;
library_namespace.debug('[' + (i + 1) + '/' + l + '] [' + list[i] + ']: '
+ (data ? type === 'string' && /^[a-z\d\-]+:\/\//i.test(data) ?
'' + decodeURI(data) + ''
: data
: '[' + type + '] ' + (String(data) || '(null)')),
1, 'set_drop_target.ondrop');
if (list[i] in set_drop_target.handler) {
type = set_drop_target.handler[list[i]];
for ( var h = 0, _t = this,
timeout_binder = (typeof setTimeout === 'function' || typeof setTimeout === 'object') &&
function() {
library_namespace.debug('準備執行。 (' + data + ')', 2, 'set_drop_target.ondrop');
//library_namespace.debug('' + type[h]);
type[this].call(_t, data);
library_namespace.debug('執行完畢。', 2, 'set_drop_target.ondrop');
}; h < type.length; h++) {
try {
if(timeout_binder) {
library_namespace.debug('use setTimeout to run:
'
+ type[h].toString().replace(/\n/g, '
'), 2,
'set_drop_target.ondrop');
setTimeout(timeout_binder.bind(h), 0);
} else {
library_namespace.debug('directly run. typeof setTimeout: [' + typeof setTimeout + '].', 2, 'set_drop_target.ondrop');
type[h].call(this, data);
}
} catch (e) {
library_namespace.warn('set_drop_target.ondrop: Error to run ' + list[i] + '.' + h);
library_namespace.error(e);
}
}
}
} catch (e) {
library_namespace.debug('Error to get data of [' + list[i] + ']: ' + e,
1, 'set_drop_target.ondrop');
//library_namespace.error(e);
}
}
// 處理 files. IE9 沒有 dataTransfer.files。
// http://www.html5rocks.com/en/tutorials/file/dndfiles/
// https://github.com/MrSwitch/dropfile
if((list = event.dataTransfer.files)
&& (l = list.length)){
library_namespace.debug('Drop ' + l + ' file object(s).', 1, 'set_drop_target.ondrop');
for (i = 0; i < l; i++) {
data = list[i];
library_namespace.debug('[' + (i + 1) + '/' + l + '] '
+ data.name + '' + (data.type ? ' (' + data.type + ')' : '') + ': ' + data.size + ' bytes.',
1, 'set_drop_target.ondrop');
// 若是小圖,則直接顯示出來。
if (/^image\/\w+/.test(data.type) && data.size < 1000000) {
_.read_file(data, function(event) {
var contents = event.target.result;
library_namespace.debug('' + this.file.name + ': ' + contents.length
+ ' chars starting with [' + contents.slice(0, 30).replace(/
* e.g., {type_name : handler },
* e.g., { type_name : { id : handler } }
*/
set_drop_target.add_handler = function add_handler(handler_hash) {
if (!library_namespace.is_Object(handler_hash)) {
return;
}
var type_name, handler_list, handler, id;
for (type_name in handler_hash) {
library_namespace.debug('adding [' + type_name + '].');
handler_list = set_drop_target.handler[type_name];
if (!Array.isArray(handler_list))
set_drop_target.handler[type_name] = handler_list = [];
handler = handler_hash[type_name];
library_namespace.debug('adding [' + type_name + '] ' + handler, 1, 'set_drop_target.add_handler');
if (library_namespace.is_Function(handler)) {
handler_list.push(handler);
} else if (library_namespace.is_Object(handler)) {
for (id in handler)
handler_list[id] = handler[id];
} else {
library_namespace.warn('unknown handler: ' + handler);
}
}
};
_// JSDT:_module_
.
set_drop_target = set_drop_target;
// File API
_// JSDT:_module_
.
read_files = function(files, handler, index) {
// check files type
if (!library_namespace.is_type(files, 'FileList')) {
if(handler && typeof handler.error === 'function')
//handler.error.call(null);
handler.error();
return;
}
if(isNaN(index)){
// 初始化 initialization
handler = _.read_file.regular_handler(handler);
index = 0;
}
// 依序讀入個別檔案內容。
_.read_file(files[index], [ handler, {
loadend : function() {
if (++index < files.length)
_.read_files(files, handler, index);
}
} ]);
};
// File API
function read_file(file, handler, encoding, start, end) {
var blob, reader = library_namespace.is_WWW(true)
//
&& window.FileReader && new window.FileReader();
if (!reader) {
library_namespace.error('read_file: This browser / platform does not support FileReader.');
return;
}
// check file type
if (!library_namespace.is_type(file, 'File')) {
if(handler && typeof handler.error === 'function')
//handler.error.call(null);
handler.error();
return;
}
// 非標準! 但這樣設定後,event handler 中即可使用 this.file 取得相關資訊。
reader.file = file;
add_listener( [ _.read_file.regular_handler(handler), {
error : function(event) {
var error = event.target.error, code = error.code, message;
switch (code) {
case error.NOT_FOUND_ERR:
message = 'File [' + file.name + '] Not Found!';
break;
case error.NOT_READABLE_ERR:
message = 'File [' + file.name + '] is not readable!';
break;
case error.ABORT_ERR:
message = 'User aborted reading [' + file.name + '].';
break;
case error.SECURITY_ERR:
// 多是因不能 DnD local files.
message = 'Security error to read [' + file.name + '].';
break;
default:
error = _.read_file.code_to_name || (_.read_file.code_to_name = swap_key_value(error, [], /^[A-Z_\-\d]+$/));
if (code in error)
message = '' + error[code] + ' to read [' + file.name + '].';
}
library_namespace.warn('read_file: ' + (message || 'Error ' + code + ' to read [' + file.name + '].'));
},
loadend : function() {
// 預防 memory leak.
delete reader.file;
//library_namespace.debug('reader.file deleted.', 2, 'read_file');
}
} ], reader);
if (start || end) {
if (isNaN(start = parseInt(start))
|| start < 0)
start = 0;
if (!isNaN(end = parseInt(end))
&& end > start && end < file.size)
blob = file.slice ? file.slice(start, end)
: file.webkitSlice ? file.webkitSlice(start, end)
: file.mozSlice && file.mozSlice(start, end);
}
if(!blob)
blob = file;
library_namespace.debug('read-in [' + file.name + ']' + (encoding ? ' as ' + encoding : '') + '.', 0, 'read_file');
if ((!encoding || encoding === 'binary')
// IE10 沒有 .readAsBinaryString
&& reader.readAsBinaryString)
reader.readAsBinaryString(blob);
else if(encoding === 'url')
reader.readAsDataURL(blob);
else
// UTF-8 is assumed if this parameter is not specified.
// https://developer.mozilla.org/en/DOM/FileReader
reader.readAsText(blob, encoding || 'UTF-8');
};
read_file.regular_handler = function(handler) {
if (typeof handler === 'function')
handler = {
load : handler
};
if (library_namespace.is_Object(handler)) {
if (typeof handler.status === 'string')
handler.status = get_element(handler.status);
if (is_HTML_element(handler.status)) {
// progress bar
var progress_bar = handler.status;
if(!handler.progress)
handler.progress = function(event) {
if (event.lengthComputable) {
// 讀取比例
//var percent_loaded;
set_text(progress_bar, '[' + this.file.name + '] ' +
(progress_bar.style.width = Math.round(event.loaded / event.total * 100) + '%'));
}
};
if(!handler.load)
handler.load = function(event) {
set_text(progress_bar, '[' + this.file.name + '] loaded.');
};
delete handler.status;
}
}
return handler;
};
_// JSDT:_module_
.
read_file = read_file;
// about drag-and-drop @ IE6 ---------------------------
/*
2008/1/24 0:51:17
*/
//CSS of body
get_drag_path.bCSS = 'margin:0;padding:.2em;color:#e42;background-color:#eff;';
// default contents in HTML
get_drag_path.dC = 'Drop Here (不能拖曳多個物件)';
// show infomation after every drag
get_drag_path.show = 1;
// drag object
get_drag_path.o = 'dropT';
// 每次執行完是否應顯示
get_drag_path.shouldShow = function(o) {
return o == showM.so;
};
// href Object & Array
get_drag_path.href_hash = Object.create(null);
get_drag_path.href_list = [];
// 未設定目錄。拖曳功能只在 IE6 有效。
get_drag_path.able = function() {
var n = window ? window.navigator : 0;
try {
return n && (n = n.appVersion) && (n = n.match(/MSIE (\d+)/))
&& n[1] == 6;
} catch (e) {
// 呼叫 navigator.* 可能有 -2147024882 "存放裝置空間不足,無法完成此操作。"
// http://www.dotblogs.com.tw/alonstar/archive/2008/10/09/5625.aspx
// 結果原來是我的機碼不知道為什麼多了一大堆.NET CLR 3.0的版本,找了一台正常的比對之後,把多的機碼刪除就好了。
// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\5.0\User Agent\Post Platform
return !!get_drag_path.href_list;
}
};
get_drag_path.add = function(p) {
// sl('get_drag_path: add path ['+p+']');
// 不能計算數目:不準 可能會有 file:///, http:// 等
get_drag_path.href_hash[this.href = p] = 1;
};
// 每 get_drag_path.interval 執行一次
function get_drag_path() {
var _s = arguments.callee,
// 或者直接用 dropT.location.href,不透過 document.getElementById.
o = document.getElementById(_s.o), w = o.contentWindow, bU = 'about:blank', i, t = [];
if (w.location.href != _s.href || w.location.href != bU) {
// 處理中隱藏,預防此時再被拖進。
o.style.display = 'none';
if (w.location.href != bU) {
// sl('get_drag_path: get href ['+w.location.href+']');
i = unescape(getPathOnly(w.location.href));
// sl('get_drag_path: get unescaped href ['+i+']');
// NOT GOOD: if(!i.indexOf('file:///'))i=getFP(getPathOnly(i));
// drag 的都是完整 path。getPathOnly 應該先於 unescape,預防 # 等字元。
if (/^[a-z]:\//i.test(i))
i = getFP(i.replace(/\//g, '\\'));
_s.add(i);
w.location.href = bU;
if (_s.show)
_s.d(), _s.afterAdd && _s.afterAdd();
}
if (bU == w.location.href)
// 用 try: 有時 about:blank 還沒設定好
try {
// 無法用 className
var s = w.document.body;
s.style.cssText = _s.bCSS;
// 只能在 about:blank 設定
s.innerHTML = _s.dC;
var s = _s.shouldShow;
o.style.display = (typeof s === 'function' ? s(_s.o) : s) ? 'block'
: 'none';
} catch (e) {
}
}
return _s.href;
}
// delete url in collection
get_drag_path.d = function(u) {
if (u === 1) {
get_drag_path.href_hash = Object.create(null);
return;
} else if (u in get_drag_path.href_hash)
delete get_drag_path.href_hash[u];
get_drag_path.href_list = [];
var t = [];
for (i in get_drag_path.href_hash){
get_drag_path.href_list.push(i);
t.push('