谷歌插件开发(实现CSDN快速登陆)

谷歌浏览器插件带来了很大的方便,于是就想着是不是也可以开发一个来用用。几经折腾下,开发了个CSDN快速 登陆的插件。下面简述一下开发的步骤。

1、开发工具:谷歌浏览器(我开发时用的是chrome 30.0.1599.101 )、HTML/JS/CSS/JSON开发工具(UE、VS等,当然也可以用记事本)

2、开发过程

(1)新建清单文件manifest.json:该名字不可以改。下面是代码

 

{

    "manifest_version": 2,   

    "background": {

        "page": "main.html"//后台运行页,page和scrptis只能选择一个		

    },

    "browser_action":{

        "default_icon":"assets/images/Icon.png",//插件默认图标

        "default_title":"__MSG_manifest_iconTitle__",//插件标题

        "default_popup":"popup.html"//单击插件图标时弹出的页面

    },

    "default_locale":"en",//默认本地化语言

    "description":"__MSG_manifest_appDescription__",//插件描述

    "icons":{//显示的图标

        "16":"assets/images/Icon.png",

        "128":"assets/images/Icon.png"

    },

    "name":"__MSG_manifest_appName__",//插件名字

    "options_page":"options.html",//插件选项页

    "permissions":[ "proxy", "tabs", "<all_urls>","notifications"],//申请需要的权限

    "version":"1.1.1",//插件版本

    "minimum_chrome_version":"18.0.0"//浏览器最低版本    

}

其中__MSG_manifest_iconTitle__、__MSG_manifest_appDescription__、__MSG_manifest_appName__是依据系统语言的本地化配置,比如在简体中文系统和英文系统时会本地化成相应的语言,见下图

 

谷歌插件开发(实现CSDN快速登陆)谷歌插件开发(实现CSDN快速登陆)

(2)新建弹出页(popup.html)

写HTML和CSS代码,排布出如上图所示的界面

 

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

    <link rel="stylesheet" href="assets/styles/popup.css" type="text/css">

    <script src="assets/libs/jquery-1.7.2.min.js" type="text/javascript"></script>

    <script src="assets/scripts/Popup.js" type="text/javascript"></script>

</head>

<body>   

    <div id="set_config">

        <div class="header title" data-i18n-content="popup_setting">Setting</div>

        <div class="header light">

            <table>

                <tr>

                    <th>

                        <span data-i18n-content="popup_account_id">User</span>

                    </th>

                    <td>

                        <input type="text" id="setting_account_id" value="" />



                    </td>



                </tr>

                <tr>

                    <th>

                        <span data-i18n-content="popup_password">Password</span>

                    </th>

                    <td>

                        <input type="password" id="setting_password" value="" />

                    </td>

                </tr>                

            </table>

        </div>

        <div class="header light">

            <table class="control">

                <tr>

                    <td>

                        <button class="button bold" id="setting_login" data-i18n-content="popup_setting_login">Save</button>

                    </td>

                    <td>    </td>

                    <td>

                        <button class="button bold" id="setting_cancel" data-i18n-content="popup_setting_cancel">Cancel</button>

                    </td>

                </tr>

            </table>

        </div>

    </div>

</body>



</html>

注意:这里面也采用了本地化配置,data-i18n-content="popup_setting"一类的写法,就是进行本地化配置,不过需要通过i18n.js来配套实现。i18n表示的是国际化。人们常把I18N作为“国际化”的简称,其来源是英文单词 internationalization的首末字符i和n。18为中间的字符数。
这里面还用到了popup.js和jquery。jquery是JS库,网上可以下载到。popup.js代码如下

 

 

/// <reference path="Config.js"/>

/// <reference path="Settings.js"/>

/// <reference path="Notify.js"/>



var Popup = {};

Popup.CONTROL_IDS = {

    SET_CANCEL: "setting_cancel",

    SET_LOGIN: "setting_login",

    SETTING_ACCOUNT_ID: "setting_account_id",

    SETTING_PASSWORD: "setting_password"

};



$(document).ready(function () {

    Popup.init();

    $("#" + Popup.CONTROL_IDS.SET_LOGIN).click(Popup.setLogin);

    $("#" + Popup.CONTROL_IDS.SET_CANCEL).click(Popup.setCancel);

});





Popup.init = function () {

    Popup.extension = chrome.extension.getBackgroundPage();

    Settings = Popup.extension.Settings;//Settings in Settings.js  

    Config = Popup.extension.Config;//Config in Config.js

    Notify = Popup.extension.Notify;

    I18n = Popup.extension.I18n;//I18n in I18n.js 

    I18n.process(document);

    document.body.style.visibility = "visible";

    Popup.initUI();

}



Popup.initUI = function () {

    $("#" + Popup.CONTROL_IDS.SETTING_ACCOUNT_ID).attr("value", Settings.getValue(Config.KEYS.ACCOUNT_ID, ''));

    $("#" + Popup.CONTROL_IDS.SETTING_PASSWORD).attr("value", Settings.getValue(Config.KEYS.PASSOWRD, ''));

}



Popup.openPage = function () {

    Popup.closePopup();

    chrome.tabs.create({//新建标签页

        url: Config.URLS.LOGIN

    });

}



Popup.openOptions = function () {

    Popup.closePopup();

    extension.openOptions();

}



Popup.closePopup = function () {

    window.close();

}



Popup.setCancel = function () {

    Popup.closePopup();

}



Popup.setLogin = function () {



    Settings.setValue(Config.KEYS.ACCOUNT_ID, $("#" + Popup.CONTROL_IDS.SETTING_ACCOUNT_ID).val());

    Settings.setValue(Config.KEYS.PASSOWRD, $("#" + Popup.CONTROL_IDS.SETTING_PASSWORD).val());



    Notify.notifyText(Config.FILES.NOTIFY_IMAGE, '', 'OK');



    Popup.openPage();

}

说明:

 

1) /// <reference path="Config.js"/>是VS中为了可以像类一样点出相应的字段和方法的引用方法。

2)$(document).ready是popup.html加载完成后进行相应的操作,比如初始化按钮的点击事件等。chrome是不可以在页面中直接写内连的JS的,那样有安全隐患。

 

<scritp type="text/javascript">

//内连脚本

function test(){ alert("test");}

</script>

如果非要进行内连,那必须将其转换成64码,然后连到src中(直接放到scrpit中的scr中不可以,需要放到iframe中。不知道具体是什么原因。),如下面代码。

 

 

<iframe id="sandbox-frame" sandbox="allow-scripts" src="data:text/html;base64,JTNDc2NyaXB0JTIwdHlwZSUzRCUyMnRleHQvamF2YXNjcmlwdCUyMiUzRSUwQWFsZXJ0JTI4JTIyQUFBQSUyMiUyOSUzQiUwQSUzQy9zY3JpcHQlM0U="></iframe>

 

 

3)最重要的是Popup.init函数,这个函数将后台的js引用到前台(popup.js是从前台界面popup.html中引用的,所以为前台JS),以便于更好的调用。

Popup.extension = chrome.extension.getBackgroundPage()先把后台引用到前台。

Config = Popup.extension.Config是从后台将Config引用到前台来,其中Config不是Config.js的脚本名字,而是Config.js中的var Config={}。其他的引用同理。

I18n.process(document)这是进行本地化配置。

(3)后台JS

后台JS需要放到main.html中,代码如下

 

<html>

<head>

    <meta charset="UTF-8" />

    <title></title>

    <script src="assets/libs/jquery-1.7.2.min.js" type="text/javascript"></script>

    <script src="assets/scripts/CSDN.js" type="text/javascript"></script>

    <script src="assets/scripts/Settings.js" type="text/javascript"></script>

    <script src="assets/scripts/Config.js" type="text/javascript"></script>

    <script src="assets/scripts/I18n.js" type="text/javascript"></script>

    <script src="assets/scripts/Notify.js" type="text/javascript"></script>

</head>

<body>

</body>

</html>

1)CSDN.js

 

 

/// <reference path="Config.js"/>

var CSDN = {};



chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {//添加监听事件

    var url = tab.url;

    var config = null;

    if (tab.status !== "complete") {//需要增加这一判断,不然会在页面加载和加载完成后分别触发

        return;

    }

    CSDN.login(url);

});



CSDN.CONTROL_IDS = {

    ACCOUNT_ID: "u",

    PASSWORD: "p",

    LOGIN: "aLogin",

    LOGIN_IFRAME: "logfrm"

};



CSDN.isLoginUrl = function (url) {

    if (url === Config.URLS.LOGIN) {



        return true;

    }

    else {

        return false;

    }

}



CSDN.login = function (url) {

    if (!CSDN.isLoginUrl(url)) {

        return;

    }

    var accountID = Settings.getValue(Config.KEYS.ACCOUNT_ID, '');

    var password = Settings.getValue(Config.KEYS.PASSOWRD, '');

    var scripts = "";

    if (accountID === undefined || accountID === null || accountID.replace(/(^\s*)|(\s*$)/g, "").length <= 0) {

        return;

    }



    scripts += "var loginIFrame = document.getElementById('" + CSDN.CONTROL_IDS.LOGIN_IFRAME + "');"

            + " var loginDocument=loginIFrame.contentWindow.document;"

            + "loginDocument.getElementById('" + CSDN.CONTROL_IDS.ACCOUNT_ID + "').value='" + accountID + "';"

            + "loginDocument.getElementById('" + CSDN.CONTROL_IDS.PASSWORD + "').value='" + password + "';"

            + "loginDocument.getElementById('" + CSDN.CONTROL_IDS.LOGIN + "').click();"

    chrome.tabs.executeScript(null, {//嵌入JS脚本到所打开的页面中。

        code: scripts

    });

}

2)Notify.js

 

从浏览器中发出桌面通知,代码如下

 

var Notify = {};

Notify.notifyText = function (iconUrl, title, content) {//这个要触发,必须在manifest.json中添加notifications,以申请桌面通知权限

    var notification = window.webkitNotifications.createNotification(iconUrl, title, content);

    notification.show();

}

3)其他JS代码如下

 

Config.js

var Config = {};



Config.KEYS = {

    ACCOUNT_ID: "accountID",   

    PASSOWRD: "password"

};



Config.FILES = {

    NOTIFY_IMAGE: "assets/images/Notify.png"

};



Config.URLS = {

    LOGIN: "https://passport.csdn.net/account/login"

};


Setting.js

 

 

var Settings = {};



Settings.configCache = {};



Settings.setValue = function setValue(key, value) {

    Settings.configCache[key] = value;



    var config = {};

    if (localStorage.config)

        config = JSON.parse(localStorage.config);



    config[key] = value;

    localStorage.config = JSON.stringify(config);

    return value;

};



Settings.getValue = function getValue(key, defaultValue) {

    if (typeof Settings.configCache[key] != "undefined")

        return Settings.configCache[key];



    if (!localStorage.config)

        return defaultValue;



    var config = JSON.parse(localStorage.config);

    if (typeof config[key] == "undefined")

        return defaultValue;



    Settings.configCache[key] = config[key];

    return config[key];

};



Settings.keyExists = function keyExists(key) {

    if (!localStorage.config)

        return false;



    var config = JSON.parse(localStorage.config);

    return (config[key] != undefined);

};



Settings.setObject = function setObject(key, object) {

    localStorage[key] = JSON.stringify(object);

    return object;

};



Settings.getObject = function getObject(key) {

    if (localStorage[key] == undefined)

        return undefined;



    return JSON.parse(localStorage[key]);

};



Settings.refreshCache = function refreshCache() {

    Settings.configCache = {};

};


I18n.js

 

 

var I18n = {};



I18n.messages = null;



I18n.init = function init() {

    I18n.messages = I18n.readMessages();

    //	I18n.readMessages(function(messages) {

    //		I18n.messages = messages;

    //	});

};



I18n.buildMessages = function buildMessages() {

    var result = "\n";



    $("*[data-i18n-content]").each(function (i, item) {

        result += '"' + item.getAttribute("i18n-content") + '"' +

            ': { "message": "' + item.innerHTML.replace(/[ \r\n\t]+/g, " ") + '" },\n';

    });



    $("*[data-i18n-values]").each(function (i, item) {

        $(item.getAttribute("i18n-values").split(";")).each(function (i, subItem) {

            var subItemParts = subItem.split(":");

            if (subItemParts.length == 2 && subItemParts[0].charAt(0) != ".") {

                result += '"' + subItemParts[1] + '"' +

                    ': { "message": "' + item.getAttribute(subItemParts[0]).replace(/[\r\n]/g, "\\n") + '" },\n';

            }

        });

    });



    return result;

};



I18n.readMessages = function readMessages(callback) {

    var async = (callback != undefined);

    var data = null;

    var request = new XMLHttpRequest();

    request.open("GET", chrome.extension.getURL("_locales/en/messages.json"), async);

    request.onreadystatechange = function () {

        if (this.readyState == XMLHttpRequest.DONE) {

            data = this.responseText;

            data = JSON.parse(data.replace(/[\r\n\t]+/g, " "));

            if (async)

                callback(data);

        }

    };

    request.send("");



    return data;

};



I18n.getMessage = function getMessage(messageName, substitution) {

    var result = chrome.i18n.getMessage(messageName, substitution);

    if (result == undefined || result.length == 0) {

        var messageObject = I18n.messages[messageName];

        if (messageObject != undefined) {

            result = messageObject.message;

            if (result != undefined)

                result = result.replace("$1", substitution);

        }

    }

    return result;

};



I18n.process = function process(node) {

    return I18nTemplate.process(node);

};



I18n.init();



//-------------------------------------------------------



/**

 * i18nTemplate: http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/resources/i18n_template.js

 */

var I18nTemplate = (function () {

    var handlers = {

        /**

         * This handler sets the textContent of the element.

         */

        'data-i18n-content': function (element, attributeValue) {

            element.innerHTML/*textContent*/ = I18n.getMessage(attributeValue);

        },



        /**

         * This is used to set HTML attributes and DOM properties,. The syntax

         * is: attributename:key; .domProperty:key; .nested.dom.property:key

         */

        'data-i18n-values': function (element, attributeValue) {

            var parts = attributeValue.replace(/\s/g, '').split(/;/);

            for (var j = 0; j < parts.length; j++) {

                var a = parts[j].match(/^([^:]+):(.+)$/);

                if (a) {

                    var propName = a[1];

                    var propExpr = a[2];



                    var value = I18n.getMessage(propExpr);

                    if (propName.charAt(0) == '.') {

                        var path = propName.slice(1).split('.');

                        var object = element;

                        while (object && path.length > 1) {

                            object = object[path.shift()];

                        }

                        if (object) {

                            object[path] = value;

                            // In case we set innerHTML (ignoring others) we need to

                            // recursively check the content

                            if (path.toString() === 'innerHTML') {

                                process(element);

                            }

                        }

                    } else {

                        element.setAttribute(propName, value);

                    }

                }

            }

        }

    };



    var attributeNames = [];

    for (var key in handlers) {

        if (handlers.hasOwnProperty(key)) {

            attributeNames.push(key);

        }

    }

    var selector = '[' + attributeNames.join('],[') + ']';



    function process(node) {

        var elements = node.querySelectorAll(selector);

        for (var element, i = 0; element = elements[i]; i++) {

            for (var j = 0; j < attributeNames.length; j++) {

                var name = attributeNames[j];

                var att = element.getAttribute(name);

                if (att != null) {

                    handlers[name](element, att);

                }

            }

        }

    }



    return {

        process: process

    };

})();


开发时参考了SwitchProxy的源码https://code.google.com/p/switchysharp/source/。

 

转载请注明出处http://blog.csdn.net/xxdddail/article/details/13504259

源码在此处下载http://download.csdn.net/detail/xxdddail/6469683




 

你可能感兴趣的:(csdn)