app/assets/javascripts/lib/utils/common.js
function has_attr(id){
return function(target){
return this.getAttribute(id)
}
}
function get_attr(id){
return function(target){
target = target || this;
return target.getAttribute(id)
}
}
var Util = {
image:{},
style:{}
};
Util.image.maxsize = function(w,h){
var ow = this.width;
var oh = this.height;
var rw = ow;
var rh = oh;
if(ow > w){
rw = w;
rh = oh * (w / ow);
}
if(rh > h){
rw = rw * (h / rh);
rh = h;
};
this.width = rw;
this.height = rh;
};
Util.style.visible = function(el){
setStyle(el,{visibility:"visible"})
}
function swap_channel_image(el,src){
el.onload = null;
var img = new Image();
var swap = function(){
Util.image.maxsize.call(img,200,50);
el.width = img.width;
el.height = img.height;
el.src = src;
};
img.src = src;
if(img.complete){
swap()
} else {
img.onload = swap;
}
}
function get_domain(url){
var m = (url+'/').match(get_domain.reg);
return m ? m[1] : "";
}
get_domain.reg = /https?:\/\/([^\/]*?)\//;
/*
良く使う関数
*/
var GLOBAL = this;
// bench
function _$(el){
//return typeof el == 'string' ? document.getElementById(el) : el;
if(typeof el == 'string'){
return (_$.cacheable[el])
? _$.cache[el] || (_$.cache[el] = document.getElementById(el))
: document.getElementById(el)
} else {
return el
}
}
_$.cache = {};
_$.cacheable = {};
var _ = {};
$N = function (name, attr, childs) {
var ret = document.createElement(name);
for (k in attr) {
if (!attr.hasOwnProperty(k)) continue;
v = attr[k];
(k == "class") ? (ret.className = v) :
(k == "style") ? setStyle(ret,v) : ret.setAttribute(k, v);
}
var t = typeof clilds;
(isString(childs))? ret.appendChild(document.createTextNode(childs)) :
(isArray(childs)) ? foreach(childs,function(child){
isString(child)
? ret.appendChild(document.createTextNode(child))
: ret.appendChild(child);
})
: null;
return ret;
};
function $DF(){
var df = document.createDocumentFragment();
foreach(arguments,function(f){ df.appendChild(f) });
return df;
}
function reserveName(name){
var root = this;
var ns = name.split(".");
for(var i=0;i<ns.length;i++){
var current = ns[i];
if(!root[current]) root[current] = {};
root = root[current]
}
}
function True(){return true}
function False(){return false}
function BrowserDetect(){
var ua = navigator.userAgent;
if(ua.indexOf( "KHTML" ) > -1) this.isKHTML = true;
if(ua.indexOf( "Macintosh" ) > -1) this.isMac = true;
if(ua.indexOf( "Windows" ) > -1) this.isWin = true;
if(ua.indexOf( "Gecko" ) > -1 && !this.isKHTML) this.isGecko = true;
if(ua.indexOf( "Firefox" ) > -1) this.isFirefox = true;
this.isWindows = this.isWin;
if(window.opera){
this.isOpera = true;
} else if(ua.indexOf( "MSIE" ) > -1){
this.isIE = true;
}
}
Array.from = function(array) {
// arguments
if(array.callee){
return Array.prototype.slice.call(array,0)
}
var length = array.length;
var result = new Array(length);
for (var i = 0; i < length; i++)
result[i] = array[i];
return result;
};
Function.prototype.cut = function() {
var func = this;
var template = Array.from(arguments);
return function() {
var args = Array.from(arguments);
return func.apply(null, template.map(function(arg) {
return arg == _ ? args.shift() : arg;
}));
}
};
Function.prototype.o = function(a) {
var f = this;
return function() {
return f(a.apply(null, arguments));
}
};
/*
Class
*/
Class = function(){return function(){return this}};
Class.Traits = {};
Class.create = function(traits){
var f = function(){
this.initialize.apply(this, arguments);
};
f.prototype.initialize = function(){};
f.isClass = true;
f.extend = function(other){
extend(f.prototype,other);
return f;
};
if(traits && Class.Traits[traits])
f.extend(Class.Traits[traits]);
return f;
};
// 他のクラスまたはオブジェクトをベースに新しいクラスを作成する
Class.base = function(base_class){
if(base_class.isClass){
var child = Class.create();
child.prototype = new base_class;
return child;
} else {
var base = Class();
base.prototype = base_class;
var child = Class.create();
child.prototype = new base;
return child;
}
};
// クラスを合成
Class.merge = function(a,b){
var c = Class.create();
var ap = a.prototype;
var bp = b.prototype;
var cp = c.prototype;
var methods = Array.concat(keys(ap),keys(bp)).uniq();
foreach(methods,function(key){
if(isFunction(ap[key]) && isFunction(bp[key])){
cp[key] = function(){
ap[key].apply(this,arguments);
return bp[key].apply(this,arguments);
}
} else {
cp[key] =
isFunction(ap[key]) ? ap[key] :
isFunction(bp[key]) ? bp[key] : null
}
});
return c;
}
function extend(self,other){
for(var i in other){
self[i] = other[i]
}
return self;
}
function base(obj){
function f(){return this};
f.prototype = obj;
return new f;
}
function clone(obj){
var o = {};
for(var i in obj){
o[i] = obj[i]
};
return o
}
function keys(hash){
var tmp = [];
for(var key in hash){
tmp.push(key)
}
return tmp;
}
function each(obj,callback){
for(var i in obj){
callback(obj[i],i)
}
}
function foreach(a,f){
var c = 0;
var len = a.length;
var i = len % 8;
if (i>0) do {
f(a[c],c++,a);
} while (--i);
i = parseInt(len >> 3);
if (i>0) do {
f(a[c],c++,a);f(a[c],c++,a);
f(a[c],c++,a);f(a[c],c++,a);
f(a[c],c++,a);f(a[c],c++,a);
f(a[c],c++,a);f(a[c],c++,a);
} while (--i);
};
/*
function foreach(array,callback){
var len = array.length;
for(var i=0;i<len;i++){
callback(array[i],i,array)
}
}
*/
/* Perlのjoin、中の配列も含めて同じルールでjoinする */
function join(){
var args = Array.from(arguments);
var sep = args.shift();
var to_s = Array.prototype.toString;
Array.prototype.toString = function(){return this.join(sep)}
var res = args.join(sep);
Array.prototype.toString = to_s;
return res;
}
/* */
function Arg(n){
return function(){ return arguments[n] }
}
function This(){
return function(){ return this }
}
// 関数の結果に対してsend
Function.prototype.send = function(method,args){
var self = this;
return function(){
return send(self.apply(this,arguments),method,args)
}
};
function send(self,method,args){
if(isFunction(self[method]))
return self[method].apply(self,args);
else if(isFunction(self.method_missing))
return self.method_missing(method,args)
else
return null
}
// methodに別名を付ける
function alias(method){
return function(){
return this[method].apply(this,arguments)
}
}
/*
transform functions
*/
function sender(method){
var args = Array.slice(arguments,1);
return function(self){
var ex_args = Array.from(arguments);
return send(self,method,args.concat(ex_args))
}
}
// thisに対してmethodを呼び出す関数を生成する
// methodは文字列もしくは関数
/*
invoker(arg(1),)
*/
function invoker(method){
var args = Array.slice(arguments,1);
if(isFunction(method)){
return function(){
var ex_args = Array.from(arguments);
return method.apply(this,args.concat(ex_args))
}
} else {
return function(){
var ex_args = Array.from(arguments);
return send(this,method,args.concat(ex_args))
}
}
}
/*
push : function(item){ return this.list.push(item) }
-> push : delegator("list","push");
*/
function delegator(key,method){
return function(){
var self = this[key];
return self[method].apply(self,arguments);
}
}
function getter(attr){
return function(self){return self[attr]}
}
/*
extend buildin object
*/
foreach("String,Number,Array,Function".split(","),function(c){
var klass = GLOBAL[c];
klass.isClass = true;
klass.extend = function(other){
return extend(klass.prototype,other);
}
klass.prototype["is"+c] = true
})
Object.extend = extend;
/*
and more extra methods
*/
Array.prototype.min = function(cmp){return (cmp?this.sort(cmp):this.sort()).first()}
Array.prototype.max = function(cmp){return (cmp?this.sort(cmp):this.sort()).last()}
Array.prototype.compact = function(){
return this.remove("");
}
Array.extend({
isArray : true,
clone : function(){ return this.concat() },
clear : function(){ this.length = 0; return this },
delete_at : function(pos){
return this.splice(pos,1);
},
first : function(size){
return (size == undefined) ? this[0] : this.slice(0,size)
},
last : function(size){
return (size == undefined) ? this[this.length-1] : this.slice(this.length-size)
},
select : alias("filter"),
remove : function(to_remove){
return this.select(function(val){return val != to_remove ? true : false});
},
compact : invoke("remove",""),
// 重複をなくす、破壊的
uniq : function(){
var tmp = {};
var len = this.length;
for(var i=0;i<this.length;i++){
if(tmp.hasOwnProperty(this[i])){
this.splice(i,1);
if(this.length == i){break}
i--;
}else{
tmp[this[i]] = true;
}
}
return this;
},
// 各要素にメソッドを送る
invoke : function(){
var args = Array.from(arguments);
var method = args.shift();
return this.map(sender(method,args));
},
// ハッシュの配列から指定キーのvalueのみを集めた配列を返す
pluck : function(name){
return this.map(getter(name))
},
partition : function(callback,thisObj) {
var trues = [], falses = [];
this.forEach(function(v,i,self){
(callback.call(thisObj,v,i,self) ? trues : falses).push(v);
});
return [trues, falses];
}
});
/*
detect
*/
function isString(obj){
return (typeof obj == "string" || obj instanceof String) ? true : false
}
function isNumber(obj){
return (typeof obj == "number" || obj instanceof Number) ? true : false;
}
function isElement(obj){
return obj.nodeType ? true : false;
}
function isFunction(obj){
return typeof obj == "function";
}
function isArray(obj){
return obj instanceof Array;
}
function isRegExp(obj){
return obj instanceof RegExp
}
function isDate(obj){
return obj instanceof Date
}
/* Accessor */
function Accessor(){
var value;
var p_getter = this.getter;
var p_setter = this.setter;
var accessor = function(new_value){
if(arguments.length){
var setter = accessor.setter || p_setter;
return (value = setter(new_value, value));
} else {
var getter = accessor.getter || p_getter;
return getter(value)
}
return (arguments.length) ? (value = new_value) : value
};
accessor.isAccessor = true;
return accessor;
}
Accessor.prototype.getter = function(value){ return value };
Accessor.prototype.setter = function(value){ return value };
/*
Cookie
*/
var Cookie = Class.create();
Cookie.extend({
initialize: function(opt){
this._options = "name,value,expires,path,domain,secure".split(",");
this._mk_accessors(this._options);
this.expires.setter = function(value){
if(isDate(value)){
value = this.expires.toString();
} else if(isNumber(value)){
value = new Date(new Date() - 0 + value).toString();
}
return value
}
if(opt) this._set_options(opt);
},
_set_options : function(opt){
var self = this;
this._options.forEach(function(key){
opt.hasOwnProperty(key) && self[key](opt[key])
})
},
_mk_accessors: function(args){
for(var i=0;i<args.length;i++){
var name = args[i];
this[name] = new Accessor()
}
},
parse: function(str){
var hash = {};
var ck = str || document.cookie;
var pairs = ck.split(/\s*;\s*/);
pairs.forEach(function(v){
var tmp = v.split("=",2);
hash[tmp[0]] = tmp[1];
})
return hash;
},
bake: function(){
document.cookie = this.as_string();
},
as_string: function(){
var e,p,d,s;
e = this.expires();
p = this.path();
d = this.domain();
s = this.secure();
var options = [
(e ? ";expires=" + e.toGMTString() : ""),
(p ? ";path=" + p : ""),
(d ? ";domain=" + d : ""),
(s ? ";secure" : "")
].join("");
var cookie = [this.name(),"=",this.value(),options].join("");
return cookie;
}
});
Cookie.default_expire = 60*60*24*365*1000;
function setCookie(name,value,expires,path,domain,secure){
if(isDate(expires)){
expire_str = "expires="+expires.toString();
} else if(isNumber(expires)){
expire_str = "expires="+new Date(new Date() - 0 + expire).toString();
} else {
expire_str = "expires="+new Date(new Date() - 0 + Cookie.default_expire).toString();
}
if(!path) path = "; path=/;";
var cookie = new Cookie({
name : name,
value : value,
path : path || "/",
expires : expires
});
cookie.bake();
}
function getCookie(key){
var hash = new Cookie().parse();
return hash[key];
}
/* Array */
Array.extend({
collect : alias("map"),
reduce : function(callback){
return this.map(callback).join("")
}
});
/* Number */
Number.extend({
toHex : invoker("toString",16),
zerofill : function(len){
var n = "" + this;
for(;n.length < len;)
n = "0" + n;
return n;
},
// 両端を含む
between : function(a,b){
var min = Math.min(a,b);
var max = Math.max(a,b);
return (this >= min && this <= max);
}
});
/* Function */
Function.extend({
applied : function(thisObj,args){
var self = this;
return function(){
return self.apply(thisObj,args)
}
},
bindThis : function(thisObj){
var self = this;
return function(){
return self.apply(thisObj,arguments)
}
},
bind : alias("bindThis"),
// 引数をsliceする
slicer : function(to,end){
var self = this;
return function(){
var sliced = Array.slice(arguments,to,end);
return self.apply(this,sliced);
}
}
});
function loadRaw(url){
var req = new XMLHttpRequest;
var res;
req.open("GET",url,false);
req.onload = function(){
res = req.responseText;
};
req.send(null);
return res;
}
function loadJson(url,callback){
if(dev){
if(!dummy[url]){return}
var json = dummy[url].isString ? eval("("+dummy[url]+")") : dummy[url];
callback(json);
return;
}
var req = new XMLHttpRequest;
req.open("GET",url,true);
req.onload = function(){
eval("var json ="+req.responseText);
callback(json)
};
req.send(null)
}
/*
className
*/
function hasClass(element,classname){
element = _$(element);
var cl = element.className;
var cls = cl.split(/\s+/);
return cls.indexOf(classname) != -1;
}
function addClass(element,classname){
element = _$(element);
var cl = element.className;
if(!contain(cl,classname)){
element.className += " " + classname;
}
}
function removeClass(element,classname){
element = _$(element);
var cl = element.className;
var cls = cl.split(/\s+/);
element.className = cls.remove(classname).join(" ");
}
function switchClass(element, classname){
element = _$(element);
var cl = element.className;
var tmp = classname.split("-");
var ns = tmp[0];
var cls = cl.split(/\s+/);
var buf = [];
cls.forEach(function(v){
if(v.indexOf(ns+"-") != 0) buf.push(v)}
);
buf.push(classname);
element.className = buf.join(" ");
}
function toggleClass(element, classname){
element = _$(element);
hasClass(element, classname) ?
removeClass(element, classname):
addClass(element, classname);
}
/* 文字列が含まれているかの判別 */
function contain(self,other){
if(isString(self) && isString(other)){
return self.indexOf(other) != -1
}
if(isRegExp(other)){
return other.test(self)
}
}
/* Form */
var Form = {};
Form.toJson = function(form){
var json = {};
var len = form.elements.length;
foreach(form.elements, function(el){
if(!el.name) return;
var value = Form.getValue(el);
if(value != null){
json[el.name] = value
}
});
return json;
};
Form.getValue = function(el){
return (
(/text|hidden|submit/.test(el.type)) ? el.value :
(el.type == "checkbox" && el.checked) ? el.value :
(el.type == "radio" && el.checked) ? el.value :
(el.tagName == "SELECT") ? el.options[el.selectedIndex].value :
null
)
};
// formを埋める
Form.fill = function(form,json){
form = _$(form);
foreach(form.elements, function(el){
var name = el.name;
var value = json[name];
if(!name || value == null) return;
(/text|hidden|select|submit/.test(el.type)) ?
(el.value = value) :
(el.type == "checkbox") ? (el.value = value, el.checked = true) :
(el.type == "radio") ?
(value == el.value) ? (el.checked = true) : (el.checked = false) :
null
})
}
Form.setValue = function(el, value){
el.value = value;
}
Object.extend(Form,{
disable: function(el){
_$(el).disabled = "disabled";
},
enable: function(el){
_$(el).disabled = "";
},
disable_all: function(el){
el = _$(el);
Form.disable(el);
var child = el.getElementsByTagName("*");
foreach(child, Form.disable);
},
enable_all: function(el){
el = _$(el);
Form.enable(el);
var child = el.getElementsByTagName("*");
foreach(child, Form.enable);
}
});
/* Cache */
var Cache = Class.create();
Cache.extend({
initialize : function(option){
this._index = {};
this._exprs = {};
this._cache = [];
if(option){
this.max = option.max || 0;
}
},
_get: function(key){
return this._index["_" + key];
},
get: function(key){
return this._get(key)[1]
},
set: function(key,value){
// delete
if(this.max && this._cache.length > this.max){
var to_delete = this._cache.shift();
delete this._index["_" + to_delete[0]];
}
// update
if(this.has(key)){
this._get(key)[1] = value;
} else {
// create
var pair = [key,value];
this._cache.push(pair);
this._index["_"+key] = pair;
}
return value;
},
set_expr: function(key,expr){
this._exprs["_" + key] = expr;
},
get_expr: function(key){
return this._exprs["_" + key] || null;
},
check_expr: function(key){
var expr = this.get_expr(key);
if(expr){
var r = new Date() - expr;
var f = (r < 0) ? true : false;
// if(!f) message("再読み込みします")
return f;
} else {
return true;
}
},
has : function(key){
return (this._index.hasOwnProperty("_" + key) && this.check_expr(key));
},
clear : function(){
this._index = {};
this._cache = [];
},
find_or_create : function(key,callback){
return this.has(key) ? this.get(key) : this.set(key,callback())
}
});
Number.extend({
times: function(callback){
var c = 0;
for(;c<this;c++) callback(c)
}
});
String.escapeRules = [
[/&/g , "&"],
[/</g , "<"],
[/>/g , ">"]
];
String.unescapeRules = [
[/</g, "<"],
[/>/g, ">"],
[/&/g, "&"]
];
String.extend({
strip : invoker("replace",/^\s+(.*?)\s+$/,"$1"),
repeat : function(num){
var buf = [];
for(var i=0;i<num;buf[i++]=this);
return buf.join("");
},
mreplace : function(rule){
var tmp = ""+this;
foreach(rule,function(v){
tmp = tmp.replace(v[0],v[1])
});
return tmp;
},
escapeHTML : invoker("mreplace",String.escapeRules),
unescapeHTML : invoker("mreplace",String.unescapeRules),
ry : function(max,str){
if(this.length <= max) return this;
var tmp = this.split("");
return Array.concat(this.slice(0,max/2),str,this.slice(-max/2)).join("")
},
camelize : invoker("replace",/-([a-z])/g, Arg(1).send("toUpperCase"))
});
/* Math */
Math.rand = function(num){return Math.random() * num};
function inspect(obj){
return keys(obj).map(function(key){
return key +" = "+obj[key] + "\n";
})
}
Object.hasMethod = function(object,method){
if(object && typeof object[method] == "function")
return true;
else
return false;
};
Object.toQuery = function(self){
var buf = [];
for(var key in self){
var value = self[key];
if(isFunction(value)) continue;
buf.push(
encodeURIComponent(key)+"="+
encodeURIComponent(value)
)
}
return buf.join("&");
}
/* from prototype.js */
var Position = {
// set to true if needed, warning: firefox performance problems
// NOT neeeded for page scrolling, only if draggable contained in
// scrollable elements
includeScrollOffsets: false,
// must be called before calling withinIncludingScrolloffset, every time the
// page is scrolled
prepare: function() {
this.deltaX = window.pageXOffset
|| document.documentElement.scrollLeft
|| document.body.scrollLeft
|| 0;
this.deltaY = window.pageYOffset
|| document.documentElement.scrollTop
|| document.body.scrollTop
|| 0;
},
realOffset: function(element) {
var valueT = 0, valueL = 0;
do {
valueT += element.scrollTop || 0;
valueL += element.scrollLeft || 0;
element = element.parentNode;
} while (element);
return [valueL, valueT];
},
cumulativeOffset: function(element) {
var valueT = 0, valueL = 0;
do {
valueT += element.offsetTop || 0;
valueL += element.offsetLeft || 0;
element = element.offsetParent;
} while (element);
return [valueL, valueT];
},
positionedOffset: function(element) {
var valueT = 0, valueL = 0;
do {
valueT += element.offsetTop || 0;
valueL += element.offsetLeft || 0;
element = element.offsetParent;
if (element) {
p = Element.getStyle(element, 'position');
if (p == 'relative' || p == 'absolute') break;
}
} while (element);
return [valueL, valueT];
},
offsetParent: function(element) {
if (element.offsetParent) return element.offsetParent;
if (element == document.body) return element;
while ((element = element.parentNode) && element != document.body)
if (Element.getStyle(element, 'position') != 'static')
return element;
return document.body;
},
// caches x/y coordinate pair to use with overlap
within: function(element, x, y) {
if (this.includeScrollOffsets)
return this.withinIncludingScrolloffsets(element, x, y);
this.xcomp = x;
this.ycomp = y;
this.offset = this.cumulativeOffset(element);
return (y >= this.offset[1] &&
y < this.offset[1] + element.offsetHeight &&
x >= this.offset[0] &&
x < this.offset[0] + element.offsetWidth);
},
withinIncludingScrolloffsets: function(element, x, y) {
var offsetcache = this.realOffset(element);
this.xcomp = x + offsetcache[0] - this.deltaX;
this.ycomp = y + offsetcache[1] - this.deltaY;
this.offset = this.cumulativeOffset(element);
return (this.ycomp >= this.offset[1] &&
this.ycomp < this.offset[1] + element.offsetHeight &&
this.xcomp >= this.offset[0] &&
this.xcomp < this.offset[0] + element.offsetWidth);
},
// within must be called directly before
overlap: function(mode, element) {
if (!mode) return 0;
if (mode == 'vertical')
return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
element.offsetHeight;
if (mode == 'horizontal')
return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
element.offsetWidth;
},
clone: function(source, target) {
source = _$(source);
target = _$(target);
target.style.position = 'absolute';
var offsets = this.cumulativeOffset(source);
target.style.top = offsets[1] + 'px';
target.style.left = offsets[0] + 'px';
target.style.width = source.offsetWidth + 'px';
target.style.height = source.offsetHeight + 'px';
},
page: function(forElement) {
var valueT = 0, valueL = 0;
var element = forElement;
do {
valueT += element.offsetTop || 0;
valueL += element.offsetLeft || 0;
// Safari fix
if (element.offsetParent==document.body)
if (Element.getStyle(element,'position')=='absolute') break;
} while (element = element.offsetParent);
element = forElement;
do {
valueT -= element.scrollTop || 0;
valueL -= element.scrollLeft || 0;
} while (element = element.parentNode);
return [valueL, valueT];
},
clone: function(source, target) {
var options = Object.extend({
setLeft: true,
setTop: true,
setWidth: true,
setHeight: true,
offsetTop: 0,
offsetLeft: 0
}, arguments[2] || {})
// find page position of source
source = _$(source);
var p = Position.page(source);
// find coordinate system to use
target = _$(target);
var delta = [0, 0];
var parent = null;
// delta [0,0] will do fine with position: fixed elements,
// position:absolute needs offsetParent deltas
if (Element.getStyle(target,'position') == 'absolute') {
parent = Position.offsetParent(target);
delta = Position.page(parent);
}
// correct by body offsets (fixes Safari)
if (parent == document.body) {
delta[0] -= document.body.offsetLeft;
delta[1] -= document.body.offsetTop;
}
// set position
if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
if(options.setWidth) target.style.width = source.offsetWidth + 'px';
if(options.setHeight) target.style.height = source.offsetHeight + 'px';
},
absolutize: function(element) {
element = _$(element);
if (element.style.position == 'absolute') return;
Position.prepare();
var offsets = Position.positionedOffset(element);
var top = offsets[1];
var left = offsets[0];
var width = element.clientWidth;
var height = element.clientHeight;
element._originalLeft = left - parseFloat(element.style.left || 0);
element._originalTop = top - parseFloat(element.style.top || 0);
element._originalWidth = element.style.width;
element._originalHeight = element.style.height;
element.style.position = 'absolute';
element.style.top = top + 'px';;
element.style.left = left + 'px';;
element.style.width = width + 'px';;
element.style.height = height + 'px';;
},
relativize: function(element) {
element = _$(element);
if (element.style.position == 'relative') return;
Position.prepare();
element.style.position = 'relative';
var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
element.style.top = top + 'px';
element.style.left = left + 'px';
element.style.height = element._originalHeight;
element.style.width = element._originalWidth;
}
}
// Safari returns margins on body which is incorrect if the child is absolutely
// positioned. For performance reasons, redefine Position.cumulativeOffset for
// KHTML/WebKit only.
if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
Position.cumulativeOffset = function(element) {
var valueT = 0, valueL = 0;
do {
valueT += element.offsetTop || 0;
valueL += element.offsetLeft || 0;
if (element.offsetParent == document.body)
if (Element.getStyle(element, 'position') == 'absolute') break;
element = element.offsetParent;
} while (element);
return [valueL, valueT];
}
}
Position.cumulativeOffsetFrom = function(element,from) {
var valueT = 0, valueL = 0;
do {
valueT += element.offsetTop || 0;
valueL += element.offsetLeft || 0;
element = element.offsetParent;
} while (element && element != from);
return [valueL, valueT];
};
/* CSS */
function parseCSS(text){
var pairs = text.split(";");
var res = {};
pairs.forEach(function(pair){
var tmp = pair.split(":");
res[tmp[0].strip()] = tmp[1];
});
return res;
}
// cssセット、透明度、floatの互換性を取る
function setStyle(element,style){
element = _$(element);
var es = element.style;
if(isString(style)){
es.cssText ? (es.cssText = style) : setStyle(element,parseCSS(style));
} else {
// objectの場合
each(style,function(value,key){
if(setStyle.hack.hasOwnProperty(key)){
var tmp = setStyle.hack[key](key,value);
key = tmp[0],value = tmp[1]
}
element.style[key.camelize()] = value
});
}
}
setStyle.hack = {
opacity : function(key,value){
return (
(/MSIE/.test(navigator.userAgent))
? ["filter" , 'alpha(opacity='+value*100+')']
: [ key , value]
)
}
}
function getStyle(o,s){
var res;
try{
if (document.defaultView && document.defaultView.getComputedStyle){
res = document.defaultView.getComputedStyle(o, null).getPropertyValue(s);
} else {
if (o.currentStyle){
var camelized = s.replace(/-([^-])/g, function(a,b){return b.toUpperCase()});
res = o.currentStyle[camelized];
}
}
return res;
} catch(e){}
return "";
}
var Element = {};
Element.getStyle = getStyle;
/*
*/
// var Config = {}
// Task
/*
並列してリクエストを投げる、
- 完了したものからcompleteフラグを立てる
- 監視者のupdateメソッドを呼び出す
var task = new Task([loadConfig,func,func]);
task.oncomplete = function(){
// complete !
};
task.exec();
api["config/load"] = new LDR.API("/api/config/load").requester("post");
new Task(loadconfig);
LDR.API.prototype.toTask = function(){
}
*/
Object.extend(Function.prototype,{
/* TIMERS */
_timeouts : [],
_interals : [],
do_later : function(ms){
this._intervals.push(setTimeout(this,ms));
return this;
},
bg : function(ms){
this._intervals.push(setInterval(this,ms));
return this;
},
kill : function(){
this._timeouts.forEach(function(pid){
clearTimeout(pid)
});
this._intervals.forEach(function(pid){
clearInterval(pid)
})
},
/* TASK */
observers : [],
complete : function(result){
this.result_code = result;
this.observers.invoke("update", this)
},
_changed : false,
changed : function(state){
return arguments.length ? (this._changed = state) : this._changed;
},
add_observer : function(observer){
this.observers.push(observer)
return this;
}
})
function loadConfig(){
var task = arguments.callee;
var api = new LDR.API("/api/config/load");
return api.post({},function(res){
extend(app.config,res);
task.complete();
});
}
function Task(tasks,callback){
var self = this;
this.tasks = tasks;
tasks.map(function(v){
return isFunction(v) ? v : send(v,"toTask")
}).invoke("add_observer", this);
if(callback){
this.oncomplete = callback;
this.exec();
}
return this;
}
Task.prototype = {
isTask : true,
exec : function(){
this.tasks.invoke("call",null);
},
update : function(f){
send(this,"onprogress");
}
}
Array.prototype.toTask = function(){
return new Task(this);
}
/*
super
*/
/*
parent
this.parent.update();
this.parent.parent.update();
-> parent(this,"update")
*/
/*
function parent(obj, method, args){
var p = obj.parent;
while(p){
send(p,method,args);
p = obj.parent;
}
}
*/
/*
invoke 別のクラスに処理を伝播させる
invoke(this, "method_name", arguments);
*/
function invoke(obj, method, args){
var o = obj.parent;
for (;typeof(o) != 'undefined'; o = o.parent) {
if (typeof(o[method]) == 'function') {
return o[method].apply(obj, args);
}
}
return false;
}
/*
next たらいまわしにする。
this.parent.childs
next(this, "initialize");
*/
function next(obj, method, args){
obj.parent.childs.invoke(method,args)
}
function childOf(element, ancestor){
element = _$(element), ancestor = _$(ancestor);
while (element = element.parentNode)
if (element == ancestor) return true;
return false;
}
function _$ref(element){
}
String.prototype.op = function(){
return new Function("a,b","return a"+this+"b");
}
// regexp merger
// 正規表現を複数行にわたって記述できるようにします。
RegExp.prototype.get_body = function(){
var str = this.toString();
return str.slice(1,str.lastIndexOf("/"));
};
RegExp.prototype.get_flags = function(){
return [
this.ignoreCase ? "i":"",
this.global ? "g":"",
this.multiline ? "m":""
].join("");
};
RegExp.concat = function(){
var args = Array.from(arguments);
var buf = [];
args.forEach(function(reg){
buf.push(reg.get_body());
});
var flag = args[args.length-1].get_flags();
return new RegExp(buf.join(""), flag);
}
Array.prototype.flatten = function(){
var res = [];
this.forEach(function(a){
if(isArray(a))
a = a.flatten();
res = res.concat(a)
});
return res;
};
Function.prototype.forEachArgs = function(callback){
var f = this;
return function(){
var target = Array.from(arguments).flatten();
if(!target.length) return;
target.forEach(function(v){
callback ? f(callback(v)) : f(v)
})
}
};
// last_error
window.__ERROR__ = null;
Function.prototype._try = function(){
var self = this;
return function(){
try{
return self.apply(this, arguments)
} catch(e){
__ERROR__ = e;
// alert(e);
}
}
};
/*
Element Updater
*/
function MakeUpdater(label){
var hash = {};
var updater = (label?label+"_":"") + "updater";
var update = (label?label+"_":"") + "update";
function get_func(label){
return(
isFunction(hash["_"+label])
? hash["_" + label]
: function(){}
);
}
var u = GLOBAL[update] = function(label){
if(isRegExp(label)){
keys(hash).filter(function(l){
l = l.slice(1);
return label.test(l)
}).forEach(function(label){
label = label.slice(1);
get_func(label).call(_$(label));
})
} else {
return get_func(label).call(_$(label));
}
}.forEachArgs();
GLOBAL[updater] = function(label, callback){
if(callback){
hash["_"+label] = callback;
} else {
return function(){ u(label) }
}
};
}
MakeUpdater();
var Element = {
show: function(el){
if(el) el.style.display = "block"
}.forEachArgs(_$),
hide: function(el){
if(el) el.style.display = "none"
}.forEachArgs(_$),
toggle: function(el){
el = _$(el);
el.style.display = (el.style.display != "block") ? "block" : "none";
},
childOf: function(){},
getStyle : getStyle
};
GLOBAL.sortModes = {
modified_on: "New",
"modified_on:reverse": "Old",
unread_count: "Unread Items (desc.)",
"unread_count:reverse": "Unread items (asc.)",
"title:reverse": "Title",
rate: "Rating",
subscribers_count: "Subscribers (desc.)",
"subscribers_count:reverse": "Subscribers (asc.)"
}
GLOBAL.viewModes = {
flat: "Flat",
folder: "Folder",
rate: "Rating",
subscribers: "Subscribers",
domain: "Domain",
}