trello怎么导出表格
在上一部分中,我们构建了扩展的基础,通过基于Foundation的自定义设置屏幕并使用TrelloJavaScript客户端库来实现身份验证。 在这一部分中,我们将通过添加导出逻辑和UI来完成扩展。
讯息传递
当我们在设置屏幕上通过Trello进行身份验证时,Trello令牌将保存在本地存储中。 但是,设置页面是它自己的页面,并且实际上是它自己的环境– ergo,扩展程序的后台页面和扩展程序的内容脚本都无法访问它。 这是我们需要使用消息传递的地方 。
chrome.extension.sendMessage
API用于在后台页面之间发送消息。 在本例中,我们将使用它将令牌从设置页面发送到我们的后台页面。 由于我们的设置工作一完成便完成,我们不妨自动关闭该标签,以提高用户友好性。
将settings.js
中的init
函数的第一部分更新为:
// Check if page load is a redirect back from the auth procedure
if (HashSearch.keyExists('token')) {
Trello.authorize(
{
name: "Trello Helper Extension",
expiration: "never",
interactive: false,
scope: {read: true, write: false},
success: function () {
chrome.extension.sendMessage({
command: 'saveToken',
token: localStorage.getItem('trello_token')
}, function(data) {
chrome.tabs.getCurrent(function (tab) {
chrome.tabs.remove(tab.id)
});
});
},
error: function () {
alert("Failed to authorize with Trello.")
}
});
}
使用此逻辑,我们告诉Trello库在身份验证完成时向扩展发送消息,并且一旦它收到一条返回消息,即收到了该消息(即function(data)
部分),便关闭当前选项卡。
现在让我们处理背景页面。 首先,将background.html
的内容更改为此:
<!doctype html>
<script type="text/javascript" src="scripts/key.js"></script>
<script type="text/javascript" src="scripts/background.js"></script>
<script type="text/javascript" src="lib/jquery-2.1.1.min.js"></script>
<script type="text/javascript" src="lib/trello_client.js"></script>
我们像以前一样加载应用程序密钥,将用于逻辑的后台脚本以及Trello客户端。 显然,我们也需要jQuery –这是Trello的依赖项。
然后,将scripts/background.js
更改为:
chrome.extension.onMessage.addListener(
function (request, sender, sendResponse) {
chrome.pageAction.show(sender.tab.id);
// Now we have a token saved locally, as fetched from the settings page after authorization.
if (request.command == 'saveToken') {
localStorage.setItem('trello_token', request.token);
sendResponse();
return true;
}
});
这是从设置页面接收消息的部分。 它从请求中获取令牌并将其保存到localStorage中以备将来使用。 我们使用带有command
的对象形成作为主键,因为我们打算稍后将其他命令发送到后台页面。
自动设定
在saveToken
命令上方,让我们saveToken
另一个块:
if (!request.command && !localStorage.getItem('trello_token')) {
chrome.tabs.create({url: chrome.extension.getURL('settings/index.html')});
sendResponse();
return true;
}
如果我们没有发出特定命令,并且我们的用户尚未通过Trello进行身份验证,请在新标签页中打开设置页面。 这样可以确保在首次安装扩展程序后立即在浏览器中访问Trello板后立即打开设置页面。
添加菜单选项
Trello的UI非常不适合自定义。 列表中的元素中没有ID(作为数据属性或任何类型的链接),而卡片则具有ID。 单击右上角的列表选项按钮时生成的上下文菜单都是在每次调用时都从头开始重建的(太多杀伤力了吗?),并且全部都归类为“弹出”框,即如果您单击用户界面中几乎所有其他菜单,也会被召唤。 更糟糕的是,一旦调用列表的弹出菜单,菜单本身就没有被调用的列表的标识符,因此您不了解其上下文,这使得轻松获取列表的ID来正确查询列表的ID变得特别困难。 Trello API并获取卡以进行导出。 这就是为什么后面的内容看起来像很多可骇的骇客的原因,但是那是因为。
要将菜单选项添加到上下文菜单,我们需要编辑main.js
内容脚本。 变成这样:
chrome.extension.sendMessage({}, function (response) {
var readyStateCheckInterval = setInterval(function () {
if (document.readyState === "complete") {
clearInterval(readyStateCheckInterval);
var popover = $(".pop-over");
$('.list-header-menu-icon').click(function(event) {
var popover_summoned_interval = setInterval(function () {
if ($(popover).is(':visible')) {
clearInterval(popover_summoned_interval);
$(".pop-over .content").append('<hr><ul class="pop-over-list"> <li><a class="js-export-list" href="#">Export This List</a></li> </ul>');
$(".js-export-list").click(function(e){
// EXPORT LIST
});
}
}, 50);
});
}
}, 10);
});
以var popover = $(".pop-over");
,我们设置了一个变量来保存popover对象,只不过我们不必继续重新获取它。 然后,当单击列表上的菜单按钮( .list-header-menu-icon
)时,我们将召唤一个间隔,该间隔会不断注意弹出窗口是否可见。 一旦它变得可见,检查就会停止,并且菜单选项会附加到所有选项的底部,特别是经过精心设计,使其看起来与其余选项相似,因此适合。最后,将click事件处理程序绑定到此选项,以便我们可以单击该选项时,请调用“导出”。 但是..我们怎么知道我们需要出口什么? 我们导出哪种格式?
查找列表ID
就像我之前说过的那样,Trello的UI众所周知对开发人员不友好。 它不提供带有DOM元素的列表ID,因此找到它们并不容易。 为什么我们需要列表ID? 要查询Trello API并获取卡,以便我们可以导出它们-我们已经说过,由于UI在大型板上的不稳定性,我们不会解析UI,但是将依赖于API。
幸运的是,如果我们检查单个列表中的卡,我们可以看到它们实际上确实具有href
属性,并且其中包含卡ID。 通过了解卡ID,我们可以查询Trello的信息并获取其父列表的ID。 但是..如果弹出菜单未附加在列表上,我们如何找出单击的列表? 我们不能只抓住我们遇到的第一张牌,那太随机了。
单击菜单按钮时,我们可以使用jQuery触发的event
。 这个很重要! 我们使用菜单按钮上的原始单击,而不是单击“导出”选项,这是因为虽然原始按钮绑定到了我们想要导出的列表,但是生成的实际菜单却没有 ,因此几乎使我们无法找出要处理的清单。 代替上面的代码中的// EXPORT LIST
注释,添加以下代码:
exportList(event);
然后,创建函数:
function exportList(event) {
var first_card_id = findFirstCardId(event);
if (!first_card_id) {
alert('No cards found in the list.');
return false;
}
}
最后,创建findFirstCardId
函数:
/**
* Uses the menu button on a card to find the first card in that list and get its ID
* Returns false if not found, or the ID if there is a card
* @param event
* @returns bool | string
*/
function findFirstCardId(event) {
var titles = $(event.currentTarget).parent().parent().find('a.list-card-title:first');
if (titles[0] === undefined) {
console.error('List has no cards!');
return false;
} else {
return $(titles[0]).attr('href').split('/')[2];
}
}

免费学习PHP!
全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。
原价$ 11.95 您的完全免费
我们获取事件目标的祖父母(列表),并在其中找到第一个卡片标题。 标题包含以下形状的href
:
如果未找到标题,我们将提醒用户该列表无法导出。 否则,我们提取并返回卡的ID。
现在,我们的exportList
函数具有卡ID,我们可以使用它来找到列表ID。 如果我们查看API文档 ,则可以使用URL card/{{ID}}
来获取所需的信息。 为了最小化我们要求Trello返回的数据量,我们还可以将查询限制为仅具有fields
param的idList
属性。 让我们向background.js
添加一个新命令。
if (request.command == 'getCardListId') {
trelloInit();
Trello.rest('GET', 'cards/'+request.id, {fields: "idList"}, function(data){
sendResponse(data);
}, function (data) {
sendResponse(data);
});
return true;
}
我们也需要定义trelloInit
函数。 在调用与Trello交互的命令之前,我们可以每次调用一次,因此正确设置了令牌和密钥,并且100%确定我们的请求已通过身份验证。
function trelloInit() {
Trello.setKey(APP_KEY);
Trello.setToken(localStorage.getItem('trello_token'));
}
现在,我们已成功获取列表ID。
提取列表卡
再返回几行代码,回到main.js
,我们现在有了一个exportList
函数,如下所示:
function exportList(event) {
var first_card_id = findFirstCardId(event);
if (!first_card_id) {
alert('No cards found in the list.');
return false;
}
chrome.extension.sendMessage({
command: 'getCardListId',
id: first_card_id
}, function(data){
if (data.idList !== undefined) {
chrome.extension.sendMessage({
command: 'getListCards',
id: data.idList
}, function(data) {
console.log(data);
});
}
});
}
在“人文”中,这是:
- 获取第一张卡的ID
- 如果找不到ID,则列表显然为空
- 如果找到ID,请调用后台页面,并通过调用Trello API告诉它为我们提供列表ID
- 如果列表ID合适,请再次调用后台页面以获取列表卡片,完成后将结果输出到控制台。
回到后台页面,我们现在可以根据API文档来构建getListCards
命令:
if (request.command == 'getListCards') {
trelloInit();
Trello.rest('GET', 'lists/'+request.id+'/cards', {}, function(data){
sendResponse(data);
}, function (data) {
sendResponse(data);
});
return true;
}
如果现在重新加载并测试扩展,您不仅应该能够看到导出选项出现在列表中,而且还可以在单击选项后在控制台中找到我们正在寻找的导出数据。
导出格式
现在,我们将采用一种简化的导出方法,因为本教程的运行时间很长。 我们将为用户提供TXT或JSON的选择,以及我们预先定义的形状和形式。 现在,文本输出将如下所示:
Topic: Test Card 1
Description:
This is a description
Test Card 2
Test Card 3
Topic: Test Card 4
Description:
This is another description
Test Card 5
而JSON将是从Trello收到的内容,即:
显然,JSON数据会产生更多的信息,但编辑起来也容易得多-只需将其粘贴到任何IDE或JSON Online Online或JSON到CSV之类的工具中,就可以了。
要导出,我们需要一个模态窗口,将数据粘贴到该窗口中。 这里有一个吸引人的选项是Foundation框架,因为我们已经在设置页面中使用了它,并且它具有自己的模式弹出组件,但是Foundation和TrelloCSS都没有正确命名,并且在Trello的原因中包括了FoundationCSS。 我们还预先包含了jQuery,但是要再次启动并运行Dialog,我们还需要包含jQuery UI,即使这样还不够-Chrome扩展程序不支持通过相对url()
加载CSS中的图像url()
语法,这是jQuery UI所使用的–我们必须重写jQuery UICSS才能使用本地扩展URL或使用base64编码的图像,这两种方法都没有吸引力。
相反,我们将设计自己的弹出窗口,并使用Trello的某些现有样式,而忽略沿途的所有冲突。 我将最终的代码放在这里,然后对其进行解释。 请创建lib/TrelloHelper/js/exportPopup.js
,并提供以下内容:
var exportPopup;
var TrelloExportPopup = function() {
}
TrelloExportPopup.prototype.init = function() {
// When run, this makes sure the popup isn't around.
// If it finds the popup residue, it removes it, paving the way for a fresh one.
var popoverScan = $('.trello_helper_export_popup');
if ($(popoverScan).length > 0) {
$(popoverScan).remove();
}
popoverScan = null;
// Create our new popup, hidden by default
exportPopup = $('<div class="trello_helper_export_popup" style="display: none"></div>');
// Create a header area for the popup, which will contain the buttons / tabs
// Create a body area, which will contain the export data
var header = $('<div class="trello_helper_export_popup_header"></div>');
var body = $('<div class="trello_helper_export_popup_body"></div>');
// Create areas for exporting the data - simple non-editable textareas
var textarea = $('<textarea class="trello_helper_export_popup_textarea exportarea" readonly="true" style="display: none"></textarea>');
var jsonarea = $('<textarea class="trello_helper_export_popup_jsonarea exportarea" readonly="true" style="display: none"></textarea>');
// Create header buttons / tabs
var textButton = $('<a href="#" class="exporttab button" data-area="text">Text Export</a>');
var jsonButton = $('<a href="#" class="exporttab button" data-area="json">JSON Export</a>');
var closeButton = $('<a href="#" class="button right">Close</a>');
// Have the close button close our tab, and do the same if the user clicks outside the popup
$(closeButton).click(this.hide);
// Put everything together
$(header).append(jsonButton).append(textButton).append(closeButton);
$(body).append(textarea).append(jsonarea);
$(exportPopup).append(header).append(body);
// Add out popup to the Trello page
$("#content").append(exportPopup);
// Bind listeners to the buttons / tabs in the header, so we can switch output modes
$(".exporttab").click(function (e) {
var area = e.currentTarget.dataset.area;
$(".exportarea").hide();
$(".trello_helper_export_popup_" + area + "area").show();
});
};
TrelloExportPopup.prototype.hide = function() {
// Execute hiding logic only if the popup is visible
if ($(".trello_helper_export_popup").is(":visible")) {
$(exportPopup).hide();
}
};
TrelloExportPopup.prototype.show = function(data) {
// Hide all textareas
$(".exportarea").hide();
// Show the first one by simulating a click on the first tab
// This makes sure our export popup always opens in JSON mode
$(".exporttab")[0].click();
var text = '';
var cardCount = data.length;
var i = 0;
while (i < cardCount) {
text += 'Topic: ' + data[i].name;
if (data[i].desc) {
text += '\nDescription:\n' + data[i].desc;
}
text += '\n\n\n';
i++;
}
$(exportPopup).find('.trello_helper_export_popup_textarea').text(text);
$(exportPopup).find('.trello_helper_export_popup_jsonarea').text(JSON.stringify(data));
$(exportPopup).show();
};
我选择在主脚本之外添加弹出逻辑,以便稍后可以轻松地对其进行改进。 我还选择了“面向对象”方法,因为我喜欢它。 我们定义了一个新的TrelloExportPopup“类”,它使用三种方法-初始化,显示和隐藏。 内容脚本加载后将立即调用Init。 它是负责构建弹出窗口,附加正确的事件侦听器并将整个内容添加到Trello板HTML中的方法。 将.button
类添加到弹出窗口标题中的按钮上,以确保我们得到的外观与当前Trello UI一致。 我要查找的外观是一种“选项卡式”界面-单击“文本”,然后显示文本导出,单击“ JSON”,然后显示JSON。
hide方法将隐藏弹出窗口,但前提是该弹出窗口以可见形式存在于页面中的某处。 show方法自动激活第一个(JSON)选项卡视图,并使用所需数据填充导出区域。 JSON区域是一个简单的字符串转储-字符串形式的JSON数据输出,而文本区域目前仅在单独的行上输出卡的标题和描述,每行之间有两个空行-高度“复制粘贴友好”。
我们现在需要做的就是对其进行一些样式化。 这是lib/TrelloHelper/css/exportpopup.css
:
.trello_helper_export_popup {
background-color: white;
z-index: 1000;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%); /* Yep! */
width: 48%;
min-height: 50%;
border-radius: 3px;
border: 1px solid #dbdbdb;
border-bottom-color: #c2c2c2;
box-shadow: 0 1px 6px rgba(0,0,0,.15);
}
.trello_helper_export_popup_body {
position: absolute;
right: 0;
left: 0;
bottom: 0;
top: 55px;
}
.trello_helper_export_popup .button {
margin: 10px;
}
.trello_helper_export_popup .button .right {
float: right;
}
.trello_helper_export_popup textarea {
height: 100%;
}
这样可以确保弹出窗口居中,并且看起来像本机Trello弹出窗口。 它还确保将向我们显示导出内容的文本区域将填充弹出窗口的其余空间。 现在让我们在内容脚本中包含这些文件:
"content_scripts": [
{
"matches": ["https://trello.com/b/*"],
"css": ["lib/TrelloHelper/css/exportpopup.css"],
"js": [
"lib/jquery-2.1.1.min.js",
"lib/TrelloHelper/js/exportpopup.js",
"scripts/main.js"
],
"run_at": "document_idle"
}
],
最后,让我们使用新的弹出逻辑为main.js
。 main.js
的最终版本如下所示:
var tep = new TrelloExportPopup();
chrome.extension.sendMessage({}, function (response) {
var readyStateCheckInterval = setInterval(function () {
if (document.readyState === "complete") {
clearInterval(readyStateCheckInterval);
var popover = $(".pop-over");
tep.init();
$('.list-header-menu-icon').click(function (event) {
var popover_summoned_interval = setInterval(function () {
if ($(popover).is(':visible')) {
clearInterval(popover_summoned_interval);
$(".pop-over .content").append('<hr><ul class="pop-over-list"> <li><a class="js-export-list" href="#">Export This List</a></li> </ul>');
$(".js-export-list").click(function (e) {
exportList(event);
});
}
}, 50);
});
}
}, 10);
});
function exportList(event) {
tep.hide();
var first_card_id = findFirstCardId(event);
if (!first_card_id) {
alert('No cards found in the list.');
return false;
}
chrome.extension.sendMessage({
command: 'getCardListId',
id: first_card_id
}, function (data) {
if (data.idList !== undefined) {
chrome.extension.sendMessage({
command: 'getListCards',
id: data.idList
}, function (data) {
tep.show(data);
});
}
});
}
我们首先“实例化” TrelloExportPopup,以便可以在代码中使用其方法。 然后,在将click事件监听器绑定到菜单之前,我们使用tep.init()
初始化我们的弹出窗口,这样它就可以在DOM中正常使用,并且在需要之前就可以使用了。 单击“导出”链接后,我们将像以前一样调用exportList
函数。
在exportList
函数中,我们首先使用tep.hide()
隐藏弹出窗口, tep.hide()
在浏览另一个列表的菜单时打开该弹出窗口,然后,一旦从背景页面中获取卡片,便显示导出弹出窗口与tep.show(data)
。 而已!
现在重新加载扩展,刷新Trello页面,您应该有一个有效的导出选项!
错误和改进
我故意留下了一些错误和警告。 如果有足够的兴趣,我们将在以后的文章中与那些人打交道,为故障安全调整和优化扩展。 这里仍然有一些改进:
快取
为了加快速度以备将来使用,我们可以使用localStorage记住列表属于哪个板。 请注意,如果您从一个板到另一个板移动一个列表,这可能会中断,因此请仔细实现此功能–确保为列表移动添加另一个侦听器,以便使缓存的数据无效!
重复的导出选项生成
如果在菜单仍处于打开状态时疯狂地单击菜单图标,则将继续在菜单底部添加新的“导出”选项。 需要实施故障安全措施,以检查该选项是否已经存在。
初始化问题
在拥有数百个董事会和成员的庞大董事会上,Trello的UI变得非常慢。 这会导致文档就绪事件不起作用,并且脚本的init部分在绑定任何侦听器的UI元素之前执行。 因此,菜单有时不具有“导出”选项,并且直到刷新后才能获取。
更衣板
更换板会杀死当前的UI,并为新板重建它。 然而,问题在于事件监听器的元素也被杀死了-因此我们的菜单不再召唤Export选项。 与上述问题类似,更改时需要触发重新初始化才能正常工作。
无限循环
从天文学角度来看,菜单单击后弹出窗口不会呈现的可能性很小(也许Trello改变了他们的UI,也许他们改变了类,或者他们只是有某种UI错误),在这种情况下,循环检查它的可见性将变得无限大,占用大量CPU资源,直到该选项卡的进程被杀死为止。 对此采取保护措施将是不错的。
结论
在这个简短的系列文章中,我们为Trello构建了一个简单的Chrome扩展程序,该扩展程序使我们可以将给定列表中的卡导出为JSON或TXT列表。 使用此示例为基础,并创建自己的Trello扩展-您可以完成的工作仅受您的想象力限制(以及Trello API提供的功能:))。 身份验证已为您解决,逻辑模板到位–开始编码!
我们在本系列教程中编写的代码可在Github上获得 。
您想继续阅读本教程吗? 实施了更多功能吗? 让我知道! 反馈表示赞赏!
翻译自: https://www.sitepoint.com/build-trello-chrome-extension-exporting-lists/
trello怎么导出表格