此用户脚本在每个代码段的顶部添加了“ Review”链接。单击后,它将在每个代码行的前面添加复选框。您选中要评论的行的复选框,再次单击链接-现在已更改为“添加到答案”,然后点击链接-代码将复制到您的答案中。
我相信该用户脚本可以显着减少上下滚动,在该位置中,您始终可以从问题中复制一些代码,将其粘贴到答案中,然后再次向上滚动,然后复制代码,向下滚动,粘贴,向上复制等...现在,您只需从上至下浏览代码,然后选择要评论的行即可。
我已经测试了此用户脚本使用Google Chrome + Tampermonkey,但我认为它也应与Firefox + Greasemonkey以及支持用户脚本的其他浏览器/扩展组合一起使用。
该代码也可在GitHub上获得。
如果可以从链接中包含用户脚本,请使用此链接。
// ==UserScript==
// @name Auto-Review
// @author Simon Forsberg
// @namespace zomis
// @homepage https://www.github.com/Zomis/Auto-Review
// @description Adds checkboxes for copying code in a post to an answer.
// @include http://stackoverflow.com/*
// @include http://meta.stackoverflow.com/*
// @include http://superuser.com/*
// @include http://serverfault.com/*
// @include http://meta.superuser.com/*
// @include http://meta.serverfault.com/*
// @include http://stackapps.com/*
// @include http://askubuntu.com/*
// @include http://*.stackexchange.com/*
// @exclude http://chat.stackexchange.com/*
// ==/UserScript==
function embedFunction(name, theFunction) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.textContent = theFunction.toString().replace(/function ?/, 'function ' + name);
document.getElementsByTagName('head')[0].appendChild(script);
}
embedFunction('showAutoreviewButtons', function(clickedObject) {
var i;
if ($(clickedObject).data('review')) {
var answer = $("#wmd-input");
var answer_text = answer.val();
var added_lines = 0;
var added_blocks = 0;
// loop through checkboxes and prepare answer
var checkboxes = $("input.autoreview");
var block = [];
for (i = 0; i < checkboxes.length; i++) {
if (!$(checkboxes[i]).prop('checked')) {
continue;
}
var checkbox = $(checkboxes[i]);
var line_data = (checkbox).data('line');
block.push(line_data);
if ((i === checkboxes.length - 1) || !$(checkboxes[i + 1]).prop('checked')) {
// add block
var block_line;
var cut_count = 1000;
for (block_line = 0; block_line < block.length; block_line++) {
var cut_this = block[block_line].indexOf(block[block_line].trim());
if (cut_count > cut_this) {
cut_count = cut_this;
}
}
for (block_line = 0; block_line < block.length; block_line++) {
answer_text = answer_text + "\n " + block[block_line].substr(cut_count);
}
answer_text += "\n\n---\n";
added_lines += block.length;
added_blocks++;
block = [];
}
}
answer.val(answer_text);
alert(added_lines + " lines in " + added_blocks + " blocks added to answer.");
return;
}
$(clickedObject).data('review', true);
$(clickedObject).text("Add to answer");
var spans = $("code span", $(clickedObject).next());
console.log(spans.length);
var count = spans.length;
var line = "";
var first = null;
for (i = 0; i < count; i++) {
var element = $(spans[i]);
if (first === null) {
first = element;
}
if (element.text().indexOf("\n") !== -1) {
console.log(i + " line: " + line);
var lines = element.text().split("\n");
element.text("");
for (var line_index = 1; line_index < lines.length; line_index++) {
var current_line = lines[line_index];
var prev_line = lines[line_index - 1];
var span;
// Add the last part of the previous line
if (line_index == 1) {
line += prev_line;
span = $('<span class="pln zomis before">' + prev_line + '\n</span>');
element.after(span);
element = span;
}
// Add the checkbox for the previous line
if (line.length > 0) {
var dataProperty = 'data-line="' + line + '" ';
var checkbox = $('<input type="checkbox" ' + dataProperty + ' class="autoreview"></input>');
first.before(checkbox);
first = null;
}
// Add the beginning <span> element for the current line
if (line_index < lines.length - 1) {
current_line += "\n";
}
span = $('<span class="pln zomis after">' + current_line + '</span>');
element.after(span);
first = span;
element = span;
line = current_line;
}
}
else {
line += element.text().replace(/\/g, '\\').replace(/"/g, '\"');
}
}
if (line.length > 0) {
dataProperty = 'data-line="' + line + '" ';
checkbox = $('<input type="checkbox" ' + dataProperty + ' class="autoreview"></input>');
first.before(checkbox);
}
});
$('pre code').parent().before('<a href="javascript:void(0);" onclick="showAutoreviewButtons($(this))">(Review)</a>');
主要问题:
我是否遵循JavaScript约定?我看到
people.coding( "like this" );
每个参数周围都有多余的空格,而且我还看到人们在方法开始时声明所有变量。这是一些官方惯例吗?我在这里违反任何正式约定吗?我觉得我在JavaScript代码中使用了Java约定。在保持浏览器兼容性的同时,是否可以清理代码,使用实用程序方法和内容?例如,在代码中找出一个块的缩进量时,我正在考虑如何在Java中使用
block.stream().mapToInt(str -> str.indexOf(str.trim())).min()
进行操作,可以在此处执行类似的操作吗?欢迎任何其他评论!
我敢打赌,有很多事情可以改进。它是用户脚本这一事实使我对可以做的事情感到有些限制,但这也许只是因为我不知道如何为用户脚本做这些操作。
我打算将此用户脚本发布到当我对此感到满意时,可以在http://www.stackapps.com上将任何功能请求/ UI建议添加为github上的问题,也可以在The 2nd Monitor中对我进行ping操作。
自动为任何在编写答案时使用脚本的人提供帮助!
#1 楼
命名我知道命名可能很难,但是'Auto-Review'的名称与StackExchange上现有的UserScript叫AutoReviewComments
协议
的名称有点冲突
您有很多用户脚本约定无法遵守。
首先,对于Firefox,您需要将标头部分包装到“保留的”注释块中:
/** @preserve
// ==UserScript==
.....
// ==/UserScript==
*/
处理javascript后,需要保留该内容以保留注释块。这样,“编译”版本就可以保留引用,并让FireFox知道它的含义。
其他浏览器可能没有相同的要求。
此外,您还需要指定
@grant
权限,以便GreaseMonkey满意。在您的情况下,none
是合适的:// @grant none
一旦进行了这些修改,用户脚本就会很好地加载到FireFox中。
可用性
,我建议您进行四项用户体验增强:
没有弹出框-弹出窗口令人分心,
滚动到插入内容-插入代码块后,滚动到编辑点并使它在屏幕上可见
在答案输入框上触发更改事件-这将更新答案的“预览”。目前,您必须在答案框中手动更改某些内容才能更新预览。
处理复选框后,应清除它们。如果以后需要复制不同的块,则必须取消选中每个框都是PITA。
审阅
双数组解引用是不必要的微优化。您具有以下代码(使用用户脚本在此处复制):
for (i = 0; i < checkboxes.length; i++) {
if (!$(checkboxes[i]).prop('checked')) {
continue;
}
var checkbox = $(checkboxes[i]);
var line_data = (checkbox).data('line');
该代码重复引用了
$(checkboxes[i])
。我想这是因为如果不检查变量,您不想承担该变量的开销。这是早期优化。该代码将更简单地为:for (i = 0; i < checkboxes.length; i++) {
var checkbox = $(checkboxes[i]);
if (!checkbox.prop('checked')) {
continue;
}
var line_data = (checkbox).data('line');
var
声明。 JavaScript将所有变量声明“提升”到包含它的函数的顶部。与其他语言不同,JavaScript不应使用“块本地”声明进行编码。最佳做法是将所有变量声明移到函数的第一项。这个堆栈溢出的答案比我做的要好得多。评论
\ $ \ begingroup \ $
虽然所有var声明都已挂起,但我仍然认为避免在函数顶部使用var声明的怪物块会减少两种危害。我宁愿不小心将一个标识符声明为var两次,也不愿由于声明和定义之间的分离而根本不声明它。
\ $ \ endgroup \ $
– 200_success
15年1月27日在5:42
#2 楼
编码风格我不是JavaScript专家,但是我很确定编码风格指南比Java严格得多,例如。
>在运算符之间使用空格的方式,
以及像Java中的大括号的放置方式似乎很常见,
我从未听说过有人反对。
还有其他一些样式,例如您提到的那些,
,但它们很少见。
有些人也更喜欢使用2个空格而不是4个空格的缩进,
但这在很大程度上似乎是一种品味问题。
作为参考,
PyCharm是由JetBrains(与IntelliJ相同的名称)进行Python + Web开发的出色IDE,
对JavaScript具有良好的支持,
也不反对您的代码就风格而言。
我认为这是一个好兆头。
对于
people.coding( "like this" );
之类的代码,自动格式化功能会删除括号内的空格。
错误的做法
首先,将代码粘贴到http://jshint.com/中并亲自查看:
一个重复的变量定义:
checkbox
一些超出范围的变量
此外,
我发现奇怪的是,您没有充分利用
embedFunction
中的jQuery。由于您已经在脚本中的其他地方使用jQuery了很多,因此
例如,而不是:
>
您可以将其简化为:原样”。我会尝试找出原因。同时,我的反对意见仍然存在:在同一脚本中混合使用经典JavaScript和jQuery有点奇怪,好像是由两个不同的人或同一个人在不同的时间完成的一样。我认为最好保持一致并要么不依赖jQuery就编写经典JavaScript,要么完全拥抱jQuery。
缓存
$(...)
查找的结果DOM查找并不便宜。
因此,只要您重复查找,就可以考虑在变量中进行缓存,例如在这里:
document.getElementsByTagName('head')[0].appendChild(script);
以上是如果先分配给
checkbox
更好,然后再分配if
,则更好。当然也可以很好地缓存它。奇怪的元素
在这一行上:
$('head').append(script);
checkboxes[i]
周围的括号很...好奇... 您不需要它们,
可能会使读者误以为它是jQuery并被误删了
$(clickedObject)
( 扩展分配
此分配可以替换为
checkbox
扩展分配:if (!$(checkboxes[i]).prop('checked')) {
continue;
}
var checkbox = $(checkboxes[i]);
评论
\ $ \ begingroup \ $
$('head')。append(script);不起作用,我收到了很好的错误消息“未定义不是函数”。似乎由于某种原因未定义JQuery。 (我想它还没有被加载)
\ $ \ endgroup \ $
–西蒙·福斯伯格
15年1月27日,11:35
\ $ \ begingroup \ $
这让我感到惊讶,因为如果未加载jQuery,则在embedFunction(...)调用之后立即拥有的$('pre code')应该首先给出相同的错误。今晚我将尝试使用您的脚本。我现在在评论中对此进行了小幅更新。
\ $ \ endgroup \ $
– janos
15年1月27日在12:29
#3 楼
我知道这段代码已经存在大约5年了,但是尽管这些站点上的DOM发生了一些变化,但看起来仍然可以正常工作。自发布此书以来,您无疑已经学到了很多东西,但是我觉得还有其他事情尚未提及/并入github脚本中,可以改善/简化代码。我最近已经习惯了github风格的UI,它通过单击和拖动选择来选择要注释的行。我考虑过制作这样的用户脚本,并且可能会利用其中的一些代码。我开始修改它,发现它在一个巨大的功能中有很多代码,以及一些大循环。我建议为事件处理程序使用单独的功能,例如一个用于单击按钮以添加复选框,另一个用于单击按钮以将选中的行添加到评论。我知道这不是单一责任原则的直接应用,但感觉很相关。
jQuery
:checked
选择器可以简化代码,以便从以下位置复制到答案时找到复选框:
var checkboxes = $("input.autoreview");
for (i = 0; i < checkboxes.length; i++) {
if (!$(checkboxes[i]).prop('checked')) {
continue;
}
var checkbox = $(checkboxes[i]);
对此:
var checkboxes = $("input.autoreview:checked");
for (i = 0; i < checkboxes.length; i++) {
var checkbox = $(checkboxes[i]);
可以使用功能性方法而是使用
Array.reduce()
。 jQuery确实具有类似的功能方法,例如.map()
和.each()
的过滤方法,它们类似于Array.map()
的本机数组方法,但是请注意jQuery等效项之间的参数差异。例如,在代码来弄清楚我正在考虑如何在Java中使用
block.stream().mapToInt(str -> str.indexOf(str.trim())).min()
的块的缩进,可以在此处执行类似的操作吗?使用ecmascript- 6个功能可以简化诸如取消引用数组之类的事情,即使用
for...of
循环。在回顾了您的Ur代码的Royal游戏之后,我知道您熟悉箭头功能。它们可以与Array.map()
,Array.filter()
和Array.reduce()
等功能方法一起使用,以简化语法。更新:PR#4已创建并合并,其中包含来自上面的许多建议。
评论
\ $ \ begingroup \ $
确实有很多好处!随时提出请求请求或其他任何内容,或使用我为其他项目编写的代码。这不是我打算维护的任何内容。
\ $ \ endgroup \ $
–西蒙·福斯伯格
20年4月21日在10:00
评论
我不喜欢您必须单击每行一个复选框。目前,我只是用鼠标中键点击编辑并复制了相关部分。当我必须处理12行以上的代码时,您的工具又如何更快?@Pimgd当前可能不是,但是我正在寻找改善方法。例如按住shift键并单击一个复选框以从先前选择的复选框中选择所有行?
是的,这样做。会帮助吨。