65.9K
CodeProject 正在变化。 阅读更多。
Home

Google Chrome 扩展 - CodeProject 声誉监视器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.97/5 (91投票s)

2010年8月2日

CPOL

10分钟阅读

viewsIcon

185834

downloadIcon

1413

Google Chrome 扩展,可抓取您的声望积分和图表,并跟踪更新之间的变化。

CodeProject Reputation Extension

V2 重要更改

由于 Google 为保护用户免受恶意代码侵害而实施的政策变更,该扩展需要进行多项更改。

 

  • 将 manifest 更新为新的 V2 标准。
  • 从 Chrome 网上应用店分发扩展。
  • 从 HTML 页面中删除内联脚本块。

 

我还利用这些更改升级了新的 jQuery 文件,并重构了部分其他代码。

引言

本文是为了尝试一些新主题而撰写的。为了尝试这些新主题,最好尝试开发一个功能性组件,而不是仅仅玩弄代码语法。

本文将探讨如何构建一个 Google Chrome 扩展,以及我如何利用 jQuery 和 jQuery UI 来构建该扩展。那么这个扩展会做什么呢?该扩展可以获取用户 CodeProject 个人资料页面的来源,并抓取他们的声望积分。该扩展将这些积分存储在本地,并比较与 Code Project 之间的轮询变化,然后将这些信息呈现到一个漂亮的小表格中。该扩展还可以获取成员的声望图表并在扩展中显示。

背景

构建此扩展所需的信息可以在 Google Chrome 扩展的页面上找到。有关 jQuery 和 jQuery UI 的信息,请参见此处此处

Chrome 扩展

Chrome 扩展实际上是一系列包含完全嵌入的 JavaScript 和 CSS 的 HTML 文件,或者可以链接到其他 JavaScript、CSS 和图像文件。为了让 Chrome 知道如何处理所有这些文件以及如何将其呈现给用户,项目根目录中的 manifest 文件定义了各种元素。manifest 文件必须命名为 'manifest.json'。

让我们来看看为这个扩展制作的 manifest 文件

{
  "manifest_version": 2,
  "name": "CodeProject Reputation Watcher",
  "short_name": "CPRepWatcher",
  "version": "2.0",
  "content_security_policy": "script-src 'self' https://# 'unsafe-eval'; object-src 'self' ",
  "description": "Extension to retrieve a CodeProject accounts reputation points.",
  "icons": {
      "48":"images/bob48.png",
      "128":"images/bob128.png"
  },
  "browser_action": {
    "default_icon": "images/bob.png",
    "default_popup": "cprepwatch.html"
  },
  "options_page": "options.html",
  "permissions": [
    "http://*.codeproject.com/"
  ]
}

有一些基本属性,如 'name'、'version' 和 'description',这些都是不言而喻的。'icons' 元素定义了扩展可用的图像;这些图像会显示在安装后的 Chrome 扩展页面上。

'browser_action' 元素告诉 Chrome 在工具栏中显示哪个图标,以及哪个 HTML 文件是扩展图标被点击时的主要弹出窗口。

'options_page' 元素告诉 Chrome 将显示哪个 HTML 页面,允许用户设置扩展使用的任何选项/用户设置。此页面可以通过右键点击工具栏按钮显示的选项菜单访问,或者从 Chrome 的工具菜单访问的 Chrome 扩展页面上的选项链接访问。

'permissions' 元素定义了扩展想要访问的站点,并用于跨站点安全模型。

(Manifest 版本 1) 'update_url' 元素定义了自动更新工具用于检查扩展新版本修订版的 XML 文件。从 V2 开始,由于扩展托管在 Chrome 商店中,因此不再需要此项。Chrome 浏览器负责版本更新过程。此属性随后被删除。

您还可以看到新规则要求的 'manifest_versions''content_security_policy' 更改。我还注意到,上传到 chrome 商店的人不喜欢 manifest 中有注释行,因此也必须删除这些注释。这只是通过反复试验才发现的,因为错误消息并没有提供太多帮助。

根据您的需求,还可以向 manifest 文件添加其他一些元素;这些元素的详细信息可以在 Chrome 扩展开发者页面上找到。

添加 jQuery 和 jQuery UI

要使用这些 JavaScript 库,您需要先从开发者站点下载它们,在此处此处。在 jQuery UI 站点上,还有许多预定义的样式可用于 UI 元素,您还可以使用网站的样式生成器创建自己的样式。下载包含库和样式的 zip 文件后,解压缩这些文件并将它们添加到您的项目文件夹中。每个想要使用这些库的页面都必须在 HTML 中链接它们。这很容易通过标准标记来实现。

<link type="text/css" 
      href="css/custom-theme/jquery-ui-1.8.2.custom.css" rel="Stylesheet" />
<script type="text/javascript" src="jquery/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="jquery/jquery-ui-1.8.2.custom.min.js"></script>
<script type="text/javascript" src="js/cpjshelper.js"></script>

您还会注意到有一个指向 'js/cpjshelper.js' JavaScript 文件的引用。随着扩展的开发,常见的共享辅助函数被移到了这个文件中,以最大化代码重用并使 HTML 文件更整洁。

为什么使用 jQuery?

jQuery 提供了一种出色的操作和遍历 DOM 的方法。一旦我掌握了它的语法,它就使事情变得非常容易,这只需要很短的时间。以下是一些基本示例,说明它可以做什么

//Insert some HTML into a Div element named 'holdingdata'
$("#holdingdata").html("the html markup would go here");
$("#anElement").hide();        //Hide an element
$("#anElement").show();        //Show an element
$("p").each(function(){ $(this).hide();});
//Find all 'p' tags and hide them

下面的 jQuery 命令在浏览器文档加载完成后执行一个函数。该函数设置一个计时器,在一段时间后调用另一个函数。.get() 执行一个 HTTP GET 的 AJAX 查询,然后将返回的数据传递给另一个函数进行处理。AJAX 调用可以是同步或异步的,取决于您的需求。这两个辅助函数是用于处理 CodeProject 地址和数据的 JavaScript 函数。

$(document).ready(function () {
    setTimeout(function () {
        //Start loading the data from Codeproject profile
        $.get(getCPMemberProfile(), function (data) {
            setCPProfileData(data);
        });
    }, 1000);
});

这仅仅是 jQuery 全部功能的冰山一角,如果您访问开发者站点并浏览文档,您很快就会明白我的意思。

为什么使用 jQuery UI?

jQuery UI 提供了一套全面的界面小部件,可以插入到您的 HTML 中,然后使用 CSS 标记,提供一套丰富的界面组件。在此扩展中,使用的组件是 Tabs 面板和一个基本按钮。

Tabs 面板的创建非常简单,如下所示

<script type="text/javascript">
                       $(function() {
                           $("#tabs").tabs();
                       });
</script>
<div id="tabs" style="height: 400px;">
    <!-- Tab Pages -->
    <ul>
        <li><a href="#tabs-1">Reputation Points</a></li>
        <li><a href="repgraph.html">Reputation Graph</a></li>
        <li><a href="#tabs-3">Options</a></li>
        <li><a href="about.html">About</a></li>
    </ul>
    <!-- Tab 1 Rep Points -->
    <div id="tabs-1" style="padding-left: 5px">
        <!-- Main Rep Page content -->
    </div>
    <!-- Tab 2 Rep Graph ; Note: This does not require a section 
           as it is a link URL in tab definition above. -->
    <!-- Tab 3 Options -->
    <div id="tabs-3" style="padding-left: 5px">
        <!-- Options Tab Content goes Here -->
    </div>
    <!-- Tab 4 About ; Note: This does not require a section 
            as it is a link URL in tab definition above. -->
</div>

您还会注意到 Tab 2 (Rep Graph) 和 Tab 4 (About) 是对扩展文件内外部文档的引用。这些内容通过 AJAX 加载,然后注入到当前页面的 DOM 的相应标签位置。

抓取 CodeProject 内容

为了检索 CodeProject 内容,一个 JavaScript 函数首先使用 AJAX 调用加载成员个人资料页面。返回的内容然后被放置在页面上的一个隐藏的 Div 块中,然后可以使用 jQuery 访问、遍历和解析该块。CodeProject 内容中有三个主要的 Element 用于标识要抓取的区域。它们是 'ctl00_MC_Prof_TotalRepBox' 用于总体成员级别,'ctl00_MC_Prof_TotalRep' 用于总声望积分,以及 'ctl00_MC_Prof_Status' 用于所有类别的单个积分。

//The Total Reputation Member Level is Found in
if ($("#ctl00_MC_Prof_TotalRepBox").hasClass("nostatus")) { $("#repStatus0").html(" "); };
if ($("#ctl00_MC_Prof_TotalRepBox").hasClass("bronze")) { $("#repStatus0").html("Bronze"); };
if ($("#ctl00_MC_Prof_TotalRepBox").hasClass("silver")) { $("#repStatus0").html("Silver"); };
if ($("#ctl00_MC_Prof_TotalRepBox").hasClass("gold")) { $("#repStatus0").html("Gold"); };
if ($("#ctl00_MC_Prof_TotalRepBox").hasClass("platinum")) 
              { $("#repStatus0").html("Platinum"); };

//The Total Reputation is found in this node
var thestring = $("#ctl00_MC_Prof_TotalRep");
if (thestring) { newRep[0] = thestring.text(); } else { newRep[0] = "0"; }
$("#loadRepTotal").html(newRep[0]);

//Reputation Points table
holdingdata.innerHTML = $('table.member-rep-list').html();

一旦内容被找到并复制到 holding Div 中,jQuery 就被用来提取内部元素中的文本。下面是用于定位每个 TableRow,然后在其中找到每个 TableData 并定位 PointsCategoryStatus 级别,然后将它们注入 DOM 以便呈现给用户的代码。

$("#holdingdata").find("tr").each(function (iTR) {
    $(this).find("td").each(function (iTD) {
        var MemberLevel = "";
        if ($(this).hasClass("nostatus")) { MemberLevel = "" };
        if ($(this).hasClass("bronze")) { MemberLevel = "Bronze" };
        if ($(this).hasClass("silver")) { MemberLevel = "Silver" };
        if ($(this).hasClass("gold")) { MemberLevel = "Gold" };
        if ($(this).hasClass("platinum")) { MemberLevel = "Platinum" };
         
         
         //Version 1.6 21st March 2011, Additional second link in each category
         //iterate all the links determining a Category/Value pair
         var thevalue = $(this).find("div.medium-text").text();
         if (!thevalue) { thevalue = ""; 
         $(this).find("a").each( function (iA) {
            var category = $(this).text();             
            var category = $(this).find("a").text();

            if (!category) { category = "No Data"; };
            category = category.toUpperCase(category);            
            switch (category) {
                case ("AUTHOR"):
                    newRep[1] = thevalue;
                    $("#loadRepAuthor").html(newRep[1]);
                    $("#repStatus1").html(MemberLevel);
                    break;
                case ("AUTHORITY"):
                    newRep[2] = thevalue;
                    $("#loadRepAuthority").html(newRep[2]);
                    $("#repStatus2").html(MemberLevel);
                    break;
                // Other case statements
                    for the other categories continue...........
            }
        });
    });
});

测试代码

为了测试代码,首先将未打包的扩展加载到 Chrome 中。要做到这一点,选择 '工具',然后是 '扩展' 菜单,展开开发者面板,然后选择 '加载未打包的扩展...',然后导航到包含扩展所有文件的文件夹。扩展将被加载,显示为未打包,并且 manifest 中指定的图标等应该出现在工具栏和扩展的左侧。

要查看幕后情况,您可以右键点击工具栏并选择 '检查弹出窗口',查找错误,查看本地存储中存储了什么等等。在修改代码库/HTML 文件时,只需点击扩展中的 '重新加载' 即可更新。

为了辅助测试,您可以在扩展中放置一些 JavaScript 代码输出到 Chrome 调试器;这很简单,就像

//Output the contents of a variable to the debugger
console.log(variablename);
//Output a string to the debugger
console.log("Some text.");

本地存储数据/设置

对象可以本地存储,在此扩展中,存储了 CodeProject 成员 ID 以及上一次数据轮询的声望积分。持久化数据很容易,正如您下面所见,在需要时也很容易召回数据。

// Put data in the local store
var sometext = "Hello";
localStorage["AnyKeyName"] = sometext;

// Get data from the local store
var sometext;
sometext = localStorage["AnyKeyName"];

// Test the data does exist and was read
if (!sometext)
{
    // The data is not present in the local store
}

打包和部署/托管

扩展有两种分发方法

  1. 未打包方法,虽然有效,但主要适用于测试和开发场景。
  2. 通过 Chrome 网上应用店进行 Google 托管。

未打包的扩展可以从此文章下载,该扩展也已发布到 Chrome 网上应用店。

已不再允许打包的扩展。这些将被浏览器阻止并禁用。

有关打包、部署和 Google 托管的更多信息,请参阅扩展打包

如何使用此扩展?

您可以下载并安装未打包的扩展,或者点击上面的链接从网上应用店安装。

注意: 在“工具 | 扩展”菜单中安装未打包的扩展(以开发者模式)将允许您从源代码安装。但是,浏览器会不断提醒您并询问您是否要禁用此模式。

通过以上任何一种方法安装后,您只需从选项菜单项、扩展选项链接,或从实际扩展的选项卡中,将其设置为您的 CodeProject 成员 ID。您的成员 ID 可以在您的帐户的个人资料页面上找到。

每次点击扩展工具栏按钮时,它将显示文章顶部的页面,并用您最新的积分更新表格。

扩展上的其他标签如下:声望图、选项和关于。

扩展卸载

安装扩展后,只需点击卸载链接并删除解压缩未打包扩展的源文件夹即可。

下一步

代码库可能不是最优化的,所以需要整理一下,但和往常一样,一旦它能工作,我就不愿意改变任何东西。如果我有时间,我可能会研究一下,并可能添加一些其他功能,比如自动刷新。

跟踪使用情况和用户交互

可以通过将 Google Analytics 代码添加到文件中来跟踪扩展的使用情况。通过此,您可以跟踪正在查看的页面、被点击的按钮等。有关 Analytics 集成的更多信息可以在此处找到。

关注点

由于这是我第一次接触 Chrome 扩展、jQuery 和 jQuery UI,这无疑是一项挑战,但也非常有益。

已知问题

Chrome 中似乎有一个奇怪的缓存相关问题,这只有在您输入无效的 CodeProject 成员 ID 时才会出现:例如,导航到您的成员个人资料,然后导航到一个无效的个人资料,导航到另一个人的个人资料,再导航到同一个无效的个人资料,您会看到您最初输入的成员个人资料显示出来……我无法解释这一点,而且对于扩展的正常使用来说,这并不重要。只要您使用有效的成员 ID:一切都会正常。

历史

(版本号与代码更改相关,而不是文章修订版。)

  • V2.0 2014 年 6 月 18 日 - 更新至新的 Chrome 要求,jQuery 更新至 V1.11.1
  • 2013 年 10 月 23 日 - 由于 Chrome 更改,更新安装说明
  • V1.6, 2011 年 3 月 21 日 - 为 CodeProject DOM/成员个人资料更改而更新
  • V1.5, 2010 年 12 月 13 日 - 为 CodeProject DOM 更改而更新
  • V1.4, 2010 年 10 月 20 日 - 添加了总体成员级别
  • V1.3, 2010 年 9 月 10 日 - 解决了一些 Google Analytics 问题
  • V1.2, 2010 年 9 月 9 日 - 修复了一些 JS 错误,将“关于”内容移至独立文件并通过 AJAX 调用,添加了 Google Analytics 跟踪。还在文章中介绍了到私有 Web 服务器的打包和部署详细信息
  • V1.1, 2010 年 8 月 4 日 - 修复以处理新的成员状态 CSS 类 ID;从 zip 文件中删除了冗余的 CSS 主题
  • V1.0, 2010 年 8 月 1 日 - 文章的第一个版本
© . All rights reserved.