読み込んでいます...

不知道看到这篇文章的各位朋友们有没有用过遨游,遨游有一个很好的特性,并且这个特性是我特别喜欢的,就是鼠标手势,比如打开一个链接,直接把鼠标点到超链接上,然后按住拖动,就可以在一个新窗口中打开点的链接,这样就非常的快的打开链接,而不用按鼠标中键或者按ctrl然后点一下才打开链接,所以这是我特别喜欢的功能。

搜了一下,看了Firefox好像没有这样的功能,而有这样功能的几个插件都没有我想定制的特性(比如鼠标手势,从左到右移动鼠标就是返回),所以我决定自己写一个。

在Firefox中,浏览器可以添加事件,并添加属性,这些事件分别为draggesture,ondragover,ondragdrop,ondragexit,这四个事件分别对应的几个nsDragAndDrop对象(这是一个XPCOM对象)的几个事件,分别为startDrag,dragOver,drop和,dragExit四个事件,所以我们编写以下代码。

var DragUrLink =
{
    OnMainLoad: function(){
        
try
        {
            getBrowser().addEventListener(
draggesture,
                         function(
event) {nsDragAndDrop.startDrag(event, DragObserver);} , true);
            getBrowser().setAttribute(
ondragover,
                        
nsDragAndDrop.dragOver(event, DragObserver));
            getBrowser().setAttribute(
ondragdrop,
                        
nsDragAndDrop.drop(event, DragObserver));
            getBrowser().setAttribute(
ondragexit,
                         ‘
nsDragAndDrop.dragExit(event, DragObserver));
        }
        
catch(e)
        {
          
//alert(e)
        }
    }
};

上面的代码可以添加事件,也可以添加属性,反正对象getBrowser(同gBrowser),所以起到的效果是一样的。在nsDragAndDrop对象的几个方法中,传递的参数都是event和一个类(如果javascript里面可以说成是类的话)或者对象,这些对象里面都要重写(如果可以叫重写的话)一些方法,而且这些方法是固定的,基本上玩不出什么花样,所以这里我就写了一个接口,提供给大家使用,如果你需要响应Drag和Drop方法的话,可以尝试用下面的代码。

//Copyright GuoJing http://www.jguoer.com
//
如果不会可以直接Copy
var DragObserver = {
    Cc : Components.classes,
    url:
"",
    isend:
1,
    times:
0,
    onDragStart:
function(e, aXferData, dragAction){
        
//拖动事件开始时
        this.isend = 0;
    },

    onDragOver: function(e, aFlavour, aDragSession){
        
//拖动事件执行时
        var transData = DragObserver
                        .getTransferData(aFlavour.contentType, aDragSession);
        
if(transData.dataObj.value){
            
var DataObj = transData.dataObj.value
                        .QueryInterface(Components.interfaces.nsISupportsString);
            
var sourceUri = DataObj.data.substring(0, transData.len.value);
            
//拖动的数据是以\n分割
            var DragData = sourceUri.split("\n");
            
//获取拖动的数据
            this.url = DragData[0];
        }
    },

    onDrop: function (e, aDropData, aDragSession){
    },

    unInit: function(){
    },

    onDragExit: function(e, aDragSession){
      
//当结束拖动时发生
        if(this.isend == 0)
        {
            DragObserver.reload();
        }
      
//设置flag为1,那么下次结束拖动时就不会再操作了
       //这里值得注意的是,一次拖动时会响应多次拖动结束事件
        this.isend = 1;
    },

    reload:function()
    {
        
//这里是结束时发生一次的方法
        //if(DragObserver.IsContain(this.url,’http://’))
        //{
            //gBrowser.addTab(this.url);
        //}
        //openUILink("http://www.jguoer.com", null, false, true);
        alert(this.url);
    },

    checkSession : function(){
    },

    canDrop : function(e, aDragSession){
    },

    getSupportedFlavours: function (){
      
//设置数据对象
       var flavourSet = new FlavourSet();
       flavourSet.appendFlavour(
"text/x-moz-url");
       flavourSet.appendFlavour(
"application/x-moz-file", "nsIFile");
       flavourSet.appendFlavour(
"text/unicode");
           flavourSet.appendFlavour(
"text/html");
      
return flavourSet;
    },

    getTransferData : function(aContentType, aDragSession){
     
//这里是获取拖动的数据,具体可以查nsITransferable接口
      var transfer = this.Cc["@mozilla.org/widget/transferable;1"].
                createInstance(Components.interfaces.nsITransferable);
      transfer.addDataFlavor(aContentType);
      aDragSession.getData (transfer,
0);
      
var Data = {};
      Data.dataObj
= new Object();
      Data.len
= new Object();
      
try{
        transfer.getTransferData(aContentType, Data.dataObj, Data.len);
      }
catch (ex) {}
      
return Data;
    },

    IsContain:function(str,para)
    {
        
var regex=new RegExp(para, g).exec(str);
        
if(regex)
        {
            
//if the string contain the para
            return true;
        }
        
else
        {
            
return false;
        }
    }
}

上述代码就实现了响应拖动的事件,看上去是不是很复杂很麻烦,其实确实很复杂很麻烦,我也是查了很多资料才知道要这么写的,注意其中一些方法是系统内部彼此调用的,感觉很像重写或者重载的感觉,所以虽然你不知道这个是怎么执行的,但是必须这么写。

其中有一些方法,这里我就不列举了,例如onDragStart,可以不写,但是不写就不会响应,还有名字和参数最好也要写成一致的。因为当浏览器响应的时候,会自动传递这些参数以便在浏览器钟使用或进行转换。这些事件响应过程分别为,开始拖动=》canDrop=》获取传递的数据=》过滤数据(getSupportedFlavours)=》onDragOver=》查看会话=》onDragExit,当然,这些步骤并不会响应一次,在移动的时候可能会响应多次。

看到这里,你应该觉得一个小小的功能实现起来太麻烦了,好在Firefox 3.5提供了更好的API,可以直接响应DragEnd方法,示例代码如下所示。

OnMainLoad: function(){
    
try
    {
        getBrowser().setAttribute(
ondragend, DragUrLink.DoSomeThing(event));
    }
    
catch(e)
    {
       
//出错处理
    }
},

DoSomeThing:function(event)
{
    
//执行响应的事件
}

是不是非常简单?所以赶快升级到3.5吧,3.5的API和HTML5的支持更上一层楼了。

OK,最后,如果你还不能理解,就制作一个3.5的程序,如果你能搞定老的API的拖动效果,那么祝贺你,你比我强多了:),因为老的虽然可以实现,但是实现的太复杂了,用了好多类,所以我还是决定只支持3.5。

示例

385路过 5评论 Firefox Addon 阅读全文..
  1. 诡异的西红柿 @

    @chanseat
    So I think 3.5 it’s better now!

  2. chanseat @

    It’s so complicate!

  3. Meta @

    lol ,thx.

  4. 诡异的西红柿 @

    @Meta
    what the hell man..?

  5. 置顶的更新 : GuoJing's Blog | 用心对待每一行代码 @

    [...] Firefox Add-on – Drag and Drop [...]

:-D :-? 8) :cry: 8-O :lol: :-x :-| :?: :-P :oops: :roll: :( :) :-o :wink: more »