IE6设置Image.src的bug

这个问题我现在也没彻底搞懂。网站有一块需要建立一个Image对象,设置好src属性,onerror和onload属性,然后把Image添加为div的子元素,交给浏览器去请求图片并渲染(请看p.s.)。用其他浏览器都很正常,但用IE6浏览器访问,虽然能得到图片,但服务器的日志里会报错,第一个Exception是Connection reset by peer,第二个是多次调用response.getOutputStream()或getJspWriter()。
上了调试器,发现一次图片的调用,服务器会在入口函数的断点停留两次,说明浏览器发出了两次请求。用Fiddler看各次请求的内容,居然再也无法重现错误了。换用HttpWatch,终于重现了错误。每次图片的调用都会有两个请求,第一个请求发出后马上被掐掉(Aborted),然后接着发出第二个请求。这解释了为什么会抛Connection reset by peer的异常。第二个异常的原因,估计是当浏览器的reset请求到达服务器时,服务器的代码已经完成了生成图片的工作,并把图片塞进了response,这个时候抛来一个异常,被forward到error.jsp,于是乎二次调用了getJspWriter,报错。
网上搜了搜这个问题,有少许提到这个bug。我的解决方法很简单,就是在image append到div之后,再设置src属性。经测试解决了IE6的Aborted问题,其他浏览器,如IE7,FF3和Chrome都没什么影响。
p.s. 后来看到玉伯的博客,发现Image对象在设置了src对象以后就马上请求图片,并不等到被添加到DOM上再请求,因为Image本来就是用来做图像预加载的。所以原本的代码就有一些错误,应该先设置onerror和onload属性后,再设置src才有意义。
p.s.2 这里是一篇描述了IE中Aborted的文章,推翻了不少本文的无妄猜测。
p.s.3 经我第三次的测试,发现IE6中如果先设置image.src在appendChild,会出现Aborted问题,相反顺序则没有问题。

“Internet Explorer 无法打开 Internet站点已终止操作”问题

    以前偶尔被这个问题困扰,总是不知不觉就解决了,这次留个记录。

    先贴个Reference

    症状:打开页面,渲染到一半,弹出对话框,内容如题。点击确定后转到IE自己的错误页面,一点错误信息都没有。Google一番后,得出几个可能性:1、Debugger插件作怪;2、Javascript引号没匹配好;3、在页面渲染期间进行了insertChild操作。

    首先禁用所有调试插件,并设置禁用调试。无效。调出Multiple IE用IE6访问,问题依旧,排除第一条。

    第二人肉扫描代码,没发现问题。Firefox和Chrome页面均正常,基本排除第二条。

    第三条就看Ext.onReady()的位置了,发现了问题。在代码的最后用Ext.onReady()包裹了grid的render调用,但这不够。需要把整个grid的创建过程给embrace(不知道中文用啥好)起来,因为在GridPanel的constructor里就开始渲染了(没有设置lazy-render)。

JavaScript高级程序设计读书笔记(二)

终于有一本书的读书笔记写到第二篇了,呵呵~~不过这本书的第一篇读书笔记更像是速记的内容:)
1. Javascript只有public作用域,没有private,更不用说protected,另外也没有静态方法。
2. this指向的是调用该方法的对象
    obj.color = “red”;
    obj.show = function(){
       alert(this.color);    //output “red”
    }
3. 定义类的几种方法(略去最后一种,根本没看懂,而且说非常不推荐这种做法)
(1) Factory
function showColor(){
    alert(this.color);
}
function createCar(color, doors, mpg){
    var temp = new Object;
    temp.color = color;
    temp.doors = doors;
    temp.mpg = mpg;
    temp.showColor = showColor;
}

var car = createCar(“red”, 4, 23);
缺点:没有共享函数。不同的实例间可能有不同的函数调用。可以改变一个对象的函数绑定。不用new构造,不像是类(当然,只是不像)。
(2) Constructor
function Car(color, doors, mpg){
    this.color = color;
    this.doors = doors;
    this.mpg = mpg;
    this.showColor = function(){
       alert(this.color);
    }
}

var car = new Car(“red”, 4, 23);
优点:用new构造
缺点:同工厂的第一点。
(3)Prototype
function Car(){}
Car.prototype.color = “red”;
Car.prototype.doors = 4;
Car.prototype.mpg = 23;
Car.prototype.showColro = function(){
    alert(this.color);
}

var car = new Car();
优点:函数真正共享,不会出现不同实例之间使用不同函数的情况(指的是同一函数名的情况下,同时Javascript里不存在函数重载)。可以使用car instanceof Car
缺点:显而易见,函数共享的同时把属性也共享了,没什么比这个更糟糕的了。
(4) Mixed Constructor/Prototype
function Car(color, doors, mpg){
    this.color = color;
    this.doors = doors;
    this.mpg = mpg;
}
Car.prototype.showColor = function(){
    alert(this.color);
}

var car = new Car(“red”, 4, 23);
优点:函数真正共享,但不共享属性。不过我发现可以把属性加入prototype来实现静态的属性。也可以使用car instanceof Car
(5) Dymanic Prototype
function Car(color, doors, mpg){
    …
    if(typeof Car._initialized == “undefined”){
       Car.prototype.showColor = function(){
          alert(this.color);
        }
    Car._initialized = true;
    }
}
这个更大的进步就在于,函数的创建只有一次了。
4. 一个StringBuffer实例,通过Array.join()来实现append()。同时还有实现Array.indexOf()方法(这个Prototype.js里也有的)。前面一个用的是构造类,后面用的是prototype

FCKEdtior初步集成

我使用的是Javascript版本+Java的。主要用Javascript, Java的只是用来参考一下源代码。
1. 拷贝文件,主要是js包里的,根目录下fckeditor.js, fckconfig.js, fckstyles.js, fcktemplates.js以及editor目录拷贝到web应用下。拷贝到哪里与以后要设置的BasePath有关系。
2. 显示代码: 在页面里包含 fckeditor.js。然后写这一段:
<script type=”text/javascript”>
var oFCKeditor = new FCKeditor(‘content’) ;
oFCKeditor.BasePath = “fckeditor/” ;
oFCKeditor.Height = 600;
oFCKeditor.ToolbarSet = “Default” ;
oFCKeditor.Value = ”;
oFCKeditor.Create();
</script>
最主要是BasePath的设置。比如你把fckeditor.js放在了http://localhost:8080/test/fckeditor/fckeditor.js,你的调用文件在http://localhost:8080/test下,你就把BasePath设成”fckeditro/”(后面要跟’/’)
3. 上传文件的设置:
(1)修改fckconfig.js里的最后几部分,如LinkUploadURL, ImageUploadURL, FlashUploadURL,改成你上传文件的地址。不管那些什么Language了。
(2)修改editor/filemanager/browser/default/frmupload.html,把那个form的action改成上传的地址。这个不知道为什么,我是找了好久才找到的。
(3)编写upload servlet。参考Java包里的那个ConnectorServlet里的doPost()方法。 主要是返回值要设对。

javascript高级程序设计读书笔记(一)

上“人机交互”课上时记的一些东西,留下来备忘。上次那个JVM书的读书笔记真的只有一篇了,因为只能在IBM里才能看到,呵呵~~
1. isFinit(Number) 判断数字是不是无穷大, isNan(..)判断是不是数字
2. parseInt(String, int), 可以解析各种进制的整数
3. Nan != NaN, typeof(null) == “object”
4. Stirng.charCodeAt(int)
5. String.slice()基本上等于String.substring,不同的是substring(3, -4) == substring(3),对于负数,substring是忽略的。
6. ===, !==
7. Array.push(), Array.pop(), Array.shift(), Array.unshift()
8. Array.splice(),可以插入、替换、删除数组中的元素
9. Global对象,很大部分全局函数是Global对象的属性
10. encodeURI(), encodeURIComponent()

javascript获取textarea光标选择位置和内容方法(IE, Firefox)

在网上用baidu找了很久,找到的都是IE的方法,Firefox都不能用。 而且很多要用到<textarea>.focus()方法,用起来很不方便。
后来转用Google,搜了下”textarea cursor”,第一个就有好方法。我根据最后一个家伙的comments,写了一个sample,应该还是挺好用的。
原文地址:http://weblogs.asp.net/skillet/archive/2005/03/24/395838.aspx
<html>
<head>
<title>TEST</title>
<style>
body,td{
font-family: verdana, arial, helvetica, sans-serif;
font-size: 12px;
}
</style>
<script type=”text/javascript”>
var start=0;
var end=0;
function add(){
var textBox = document.getElementById(“ta”);
var pre = textBox.value.substr(0, start);
var post = textBox.value.substr(end);
textBox.value = pre + document.getElementById(“inputtext”).value + post;
}
function savePos(textBox){
//如果是Firefox(1.5)的话,方法很简单
if(typeof(textBox.selectionStart) == “number”){
start = textBox.selectionStart;
end = textBox.selectionEnd;
}
//下面是IE(6.0)的方法,麻烦得很,还要计算上’\n’
else if(document.selection){
var range = document.selection.createRange();
if(range.parentElement().id == textBox.id){
// create a selection of the whole textarea
var range_all = document.body.createTextRange();
range_all.moveToElementText(textBox);
//两个range,一个是已经选择的text(range),一个是整个textarea(range_all)
//range_all.compareEndPoints()比较两个端点,如果range_all比range更往左(further to the left),则                //返回小于0的值,则range_all往右移一点,直到两个range的start相同。
// calculate selection start point by moving beginning of range_all to beginning of range
for (start=0; range_all.compareEndPoints(“StartToStart”, range) < 0; start++)
range_all.moveStart(‘character’, 1);
// get number of line breaks from textarea start to selection start and add them to start
// 计算一下\n
for (var i = 0; i <= start; i ++){
if (textBox.value.charAt(i) == ‘\n’)
start++;
}
// create a selection of the whole textarea
var range_all = document.body.createTextRange();
range_all.moveToElementText(textBox);
// calculate selection end point by moving beginning of range_all to end of range
for (end = 0; range_all.compareEndPoints(‘StartToEnd’, range) < 0; end ++)
range_all.moveStart(‘character’, 1);
// get number of line breaks from textarea start to selection end and add them to end
for (var i = 0; i <= end; i ++){
if (textBox.value.charAt(i) == ‘\n’)
end ++;
}
}
}
document.getElementById(“start”).value = start;
document.getElementById(“end”).value = end;
}
</script>
</head>
<body>
<form action=”a.cgi”>
<table border=”1″ cellspacing=”0″ cellpadding=”0″>
<tr>
<td>start: <input type=”text” id=”start” size=”3″/></td>
<td>end: <input type=”text” id=”end” size=”3″/></td>
</tr>
<tr>
<td colspan=”2″>
<textarea id=”ta” onKeydown=”savePos(this)”
onKeyup=”savePos(this)”
onmousedown=”savePos(this)”
onmouseup=”savePos(this)”
onfocus=”savePos(this)”
rows=”14″ cols=”50″></textarea>
</td>
</tr>
<tr>
<td><input type=”text” id=”inputtext” /></td>
<td><input type=”button” onClick=”add()” value=”Add Text”/></td>
</tr>
</table>
</form>
</body>
</html>