为Diigo创建Chrome扩展程序,第1部分

Bookmark services are a dime a dozen these days. When your career and hobbies require you to have hundreds of links saved, things tend to get messy. I eventually settled on Diigo because of its support for both lists and tags – you can add multiple tags to every bookmark, and you can add every bookmark to a list. But visiting these bookmarks is tedious – I first have to open my Diigo library in a new tab, and then click on the bookmark in the list before me. If my library is complex and deeply nested, all the more trouble – I need to further filter my search by clicking the filters on the left hand side, and I'm already spending much more time trying to get to my bookmarked site than I should.

这些天,书签服务是一角钱。 当您的职业和兴趣爱好要求您保存数百个链接时,事情就会变得一团糟。 我最终决定使用Diigo,因为它既支持列表又支持标签-您可以将多个标签添加到每个书签,也可以将每个书签添加到列表。 但是访问这些书签很麻烦–我首先必须在一个新选项卡中打开Diigo库,然后在我之前的列表中单击书签。 如果我的图书馆很复杂并且嵌套得很深,那就更麻烦了–我需要通过单击左侧的过滤器来进一步过滤搜索,而且我已经花了更多的时间试图访问加有书签的网站。

规划 (Planning)

In this series, we'll create a Google Chrome extension which hooks up to the Diigo API, retrieves the bookmarks saved there, and syncs them into a folder on the Chrome bookmarks bar. This folder will have several levels:

在本系列中,我们将创建一个Google Chrome扩展程序,该扩展程序与Diigo API挂钩,检索在那里保存的书签,并将它们同步到Chrome书签栏上的文件夹中。 该文件夹将具有多个级别:

  1. Root level. A subfolder called "Tags" will be here, as well as all the bookmarks the user tags as bbs-root.

    根级别。 子文件夹“ Tags”以及所有用户标签为bbs-root的书签都将在此处。
  2. Tags level. The "tags" subfolder will contain one folder for every tag the user has in their Diigo library. Entering said folder lists all the posts with the given tag.

    标签级别。 对于用户在Diigo库中具有的每个标签,“标签”子文件夹将包含一个文件夹。 输入所述文件夹将列出所有具有给定标签的帖子。

Unfortunately, since Diigo's API is rather underdeveloped, there is no way to delete tags should they be left empty, nor is there a way to delete a bookmark from Diigo if it gets deleted in Chrome – yet. If this API shows up, I'll leave it to someone else to write a followup article. Likewise, the Diigo API does not support lists as of this moment. Once they add this functionality, it should be straightforward enough to upgrade this extension with a "Lists" subfolder.

不幸的是,由于Diigo的API尚不完善,因此如果将标签留空,则无法删除标签,如果在Chrome中将其删除,也无法从Diigo中删除书签。 如果显示此API,我将其留给其他人编写后续文章。 同样,Diigo API目前不支持列表。 一旦他们添加了此功能,就应该足够简单直接地使用“列表”子文件夹升级此扩展。

It's important to note that Google is very monopolistic with its bookmarks service. Chrome has a maximum write limit built in, meaning you cannot do more than 100 writes (create, update and delete) via the chrome.bookmarks API per hour. What this means is that if someone has more than 100 tags/lists/bookmarks in Diigo, their browser will take several hours before fetching them all and eventually settling for fewer writes (only updates, creates and deletes from that point onward should be far less common). We'll also be using JavaScript 1.7 constructs like the let keyword, so you should go into chrome://flags and enable "Experimental JavaScript". Could it be done without let? Absolutely. But I firmly believe that staying away from new technology just because it's not everywhere yet is harmful to both developers and the web in general. JS 1.7 came out 7 years ago, which is something like three centuries in internet years. In addition to let, we'll be using "strict mode", because let cannot be used without it.

请务必注意,Google的书签服务非常垄断。 Chrome具有内置的最大写入限制 ,这意味着您每小时通过chrome.bookmarks API进行的写入(创建,更新和删除)最多不能超过100次。 这意味着,如果某人在Diigo中拥有超过100个标签/列表/书签,则他们的浏览器将需要花费几个小时才能将其全部获取,并最终减少了写入次数(从那时起,仅更新,创建和删除操作应该少得多)共同)。 我们还将使用诸如let关键字之类JavaScript 1.7结构,因此您应该进入chrome://flags并启用“ Experimental JavaScript”。 可以不let完成吗? 绝对。 但我坚信,来自新技术,只是因为它不是到处但避而远之是有害的开发商和一般的网络。 JS 1.7是在7年前问世的,这在互联网时代已经差不多三个世纪了。 除了let ,我们还将使用“严格模式” ,因为没有let不能使用let

Note that this means people without experimental JS enabled won't be able to install and use this extension, at least until JS 1.7 support is enabled by default in Chrome.

请注意,这意味着未启用实验性JS的用户将无法安装和使用此扩展程序,至少直到在Chrome中默认启用JS 1.7支持为止。

自举 (Bootstrapping)

First, let's create a folder in which we'll hold our extension's source code. Create a folder structure such as this one, and leave the JS and JSON files blank.

首先,让我们创建一个文件夹,其中保存扩展程序的源代码。 创建一个这样的文件夹结构,并将JS和JSON文件留空。

/
    icons/
    background.js
    manifest.json

What we need next is the manifest.json file filled out.

接下来需要填写的manifest.json文件。

{
    "name": "Diigo Bookmark Bar Sync",
    "description": "Sync Diigo Bookmarks to Chrome",
    "version": "1.0.0.0",
    "background": {
        "scripts": ["background.js"]
    },
    "permissions": [
        "bookmarks", "https://secure.diigo.com/api/v2/"
    ],
    "browser_action": {
        "default_icon": {
            "19": "icons/19.png",
            "38": "icons/38.png"
        },
        "default_title": "Diigo BBS"
    },
    "icons": {
        "16": "icons/16.png",
        "48": "icons/48.png",
        "128": "icons/128.png"
    },
    "manifest_version": 2
}

If you've followed along with my previous Chrome Extension tutorial on Sitepoint, you should be familiar with all the keys and their values.

如果您已经按照之前在Sitepoint上的Chrome扩展教程进行了学习 ,则应该熟悉所有键及其值。

There are three novelties you might not be familiar with: the fact that we're using a JS background page instead of HTML (irrelevant either way – JS is unnoticeably faster), we're requesting the "bookmarks" permission to ask Chrome to let us edit them, and we're requesting permission to access https://secure.diigo.com/api/v2/ which helps us with cross origin ajax or, in other words, lets us do Ajax calls on Diigo without raising security flags.

您可能不熟悉以下三种新颖性:我们使用的是JS后台页面而不是HTML(这两种方法都不相关-JS的速度明显更快),我们正在请求“书签”权限,以要求Chrome浏览器允许我们对其进行编辑,然后请求访问https://secure.diigo.com/api/v2/许可,这可以帮助我们使用跨源ajax ,换句话说,就是让我们在Diigo上进行Ajax调用而不会引发安全标志。

We're also using a browser_action, which means we'll have a persistent icon NEXT to our omnibar at all times – not inside it while we're on a specific page, as is the case with page actions.

我们还使用了browser_action ,这意味着我们将始终在多功能栏上添加一个永久图标NEXT,而不是在特定页面上时在其内部,就像页面操作一样。

Make some icons for your extension in sizes mentioned in the manifest.json file and add them to the icons folder, or just download mine and put them there.

为manifest.json文件中提到的扩展名制作一些图标,然后将其添加到icons文件夹,或者直接下载我的图标并将其放在此处。

At this point, we can test our extension by loading it into the extensions tab (chrome://extensions). Make sure "Developer Mode" is checked, and click "Load Unpacked Extension", then point Chrome to the folder where you've put the files. If everything goes well, the extension's icon should appear in the top bar to the right of the omnibar and if you mouse over it, you should see "Diigo BBS" pop up.

此时,我们可以通过将扩展程序加载到扩展程序标签(chrome:// extensions)中来对其进行测试。 确保选中“开发人员模式”,然后单击“加载解压的扩展程序”,然后将Chrome指向放置文件的文件夹。 如果一切顺利,扩展程序的图标应显示在多功能条右侧的顶部栏中,如果将鼠标悬停在扩展条上,则应该会弹出“ Diigo BBS”。

Diigo API (Diigo API)

To gain access to Diigo's API, you need to sign up for an API key. This will provide you with a string of random characters which you need to send along with every Diigo API request in order to identify yourself (actually, in order to identify your app – every app will have a different API key).

要访问Diigo的API,您需要注册一个API密钥 。 这将为您提供一串随机字符,您需要将其与每个Diigo API请求一起发送以识别自己(实际上,为了识别您的应用程序-每个应用程序都将具有不同的API密钥)。

Diigo's API is severely underdeveloped, but RESTful which means we call the same URL for acting on the same object (i.e. Bookmarks) every time, but change the request type (GET fetches, POST updates and inserts, DELETE deletes the bookmark – not yet implemented). We'll explain this into a bit more depth soon.

Diigo的API严重欠发达,但是RESTful意味着我们每次都调用相同的URL来作用于相同的对象(即Bookmarks),但是更改了请求类型(GET获取,POST更新和插入,DELETE删除书签)–尚未实现)。 我们很快将对此进行更深入的说明。

Essentially, communicating with the API is as simple as sending a request to the URL, filled with the required parameters. If we assume there's a user called "Joel", to fetch 10 of Joel's bookmarks, we use https://secure.diigo.com/api/v2/bookmarks?key=your_api_key&user=joel&count=100&filter=all

从本质上讲,与API进行通信就像将请求发送到URL一样简单,并填充所需的参数。 如果我们假设有一个名为“ Joel”的用户,要获取Joel的10个书签,我们将使用https://secure.diigo.com/api/v2/bookmarks?key=your_api_key&user=joel&count=100&filter=all

The response to this request will either be an error code if something went wrong, or a JSON object. This JSON object will either contain nothing if Joel has no bookmarks, or will contain data blocks corresponding to information on those bookmarks, much like the example in the API docs demonstrates:

如果出现问题,对此请求的响应将是错误代码,或者是JSON对象。 如果Joel没有书签,此JSON对象将不包含任何内容,或包含与这些书签上的信息相对应的数据块,就像API文档中的示例所示:

[
  {
    "title":"Diigo API Help",
    "url":"http://www.diigo.com/help/api.html",
    "user":"foo",
    "desc":"",
    "tags":"test,diigo,help",
    "shared":"yes",
    "created_at":"2008/04/30 06:28:54 +0800",
    "updated_at":"2008/04/30 06:28:54 +0800",
    "comments":[],
    "annotations":[]
  },
  {
    "title":"Google Search",
    "url":"http://www.google.com",
    "user":"bar",
    "desc":"",
    "tags":"test,search",
    "shared":"yes",
    "created_at":"2008/04/30 06:28:54 +0800",
    "updated_at":"2008/04/30 06:28:54 +0800",
    "comments":[],
    "annotations":[]
  }
]

It's easy to extract everything we need from this JSON data once we receive it, but we'll get to that in a minute.

接收到JSON数据后,就很容易提取我们需要的所有内容,但是我们将在一分钟内完成。

The API docs say

API文档说

The authentication uses HTTP Basic authentication – a standard authentication method that includes base64 encoded username and password in the Authorization request header.

身份验证使用HTTP基本身份验证-一种标准的身份验证方法,在授权请求标头中包含base64编码的用户名和密码。

.. but there is neither an explanation nor a demo of this.

..但既没有解释也没有演示。

It means the following: when you access the actual URL for the API in the browser try clicking this, you get prompted for a username and password.

意思是:当您在浏览器中访问API的实际URL时,请尝试单击this ,提示您输入用户名和密码。

alt

If you fail to enter the proper credentials, you get a 403 response, which means you have insufficient access.

如果您无法输入正确的凭据,则会收到403响应,这意味着您没有足够的访问权限。

alt

If you do have the proper credentials, you can access the URL in two ways: either punch them in and submit the form, or include them in the URL, like so: https://myusername:mypassword@secure.diigo.com/api/v2/bookmarks?key=your_api_key&user=joel&count=100&filter=all where myusername and mypassword should be replaced by your information respectively. You can even test this right now in your browser if you registered for an API key and have a valid Diigo account. You should get either an empty array ([]) or a list of your bookmarks (or the public bookmarks of the user you've defined in the user parameter of the URL).

如果您确实具有适当的凭据,则可以通过两种方式访问​​URL:打Kong并提交表单,或将其包含在URL中,例如: https://myusername:mypassword@secure.diigo.com/api/v2/bookmarks?key=your_api_key&user=joel&count=100&filter=all ,其中myusernamemypassword应该分别替换为您的信息。 如果您注册了API密钥并拥有有效的Diigo帐户,您甚至可以立即在浏览器中测试此功能。 您应该获得一个空数组([])或书签列表(或在URL的user参数中定义的用户的公共书签)。

So what does base64 encoding it mean? It means we need to run the username and password through an additional filter, just to account for any weird characters in the password. The string myuser:mypass will thus be converted to bXl1c2VyOm15cGFzcw== (test it here).

那么base64编码是什么意思? 这意味着我们需要通过其他过滤器来运行用户名和密码,只是为了解决密码中的任何奇怪字符。 字符串myuser:mypass将因此转换为bXl1c2VyOm15cGFzcw== ( 在此处进行测试)。

So how do we put all this together?

那么我们如何将所有这些放在一起?

编码和发送 (Encoding and sending)

First we'll need a way to base64 encode a string. Seeing as JS doesn't have this functionality built in, we can use the code from Webtoolkit. Paste that code into your background.js file. If you want, you can even minify it to make it more compact.

首先,我们需要一种对字符串进行base64编码的方法。 鉴于JS没有内置此功能,我们可以使用Webtoolkit中的代码。 将该代码粘贴到您的background.js文件中。 如果需要,您甚至可以缩小尺寸以使其更紧凑。

Next, we need to tell the API URL we want to Authorize. This is done with an Authorize header, and when using native XHR objects for Ajax, we can do this with the xml.setRequestHeader('Authorization', auth); method, where auth is a string containing authorization data.

接下来,我们需要告诉我们要授权的API URL。 这是通过Authorize标头完成的,当将本机XHR对象用于Ajax时,我们可以使用xml.setRequestHeader('Authorization', auth); 方法,其中auth是包含授权数据的字符串。

Let's make a common function that generates this auth string.

让我们创建一个生成此身份验证字符串的通用函数。

function make_basic_auth(user, password) {
  var tok = user + ':' + password;
  var hash = Base64.encode(tok);
  return "Basic " + hash;
}

As you can see, the returned string will be "Basic " + whatever was calculated from user+pass string as the Base64 value. This string is what the Authorization header needs in order to gain access to the URL we'll be sending it to. It is, essentially, identical to you punching in your username and password manually when you access the URL through the browser.

如您所见,返回的字符串将是“ Basic” +从user + pass字符串计算为Base64值的任何值。 为了获得对我们将其发送到的URL的访问权限,Authorization标头需要此字符串。 从本质上讲,它与您通过浏览器访问URL时手动输入用户名和密码相同。

You might be wondering – couldn't we just add user:pass to the beginning of the URL like we can in the browser, as well, and just ignore the Base64 business? Yes, but then you aren't accounting for misc characters and might run into some serious trouble with invalid requests – for example, the "@" symbol denotes the beginning of the server address and having it in the password would throw a wrench into our efforts.

您可能想知道–我们是否也不能像在浏览器中那样仅将user:pass添加到URL的开头,而只是忽略Base64业务? 是的,但是您并没有考虑其他字符,并且可能会因无效请求而遇到一些严重麻烦–例如,“ @”符号表示服务器地址的开头,将其输入密码后,就会使我们陷入困境。努力。

Finally, let's make an XHR request to the API.

最后,让我们向API发出XHR请求。

var auth = make_basic_auth('user','pass');
var url = 'https://secure.diigo.com/api/v2/bookmarks?key=your_api_key&user=desireduser&count=100&filter=all';

xml = new XMLHttpRequest();
xml.open('GET', url);
xml.setRequestHeader('Authorization', auth);
xml.send();

xml.onreadystatechange = function() {
    if (xml.readyState === 4) {
        if (xml.status === 200) {
            console.log(xml.responseText);
        } else {
            console.error("Something went wrong!");
        }
    }
};

Of course, replace "user", "pass", "your_api_key" and "desireduser" with your values.

当然,用您的值替换“ user”,“ pass”,“ your_api_key”和“ desireduser”。

If we reload our extension now with an open background page (click _generated_background_page.html in the extensions screen to see the background page and console error reports (if any) for our extension), we should see everything is working fine – i.e. there should be no errors in the console of the background page, and there should either be "[]" (an empty array) or something like the following figure:

如果我们现在使用打开的后台页面重新加载扩展程序(在扩展程序屏幕中单击_generated_background_page.html以查看扩展程序的背景页面和控制台错误报告,如果有的话),我们应该会看到一切运行正常–即应该有后台页面的控制台中没有错误,并且应该有“ []”(空数组)或类似下图的内容:

alt

第一部分的结论 (Conclusion of Part 1)

In this part, we've bootstrapped our extension, explained, implemented and demonstrated the Diigo API call. In Part 2, we'll write the bulk of our extension.

在这一部分中,我们已经引导了我们的扩展,解释,实现和演示了Diigo API调用。 在第2部分中,我们将编写大部分扩展。

翻译自: https://www.sitepoint.com/creating-chrome-extension-diigo-part-1/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值