Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // http://crocodillon.com/blog/always-catch-localstorage-security-and-quota-exceeded-errors
- function isQuotaExceeded(e) {
- var quotaExceeded = false;
- if(e) {
- if(e.code) {
- switch(e.code) {
- case 22:
- quotaExceeded = true;
- break;
- case 1014:
- // Firefox
- if(e.name === 'NS_ERROR_DOM_QUOTA_REACHED') {
- quotaExceeded = true;
- }
- break;
- }
- } else if(e.number === -2147024882) {
- // Internet Explorer 8
- quotaExceeded = true;
- }
- }
- return quotaExceeded;
- }
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString#Polyfill
- function pad(number) {
- if(number < 10) {
- return '0' + number;
- }
- return number;
- }
- // --------------------------------------------------
- (function(config) {
- // © Farxiel
- var DEFAULT_TIMEZONE = +4.0;
- var lang = {
- // запросы
- loginRequest: "Пожалуйста залогиньтесь.",
- startCommentRequest: "Время или ID, комментарии начиная с которого будут помечены как новые:\n\tФормат времени: YYYY-MM-DD hh:mm:ss\n\tФормат ID: число",
- timezoneRequest: "Часовой пояс:\n\tФормат: UTC±hh:mm или MSK±hh:mm\n\tПример / Москва:\tUTC+03:00, UTC+03, MSK+00:00, MSK+00\n\tПример / Киев:\tUTC+02:00, UTC+02, MSK-01:00, MSK-01",
- invalidDonorFixRequest: "В соответствии с настройками, Вы можете использовать сохранённые ранее комментарии. Сделать это?",
- // уведомления
- readyNotify: "Готово.",
- debugElapsedTimeNotifyPrefix: "Время работы: ",
- timezoneReadyNotify: "Часовой пояс получен.",
- logoutNotify: "Выход с аккаунта выполнен.",
- loginNotify: "Вход в аккаунт выполнен.",
- topicReadyNotify: "Источник комментариев загружен.",
- importCommentsNotify: "Импорт комментариев...",
- processCommentsNotify: "Обработка импортированных комментариев...",
- fixAndUtaPageNotify: "Восстановление повреждённой страницы и дополнение до залогиненного состояния...",
- setViewStateNotify: "Установка статусов прочитанности комментариев...",
- loadNewCommentsNotify: "Загрузка новых комментариев...",
- timeReplaceNotifyPrefix: "Замена времени:",
- debugNcSavedNotifyPrefix: "Комментарий сохранён как точка отсчёта, ID=",
- // ошибки
- lsSaveError: "Ошибка при сохранении данных в localStorage.\n",
- lsQuotaExceededErrorPrefix: "Превышен лимит хранилища. Попробуйте увеличить его.\nВ Firefox это можно сделать по адресу about:config, изменив параметр \"dom.storage.default_quota\" (размер в Кб). Текущий размер комментариев — ",
- lsQuotaExceededErrorSuffix: " байт.\n\nOK — Попытаться сохранить комментарии ещё раз\nОтмена — Пропустить и продолжить без сохранения комментариев",
- invalidDonorError: "Ошибка доступа к элементам страницы-донора. Возможно, она не смогла загрузиться из-за того что также сломалась.",
- invalidInputError: "Неверный формат.",
- invalidConfigError: "Неверная конфигурация.",
- unrelatedAddressError: "Ошибка:\nДанный скрипт не предназначен для страниц, расположенных по адресам, таким, как текущий.",
- commonError: "Что-то пошло не так.",
- // прочее
- daysShort: "д",
- months_gen: [
- "января",
- "февраля",
- "марта",
- "апреля",
- "мая",
- "июня",
- "июля",
- "августа",
- "сентября",
- "октября",
- "ноября",
- "декабря"
- ]
- };
- var loc = location.pathname.match(/^\/blog(\/[A-Za-z\d\-_]+)?\/(\d+)\.html/);
- if(loc == null) {
- return alert(config.messageHeader + lang.unrelatedAddressError);
- }
- var tidStr = loc[2];
- var tid = parseInt(tidStr);
- var lsItemName = {
- "lastViewedComment": "tabun.utils.HugeThreadHelper.lastViewedComment,topic"+tidStr,
- "timezone": "tabun.utils.HugeThreadHelper.timezone",
- "commentsBak": "tabun.utils.HugeThreadHelper.commentsBak,topic"+tidStr,
- "footerBak": "tabun.utils.HugeThreadHelper.footerBak",
- "commentsScriptBak": "tabun.utils.HugeThreadHelper.commentsScriptBak,topic"+tidStr
- };
- var context = {
- "state":0,
- "lastCommentId":0,
- "handler2_mo":null,
- "timezone":null,
- "h1_control":0,
- "h2_control":0,
- "debugLTF_count":0
- };
- var time0 = Date.now();
- // создание временного фрейма, в котором мы разлогинимся, загрузим пост и возьмём из него 1-ю часть комментов и в котором залогинимся обратно
- var workFrame = document.createElement("iframe");
- with(workFrame.style) {
- position = "absolute";
- left = "0px";
- top = "0px";
- width = "100%";
- height = "100%";
- border = "2px dashed black";
- }
- document.body.appendChild(workFrame);
- function workFrameLoadHandler(e, important) {
- if(important !== true && context.h1_control > 0) {
- if(context.h1_control & 1) setTimeout(arguments.callee, 10, e, important);
- return;
- }
- context.state++;
- switch(context.state) {
- case 1:
- console.log(config.logHeader + lang.logoutNotify);
- // загружаем страницу поста ...
- workFrame.contentWindow.location.replace(location.href);
- break;
- case 2:
- console.log(config.logHeader + lang.topicReadyNotify);
- // ... копируем оттуда комменты на основную страницу ...
- importComments(workFrame.contentDocument);
- // ... восстанавливаем элементы, не загруженные из-за отказа скрипта на сервере (некоторые делаем уже такими, какими их видит залогиненный пользователь)
- fixAndUtaPage(workFrame.contentDocument);
- // данные во фрейме больше не нужны, для уменьшения занимаемой памяти удалим из фрейма весь груз
- workFrame.contentDocument.body.innerHTML = "";
- // обрабатываем скопированные комменты:
- // 1. дополняем их до версий, какие видит залогиненный пользователь
- // 2. ищем коммент с максмальным ID
- processComments();
- // сохраняем максимальный ID коммента в спец. поле, с которым работает Табун
- document.getElementById("new_comments_counter").setAttribute("data-id-comment-last", context.lastCommentId);
- // переходим на страницу логина
- workFrame.contentWindow.location.replace("/login/");
- break;
- default:
- // ещё не залогинились
- if(workFrame.contentDocument.getElementById("dropdown-user") == null) {
- // если разрешено, отображаем приглашение залогиниться
- if(config.enableLoginNotify) alert(config.messageHeader + lang.loginRequest);
- // уже залогинились
- } else {
- console.log(config.logHeader + lang.loginNotify);
- // удаляем этот фрейм с основной страницы
- document.body.removeChild(workFrame);
- // симулируем событие, на которое повешена инициализация поддержки комментов в табунском скрипте комментов
- document.dispatchEvent(new Event("DOMContentLoaded"));
- // продолжим в handler2 после окончания загрузки новых комментов
- window.MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
- context.handler2_mo = new MutationObserver(function(mutations) {
- context.handler2_mo.disconnect();
- context.handler2_mo = null;
- handler2();
- });
- context.handler2_mo.observe(document.getElementById("new_comments_counter"), {"attributes": true});
- // подгружаем новые комменты
- loadNewComments();
- }
- }
- }
- function start1() {
- // отслеживаем, когда загрузится страница (каждый раз после обновления адреса фрейма) для запуска обработки страницы по каждому адресу
- window.addEventListener("DOMFrameContentLoaded", function(e) {
- if(e.target !== workFrame) return;
- if(context.h2_control & 2) return;
- context.h1_control = 1;
- workFrame.removeEventListener("load", workFrameLoadHandler);
- workFrameLoadHandler(e, true);
- context.h1_control++;
- });
- workFrame.addEventListener("load", workFrameLoadHandler);
- // разлогиниваемся и запускаем цикл переходов внутри фрейма
- workFrame.src = document.querySelector(".item-signout>a").href;
- }
- // проверка [и получение] сохранённого часового пояса
- if(config.timezoneUseCache) {
- var tzSpec = localStorage.getItem(lsItemName.timezone);
- if(tzSpec != null) {
- tzSpec = tzSpec.split(":");
- if(parseFloat(tzSpec[0]) == config.timezoneRevision) {
- context.timezone = parseFloat(tzSpec[1]);
- console.log(config.logHeader + lang.timezoneReadyNotify);
- }
- }
- }
- // запрос часового пояса у пользователя
- function requestTimezone() {
- var tzText = prompt(config.messageHeader + lang.timezoneRequest, "UTC+03:00"), match;
- if(tzText != undefined && (match = tzText.match(/^(UTC|MSK)([\+\-]\d+)(\:(\d+))?$/)) != null) {
- var tzHours = parseInt(match[2]);
- var tzMinutes = parseInt(match[4] || 0) * (tzHours > 0 ? 1 : -1);
- if(match[1] == "MSK") tzHours += 3;
- return tzHours + (tzMinutes / 60);
- } else {
- if(tzText != undefined) alert(config.messageHeader + lang.invalidInputError);
- return requestTimezone();
- }
- }
- // выбрать и (если разрешено) сохранить часовой пояс
- function setAndSaveTimezone(timezone) {
- if(isNaN(timezone)) return alert(config.messageHeader + lang.commonError);
- context.timezone = timezone;
- if(config.timezoneUseCache) {
- var tzSpec = config.timezoneRevision.toString() + ":" + timezone.toString();
- localStorage.setItem(lsItemName.timezone, tzSpec);
- }
- console.log(config.logHeader + lang.timezoneReadyNotify);
- }
- if(context.timezone == null) {
- // если часовой пояс ещё не известен (или недействителен) и если он должен загрузиться из настроек сайта - сначала откроем их
- switch(config.timezoneSource) {
- case "frame":
- var settingsPageFrame = document.createElement("iframe");
- with(settingsPageFrame.style) {
- position = "absolute";
- right = "0px";
- top = "0px";
- width = "50%";
- height = "100%";
- border = "2px dashed blue";
- }
- document.body.appendChild(settingsPageFrame);
- settingsPageFrame.addEventListener("load", function(e) {
- settingsPageFrame.removeEventListener(e.type, arguments.callee);
- setAndSaveTimezone(parseFloat(settingsPageFrame.contentDocument.getElementsByName("settings_general_timezone")[0].value));
- document.body.removeChild(settingsPageFrame);
- // запукаем цикл переходов
- start1();
- });
- settingsPageFrame.src = "/settings/tuning/";
- break;
- default:
- alert(config.messageHeader + lang.invalidConfigError);
- case "input":
- setAndSaveTimezone(requestTimezone());
- start1();
- break;
- }
- // если ч.п. известен и действителен
- } else start1();
- function handler2() {
- // указываем, какие комменты считать прочитанными, а какие новыми
- setViewState(false);
- // подготавливаем и отображаем сообщение о готовности
- // вычисление времени работы скрипта (включая время загрузки данных и задержки на сообщениях/запросах), преобразование в строку
- var timeElapsed = Date.now() - time0;
- var timeElapsedDays = Math.floor(timeElapsed / 86400000);
- var timeElapsedStr = (timeElapsedDays > 0 ? timeElapsedDays.toString() + lang.daysShort + ", " : "") + new Date(timeElapsed).toISOString().substr(11, 8);
- console.log(config.logHeader + lang.readyNotify + config.messageInlineSep + lang.debugElapsedTimeNotifyPrefix + timeElapsedStr);
- // если разрешено, также отображаем в окне
- if(config.enableReadyNotify) alert(config.messageHeader + lang.readyNotify + config.messageSep + lang.debugElapsedTimeNotifyPrefix + timeElapsedStr);
- }
- function setCommentsHTML(commentsHTML) {
- var tempEl1;
- // создание контейнера, копирование в него всего HTML-кода
- tempEl1 = createElement("div", "comments", "comments", {
- "innerHTML": commentsHTML
- });
- document.getElementById("content").appendChild(tempEl1);
- }
- function importComments(sourceDocument) {
- console.log(config.logHeader + lang.importCommentsNotify);
- var comments = sourceDocument.getElementById("comments");
- if(comments != null) {
- var commentsHTML = comments.innerHTML;
- setCommentsHTML(commentsHTML);
- if(config.autoBackupDonor) (function() {
- try {
- localStorage.setItem(lsItemName.commentsBak, commentsHTML);
- } catch(e) {
- if(isQuotaExceeded(e)) {
- if(confirm(config.messageHeader + lang.lsQuotaExceededErrorPrefix + commentsHTML.length.toString() + lang.lsQuotaExceededErrorSuffix)) arguments.callee();
- } else alert(config.messageHeader + lang.lsSaveError + config.messageSep + e.toString());
- }
- })();
- } else {
- var commentsHTML = localStorage.getItem(lsItemName.commentsBak);
- if(commentsHTML != null && commentsHTML.length > 0) {
- if(confirm(config.messageHeader + lang.invalidDonorError + config.messageSep + lang.invalidDonorFixRequest)) {
- setCommentsHTML(commentsHTML);
- } else {
- alert(config.messageHeader + lang.commonError);
- }
- } else alert(config.messageHeader + lang.invalidDonorError);
- }
- }
- function processComments() {
- console.log(config.logHeader + lang.processCommentsNotify);
- var tempEl1, tempEl2;
- var lastCommentId = 0;
- var tzFixOffset = context.timezone - DEFAULT_TIMEZONE;
- var commentList = document.getElementById("comments").getElementsByClassName("comment");
- for(var i=0; i<commentList.length; i++) {
- var comment = commentList[i];
- var commentInfo = comment.querySelector("ul.comment-info");
- var idStr = comment.getAttribute("data-id");
- var id = parseInt(idStr);
- // если у коммента нет блока comment-info (удалённый или заминусованный коммент), добавляем пустой
- if(commentInfo == null) {
- commentInfo = createElement("ul", "comment-info", null);
- // добавляем ссылку на комментарий
- tempEl1 = createElement("li", "comment-link", null);
- tempEl2 = createElement("a", null, null, {
- "href": "#comment"+idStr,
- "title": "Ссылка на комментарий"
- });
- tempEl3 = createElement("i", "icon-synio-link", null);
- tempEl2.appendChild(tempEl3);
- tempEl1.appendChild(tempEl2);
- commentInfo.appendChild(tempEl1);
- comment.appendChild(commentInfo);
- }
- // ищем коммент с максимальным ID
- if(id > lastCommentId) lastCommentId = id;
- // добавление кнопки "В избранное"
- tempEl1 = createElement("li", "comment-favourite");
- tempEl2 = createElement("div", "favourite", null, {
- "onclick": "return ls.favourite.toggle("+idStr+", this, 'comment');",
- "innerHTML": "В избранное"
- });
- tempEl1.appendChild(tempEl2);
- tempEl2 = createElement("span", "favourite-count", "fav_count_comment_"+idStr, {"hidden":"hidden"});
- tempEl1.appendChild(tempEl2);
- commentInfo.insertBefore(tempEl1, commentInfo.querySelector("li.comment-link"));
- // добавление кнопки "Ответить"
- tempEl1 = document.createElement("li");
- tempEl2 = createElement("a", "reply-link link-dotted", null, {
- "href": "#",
- "onclick": "ls.comments.toggleCommentForm("+idStr+"); return false;",
- "innerHTML": "Ответить"
- });
- tempEl1.appendChild(tempEl2);
- commentInfo.appendChild(tempEl1);
- // если наш часовой пояс не московский - исправляем время в московских метках времени
- if(context.timezone != DEFAULT_TIMEZONE) {
- var timeEl = commentInfo.querySelector("li.comment-date>time");
- if(timeEl != null) {
- // преобразуем компоненты времени в числа
- var timeC = timeEl.getAttribute("datetime").split(/[^\d]/).map(function(v) {return parseInt(v);});
- // 0..5 - компоненты времени
- var newTime = new Date(timeC[0], timeC[1]-1, timeC[2], timeC[3], timeC[4], timeC[5], 0);
- newTime.setTime(newTime.getTime()+(3600000*tzFixOffset));
- var oldTimeLocaleString = timeEl.innerHTML;
- var newTimeDisplayStr = newTime.getDate().toString() + " " + lang.months_gen[newTime.getMonth()] + " " + newTime.getFullYear().toString() + ", " + pad(newTime.getHours()) + ":" + pad(newTime.getMinutes()) + ":" + pad(newTime.getSeconds());
- timeEl.innerHTML = newTimeDisplayStr;
- timeEl.setAttribute("title", newTimeDisplayStr);
- timeEl.setAttribute("datetime", newTime.toISOString());
- timeEl.setAttribute("data-timestamp", newTime.getTime().toString());
- if(config.debugLTF && (config.debugLTF_JFN == -1 || config.debugLTF_JFN > context.debugLTF_count)) {
- console.log(config.logHeader + lang.timeReplaceNotifyPrefix + " " + oldTimeLocaleString.trim() + " → " + timeEl.innerHTML);
- context.debugLTF_count++;
- }
- }
- }
- }
- context.lastCommentId = lastCommentId;
- }
- function fixAndUtaPage(sourceDocument) {
- console.log(config.logHeader + lang.fixAndUtaPageNotify);
- var tempEl1, tempEl2, tempEl3, tempEl4, tempEl5;
- // добавление блока подписки на комменты
- tempEl1 = document.querySelector("#comments>.comments-header");
- tempEl2 = createElement("div", "subscribe");
- tempEl3 = createElement("input", "input-checkbox", "comment_subscribe", {
- "type": "checkbox",
- "onchange": "ls.subscribe.toggle('topic_new_comment', '"+tidStr+"', '', this.checked);"
- });
- tempEl2.appendChild(tempEl3);
- tempEl3 = createElement("label", null, null, {
- "for": "comment_subscribe",
- "innerHTML": "подписаться на новые комментарии"
- });
- tempEl2.appendChild(tempEl3);
- tempEl1.insertBefore(tempEl2, tempEl1.lastElementChild);
- // добавление формы загрузки картинок
- tempEl1 = createElement("div", "modal modal-image-upload", "window_upload_img");
- tempEl2 = createElement("header", "modal-header", null);
- tempEl3 = createElement("h3", null, null, {"innerHTML": "Вставка изображения"});
- tempEl2.appendChild(tempEl3);
- tempEl3 = createElement("a", "close jqmClose", null, {"href": "#"});
- tempEl2.appendChild(tempEl3);
- tempEl1.appendChild(tempEl2);
- tempEl2 = createElement("div", "modal-content");
- tempEl3 = createElement("ul", "nav nav-pills nav-pills-tabs");
- tempEl4 = createElement("li", "active js-block-upload-img-item", null, {"data-type": "pc"});
- tempEl5 = createElement("a", null, null, {
- "href": "#",
- "innerHTML": "С компьютера"
- });
- tempEl4.appendChild(tempEl5);
- tempEl3.appendChild(tempEl4);
- tempEl4 = createElement("li", "js-block-upload-img-item", null, {"data-type": "link"});
- tempEl5 = createElement("a", null, null, {
- "href": "#",
- "innerHTML": "Из интернета"
- });
- tempEl4.appendChild(tempEl5);
- tempEl3.appendChild(tempEl4);
- tempEl2.appendChild(tempEl3);
- tempEl3 = createElement("form", "tab-content js-block-upload-img-content", "block_upload_img_content_pc", {
- "method": "POST",
- "action": "",
- "enctype": "multipart/form-data",
- "onsubmit": "return false;",
- "data-type": "pc"
- });
- tempEl4 = document.createElement("p");
- tempEl5 = createElement("label", null, null, {
- "innerHTML": "Файл:",
- "for": "img_file"
- });
- tempEl4.appendChild(tempEl5);
- tempEl5 = createElement("input", "input-text input-width-full", "img_file", {
- "type": "file",
- "name": "img_file",
- "value": ""
- });
- tempEl4.appendChild(tempEl5);
- tempEl3.appendChild(tempEl4);
- tempEl4 = document.createElement("p");
- tempEl5 = createElement("label", null, null, {
- "innerHTML": "Описание:",
- "for": "form-image-title"
- });
- tempEl4.appendChild(tempEl5);
- tempEl5 = createElement("input", "input-text input-width-full", "form-image-title", {
- "type": "text",
- "name": "title",
- "value": ""
- });
- tempEl4.appendChild(tempEl5);
- tempEl3.appendChild(tempEl4);
- tempEl4 = createElement("button", "button button-primary main-upl-btn", null, {
- "type": "submit",
- "onclick": "ls.tools.uploadImg('block_upload_img_content_pc','form_comment_text');",
- "innerHTML": "Загрузить"
- });
- tempEl3.appendChild(tempEl4);
- tempEl4 = createElement("button", "button jqmClose", null, {
- "type": "submit",
- "innerHTML": "Отмена"
- });
- tempEl3.appendChild(tempEl4);
- tempEl2.appendChild(tempEl3);
- tempEl3 = createElement("form", "tab-content js-block-upload-img-content", "block_upload_img_content_link", {
- "method": "POST",
- "action": "",
- "enctype": "multipart/form-data",
- "onsubmit": "return false;",
- "data-type": "link"
- });
- tempEl3.style.display = "none";
- tempEl4 = document.createElement("p");
- tempEl5 = createElement("label", null, null, {
- "innerHTML": "Ссылка на изображение:",
- "for": "img_file"
- });
- tempEl4.appendChild(tempEl5);
- tempEl5 = createElement("input", "input-text input-width-full", "img_url", {
- "type": "text",
- "name": "img_url",
- "value": "http://"
- });
- tempEl4.appendChild(tempEl5);
- tempEl3.appendChild(tempEl4);
- tempEl4 = document.createElement("p");
- tempEl5 = createElement("label", null, null, {
- "innerHTML": "Описание:",
- "for": "form-image-url-title"
- });
- tempEl4.appendChild(tempEl5);
- tempEl5 = createElement("input", "input-text input-width-full", "form-image-url-title", {
- "type": "text",
- "name": "title",
- "value": ""
- });
- tempEl4.appendChild(tempEl5);
- tempEl3.appendChild(tempEl4);
- tempEl4 = createElement("button", "button button-primary", null, {
- "type": "submit",
- "onclick": "ls.tools.uploadImg('block_upload_img_content_link','form_comment_text');",
- "innerHTML": "Загрузить"
- });
- tempEl3.appendChild(tempEl4);
- tempEl4 = createElement("button", "button jqmClose", null, {
- "type": "submit",
- "innerHTML": "Отмена"
- });
- tempEl3.appendChild(tempEl4);
- tempEl2.appendChild(tempEl3);
- tempEl1.appendChild(tempEl2);
- document.getElementById("content").appendChild(tempEl1);
- // добавление кнопки и формы добавления комментария
- tempEl1 = createElement("h4", "reply-header", "comment_id_0");
- tempEl2 = createElement("a", "link-dotted", null, {
- "href": "#",
- "innerHTML": "Оставить комментарий",
- "onclick": "ls.comments.toggleCommentForm(0); return false;"
- });
- tempEl1.appendChild(tempEl2);
- document.getElementById("content").appendChild(tempEl1);
- tempEl1 = createElement("div", "reply", "reply");
- tempEl2 = createElement("form", null, "form_comment", {
- "method": "POST",
- "enctype": "multipart/form-data",
- "onsubmit": "return false;"
- });
- tempEl3 = createElement("textarea", "markitup-editor input-width-full", "form_comment_text", {"name": "comment_text"});
- tempEl2.appendChild(tempEl3);
- tempEl3 = createElement("button", "button button-primary", "comment-button-submit", {
- "type": "submit",
- "name": "submit_comment",
- "onclick": "ls.comments.add('form_comment', "+tidStr+", 'topic'); return false;",
- "innerHTML": "добавить"
- });
- tempEl2.appendChild(tempEl3);
- tempEl3 = createElement("button", "button", null, {
- "type": "button",
- "onclick": "ls.comments.preview();",
- "innerHTML": "предпросмотр"
- });
- tempEl2.appendChild(tempEl3);
- tempEl3 = createElement("input", null, "form_comment_reply", {
- "type": "hidden",
- "name": "reply",
- "value": "0"
- });
- tempEl2.appendChild(tempEl3);
- tempEl3 = createElement("input", null, null, {
- "type": "hidden",
- "name": "cmt_target_id",
- "value": tidStr
- });
- tempEl2.appendChild(tempEl3);
- tempEl1.appendChild(tempEl2);
- document.getElementById("content").appendChild(tempEl1);
- // копирование конца страницы
- // копирование footer
- tempEl1 = createElement("footer", null, "footer", {"innerHTML": (function() {
- var el = sourceDocument.getElementById("footer");
- if(el != null) {
- if(config.autoBackupDonor) localStorage.setItem(lsItemName.footerBak, el.innerHTML);
- return el.innerHTML;
- } else return localStorage.getItem(lsItemName.footerBak);
- })()});
- document.getElementById("container").appendChild(tempEl1);
- // добавление toolbar
- tempEl1 = createElement("aside", "toolbar", "toolbar");
- // заполнение toolbar
- tempEl2 = createElement("section", "toolbar-update", "update");
- tempEl3 = createElement("a", "update-comments", "update-comments", {
- "href": "#",
- "onclick": "ls.comments.load("+tidStr+", 'topic'); return false;"
- });
- tempEl4 = document.createElement("i");
- tempEl3.appendChild(tempEl4);
- tempEl2.appendChild(tempEl3);
- tempEl3 = createElement("div", "new-comments h-hidden", "new_comments_counter", {
- "title": "Число новых комментариев",
- "onclick": "ls.comments.goToNextComment(); return false;"/*,
- "data-id-comment-last": context.lastCommentId*/
- });
- tempEl2.appendChild(tempEl3);
- tempEl1.appendChild(tempEl2);
- document.body.appendChild(tempEl1);
- // копирование скрипта комментов
- tempEl1 = createElement("script", null, null, {
- "src": (function() {
- var temp = sourceDocument.querySelectorAll("script[src*=comments]"), src;
- if(temp.length > 0) {
- src = temp[temp.length-1].src;
- if(config.autoBackupDonor) localStorage.setItem(lsItemName.commentsScriptBak, src);
- return src;
- } else {
- return localStorage.getItem(lsItemName.commentsScriptBak) || "";
- }
- })(),
- "type": "text/javascript"
- });
- document.body.appendChild(tempEl1);
- }
- function loadNewComments() {
- console.log(config.logHeader + lang.loadNewCommentsNotify);
- try {
- ls.comments.load(tid, "topic");
- } catch(err) {
- }
- }
- function compareAgeAndSetViewState(comment, required, current) {
- if(current > required || (current == required && config.ncInclusiveLogic)) {
- comment.classList.add("comment-new");
- return 1;
- } else {
- comment.classList.remove("comment-new");
- return 0;
- }
- }
- function setViewState(ncForceRequest) {
- console.log(config.logHeader + lang.setViewStateNotify);
- // спрашиваем у юзера время, комменты начиная с которого будут помечены как новые, предварительно загрузив предыдущее введённое значение (если было сохранено)
- var ncSpecDefault = "2015-04-07 00:00:00";
- var ncSpecPrev = localStorage.getItem(lsItemName.lastViewedComment) || ncSpecDefault;
- var ncSpec = (config.ncDisableRequest && !ncForceRequest) ? ncSpecPrev : (prompt(config.messageHeader + lang.startCommentRequest, ncSpecPrev) || ncSpecPrev);
- var match;
- var newCommentsCount = 0;
- // проверка ввода/сохранения на соответствие формату времени
- if((match = ncSpec.match(/^(\d{4})\-(\d{2})\-(\d{2})\ (\d{2})\:(\d{2})(\:(\d{2}))?$/)) != null) {
- match[6] = (match[7] == undefined) ? 0 : match[7];
- match[7] = 0;
- // преобразуем компоненты времени в числа
- var ncTC = match.slice(1).map(function(v) {return parseInt(v);});
- // 0..5 - компоненты времени
- var ncTime = new Date(ncTC[0], ncTC[1]-1, ncTC[2], ncTC[3], ncTC[4], ncTC[5], 0).getTime();
- var comments = document.getElementsByClassName("comment");
- // проходимся по комментам
- // +считаем комменты, которым мы поставили статус "новый"
- for(var i=0; i<comments.length; i++) {
- var comment = comments[i];
- var cTimeEl = comment.querySelector("ul.comment-info>li.comment-date>time");
- if(cTimeEl != null) {
- var cTime;
- var cTimeSS = cTimeEl.getAttribute("data-timestamp");
- if(cTimeSS != null) {
- cTime = parseFloat(cTimeSS);
- } else {
- // преобразуем компоненты времени в числа
- var cTimeC = cTimeEl.getAttribute("datetime").split(/[^\d]/).map(function(v) {return parseInt(v);});
- // 0..5 - компоненты времени
- cTime = new Date(cTimeC[0], cTimeC[1]-1, cTimeC[2], cTimeC[3], cTimeC[4], cTimeC[5], 0).getTime();
- }
- newCommentsCount += compareAgeAndSetViewState(comment, ncTime, cTime);
- }
- // если у коммента нет информации о времени, не обрабатываем его
- }
- // проверка ввода/сохранения на соответствие формату ID
- } else if((match = ncSpec.match(/^(\d+)$/)) != null) {
- var ncId = parseInt(match[1]);
- var comments = document.getElementsByClassName("comment");
- for(var i=0; i<comments.length; i++) {
- var comment = comments[i];
- newCommentsCount += compareAgeAndSetViewState(comment, ncId, parseInt(comment.getAttribute("data-id")));
- }
- } else {
- alert(config.messageHeader + lang.invalidInputError);
- setViewState(ncForceRequest);
- return;
- }
- // ввод был успешным
- // если разрешено - сохраняем
- if(config.ncSaveInput) localStorage.setItem(lsItemName.lastViewedComment, ncSpec);
- // ставим счётчик новых комментов и показываем/скрываем его
- var new_comments_counter = document.getElementById("new_comments_counter");
- new_comments_counter.innerHTML = newCommentsCount.toString();
- new_comments_counter.classList[newCommentsCount > 0 ? "remove" : "add"]("h-hidden");
- // При выполнении ls.comments.init Табун внесёт все новые комменты в какую-то свою структуру, откуда он будет брать их при прокрутке. Я так и не понял, как мне до неё добраться, поэтому ls.comments.init().
- try {
- ls.comments.init();
- } catch(err) {
- }
- if(config.ncUpdateFromView) {
- // отслеживаем прокрутку комментов
- var goToNextComment_orig = ls.comments.goToNextComment;
- ls.comments.goToNextComment = function() {
- goToNextComment_orig();
- try {
- var comment = document.getElementsByClassName("comment-current")[0];
- var cid = comment.getAttribute("data-id");
- localStorage.setItem(lsItemName.lastViewedComment, cid);
- if(config.debugNcSaved) console.log(config.logHeader + lang.debugNcSavedNotifyPrefix + cid);
- } catch(err) {
- }
- }
- }
- }
- // экспорт setViewState
- window.setViewState = setViewState;
- // Для запроса ID/времени точки отсчёта при ncDisableRequest=true следует вызывать setViewState(true).
- // функция-макрос добавления элементов и установки им атрибутов
- function createElement(tagName, className, id, attributes) {
- var el = document.createElement(tagName);
- if(id != null) el.id = id;
- if(className != null) el.className = className;
- if(attributes != undefined) for(var name in attributes) {
- var value = attributes[name];
- if(name == "innerHTML") el[name] = value;
- else el.setAttribute(name, value);
- }
- return el;
- }
- })({
- // Настройки
- enableLoginNotify: true, // Отображать приглашение залогиниться.
- enableReadyNotify: true, // Отображать сообщение о готовности.
- ncSaveInput: true, // Хранить последнее введённое пользователем значение ID/времени.
- ncUpdateFromView: false, // Каждый комментарий, прокрученный кнопкой числа под кнопкой обновления комментариев, сохраняется как последний просмотренный и точка отсчёта новых комментариев. Переопределяет поведение ncSaveInput.
- ncDisableRequest: false, // Не запрашивать ID/время отсчёта новых комментариев. Имеет смысл при ncUpdateFromView=true.
- ncInclusiveLogic: true,
- // false: комментарий новый = ID/время комментария > ID/времени из запроса или ID последнего просмотренного комментария
- // true: комментарий новый = ID/время комментария ≥ ID/времени из запроса или ID последнего просмотренного комментария
- timezoneSource: "frame", // Источник часового пояса. Запрос у пользователя (input) или страница настроек Табуна (frame).
- timezoneUseCache: true, // Сохранить часовой пояс в localStorage и в дальнейшем брать оттуда.
- timezoneRevision: 1,
- // 1..999999999 - Версия ч.п. в настройках Табуна при timezoneUseCache=true. После изменения ч.п. в настройках Табуна, для синхронизации, измените этот параметр — кэш станет недействительным и скрипт получит новое значение часового пояса.
- // [примечание] Не смотря на формат, предполагающий номер, история изменений не сохраняется, проверяется только совпадение/несовпадение.
- autoBackupDonor: false, // При копировании комментариев из разлогиненной версии сохранить их (HTML-код). После того как перестанет открываться даже разлогиненная версия, можно будет использовать этот бекап.
- messageSep: "\n",
- messageInlineSep: " ",
- messageHeader: "",
- logHeader: "[HugeThreadHelper] ",
- // Отладка
- debugLTF: false, // Для каждого заменённого элемента времени вывести в консоль, что на что заменилось.
- debugLTF_JFN: 10, // Только первые N элементов времени для debugLTF=true.
- debugNcSaved: false // Для каждого сохранения точки отсчёта новых комментариев при прокрутке вывести уведомление в консоль.
- });
Add Comment
Please, Sign In to add comment