Sunday, August 31, 2008

unicode and html entities in javascript


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>test</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<script type="text/javascript" charset="utf-8">
var three = "叁";
// 单字符计算,多字符也可用此进行计算
var code = three.charCodeAt(0).toString(16); // 10进制转16进制
document.write(code);
document.write("<br/>");
document.write("&#x" + code + ";");
var decimal = parseInt(code, 16); // 16进制转10进制
document.write("<br/>");
document.write(decimal);
document.write("<br/>");
var san = String.fromCharCode(decimal);
document.write(san);
document.write("<br/>");
document.write("<br/>");

// javascript 支持unicode直接量
var unicode = "\u53c1"; // different from string "\\u" + "53c1"
document.write("<br/>");
document.write(unicode);
document.write("<br/>");
document.write("<br/>");

// 多字符转换,利用escape/unescape()方法进行转换,不推荐
var PRC = "中华人民共和国";
var entityChar = PRC.replace(/[^\u0000-\u00FF]/g, function($0){
return escape($0).replace(/(?:%u)(\w{4})/gi, "&#x$1;")
});
document.write("<br/>");
document.write(entityChar); // "中华人民共和国"
document.write("<br/>");
var origin = unescape(entityChar.replace(/&#x/g, '%u').replace(/;/g, ''));
document.write(origin);
</script>
</body>
</html>

unicode编码规则:
unicode码对每一个字符用4位16进制数表示。具体规则是:将一个字符(char)的高8位与低8位分别取出,转化为16进制数,
如果转化的16进制数的长度不足2位,则在其后补0,然后将高、低8位转成的16进制字符串拼接起来并在前面补上"\u"即可。

Mozilla Labs Ubiquity 试用

根据https://wiki.mozilla.org/Labs/Ubiquityhttps://wiki.mozilla.org/Labs/Ubiquity/Ubiquity_0.1_Author_Tutorial
做了一个尝试,写了一个取cookie值的Ubiq:


CmdUtils.CreateCommand({
name: "cookie",
takes: {"cookie name": noun_arb_text},
icon: "http://www.mozilla.com/favicon.ico",
description: "Get named cookie value, or all cookie value.",
preview: function( pblock, cookieName ) {
var reg = new RegExp("(?:^|\\s+)" + cookieName.text + "=(.+?)(?:;|$)", "i");
var match = context.focusedWindow.document.cookie.match(reg);
if (match) pblock.innerHTML = match[1];
else pblock.innerHTML = context.focusedWindow.document.cookie;
},
execute: function( ) {
return false;
}
})

Saturday, August 30, 2008

MySQL 数据库字符集问题

在rails项目开发中碰到一个MySQL数据库字符集问题 ,一个DEFAULT CHARSET utf8的数据库中,有一个ENGINE=MyISAM DEFAULT CHARSET=utf8的数据表,手工往其中插入中文,日文,韩文都没有问题,但通过rails添加数据记录时,中文,日文没有问题,但是插入韩文就一直乱码,rails和手工执行的sql相同,如下所示:


set names utf8;
insert TableName values('', '시험');

网上查不到什么相关资料,在rails中做了一些测试性的调整,都没有解决问题。最后决定调整mysql server的默认字符集,虽然觉得这个应该不会造成rails无法插入韩文,因为在rails中加过before_save前置过滤器,在其中先运行"set names utf8;",之后再执行insert操作,也一样是乱码。
在my.cnf中加入如下配置并重启mysql服务之后,rails就可以正常插入韩文了!!

# The MySQL server
[mysqld]
character-set-server = utf8


另摘录一段mysql server启动的参数选项说明:
·         --character-set-server=charset
使用charset作为 默认服务器字符
·         --collation-server=collation
使用collation作为 默认服务器校对规则
·         (DEPRECATED) --default-character-set=charset
使用char设置作为 默认字符集。由于--character-set-server,反对使用该选项。
·         --default-collation=collation
使用collation 作为默认校对规则。由于--collation-server,反对使用该选项。

Wednesday, August 27, 2008

My drag drop library example


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>My Drag and Drop Example</title>
<script type="text/javascript" src="/lib/prototype.js"></script>
<script type="text/javascript" src="/lib/mydragdrop.js"></script>

<style type="text/css">
#dragDiv, #dragDiv2 {
*width: 150px;
min-width: 150px;
border: #333 1px solid;
min-height: 150px;
float: left;
}
#dropDiv {
*width: 150px;
min-width: 150px;
border: #333 1px solid;
min-height: 150px;
margin-left: 20px;
float: left;
}
.hoverActive {
background-color: #ffc;
}
img {
vertical-align: middle;
}
</style>
</head>
<body>
<div id="dragDiv">
<img id="img1" src="/images/puzzle1.jpg"/><img id="img2" src="/images/puzzle2.jpg"/><img id="img3" src="/images/puzzle3.jpg"/>
</div>
<div id="dragDiv2">
<img id="img4" src="/images/puzzle4.jpg"/>
</div>

<div id="dropDiv">
</div>
<script type="text/javascript">
window.onload = function() {
new Drag('img1', {revert: false});
new Drag('img2', {revert: true});
new Drag('img3', {revert: true});
new Drag('img4', {revert: true});
Drop.add('dropDiv', {hoverclass: 'hoverActive', containers: ["dragDiv"],
onDrop: function(drag, drop) {
drag.style.left = "";
drag.style.top = "";
drop.style.borderColor = "#000";
drop.style.borderWidth = "thin";
if (drop.lastChild.nodeType == 3) drop.removeChild(drop.lastChild);
drop.appendChild(drag);
},
onHover: function(drag, drop){
drop.style.borderColor = "#886";
drop.style.borderWidth = "thick";
}
});
Drop.add('dragDiv', {hoverclass: 'hoverActive',
onDrop: function(drag, drop) {
drag.style.left = "";
drag.style.top = "";
if (drop.lastChild.nodeType == 3) drop.removeChild(drop.lastChild);
drop.appendChild(drag);
}
});
}
</script>
</body>
</html>

Here is mydragdrop.js source

MyDragDrop javascript library v0.1 based prototype 1.6.1


// MyDragDrop 0.1 - based Prototype and imitate script.aculo.us dragdrop.js

DragController = {
drags: [],
dragging: false,
currentDrag: null,
register: function(drag) {
if(this.drags.length == 0) {
Event.observe(document, "mouseup", this.endDrag.bindAsEventListener(this));
Event.observe(document, "mousemove", this.updateDrag.bindAsEventListener(this));
Event.observe(document, "keypress", this.keyPress.bindAsEventListener(this));
}
this.drags.push(drag);
},
updateDrag: function(event) {
this.currentDrag && this.currentDrag.updateDrag(event);
},
endDrag: function(event) {
this.currentDrag && this.currentDrag.endDrag(event, true);
},
keyPress: function(event) {
this.currentDrag && this.currentDrag.keyPress(event);
}
};

Drag = Class.create({
initialize: function(element) {
var defaults = {
handle: false,
zindex: 1000,
revert: false,
ghosting: false,
opacity: 0.0
};
this.element = $(element);
this.options = Object.extend(defaults, arguments[1] || {});
DragController.register(element);
// fix IE position problem.
if(Prototype.Browser.IE) {
var position = this.element.style.position;
if (position == 'static' || !position) this.element.style.position = 'relative';
}
Event.observe(element, "mousedown", this.startDrag.bindAsEventListener(this));
},
startDrag: function(event) {
if(Event.isLeftClick(event)) {
this.relativePosition = [this.element.style.left, this.element.style.top];
this.clone = this.element.cloneNode(true);
this.positionAbsolutize();
this.element.parentNode.insertBefore(this.clone, this.element);
this.originalOpacity = this.element.getOpacity();
this.element.setOpacity(0.7);
if(!this.options.ghosting) {
this.clone.setOpacity(this.options.opacity);
}
this.element.style.zIndex = this.options.zindex;
this.element.style.cursor = "move";
// hack safari inline element shadow problem.
// this negative effect is block-level element display inline
if (Prototype.Browser.WebKit && this.element.style.display != "block" &&
["a", "b", "i", "q", "s", "em", "big", "sup", "sub", "abbr", "code", "cite", "span", "quote", "small", "strike", "strong"].include(this.element.tagName.toLowerCase()))
this.element.style.display = "inline-block";
this.startPointer = [Event.pointerX(event), Event.pointerY(event)];
this.positionedOffset = [this.element.offsetLeft, this.element.offsetTop];
DragController.dragging = true;
DragController.currentDrag = this;
}
Event.stop(event);
},
updateDrag: function(event) {
if (DragController.dragging) {
var currentPointer = [Event.pointerX(event), Event.pointerY(event)];
this.element.style.left = (currentPointer[0] - this.startPointer[0] + this.positionedOffset[0] - parseInt(this.element.style.marginLeft || 0)) + "px";
this.element.style.top = (currentPointer[1] - this.startPointer[1] + this.positionedOffset[1] - parseInt(this.element.style.marginTop || 0)) + "px";
Drop.show(currentPointer, this.element);
}
Event.stop(event);
},
endDrag: function(event, success) {
if (DragController.dragging) {
DragController.dragging = false;
DragController.currentDrag = null;
this.element.setOpacity(this.originalOpacity);
var currentPointer = [Event.pointerX(event), Event.pointerY(event)];
this.element.style.position = "relative";
this.element.style.left = (currentPointer[0] - this.startPointer[0] + parseInt(this.relativePosition[0] || 0)) + "px";
this.element.style.top = (currentPointer[1] - this.startPointer[1] + parseInt(this.relativePosition[1] || 0)) + "px";
this.clone.remove(); // clone remove must before Drop event fire because clone will hold position
this.clone = null;
if(!success) {
this.revertDrag(event);
} else {
var dropped;
if (Drop.lastDrop) {
Drop.removeHoverClass();
dropped = Drop.fire(event, this.element, Drop.lastDrop);
}
if (!dropped && this.options.revert)
this.revertDrag(event);
}
}
Event.stop(event);
},
keyPress: function(event) {
if(event.keyCode != Event.KEY_ESC) return;
this.endDrag(event, false);
Event.stop(event);
},
revertDrag: function(event) {
this.element.style.left = this.relativePosition[0];
this.element.style.top = this.relativePosition[1];
},
positionAbsolutize: function() {
if (this.element.getStyle('position') == 'absolute') return;
var offsets = [this.element.offsetLeft, this.element.offsetTop];
// offsetLeft include this element's marginLeft value.
var left = offsets[0] - parseInt(this.element.style.marginLeft || 0);
var top = offsets[1] - parseInt(this.element.style.marginTop || 0);
this.element.style.position = 'absolute';
this.element.style.top = top + 'px';
this.element.style.left = left + 'px';
}
});

var Drop = {
drops: [],
lastDrop: null,
add: function(element) {
var drop = Object.extend({
hoverClass: null
}, arguments[1] || {});
drop.element = $(element);
this.drops.push(drop);
},
isContained: function(drag, drop) {
var container = drag.parentNode;
return drop.containers.detect(function(c) {return $(c) == container });
},
dragHovered: function(pointer, drag, drop) {
return ((drop.element != drag) && ((!drop.containers) || this.isContained(drag, drop)) &&
Position.within(drop.element, pointer[0], pointer[1]));
},
removeHoverClass: function() {
Element.removeClassName(Drop.lastDrop.element, Drop.lastDrop.hoverclass);
},
show: function(pointer, drag) {
if(!this.drops.length) return;
var hovered = false;
this.drops.each(function(drop) {
if(Drop.dragHovered(pointer, drag, drop)) {
hovered = true;
Drop.lastDrop = drop;
Element.addClassName(drop.element, drop.hoverclass);
if(drop.onHover) drop.onHover(drag, drop.element);
}
});
if (Drop.lastDrop && !hovered)
this.removeHoverClass();
},
fire: function(event, drag, drop) {
if (drop && this.dragHovered([Event.pointerX(event), Event.pointerY(event)], drag, drop)) {
if(drop.onDrop) drop.onDrop(drag, drop.element, event);
return true;
}
}
}

example: http://yuweijun.blogspot.com/2008/08/my-drag-drop-library-example.html

IMG is an inline element


<head>
<style type="text/css">
#div1, #div2 {
border: #333 1px solid;
background-color: #333;
height: 300px;
}
#img1 {
display: block;
}
#img2 {
vertical-align: sub; /* bottom, middle */
}
</style>
</head>
<body>
<div id="div1"><img id="img1" src="/images/puzzle1.jpg"/></div>
如果img对象不设置一下display或者vertical-align等属性,会在div底部多出一点空白,
这个就是因为img是一个inline element。
<div id="div2"><img id="img2" src="/images/puzzle2.jpg"/></div>
</body>

Monday, August 25, 2008

MySQL int型字段说明

在mysql中int型字段,不管是int(1), int(4), int(11) 其最数值都是按int值来计算,无符号数为-2147483648止2147483647,即-2^31 ~ 2^31 - 1,不过需要注意以下关于显示宽度的说明。
int后面的参数说明:该可选显示宽度规定用于显示宽度小于指定的列宽度的值时从左侧填满宽度。
当结合可选扩展属性ZEROFILL使用时, 默认补充的空格用零代替。例如,对于声明为INT(5) ZEROFILL的列,值4检索为00004。请注意如果在整数列保存超过显示宽度的一个值,当MySQL为复杂联接生成临时表时会遇到问题,因为在这些情况下MySQL相信数据适合原列宽度。
Reference: mysql5.1 chinese manual

Tidy for php5

Windows users can download the extension dll php_tidy.dll from http://snaps.php.net/win32/PECL_STABLE/.

In PHP 5 you need only to compile using the --with-tidy option.

reference php manual: CXLV. Tidy Functions

Sunday, August 24, 2008

CSS element position 计算公式

以下部分element.style的属性值需要用到parseInt(value || 0)来转换。

  • clientWidth = element.style.paddingLeft + element.style.width + element.style.paddingRight
  • clientHeight = element.style.paddingTop + element.style.height + element.style.paddingBottom
  • clinetLeft = borderLeftWidth
  • clientTop = borderTopWidth
  • clientRight = offsetWidth - clientWidth - clientLeft
  • clientBottom = offsetHeight - clientHeight - clientTop
  • element.style.left = element.offsetLeft - element.style.marginLeft
  • element.style.top = element.offsetTop - element.style.marginTop
当元素的offsetParent不是BODY时,上面最后二个公式需要特别注意。

Element offset value will change in page render stage


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>offset will change in page render stage</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<img id="image" src="http://www.google.com/logos/closing_ceremonies.gif"/>
<p>test <span id="span" style="color: blue; border: 2px solid orange; padding: 5px; background-color: yellow;">
offset will change</span> in page render stage
</p>
<script type="text/javascript" charset="utf-8">
var span = document.getElementById("span");
alert([span.offsetLeft, span.offsetTop]);
setTimeout(function(){
alert([span.offsetLeft, span.offsetTop]);
}, 1000);
</script>
</body>
</html>

比如上面的例子中,在span这个元素前还有一张图片是从服务器外部载入的,在页面渲染过程中,这个span对象会被先渲染到页面上,并有了对应的offset值,但当图片被载入页面之后,span元素又往下移了,此时offset值重新计算了,注意在opera测试中要每次清一下缓存才能看到效果。

Saturday, August 23, 2008

Get Cookie value


function getCookie(cookie) {
var reg = new RegExp("(?:^|\\s+)" + cookie + "=(.+?)(?:;|$)", "i");
var match = document.cookie.match(reg);
// if (match) return RegExp.$1;
if (match) return match[1];
}

Friday, August 22, 2008

get parameters value from url query string


function getParams(param){
var search = window.location.search;
if(search == "") return;
else{
var varsList = search.slice(1).split(/&(?:amp;)*/);
for(var i = varsList.length - 1; i >= 0; i--) {
var equalArray = varsList[i].split("=");
if(equalArray[0] == param) return equalArray[1];
}
}
}

Wednesday, August 20, 2008

如何使div内容居中


#div1, #div2 {
display: table-cell;
*display: inline; /* hack ie */
height: 200px;
vertical-align: middle;
border: #000 1px solid;
}

zindex of css

在css2.1规范中指出,如果元素的zindex值一样的话,并发生重叠,则按文档流的次序,后来者居上(from back to front)。

Sunday, August 17, 2008

AutoCompleter from local based on Prototype


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>completer demo</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<script src="/lib/prototype.js" type="text/javascript"></script>
<style type="text/css">
body {
font: 11px Lucida Grande, Verdana, Arial, Helvetica, sans serif;
}
</style>
</head>
<body>
<br/>
<div id="content">
<form>
input "a" for test:
<input id="message" name="message" size="30" type="text" />
<input type="submit" value="submit"/>
</form>
<script type="text/javascript">
//<![CDATA[
var contacts = ["aa", "aaa", "aaaa", "abb", "abbb", "ac", "acc", "accc", "aac", "aaac", "bc", "ad", "aad", "aaad", "aaaad", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "中文字体", "测试~!@#$%^&*()/?\"\\';", "北京奥运会", "姚明&刘翔"];

AutoFieldFromLocal = Class.create({
initialize: function(element, items){
this.element = $(element);
this.value = this.element.value;
this.items = items;
this.timer = null;
this.observer = null;
this.counter = 0;
this.index = 0;
this.listElements = [];
this.listsObserved = false;
this.maskShowed = false;
this.divId = "auto_complete_for_" + this.element.id;
this.listsId = "lists_of_" + this.element.id;
this.maskId = "mask_" + this.element.id;
this.element.setAttribute('autocomplete', 'off');
this.insertAfter();
this.observerStart();
},
insertAfter: function(){
new Insertion.After(this.element,
'<div id="' + this.divId + '" style="position:absolute;background-color:#fff;border:1px solid #888;margin:0;padding:0;display:none;height:200px;opacity:0.90;overflow:auto;overflow-x:hidden;z-index:1;filter:alpha(opacity=90);">' +
'<ul id="' + this.listsId + '" style="margin:0;padding:0;list-style-type: none;width:100%;"></ul></div>' +
'<div id="' + this.maskId + '" style="position:absolute;background-color:blue;border:1px solid #888;margin:0;padding:0;display:none;height:0;opacity:0;z-index:2;filter:alpha(opacity=0);"/>'
);
this.completerDiv = $(this.divId);
this.list = $(this.listsId);
this.mask = $(this.maskId);
},
observerStart: function(){
// safari/ie中监听keypress时,arrow keys箭头无法正确激活绑定的事件,改用keydown监听
// Arrow keys no longer result in keypress events, now processed in keydown default event handler
// Reference: https://lists.webkit.org/pipermail/webkit-dev/2007-December/002992.html
// keydown/keypress区别参考ppk的文章: http://www.quirksmode.org/dom/events/keys.html
if (Prototype.Browser.WebKit || Prototype.Browser.IE) Event.observe(this.element, 'keydown', this.renderLists.bindAsEventListener(this));
else Event.observe(this.element, 'keypress', this.renderLists.bindAsEventListener(this));
Event.observe(this.element, 'blur', this.onBlured.bindAsEventListener(this));
Event.observe(document, 'mousemove', this.hideMask.bindAsEventListener(this));
},
addListsObserver: function(){
var self = this;
this.listElements.each(function(li){
Event.observe(li, 'mouseover', self.onMouseOverList.bindAsEventListener(self));
Event.observe(li, 'click', self.updateField.bindAsEventListener(self));
});
this.hideMask();
},
hideMask: function() {
if (this.maskShowed) {
this.maskShowed = false;
this.mask.style.height = '0px';
this.mask.style.display = "none";
}
},
showMask: function(){
if (!this.maskShowed) {
this.maskShowed = true;
this.mask.style.height = this.completerDiv.clientHeight + 'px';
this.mask.style.display = "block";
}
},
onBlured: function(){
var self = this;
if (this.timer) clearTimeout(this.timer);
this.timer = setTimeout(function(){
self.hideMask();
self.completerDiv.hide();
}, 100);
},
updateField: function(){
this.element.focus();
if(this.listElements.length > 0 && this.index != -1)
this.element.value = this.listElements[this.index].innerHTML.replace(/&/, "&");
this.completerDiv.hide();
this.hideMask();
},
listsShowed: function(){
return this.completerDiv.style.display.toLowerCase() == 'block';
},
onSelectList: function(){
this.listElements.each(function(li){
li.style.backgroundColor = "#fff";
});
this.listElements[this.index].style.backgroundColor = "#ffb";
},
divScrollTop: function() {
var maxScrollTop = this.completerDiv.scrollHeight - this.completerDiv.clientHeight;
var scrollBottom = this.completerDiv.clientHeight + this.completerDiv.scrollTop;
var listHeight = this.listElements[0] ? this.listElements[0].clientHeight : 20;
// TODO , get li.clientHeight after insert li element and then remove it if ul list has no li child.
if (this.index == 0)
this.completerDiv.scrollTop = 0;
else if (this.index == this.listElements.length - 1)
this.completerDiv.scrollTop = maxScrollTop;
else if (this.index * listHeight < this.completerDiv.scrollTop)
this.completerDiv.scrollTop = this.index * listHeight;
else if (this.index * listHeight >= scrollBottom)
this.completerDiv.scrollTop = this.completerDiv.scrollTop + listHeight;
},
markNextList: function(){
this.showMask();
if(this.index < this.counter - 1) this.index++
else this.index = 0;
this.divScrollTop();
this.onSelectList();
},
markPrevList: function(){
this.showMask();
if(this.index > 0 ) this.index--
else this.index = this.counter - 1;
this.divScrollTop();
this.onSelectList();
},
onMouseOverList: function(event){
var elementLI = Event.findElement(event, 'LI');
this.index = this.listElements.indexOf(elementLI);
this.listElements.each(function(li){
li.style.backgroundColor = "#fff";
});
elementLI.style.backgroundColor = "#ffb";
// this.divScrollTop();
},
renderLists: function(event){
switch(event.keyCode) {
case Event.KEY_LEFT:
case Event.KEY_RIGHT:
return;
case Event.KEY_ESC:
this.completerDiv.hide();
this.hideMask();
// esc will also empty input field in ie by default, prevent default event.
Event.stop(event);
this.index = -1;
return;
case Event.KEY_TAB:
case Event.KEY_RETURN:
this.updateField();
Event.stop(event);
return;
case Event.KEY_DOWN:
if (this.listsShowed()) {
this.markNextList();
return;
}
case Event.KEY_UP:
if (this.listsShowed()) {
this.markPrevList();
return;
}
}
if (this.observer) clearTimeout(this.observer);
var self = this;
this.observer = setTimeout(function(){self.onFieldChange(event)}, 100);
},
onFieldChange: function(event){
var value = this.element.value.strip();
var autoWidth = this.element.getWidth();
var find = false;
var listItems = "";
this.counter = 0;
this.index = -1;
var self = this;
if (Prototype.Browser.IE || this.value != value || event.keyCode == Event.KEY_DOWN) {
this.value = value;
this.items.each(function(item){
if (item.include(self.value)) {
self.counter ++;
// li element defaults line-height is different in different browser:
// safari 13px, firefox3 14px
// li width must be set 100% and display block for ie, and ie scrollbar movement has related with li width, sign...
// font size should be little than 14px in ie
listItems += "<li style='line-height:14px;padding:3px;margin:0;display:block;width:100%;cursor:default;'>" + item + "</li>";
if (!find) find = true;
}
});
}
if (find) {
this.list.innerHTML = listItems;
var pos = Position.cumulativeOffset(this.element);
this.completerDiv.style.width = this.mask.style.width = (autoWidth - 2) + "px";
this.completerDiv.style.left = this.mask.style.left = pos[0] + "px";
this.completerDiv.style.top = this.mask.style.top = (pos[1] + this.element.getHeight() - 1) + "px";
this.completerDiv.style.display = "block";
this.listElements = this.list.childElements();
this.addListsObserver();
} else {
this.completerDiv.hide();
this.hideMask();
}
}
});

var af = new AutoFieldFromLocal('message', contacts);
//]]>
</script>
</div>

</body>
</html>

需要注意一下以下几点:
1、在safari/ie中对于arrow keys事件的处理方式和keydown/keypress二者区别。
2、在ie中esc默认行为会将input框中的值一起cancel。
3、在firefox中mouseover事件的控制,在用arrow keys移动选项时,用一个蒙板挡住了mouse,以防触发mouseover事件。
4、setTimeout()方法中的this需要小心其指向全局的window。
5、当y轴出现滚动条时,其实际可以滚动的长度不是element.scrollHeight,而应该是此值减去element.clientHeight。
6、IE中控制滚动条用overflow:auto; overflow-x:hidden;
7、IE中滚动条和LI元素的宽度有关系,要控制滚动条则需要设置LI宽度为100%。
8、对&作特殊处理。

Friday, August 15, 2008

MySQL server_errno=1236 problem and resolution


mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State:
Master_Host: test
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000045
Read_Master_Log_Pos: 78736775
Relay_Log_File: localhost-relay-bin.000032
Relay_Log_Pos: 78736912
Relay_Master_Log_File: mysql-bin.000045
Slave_IO_Running: No
Slave_SQL_Running: Yes
Replicate_Do_DB: search_production,dw_am
Replicate_Ignore_DB: mysql
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 78736775
Relay_Log_Space: 78736912
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: NULL
1 row in set (0.00 sec)

Check mysql error log file, get below error info:
080815 12:13:44 [ERROR] Error reading packet from server: Client requested master to start replication from impossible position ( server_errno=1236)
080815 12:13:44 [ERROR] Got fatal error 1236: 'Client requested master to start replication from impossible position' from master when reading data from binary log
080815 12:13:44 [Note] Slave I/O thread exiting, read up to log 'mysql-bin.000045', position 78736775

Because master bin log file size is 78736164, but slave want to read 78736775, cause mysql 1236 error number, This problem caused by log flush exception.

-rw-rw---- 1 mysql mysql 78736164 Aug 15 10:18 mysql-bin.000045

This problem can be resolved using below method:

mysql> STOP SLAVE;
mysql> CHANGE MASTER TO MASTER_LOG_FILE=[NEXT BIN LOG FILE], MASTER_LOG_POS=98;
mysql> START SLAVE;

[NEXT BIN LOG FILE] is 'mysql-bin.000046' in this problem, MASTER_LOG_POS value is always 98 or 4.

Thursday, August 14, 2008

javascript getTime() shortcut


>>> time1 = (new Date()).getTime(), time2 = +new Date(), time3 = new Date() * 1;
1218645767082
>>> time1
1218645767082
>>> time2
1218645767082
>>> time3
1218645767082

Wednesday, August 13, 2008

javascript get style pixel value in ie6 and ie7


var PIXEL = /^\d+(px)?$/i;
function getPixelValue(element, value) {
if (PIXEL.test(value)) return parseInt(value);
var style = element.style.left;
var runtimeStyle = element.runtimeStyle.left;
element.runtimeStyle.left = element.currentStyle.left;
element.style.left = value || 0;
value = element.style.pixelLeft;
element.style.left = style;
element.runtimeStyle.left = runtimeStyle;
return value;
};

Reference: http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291

Tweak your Object constructor [javascript tips]

注意代码中的变量名和function名的关系,书写一定要分清楚各个变量的词法作用域:
第一种情况,虽然名字相同,但词法作用域不同,不相关系。

function Tweak() { // 这里的Tweak是window的一个全局方法
var Tweak = function() { // 这里的Tweak是一个局部变量名,与window.Tweak不相关
this.init(arguments[0]);
};
Tweak.prototype = { // 局部变量名
args: arguments,
init: function() {
console.log(arguments[0]); //firefox [1, 2] //safari: [object Arguments]
return this;
}
}
return new Tweak(arguments);
}

var t = Tweak(1,2);
console.log(t.args); // [1, 2] // [object Arguments]

第二种是变量名覆写了方法名
// 如果javascript代码如下
var Tweak = Tweak(1, 2); // javascript中的function会先被解析器解析,这里Tweak(1, 2)已经在调用下面的Tweak方法,但此方法调用完成后马上被变量Tweak覆写
function Tweak() {
var Tweak = function() { // 这里的Tweak是一个局部变量名,与window.Tweak不相关
this.init(arguments[0]);
};
Tweak.prototype = { // 局部变量名
args: arguments,
init: function() {
console.log(arguments[0]); //firefox [1, 2] //safari: [object Arguments]
return this;
}
}
return new Tweak(arguments);
}
// Tweak(1, 2); // 这句代码已经执行错误,因为Tweak已经是一个对象,而不是方法了。

第三种是方法名覆写了变量名
// 如果javascript代码如下
var Tweak = {};
Tweak = function () { // Tweak 变量被重新赋为一个function对象
var Tweak = function() { // 这里的Tweak是一个局部变量名,与window.Tweak不相关
this.init(arguments[0]);
};
Tweak.prototype = { // 局部变量名
args: arguments,
init: function() {
console.log(arguments[0]); //firefox [1, 2] //safari: [object Arguments]
return this;
}
}
return new Tweak(arguments);
}
Tweak(1, 2); // 这句代码可以执行

javascript string.replace for XHTML tag


var elem = "<div/><br/><p/>";
elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){ return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ? all : front + "></" + tag + ">"; });

适用于所有浏览器,从script.aculo.us作者Thomas Fuchs一个ppt中看到此代码。

JavaScript Method Overloading


// addMethod - By John Resig (MIT Licensed)
function addMethod(object, name, fn){
var old = object[ name ];
if ( old )
object[ name ] = function(){
if ( fn.length == arguments.length )
return fn.apply( this, arguments );
else if ( typeof old == 'function' )
return old.apply( this, arguments );
};
else
object[ name ] = fn;
}

function Users(){}
addMethod(Users.prototype, "find", function(){
// Find all users...
});
addMethod(Users.prototype, "find", function(name){
// Find a user by name
});
addMethod(Users.prototype, "find", function(first, last){
// Find a user by first and last name
});

var users = new Users();
users.find(); // Finds all
users.find("John"); // Finds users by name
users.find("John", "Resig"); // Finds users by first and last name
users.find("John", "E", "Resig"); // Finds all

Reference: John Resig

java获取本地image file的尺寸大小


import java.awt.Image;
import java.awt.Toolkit;

import javax.swing.ImageIcon;

public class TestImageSize {

public static void main(String[] args) {
String url = "/Users/yu/Pictures/ms_blog_icons.jpg";
Image img = new ImageIcon(url).getImage();
int width = img.getWidth(null);
int height = img.getHeight(null);
System.out.println("Image width: " + width);
System.out.println("Image height: " + height);

Image image = Toolkit.getDefaultToolkit().getImage(url);
int width1 = image.getWidth(null);
int height1 = image.getHeight(null);
System.out.println("Image width1: " + width1);
System.out.println("Image height1: " + height1);
}
}

用CSS中的overflow 控制表格单元格文字的显示长度

对于td中包含中英文,需要将超长部分隐藏,用js控制是最方便的,也可以用CSS的overflow:hidden进行控制,这个对于二字节的字符显示支持不够友好些。

javascript 闭包妙用

在javascript中,程序是一行行执行的,在上一行返回结果后执行下一行的语句。如果在执行一条要耗时的操作,而接下来的程序操作与此条执行语句并无关系,则可将此语句放在一个闭包里去执行,用setTimeout(function(){}, 0)来激活此闭包运行,这个技巧可用于加速页面渲染,同时对多个dom对象操作。


<html>
<head>
<title>Yield demo</title>
<script type="text/javascript">
<!--
function doSave(id, doYield) {
document.getElementById(id).innerHTML = '<span style="font-style: italic;">Saving...</span>';
if (doYield) {
var startTime = (new Date()).getTime();
setTimeout(function() { doSaveImpl(id); }, 0); // runing in clousres
var endTime = (new Date()).getTime();
alert("yield time is:" + (endTime - startTime));
} else {
var startTime = (new Date()).getTime();
doSaveImpl(id);
var endTime = (new Date()).getTime();
alert(endTime - startTime); // firebug console.log()
}
}
function doSaveImpl(id) {
var numIters = 10000000;
for (var i = 0; i < numIters; i++) {
var j = Math.sqrt(i); // slow operation
}

document.getElementById(id).innerHTML = '<span style="color: #090">Saved!</span>';

setTimeout(function() { reset(id); }, 3000);
}
function reset(id) {
document.getElementById(id).innerHTML = 'Ready';
}
//-->
</script>
<style type="text/css">
.button {
border: 1px solid black;
background: #ffff9f;
padding: 5px;
font-size: 14pt;
color: black;
text-decoration: none;
-moz-border-radius: 8;
}
.status_msg {
color: #999;
margin-top: 0.5em;
font-size: 18pt;
}
</style>
</head>
<body>

<h1>Yield Demo</h1>

<h2>Without yielding:</h2>

<a href="javascript:;" onclick="doSave('noyield', false); return false;" class="button">Save</a>
<div id="noyield" class="status_msg">Ready</div>

<h2>With yielding:</h2>

<a href="javascript:;" onmousedown="doSave('yield', true); return false;" class="button">Save</a>
<div id="yield" class="status_msg">Ready</div>

</body>
</html>

Reference: http://josephsmarr.com/oscon-js/yield.html

Tuesday, August 12, 2008

解决IE6的浮动元素的双倍边距问题

对一个div设置了float:left 和 margin-left:100px 那么在IE6中,这个bug就会出现。您只需要多设置一个display即可,代码如下:


div {float:left;margin:40px;display:inline;}

Reference:http://www.javaeye.com/news/3176

Monday, August 11, 2008

Tapestry5 ComponentSource/ComponentResourcesCommon/ComponentResources/ComponentClassResolver Relationship

当知道某个组件的完整的id或者是页面的名字,就可以用ComponentSource接口的getComponent(String completeId)和getPage(String pageName)方法来获取相应的组件。
如组件名为Layout,页面为Start,则组件的completeId是Start:Layout,用getComponent("Start:Layout")来获得此Layout对象。getPage("Start")获取start页面。
其中的二个参数pageName和completeId,则可以能过ComponentResources接口提供的方法来获取,getPage()方法可以获取包含此组件的页面Page对象,ComponentResources从ComponentResourcesCommon接口继承到的方法getCompleteId()方法则可以获取mypage:foo.bar.baz形式的完整的id。另外ComponentResources接口中有很多方法比较有用,如getContainer()方法可以获取是哪个组件包含了此组件,还有createActionLink/createPageLink/getAnnotationProvider/getMessages等获取页面资源的方法。
对于获取到的pageName,可以利用ComponentClassResolver接口中提供的isPageName()方法来检查是否为pageName,另此接口也提供了另外几个操作page相关的几个方法,如resolvePageNameToClassName、resolvePageClassNameToPageName、canonicalizePageName、resolveComponentTypeToClassName等。

Integrate table with tooltip based prototype

var Tooltip = Class.create();
Tooltip.prototype = {
initialize: function(element, cid) {
var options = Object.extend({
defaultCss: true,
margin: "0px",
padding: "5px",
backgroundColor: "#FBFBF3",
border: "#EAE6C4 1px solid",
width: "300px",
deltaX: 5,
deltaY: 5,
zindex: 1000,
opacity: 0.8
}, arguments[2] || {});
this.options = options;
this.element = element;

var tooltipContent = arguments[3] || Table.cells[cid] || " ";
new Insertion.Bottom(this.element,
"<div id='" + cid + "' style='display:none;word-break:break-all;width:" + this.options.width + "'>" + tooltipContent + "</div>");
this.tooltip = $(cid);

this.displayEvent = this.showTooltip.bindAsEventListener(this);
this.hideEvent = this.hideTooltip.bindAsEventListener(this);
this.registerEvents();
},

registerEvents: function() {
Event.observe(this.element, "mouseover", this.displayEvent);
Event.observe(this.element, "mouseout", this.hideEvent);
},

showTooltip: function(event){
Event.stop(event);
var mouseX = Event.pointerX(event);
var mouseY = Event.pointerY(event) + this.options.deltaY;
var halfWidth = this.getBodyWidth() / 2;
if (mouseX > halfWidth) {
mouseX -= this.tooltip.getWidth() + this.options.deltaX;
} else {
mouseX += this.options.deltaX;
}

this.setStyles(mouseX, mouseY);
new Element.show(this.tooltip);
},

setStyles: function(x, y) {
Element.setStyle(this.tooltip, {
position: 'absolute',
top: y + "px",
left: x + "px",
zindex: this.options.zindex
});

if (this.options.defaultCss){
Element.setStyle(this.tooltip, {
margin: this.options.margin,
padding: this.options.padding,
backgroundColor: this.options.backgroundColor,
zindex: this.options.zindex,
border: this.options.border,
width: this.options.width,
opacity: this.options.opacity,
filter: 'alpha(opacity=' + this.options.opacity * 100 + ')'
});
}
},

hideTooltip: function(event){
new Element.hide(this.tooltip);
},

getBodyWidth: function(){
return document.body.clientWidth;
}

}


var Table = {
rowEvenClass: 'roweven',
rowOddClass: 'rowodd',
rawCellContent: true,
heads: {},
rows: {},
cells: {},
getBodyRows: function(table) {
var table = $(table);
var id = table.id ? table.id : table.id = "table" + $$("table").indexOf(table);
if(!Table.rows[id] && table.tBodies[0]) {
Table.rows[id] = (table.tHead && table.tHead.rows.length > 0) ? $A(table.tBodies[0].rows): $A(table.tBodies[0].rows);
}
return Table.rows[id] || [];
},
getHeadCells: function(table) {
var table = $(table);
var id = table.id ||
var id = table.id ? table.id : table.id = "table" + $$("table").indexOf(table);
if(!Table.heads[id]) {
Table.heads[id] = $A((table.tHead && table.tHead.rows.length > 0) ? table.tHead.rows[table.tHead.rows.length-1].cells: table.rows[0].cells);
}
return Table.heads[id];
},
getCellIndex: function(cell) {
var cell = $(cell);
return $A(cell.parentNode.cells).indexOf(cell);
},
getRowIndex: function(row) {
var row = $(row);
return $A(row.parentNode.rows).indexOf(row);
},
getCellText: function(cell) {
if(!cell) { return ""; }
var cell = $(cell);
textContent = cell.textContent ? cell.textContent: cell.innerText;
return textContent;
}
}

Table.Rows = {
stripe: function(table) {
var table = $(table);
var rows = Table.getBodyRows(table);
rows.each(function(row, index) {
Table.Rows.addStripeClass(table, row, index);
Table.Rows.truncateCells(table, row, index);
});
},
addStripeClass: function(table, row, index) {
table = table || row.up('table');
var css = ((index + 1) % 2 === 0 ? Table.rowEvenClass: Table.rowOddClass);
var cn = row.className.split(/\s+/);
var newCn = [];
for(var x = 0, l = cn.length; x < l; x ++) {
if(cn[x] !== Table.rowEvenClass && cn[x] !== Table.rowOddClass) { newCn.push(cn[x]); }
}
newCn.push(css);
row.className = newCn.join(" ");
},
truncateCells: function(table, row, rowIndex) {
table = table || row.up('table');
$A(row.cells).each(function(cell, cellIndex) {
var cid = table.id + "_row" + rowIndex + "_col" + cellIndex;
var cidTruncated = cid + "_truncated";
if (Table.rawCellContent) {
Table.cells[cid] = cell.innerHTML;
} else {
Table.cells[cid] = Table.getCellText(cell);
}
Table.cells[cidTruncated] = false;
try {
Table.Cells.truncateTextNodes(cell, cidTruncated);
} catch (e) {
// ignore
}
if (Table.cells[cidTruncated]) new Tooltip(cell, cid);
});
}
};

Table.Cells = {
truncate: function(node, cidTruncated) {
var nodeData = node.data;
if (/[\u4e00-\u9fa5]/.test(nodeData)) {
if (nodeData.strip().length > 20) {
node.data = nodeData.truncate(20);
if (!Table.cells[cidTruncated]) Table.cells[cidTruncated] = true;
}
} else {
if (nodeData.length > 40) {
node.data = nodeData.truncate(40);
if (!Table.cells[cidTruncated]) Table.cells[cidTruncated] = true;
}
}
},
truncateTextNodes: function(cell, cidTruncated) {
$A(cell.childNodes).each(function(node){
if (node.nodeType == 3) {
Table.Cells.truncate(node, cidTruncated);
} else if (node.nodeType == 1 && ["select", "script", "embed", "object", "textarea", "table", "iframe"].include(node.tagName.toLowerCase())) {
Table.cells[cidTruncated] = false;
throw new SyntaxError("Do not truncate " + node.tagName);
} else {
Table.Cells.truncateTextNodes(node, cidTruncated);
}
});
}
}

Table.load = function() {
$$("table").each(function(table){
Table.Rows.stripe(table);
});
}

Event.observe(window, 'load', Table.load);

Reference:
http://www.millstream.com.au/view/code/tablekit/
http://tooltip.crtx.org/

Tapestry5 ASO/ApplicationStateManager/ApplicationStatePersistenceStrategy/ApplicationStateCreator Relationship

ApplicationStateManager接口中定义了get/set一个ASO对象的方法。而ASO对象实际的存储管理则会使用ApplicationStatePersistenceStrategy这个接口实现,这个接口中同样有ASO对象的get/set方法,可以操作ASO,通过set其为null从而删除此ASO对象,在get某个ASO对象,如果此对象不存在则会调用ApplicationStateCreator接口create()方法创建此ASO对象。

Friday, August 08, 2008

element.style.display in firefox3

在mac firefox3中element.style.display = "" 与 element.style.display = "none"一样,如果需要显示此element,则需要用element.style.display = "block"

scope of javascript anonymous function


var foo = "test in global window";
function Constructor() {
this.foo = 'test in Constructor';
this.local = (function() {
alert(this.foo);
return "local";
}).apply(this);
this.globals = (function(){
alert(this.foo);
return "global";
})();
}
new Constructor();

In javascript, scope of anonymous functions is global.
匿名函数中的作用对象是全局的window对象,一般是不需要注意这点,但当在匿名函数中使用使用this就要小心,这个this是指向window的,如上所示可以用apply或者call来指定匿名函数作用于哪个对象上,但匿名函数如果在setTimeout/setInterval中使用的话则需要将this对象用别名如_self/self/_this/that替代后在匿名方法中使用,如下面二个参考文章所示。
Reference:http://yuweijun.blogspot.com/2008/05/test-scope-of-this-in-closure-and-in.html
http://www.dustindiaz.com/scoping-anonymous-functions/

Friday, August 01, 2008

component mixins 说明

component mixins 是将一个特定的组件(一般位于mixins文件夹中,多数是跟js/ajax相关,用于控制组件行为)跟另一个普通组件(位于components文件夹下)集成在一起,形成一个具有二者全部功能的组件。
component mixins 也跟普通组件相似,可以有自己的参数parameters,当它跟普通组件components中定义的参数发生冲突时,以普通组件定义的参数为准。


components:
public class Area {
@Parameter(defaultPrefix = "literal", value = "300")
private String _height;

@Parameter(defaultPrefix = "literal", value = "300")
private String _width;

@Parameter(defaultPrefix = "literal", value = "px")
private String _unit;
}
mixin:
public class EventMixin
{
@Parameter(required = true, defaultPrefix = "literal")
private String event;

@Parameter(defaultPrefix = "literal", value = "pt")
private String _unit;

public String getEventName()
{
return event;
}
}
using in template:
<t:area t:mixins="eventmixin" t:height="200" t:event="click"/>

例子中mixin和component中都有一个叫unit的参数,以component的参数为准,area组件集成了eventmixin,由于其evnet参数是必须提供的,所以在模板中area组件中要提供此参数。