Comments 19
Норм.
+2
Чтобы вызвать функцию сразу после ее объявления можно делать так:
И разве не короче было бы сделать
вместо того чтобы перечислять все возможные варианты вложенности?
(function () {
/*код */
})();
И разве не короче было бы сделать
document.querySelectorAll('.content img');
вместо того чтобы перечислять все возможные варианты вложенности?
+2
Все верно, так было бы проще, но не учитывались бы частные случаи. Например в теле поста для автора появилась кнопка редактирования с изображением, а я же все прячу……
Помещать все блоки в анонимную самовызывающуюся функцию было бы не семантично (приучаю себя к тому, чтобы код разбирался быстро и любым человеком), да и при отладке помешает.
Поправьте меня пожалуйста если я сделал неправильные выводы.
Помещать все блоки в анонимную самовызывающуюся функцию было бы не семантично (приучаю себя к тому, чтобы код разбирался быстро и любым человеком), да и при отладке помешает.
Поправьте меня пожалуйста если я сделал неправильные выводы.
+1
По-моему все возможные частные случаи перечислять более затратно, чем отключить все, а потом включить то что действительно необходимо ( белые vs черные списки). В вашем случае это 9 проходов по DOM против 2х.
Из большинства объявленных функций повторно у вас используется если я не ошибаюсь только одна. Остальное — линейное программирование. Для семантики и отладки на данном уровне комментариев вполне достаточно.
Из большинства объявленных функций повторно у вас используется если я не ошибаюсь только одна. Остальное — линейное программирование. Для семантики и отладки на данном уровне комментариев вполне достаточно.
0
Да, насчет изображений с вами соглашусь и позволю себе добавить, что в случае с перечислением не нужно будет исправлять скрипт если появится пресловутая кнопка редактирования поста с изображением. Но все же в данном случае не так сложно будет сделать быстрое исправление в угоду оптимизации.
Комментарии я стараюсь не плодить, так как лучше сделать код семантичным. Иногда имя функции отражает суть длинного комментария, а зачем лишний текст в таком случае.
Спасибо за пояснения и правильное направление для оптимизации скрипта.
Комментарии я стараюсь не плодить, так как лучше сделать код семантичным. Иногда имя функции отражает суть длинного комментария, а зачем лишний текст в таком случае.
Спасибо за пояснения и правильное направление для оптимизации скрипта.
0
Комментарии очень даже нужны. Например без комментариев в статье кусок кода
тяжело воспринять при первом прочтении — глаза мозолят «магические числа». Опять же о какой семантике может идти речь если в наличии функции hideReplies() и hideR()?
function declOfNum(number, titles) {
cases = [2, 0, 1, 1, 1, 2];
return titles[(number % 100 > 4 && number % 100 < 20) ? 2 : cases[(number % 10 < 5) ? number % 10 : 5]];
}
тяжело воспринять при первом прочтении — глаза мозолят «магические числа». Опять же о какой семантике может идти речь если в наличии функции hideReplies() и hideR()?
0
После того как получил инвайт на Хабр, для комментариев появилась ссылка «ответить» и кнопка раскрытия дерева ответов оказалась под этой ссылкой съедая свободное пространство.
Сделал хотфикс для корректного отображения и
Сделал хотфикс для корректного отображения и
теперь все выглядит так
0
Я бы хранил селекторы так:
var selectors = [
'.content > img',
'.content > div > img',
'.content > div > div > img',
];
var imgs = document.querySelectorAll(selectors.join(', '));
+1
Немного поправил код, послал пул реквест. Давно не писал на vanilla.js, местами тупил, но вроде осилил.
Скрытый текст
/* Add css rules to specified selector */
function addCSSRule(selector, rules, sheet) {
sheet = sheet || document.styleSheets[0];
if (sheet.insertRule) {
sheet.insertRule(selector + '{' + rules + '}');
} else {
sheet.addRule(selector, rules);
}
}
/* Return human-friendly declension of provided numbers */
function declOfNum(number, titles) {
cases = [2, 0, 1, 1, 1, 2];
return titles[(number % 100 > 4 && number % 100 < 20) ? 2 : cases[(number % 10 < 5) ? number % 10 : 5]];
}
/* Return chidren nodes of an element with a specified class name */
function getChildrenByClassName(element, className) {
var children = [];
for (var i = 0; i < element.childNodes.length; i++) {
if (element.childNodes[i].className == className) {
children.push(element.childNodes[i]);
}
}
return children;
}
/* Hide single nodeList */
function hideNode (nodes) {
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
node.style.display = 'none';
}
}
/* Hide nodeLists provided as array */
function hideNodes (nodes) {
if( Object.prototype.toString.call( nodes ) === '[object Array]' ) {
for (var i = 0; i < nodes.length; i++) {
hideNode(nodes[i]);
}
}
else {
hideNode(nodes);
}
}
/* Toggle visibility of provided elements */
function toggleElements (elements) {
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
element.style.display = (element.style.display != 'none' ? 'none' : 'block');
}
}
/* Create a button ( span.buttons > a.button ) */
function createBtn (className, value, onclick) {
className = className || 'button';
value = value || 'Button';
onclick = onclick || function (event) {};
var newContainer = document.createElement('span');
newContainer.className = 'buttons';
var newBtn = document.createElement('a');
newBtn.className = className + ' button';
newBtn.appendChild(document.createTextNode(value));
newBtn.href="#";
newBtn.onclick = onclick;
newContainer.appendChild(newBtn);
return newContainer;
}
/* Replies button event handler */
function commentsBtnClick (event) {
event.preventDefault();
var btn = event.currentTarget;
var comments = btn.parentNode.parentNode.parentNode.parentNode.querySelectorAll('.reply_comments');
toggleElements(comments);
}
/* C-style Main() =) */
(function(){
/* Sets of {NodeList} elements to operate with */
var allReplies = document.querySelectorAll('.reply_comments');
var sidebarImgs = document.querySelectorAll('.sidebar_right > .banner_300x500, .sidebar_right > #htmlblock_placeholder');
var contentImgs = document.querySelectorAll('.content img, .message img');
/* Hide all images and nested replies by default */
hideNodes([allReplies, sidebarImgs, contentImgs]);
/* Add button to toggle images visibility */
var newImgBtn = createBtn('habraimage', '◄ Показать изображения', function (event) {event.preventDefault(); toggleElements(contentImgs);});
document.querySelectorAll('.main_menu')[0].appendChild(newImgBtn);
/* Make buton fixed */
addCSSRule('.habraimage', 'position:fixed; right: 6%; z-index: 1;');
/* Add buttons to toggle comments visibility */
var comments = document.querySelectorAll('.comments_list > .comment_item'),
comment, combody;
for (var i = 0; i < comments.length; i++) {
comment = comments[i];
var replies = comment.querySelectorAll('.reply_comments .comment_body');
if (replies.length > 0) {
combody = getChildrenByClassName(comment, 'comment_body')[0];
replylink = getChildrenByClassName(combody, 'reply')[0];
if (combody) {
var newBtn = createBtn('hidereplies', replies.length + declOfNum(replies.length, [' ответ', ' ответа', ' ответов']), commentsBtnClick);
replylink.appendChild(newBtn);
}
}
}
})();
0
Спасибо за документирование и смену представления структуры, смерджил. Если честно, то мне было понятнее с блоками в лице именованных функциий, но ваш вариант мне весьма понравился, однако не удержался и небольшую правку все же внес:
Иначе блок с классом reply наезжал на следующий блок комментария.
Как доберусь до дома обязательно попробую исключить класс spoiler_text из функции скрытия изображений
addCSSRule('.reply', 'margin-bottom: 1em;');
Иначе блок с классом reply наезжал на следующий блок комментария.
Как доберусь до дома обязательно попробую исключить класс spoiler_text из функции скрытия изображений
0
Ну это уже лирика.
Главное что
а) функции и процедуры теперь используются по назначению — не для разметки кода, а для повторного использования,
б) мы не делаем много лишних проходов по DOM,
в) у нас нет множества циклов, которым нужно подбирать новые имена переменных для итерации
г) не нужно возиться с тоннами статичного css,
д) ну и худо-бедно код документирован.
Удачи в дальнейшей разработке!
Главное что
а) функции и процедуры теперь используются по назначению — не для разметки кода, а для повторного использования,
б) мы не делаем много лишних проходов по DOM,
в) у нас нет множества циклов, которым нужно подбирать новые имена переменных для итерации
г) не нужно возиться с тоннами статичного css,
д) ну и худо-бедно код документирован.
Удачи в дальнейшей разработке!
0
Надеюсь на вашу поддержку и дальнейшие пулл реквесты :)
Критикуйте, так как это сильно помогает не останавливаться на том что есть.
Критикуйте, так как это сильно помогает не останавливаться на том что есть.
0
Имея достаточно долгий опыт (года 2) с юзерскриптами и расширениями, сразу по-другому представил решение этой задачи. Прототипы решения у меня уже есть — и генерация кнопки, и скрывание некоторых блоков (пример). Не буду повторять велосипед, а опишу идею:
1) рисунки скрываются-открываются каскадными стилями;
2) прописываются правила CSS типа
.hideimg img{display: none!important;}
и правила незакрывания служебных картинок типа аватаров:
.hideimg img.avatar, ...{display: block!important;}
3) рисуется кнопка (например, функцией $e() в указанном скрипте HabrAjax) и на неё вешается обработчик, переключающий класс hideimg во всех нужных нам блоках. Всё, задача решена.
В кодах статьи я вижу какие-то циклы, которые при каскадных CSS не нужны. Т.е. хорошо, что автор приобрёл опыт в написании и отладке скриптов, но не всегда задача решается сложным путём. Находить другие решения можно как раз в форумах и блогах типа этого, когда другие могут подсказать решения и обогатить опыт. Пулл-реквест на гитхаб заключился бы в почти полной замене скриптов и перестройке решения.
Расширения браузера для этой задачи — тоже трата времени, оправданная разве что опытом знакомства с API расширений. Быстрее написать единый юзерскрипт, одинаково работающий в 4 или 5 основных браузерах — самое сложное будет — поддержать querySelector в IE (например, взять решение из Sizzle / jQuery).
1) рисунки скрываются-открываются каскадными стилями;
2) прописываются правила CSS типа
.hideimg img{display: none!important;}
и правила незакрывания служебных картинок типа аватаров:
.hideimg img.avatar, ...{display: block!important;}
3) рисуется кнопка (например, функцией $e() в указанном скрипте HabrAjax) и на неё вешается обработчик, переключающий класс hideimg во всех нужных нам блоках. Всё, задача решена.
В кодах статьи я вижу какие-то циклы, которые при каскадных CSS не нужны. Т.е. хорошо, что автор приобрёл опыт в написании и отладке скриптов, но не всегда задача решается сложным путём. Находить другие решения можно как раз в форумах и блогах типа этого, когда другие могут подсказать решения и обогатить опыт. Пулл-реквест на гитхаб заключился бы в почти полной замене скриптов и перестройке решения.
Расширения браузера для этой задачи — тоже трата времени, оправданная разве что опытом знакомства с API расширений. Быстрее написать единый юзерскрипт, одинаково работающий в 4 или 5 основных браузерах — самое сложное будет — поддержать querySelector в IE (например, взять решение из Sizzle / jQuery).
0
Когда появится больше одного селектора, то буду использовать массив для исключений как предложил truezemez. Нисколечко не оспариваю тот факт, что тут мне помогли и показали как сделать еще лучше и «по-взрослому». В тексте поста я хотел сказать о том, что на большинство ищут решение типовых задач из примеров обучающих курсов на профильных форумах (это я понял после гугления по совпадающему с контекстом типовой задачи вопросу).
Так ведь я и писал, что сама задача с результатом в виде расширения была хотелкой, не мог я уже лицезреть имиджборду и портянки ответов на комментарии. Это ли не повод потратить время, совместив приятное с полезным (обучение и выполнение хотелки)?
Если вы хотите поделиться со мной знаниями и указать на иные возможности реализации функционала, то я был бы весьма признателен.
Так ведь я и писал, что сама задача с результатом в виде расширения была хотелкой, не мог я уже лицезреть имиджборду и портянки ответов на комментарии. Это ли не повод потратить время, совместив приятное с полезным (обучение и выполнение хотелки)?
Если вы хотите поделиться со мной знаниями и указать на иные возможности реализации функционала, то я был бы весьма признателен.
0
Так я уже всё показал по пунктам. Нажмите ссылку «пример», посмотрите код, найдите использования $e (их там сотня) — делаются разные кнопки, панель настроек, обработчики событий, деревья. Масса вариантов очень похожего на ваши построения. И это как раз не первая итерация, а вторая, когда по коду стало видно, что много общего надо свести в одну функцию. Много полезных техник. Правда, учиться всему этому проще на обычных скриптах — их трассировать можно.
0
Да я уже смотрел ваш скрипт и во многих местах откровенно запутался. Посмотрел дифы совсем старых/относительно свежих версий, где-то докопался до истины. Пока сложно переваривать, так как хотелось бы все непонятные конструкции видеть с комментариями, но се ля ви, опыта моего маловато будет.
0
Там, действительно, очень много поводов запутаться, всё писалось кусочками, на результат. Худшее место — основной цикл подгрузки статей, самое раннее ядро по сути. Но теперь хотя бы хрошо понимаю, чего ни в каком случае не надо делать (давать слишком короткие имена, переусложнять структуру). И даёт много размышлений на будущее, как правильно надо подобное делать. Например, нужна модульность, автосборка, автотесты. И вообще, как-то отлаживать на обычных скриптах, чтобы потом переносить в юзер-, потому что отсутствие дебаггинга раза в 3 удлиняет отладку.
0
Sign up to leave a comment.
Как я учился на своих хотелках