Firefox扩展插件开发笔记(二) - 编写内嵌js脚本代码

google连不上,我的翻译插件不能用了,找了很久又没有找到其他的替代品,就像着自己能不能做一个利用baudi API的翻版,另外考虑到一些加强功能,可以对选中的文本进行wiki查询并显示wiki的结果。于是开始开发准备。明确下想法,首先打开网页时,将自己写的一个脚本(content.js)嵌入到网页中,该脚本产生一个隐藏的按钮和面板,并监听鼠标的抬起事件,当抬起并有选中文本的时候,将悬浮按钮显示,点击按钮时,获取选中的文本内容,发送翻译请求到baidu 翻译或者请求wiki页面,回传,将内容显示在面板中,搞定!

导航目录

  1. Javascript选取文本
  2. 构建Add-on代码,注入脚本到页面中

我自己做程序的时候都喜欢先把各个环节具体的做法确定下来,特别是一些关键的需要考虑的地方,这个扩展主要有以下几个考虑的地方:1.如何利用javascript获取选中文本(之前真不懂)2.如何发送翻译请求 3.如何搞定面板的显示布局。一步步来,这里先解决第一个问题

js如何选取文本

网上查了一下解决方案,在Firefox, Google Chrome, Safari, Opera中,可以用 window.getSelection(),而在在IE下,可以用 document.selection.createRange().text,我们只需要前者。

    //获取选择文本内容
    function getSelecctTxt() {
        console.log(window.getSelection());
        return window.getSelection() .toString();
    }

判断是否有选取的文本,其中的my-ad-btn就是我在js中生成的隐藏按钮div的id

    $('body') .mouseup(setHandler);
    //判断是否选取文字,处理鼠标抬起事件,显示按钮
    function setHandler(ev) {
        $('#my-add-btn') .css(
            'display','none'
        );

        ev = ev || window.event;
        if (getSelecctTxt() == '' || ev.which != 1) {
            isShow = false;
            $('.content-div').hide();
            return ;
        }
        alert("up");
        $('#my-add-btn') .css({
            top: ev.pageY + 9,
            left: ev.pageX + 9,
            display: 'inline-block',
            lineHeight: '18px'
        });
        //alert(getSelectTxt());
    }

接着再在监听按扭事件,本来想发请求到media-wiki获取wiki的json数据然后显示的,结果看了一晚上的英文API使用手册,最后终于明白如何获得对特定单词的wiki解释数据,但一看数据还需要写代码解析wiki语法规则,表示太懒了于是暴力内嵌了一个iframe直接加载对应解释的网页。
代码中wikiframe是显示wiki页面的iframe的id,trans-div是显示翻译结果的div(以后获得了的翻译结果就放在这个div里显示)的id。准备把这两个结果页面做成选项卡的样子,可以切换查看翻译结果或者wiki页面,这里先注释掉。

    //绑定点击按钮事件
    $('#my-add-btn') .click(function (e) {
        $('#my-add-btn') .css({
            display: 'none'
        });

        //$('#wikiframe').attr('src','https://en.wikipedia.org/w/index.php?useformat=mobile&title=firefox');
        //$('.content-div') .show();
        //isShow = true;
        //$('#wikiframe').css('height','0px');
        var str = getSelecctTxt();
        $('#trans-div').text(getSelecctTxt());
          console.log("selecttext:"+getSelecctTxt());
        return false;
    });

另外当用户选择的是一个词的时候将翻译成详细的词典解释,也就是需要发送请求到百度词典API,句子的话发送请求百度翻译API,这里使用正则表达式进行判断:

    //绑定点击按钮事件
    $('#my-add-btn') .click(function (e) {
        $('#my-add-btn') .css({
            display: 'none'
        });

        //$('#wikiframe').attr('src','https://en.wikipedia.org/w/index.php?useformat=mobile&title=firefox');
        //$('.content-div') .show();
        //isShow = true;
        //$('#wikiframe').css('height','0px');
        var str = getSelecctTxt();
        if(-1==(str.search(/^\s?([a-zA-Z-]{1,20}|[\u4E00-\u9FA5]{1,4})\s?$/i))){
            alert(str+" =不是单词");
        }else{
           alert(str+"=单词");
        }
        $('#trans-div').text(getSelecctTxt());
          console.log("selecttext:"+getSelecctTxt());
        return false;
    });

代码再整合一下,变成下面的样子(请忽视那一大块乱码,那是图片的base64编码):

var imageurl = 'url("data:image/gif;base64,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")';

/*判断脚本是否在frame中执行*/

if (window != top || (self.frameElement && self.frameElement.tagName == 'IFRAME')) {
    $('html,body').scrollTop(80);
    //alert('scroll');
    return ;
 }
 
 //获取选择文本内容
 function getSelecctTxt() {
    var ll = window.getSelection().toString();
    //console.err("df");
    //alert('uu');
    return window.getSelection().toString();
 }

 //添加悬浮按钮与相应CSS
 function showAddBtn() {
    $('body') .append('<a id="my-add-btn" name="my-add-btn" href="#my-add-btn"></a>');
    $('#my-add-btn') .css({
            display: 'none',
            height: '18px',
            width: '18px',
            position: 'absolute',
            zIndex: '2147483647',
            textAlign: 'center',
            lineHeight: '18px',
            textDecoration: 'none',
            font: 'bold 12px/25px Arial, sans-serif',
            color: 'rgba(62, 87, 6, 0.53)',
            background: '-moz-linear-gradient(center top , rgba(165, 205, 78, 1) 0%, rgba(107, 143, 26, 1) 100%)',
            backgroundImage: imageurl,
            backgroundSize: '18px 18px',
            opacity: '0.55',
            textShadow: '1px 1px 1px rgba(255,255,255, .22)',
            borderRadius: '18px',
            boxShadow: '1px 1px 1px rgba(0,0,0, .2), inset 1px 1px 1px rgba(255,255,255, .3)',
            transition: 'all 0.15s ease'
    });
    $('#my-add-btn') .hover(function () {
        $(this) .css({
                color: 'rgba(62, 87, 6, 1)',
                opacity: '1'
        });
        }, function () {
           $(this) .css({
                    color: 'rgba(62, 87, 6, 0.53)',
                    opacity: '0.55'
            });
        }
     );
        //如果点击在按钮上,阻止mouseup事件传播

     $('#my-add-btn') .mouseup(function (e) {
        return false
     });
  }

    /**************弹出框***************/
   //TO-DO

    showAddBtn();
    //绑定点击按钮事件
    $('#my-add-btn') .click(function (e) {
        $('#my-add-btn') .css({
            display: 'none'
        });
        var str = getSelecctTxt();
        if(-1==(str.search(/^@([a-zA-Z\u4E00-\u9FA5]{3,10}):/i))){
            alert(str+" =不是单词");
        }else{
           alert(str+"=单词");
        }
        $('#trans-div').text(getSelecctTxt());
        return false;
    });

    //判断是否选取文字,处理鼠标抬起事件,显示按钮
    function setHandler(ev) {
        $('#my-add-btn') .css(
            'display','none'
        );

        ev = ev || window.event;
        if (getSelecctTxt() == '' || ev.which != 1) {

            isShow = false;
            $('.content-div').hide();
            return ;
        }
        $('#my-add-btn') .css({
            top: ev.pageY + 9,
            left: ev.pageX + 9,
            display: 'inline-block',
            lineHeight: '18px'
        });
    }
    $('body') .mouseup(setHandler);
    $('body').mousedown(function(e){
        if(isShow) {
            if($(e.target).is('.content-div')||$(e.target).parents('.content-div').length > 0) return;
            isShow = false;
            $('.content-div').hide();
        }
    });

好了现在来构建add-on程序代码测试一下上面的的代码,懒一点的话可以把上面代码用类似油猴子的插件运行测试一下,注意需要导入jQuery哟
参考selectTextUserJs.js

嵌入content script到页面中

首先使用cfx工具初始化一下开发模板(如何运行CFX):

cfx init

这时打开lib文件夹下面lib文件的main.js,在这里写主要add-on代码,所以在这里用tabs模块将写好的javascript脚本注入到页面中,注意如果想要注入.css文件到页面中,可以使用pageMod模块:

var tabs = require("sdk/tabs"),
data = require("sdk/self").data;

//当标签页加载完成,调用tab.attach注入脚本文件
tabs.on("ready", runScript);
//装载contentScript
function runScript(tab) {
    var worker = tab.attach({
        contentScriptFile: [data.url("jquery-1.11.2.min.js"), data.url("content.js")],
    });
}

将之前的写好的脚本和jquery文件保存到add-on项目目录下的data文件夹下,使用cfx工具运行:

cfx run

如果提示没有找到firefox二进制文件,使用-b参数指定firefo.exe文件路径,不出意外的话,现在在打开的浏览器里选择一些文本就会出现一个小按钮,点击之后会显示选择的文本信息

标签: firefox, 扩展插件, add-on, content script

添加新评论