在試過ASP.NET整合Live ID登入後,只取回使用者姓名跟MSN大頭照感覺有點像辦家家酒不夠刺激,Live SDK應該拿來搞點實用的功能才過癮 -- 例如: 瀏覽SkyDrive文件與檔案。
Live Connect API提供了SkyDrive相關的REST API,只要取得Access Token,便可透過API瀏覽、讀取、變更、刪除SkyDrive下的文件、相片、影音等檔案,MSDN上有兩篇不錯的教學文章(入門概念、檔案存取API)可當成動手前的參考。
我的構想是在使用者以Live ID登入時,增加SkyDrive讀取的範圍請求,經同意後,程式先展開使用者SkyDrive的根目錄,列出資料夾與檔案;點選資料夾項目則可展開該資料夾,列出其下檔案與子資料夾;若為檔案,則點選可檢視或下載其內容。(瀏覽器依附檔名自行決定檢視或下載,例如: gif, png, jpg, txt, htm可直接開啟,zip, rar則是下載另存) 簡單來說,就是實現一個只能用來檢視的超陽春SkyDrive檔案總管!
整理需用到的SkyDrive REST API有:
是的,要做到SkyDrive檔案檢視功能,就只需要上述三個API即可搞定。
至於JavaScript操作的部分,我結合了jQuery BBQ外掛的AJAX Hisotry功能,在檢視不同資料夾時指定不同的state,以做到按瀏覽器回上頁也可回上層目錄的效果。除此之外,就是蠻單純的jQuery技巧,補充說明我寫在註解中,程式碼如下:
<!DOCTYPE html>
<html>
<head>
<title>SkyDrive Test</title>
<script type='text/javascript'
src='http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.js'></script>
<script src="jquery.ba-bbq.js" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
//取得Access Token,未成功登入時傳回null
function getAccessToken() {
var session = WL.getSession();
if (session != null && !session.error)
return session.access_token;
return null;
}
//AJAX History支援,state改變時顥示不同資料夾內容
window.lastId = null;
$(window).bind("hashchange", function (e) {
var f = e.getState("f");
if (f) listFiles(f);
});
var goUpper = "回上層";
var frmViewer = document.getElementById("frmViewer");
//列出檔案
function listFiles(folderId) {
if (!getAccessToken()) return;
//REST folderId/files可列出資料夾下的檔案清單
WL.api({
path: folderId + "/files"
}, function (res) {
var $ul = $("<ul class='f-item' />");
//folderId若以"."分成三段,代表非根目錄
//增加一個"回上層"連結
if (folderId.split('.').length > 2)
$ul.append(
"<li><img src='images/parent.png' class='icon' />" +
goUpper + "</li>");
//每個資料夾或檔案對應一個li
for (var i = 0; i < res.data.length; i++) {
var item = res.data[i];
var $li = $("<li />", {
"data-id": item.id,
"data-count": item.count,
"data-name": item.name,
"data-parent-id": item.parent_id,
"data-link": item.link
});
//id若為folder****,表示為資料夾
var isFolder = item.id.indexOf("folder") == 0;
$li.html(
"<img class='icon' src='images/" +
//資料夾與檔案Icon不同
(isFolder ? "folder" : "save") + ".png' />" +
"<span class='item-name'></span>")
.find(".item-name").text(
item.name +
//資料夾時,加顯示其下檔案數量
(isFolder ? "(" + item.count + ")" : "")
);
$ul.append($li);
}
$("#dFolder").empty().append($ul);
frmViewer.src = "";
});
}
//下載檔案內容
function downloadFile(id, name) {
//REST fileId/content可取得下載檔案內容用的連結
WL.api({
path: id + "/content"
}, function (res) {
if (res.error)
alert(res.error.message);
else {
//res.location指向可直接下載檔案二進位內容的連結
//指定成為IFrame.src,
//可直接顯示或另存檔案(由瀏覽器依附檔名決定)
frmViewer.src = res.location;
}
});
}
//點選檔案項目觸發事件
$("#dFolder").on("click", "li", function () {
var $li = $(this);
//若為回上層,則透過記憶中的前一層目錄回去
if ($li.text() == goUpper) {
$.bbq.pushState({ f: lastId });
return;
}
var id = $li.data("id");
if (id.indexOf("file") == 0)
downloadFile(id);
else {
//保留目前的folderId供稍後回上層用
lastId = $.bbq.getState("f");
$.bbq.pushState({ f: id });
}
});
$("#bList").click(function () {
if (!getAccessToken()) return;
});
});
</script>
<style>
table { width: 400px; }
td { border: 1px solid gray; }
div { margin: 2px; }
#dFolder li { color: white; text-decoration: underline; cursor: pointer; }
.bw-style { background-color: Black; color: White; }
.bw-style .icon { width: 16px; height: 16px; vertical-align: middle; }
</style>
</head>
<body>
<h1>SkyDrive Test</h1>
<table>
<tr><td style="width: 120px; vertical-align: top;">
<div id="signin"></div>
<div id="meName" class="Name"></div>
<div id="meImg"></div>
</td><td style="vertical-align: top;" class='bw-style'>
<div id="dFolder">
</div>
</td></tr>
<tr><td colspan="2">
<iframe style="width: 100%; height: 400px;" id="frmViewer"></iframe>
</td></tr>
</table>
<script src="wl.debug.js" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
WL.Event.subscribe("auth.login", function () {
var session = WL.getSession();
if (session.error)
alert("Error:" + session.error);
else {
var token = session != null ? session.access_token : null;
if (token != null) {
var url = "https://apis.live.net/v5.0/me/picture?access_token="
+ escape(token);
$("#meImg").html("<img src='" + url + "' />");
WL.api({ path: "me", method: "get" }, function (response) {
if (!response.error) {
$("#meName").html(response.name);
}
});
//取得SkyDrive Id,透過AJAX History方式觸發瀏覽
$.bbq.pushState({ f: "" });
WL.api({
path: "me/skydrive"
}, function (prop) {
$.bbq.pushState({ f: prop.id });
});
}
}
});
WL.Event.subscribe("auth.logout", function () {
$("#meImg,#meName").html("");
});
WL.init({
client_id: "0000000048076EE5",
redirect_uri: "http://www.darkthread.net/LiveSDK/callback.aspx",
scope: ["wl.signin", "wl.basic", "wl.offline_access", "wl.skydrive" ],
response_type: "code"
});
WL.ui({
name: "signin",
element: "signin"
});
});
</script>
</body>
</html>
程式執行起來的樣子如下圖,右方是檔案清單,下方放了一個IFrame。當點選資料夾(前方圖示為資料夾)時,清單會變成該資料夾展開後的項目;當點選檔案清單中檔案項目(前方Icon為小磁片),IFrame.src將指向該檔案的下載網址,若是圖檔可直接顯示,其他如ZIP檔等,則可另存新檔。(但有個小缺點,另存新檔時,SkyDrive伺服器傳回內容未提供檔名,預設URL中又臭又長像亂數的編碼預設會被當成檔名,故需要人工另外命名再存檔,此點可透過另外寫個Download Proxy ASPX來解決,但為避免失焦,並未納入範例中)
還有一點值得注意,相較於前次整合Live ID登入範例,這回我們還增加了wl.skydrive讀取範圍(Scope,可參見前文),因此同意頁面(Consent Page)可看到SkyDrive的提示(下圖紅框)。
另外,要弄出上圖中文版登入及同意網頁有個小訣竅: 依文件的說法,我們可由http://js.live.net/v5.0/zh-tw/wl.js取得正體中文版的JavaScript Library,但目前這個版本的最下方仍設定了wl_app._locale = "en";,其中的訊息也都還是英文。因此,呼叫Live帳號登入視窗時仍會顯示英文介面。暫時解法是將wl.js另存一份,並修改為wl_app._locale="zh-tw";,網頁改用此修改版就可以獲得中文版登入及同意畫面囉! 但有個缺點,未來若wl.js改版,修改版wl.js不會自動更新,我想不久後,等微軟RD真的落實wl.js多國語系化,就不用煩惱了。
程式執行後,我們點開ForApps資料夾,可以看到其下的資料夾結構,共有兩個圖檔,圖檔也可以點選檢視其內容:
跟SkyDrive網頁的瀏覽結果比對,我們查到的結果與ForApps目錄下的檔案項目與內容相符,一個陽春版SkyDrive檔案檢視工具就算大功告成囉!!