-
-
Save anonymous/dc057f6b1612532e239e to your computer and use it in GitHub Desktop.
Dollscript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Dollchan Extension Tools | |
// @version 14.10.9.0 | |
// @namespace http://www.freedollchan.org/scripts/* | |
// @author Sthephan Shinkufag @ FreeDollChan | |
// @copyright (C)2084, Bender Bending Rodriguez | |
// @description Doing some profit for imageboards | |
// @icon https://raw.github.com/SthephanShinkufag/Dollchan-Extension-Tools/master/Icon.png | |
// @updateURL https://raw.github.com/SthephanShinkufag/Dollchan-Extension-Tools/master/Dollchan_Extension_Tools.meta.js | |
// @run-at document-start | |
// @grant GM_getValue | |
// @grant GM_setValue | |
// @grant GM_deleteValue | |
// @grant GM_openInTab | |
// @grant GM_xmlhttpRequest | |
// @grant unsafeWindow | |
// @include * | |
// ==/UserScript== | |
(function de_main_func(scriptStorage) { | |
'use strict'; | |
var version = '14.10.9.0', | |
defaultCfg = { | |
'disabled': 0, // script enabled by default | |
'language': 0, // script language [0=ru, 1=en] | |
'hideBySpell': 1, // hide posts by spells | |
'spells': '', // user defined spells | |
'sortSpells': 0, // sort spells when applying | |
'menuHiddBtn': 1, // menu on hide button | |
'hideRefPsts': 0, // hide post with references to hidden posts | |
'delHiddPost': 0, // delete hidden posts | |
'ajaxUpdThr': 1, // auto update threads | |
'updThrDelay': 60, // threads update interval in sec | |
'noErrInTitle': 0, // don't show error number in title except 404 | |
'favIcoBlink': 0, // favicon blinking, if new posts detected | |
'markNewPosts': 1, // new posts marking on page focus | |
'desktNotif': 0, // desktop notifications, if new posts detected | |
'expandPosts': 2, // expand shorted posts [0=off, 1=auto, 2=on click] | |
'postBtnsCSS': 2, // post buttons style [0=text, 1=classic, 2=solid grey] | |
'noSpoilers': 1, // open spoilers | |
'noPostNames': 0, // hide post names | |
'noPostScrl': 1, // no scroll in posts | |
'correctTime': 0, // correct time in posts | |
'timeOffset': '+0', // offset in hours | |
'timePattern': '', // find pattern | |
'timeRPattern': '', // replace pattern | |
'expandImgs': 2, // expand images by click [0=off, 1=in post, 2=by center] | |
'imgNavBtns': 1, // add image navigation for full images | |
'resizeDPI': 0, // honor dpi settings | |
'resizeImgs': 1, // resize large images | |
'minImgSize': 100, // minimal image's size | |
'zoomFactor': 25, // zoom images by this factor on every wheel event | |
'webmControl': 1, // control bar fow webm files | |
'webmVolume': 100, // default volume for webm files | |
'maskImgs': 0, // mask images | |
'preLoadImgs': 0, // pre-load images | |
'findImgFile': 0, // detect built-in files in images | |
'openImgs': 0, // open images in posts | |
'openGIFs': 0, // open only GIFs in posts | |
'imgSrcBtns': 1, // add image search buttons | |
'linksNavig': 2, // navigation by >>links [0=off, 1=no map, 2=+refmap] | |
'linksOver': 100, // delay appearance in ms | |
'linksOut': 1500, // delay disappearance in ms | |
'markViewed': 0, // mark viewed posts | |
'strikeHidd': 0, // strike >>links to hidden posts | |
'noNavigHidd': 0, // don't show previews for hidden posts | |
'crossLinks': 0, // replace http: to >>/b/links | |
'insertNum': 1, // insert >>link on postnumber click | |
'addMP3': 1, // embed mp3 links | |
'addImgs': 0, // embed links to images | |
'addYouTube': 3, // embed YouTube links [0=off, 1=onclick, 2=player, 3=preview+player, 4=only preview] | |
'YTubeType': 0, // player type [0=flash, 1=HTML5] | |
'YTubeWidth': 360, // player width | |
'YTubeHeigh': 270, // player height | |
'YTubeHD': 0, // hd video quality | |
'YTubeTitles': 0, // convert links to titles | |
'addVimeo': 1, // embed vimeo links | |
'ajaxReply': 2, // posting with AJAX (0=no, 1=iframe, 2=HTML5) | |
'postSameImg': 1, // ability to post same images | |
'removeEXIF': 1, // remove EXIF data from JPEGs | |
'removeFName': 0, // remove file name | |
'sendErrNotif': 1, // inform about post send error if page is blurred | |
'scrAfterRep': 0, // scroll to the bottom after reply | |
'addPostForm': 2, // postform displayed [0=at top, 1=at bottom, 2=hidden] | |
'hangQReply': 1, // quick reply type [0=inline, 1=hanging] | |
'favOnReply': 1, // add thread to favorites on reply | |
'warnSubjTrip': 0, // warn if subject field contains tripcode | |
'fileThumb': 1, // file preview area instead of file button | |
'addSageBtn': 1, // email field -> sage button | |
'saveSage': 1, // remember sage | |
'sageReply': 0, // reply with sage | |
'captchaLang': 1, // language input in captcha [0=off, 1=en, 2=ru] | |
'addTextBtns': 1, // text format buttons [0=off, 1=graphics, 2=text, 3=usual] | |
'txtBtnsLoc': 1, // located at [0=top, 1=bottom] | |
'passwValue': '', // user password value | |
'userName': 0, // user name | |
'nameValue': '', // value | |
'noBoardRule': 1, // hide board rules | |
'noGoto': 1, // hide goto field | |
'noPassword': 1, // hide password field | |
'scriptStyle': 0, // script style [0=glass black, 1=glass blue, 2=solid grey] | |
'userCSS': 0, // user style | |
'userCSSTxt': '', // css text | |
'expandPanel': 0, // show full main panel | |
'attachPanel': 1, // attach main panel | |
'panelCounter': 1, // posts/images counter in script panel | |
'rePageTitle': 1, // replace page title in threads | |
'animation': 1, // CSS3 animation in script | |
'closePopups': 0, // auto-close popups | |
'hotKeys': 1, // enable hotkeys | |
'loadPages': 1, // number of pages that are loaded on F5 | |
'updScript': 1, // check for script's update | |
'scrUpdIntrv': 1, // check interval in days (every val+1 day) | |
'turnOff': 0, // enable script only for this site | |
'textaWidth': 300, // textarea size | |
'textaHeight': 115, | |
'qreplyRight': 0, // hanging quick reply position | |
'qreplyBottom': 25 | |
}, | |
Lng = { | |
cfg: { | |
'hideBySpell': ['Заклинания: ', 'Magic spells: '], | |
'sortSpells': ['Сортировать спеллы и удалять дубликаты', 'Sort spells and delete duplicates'], | |
'menuHiddBtn': ['Дополнительное меню кнопок скрытия ', 'Additional menu of hide buttons'], | |
'hideRefPsts': ['Скрывать ответы на скрытые посты*', 'Hide replies to hidden posts*'], | |
'delHiddPost': ['Удалять скрытые посты', 'Delete hidden posts'], | |
'ajaxUpdThr': ['AJAX обновление треда ', 'AJAX thread update '], | |
'updThrDelay': [' (сек)', ' (sec)'], | |
'noErrInTitle': ['Не показывать номер ошибки в заголовке', 'Don\'t show error number in title'], | |
'favIcoBlink': ['Мигать фавиконом при новых постах', 'Favicon blinking on new posts'], | |
'markNewPosts': ['Выделять новые посты при переключении на тред', 'Mark new posts on page focus'], | |
'desktNotif': ['Уведомления на рабочем столе', 'Desktop notifications'], | |
'expandPosts': { | |
sel: [['Откл.', 'Авто', 'По клику'], ['Disable', 'Auto', 'On click']], | |
txt: ['AJAX загрузка сокращенных постов*', 'AJAX upload of shorted posts*'] | |
}, | |
'postBtnsCSS': { | |
sel: [['Text', 'Classic', 'Solid grey'], ['Text', 'Classic', 'Solid grey']], | |
txt: ['Стиль кнопок постов*', 'Post buttons style*'] | |
}, | |
'noSpoilers': ['Открывать текстовые спойлеры', 'Open text spoilers'], | |
'noPostNames': ['Скрывать имена в постах', 'Hide names in posts'], | |
'noPostScrl': ['Без скролла в постах', 'No scroll in posts'], | |
'hotKeys': ['Горячие клавиши ', 'Keyboard hotkeys '], | |
'loadPages': [' Количество страниц, загружаемых по F5', ' Number of pages that are loaded on F5 '], | |
'correctTime': ['Корректировать время в постах* ', 'Correct time in posts* '], | |
'timeOffset': [' Разница во времени', ' Time difference'], | |
'timePattern': [' Шаблон поиска', ' Find pattern'], | |
'timeRPattern': [' Шаблон замены', ' Replace pattern'], | |
'expandImgs': { | |
sel: [['Откл.', 'В посте', 'По центру'], ['Disable', 'In post', 'By center']], | |
txt: ['раскрывать картинки по клику', 'expand images on click'] | |
}, | |
'imgNavBtns': ['Добавлять кнопки навигации по картинкам', 'Add buttons for images navigation'], | |
'resizeDPI': ['Отображать картинки пиксель в пиксель', 'Don\'t upscale images on retina displays'], | |
'resizeImgs': ['Уменьшать в экран большие картинки', 'Resize large images to fit screen'], | |
'minImgSize': [' Минимальный размер картинок (px)', ' Minimal image\'s size (px)'], | |
'zoomFactor': [' Чувствительность зума картинок [1-100]', ' Sensibility of the images zoom [1-100]'], | |
'webmControl': ['Показывать контрол-бар для webm-файлов', 'Show control bar for webm files'], | |
'webmVolume': [' Громкость webm-файлов [0-100]', ' Default volume for webm files [0-100]'], | |
'preLoadImgs': ['Предварительно загружать картинки*', 'Pre-load images*'], | |
'findImgFile': ['Распознавать встроенные файлы в картинках*', 'Detect built-in files in images*'], | |
'openImgs': ['Скачивать полные версии картинок*', 'Download full version of images*'], | |
'openGIFs': ['Скачивать только GIFы*', 'Download GIFs only*'], | |
'imgSrcBtns': ['Добавлять кнопки для поиска картинок*', 'Add image search buttons*'], | |
'linksNavig': { | |
sel: [['Откл.', 'Без карты', 'С картой'], ['Disable', 'No map', 'With map']], | |
txt: ['навигация по >>ссылкам* ', 'navigation by >>links* '] | |
}, | |
'linksOver': [' задержка появления (мс)', ' delay appearance (ms)'], | |
'linksOut': [' задержка пропадания (мс)', ' delay disappearance (ms)'], | |
'markViewed': ['Отмечать просмотренные посты*', 'Mark viewed posts*'], | |
'strikeHidd': ['Зачеркивать >>ссылки на скрытые посты', 'Strike >>links to hidden posts'], | |
'noNavigHidd': ['Не отображать превью для скрытых постов', 'Don\'t show previews for hidden posts'], | |
'crossLinks': ['Преобразовывать http:// в >>/b/ссылки*', 'Replace http:// with >>/b/links*'], | |
'insertNum': ['Вставлять >>ссылку по клику на №поста*', 'Insert >>link on №postnumber click*'], | |
'addMP3': ['Добавлять плеер к mp3 ссылкам* ', 'Add player to mp3 links* '], | |
'addVimeo': ['Добавлять плеер к Vimeo ссылкам* ', 'Add player to Vimeo links* '], | |
'addImgs': ['Загружать картинки к jpg, png, gif ссылкам*', 'Load images to jpg, png, gif links*'], | |
'addYouTube': { | |
sel: [ | |
['Ничего', 'Плеер по клику', 'Авто плеер', 'Превью+плеер', 'Только превью'], | |
['Nothing', 'On click player', 'Auto player', 'Preview+player', 'Only preview'] | |
], | |
txt: ['к YouTube-ссылкам* ', 'to YouTube-links* '] | |
}, | |
'YTubeType': { | |
sel: [['Flash', 'HTML5'], ['Flash', 'HTML5']], | |
txt: ['', ''] | |
}, | |
'YTubeHD': ['HD ', 'HD '], | |
'YTubeTitles': ['Загружать названия к YouTube-ссылкам*', 'Load titles into YouTube-links*'], | |
'ajaxReply': { | |
sel: [['Откл.', 'Iframe', 'HTML5'], ['Disable', 'Iframe', 'HTML5']], | |
txt: ['AJAX отправка постов*', 'posting with AJAX*'] | |
}, | |
'postSameImg': ['Возможность отправки одинаковых картинок', 'Ability to post same images'], | |
'removeEXIF': ['Удалять EXIF из JPEG ', 'Remove EXIF from JPEG '], | |
'removeFName': ['Удалять имя из файлов', 'Clear file names'], | |
'sendErrNotif': ['Оповещать в заголовке об ошибке отправки поста', 'Inform in title about post send error'], | |
'scrAfterRep': ['Перемещаться в конец треда после отправки', 'Scroll to the bottom after reply'], | |
'addPostForm': { | |
sel: [['Сверху', 'Внизу', 'Скрытая'], ['At top', 'At bottom', 'Hidden']], | |
txt: ['форма ответа в треде', 'reply form in thread'] | |
}, | |
'favOnReply': ['Добавлять тред в избранное при ответе', 'Add thread to favorites on reply'], | |
'warnSubjTrip': ['Предупреждать при наличии трип-кода в поле "Тема"', 'Warn if "Subject" field contains trip-code'], | |
'fileThumb': ['Область превью картинок вместо кнопки "Файл"', 'File thumbnail area instead of "File" button'], | |
'addSageBtn': ['Кнопка Sage вместо "E-mail"* ', 'Sage button instead of "E-mail"* '], | |
'saveSage': ['запоминать сажу', 'remember sage'], | |
'captchaLang': { | |
sel: [['Откл.', 'Eng', 'Rus'], ['Disable', 'Eng', 'Rus']], | |
txt: ['язык ввода капчи', 'language input in captcha'] | |
}, | |
'addTextBtns': { | |
sel: [['Откл.', 'Графич.', 'Упрощ.', 'Стандарт.'], ['Disable', 'As images', 'As text', 'Standard']], | |
txt: ['кнопки форматирования текста ', 'text format buttons '] | |
}, | |
'txtBtnsLoc': ['внизу', 'at bottom'], | |
'userPassw': [' Постоянный пароль ', ' Fixed password '], | |
'userName': ['Постоянное имя', 'Fixed name'], | |
'noBoardRule': ['правила', 'rules'], | |
'noGoto': ['поле goto', 'goto field'], | |
'noPassword': ['пароль', 'password'], | |
'scriptStyle': { | |
sel: [['Glass black', 'Glass blue', 'Solid grey'], ['Glass black', 'Glass blue', 'Solid grey']], | |
txt: ['стиль скрипта', 'script style'] | |
}, | |
'userCSS': ['Пользовательский CSS ', 'User CSS '], | |
'attachPanel': ['Прикрепить главную панель', 'Attach main panel'], | |
'panelCounter': ['Счетчик постов/картинок на главной панели', 'Counter of posts/images on main panel'], | |
'rePageTitle': ['Название треда в заголовке вкладки*', 'Thread title in page tab*'], | |
'animation': ['CSS3 анимация в скрипте', 'CSS3 animation in script'], | |
'closePopups': ['Автоматически закрывать уведомления', 'Close popups automatically'], | |
'updScript': ['Автоматически проверять обновления скрипта', 'Check for script update automatically'], | |
'turnOff': ['Включать скрипт только на этом сайте', 'Enable script only on this site'], | |
'scrUpdIntrv': { | |
sel: [ | |
['Каждый день', 'Каждые 2 дня', 'Каждую неделю', 'Каждые 2 недели', 'Каждый месяц'], | |
['Every day', 'Every 2 days', 'Every week', 'Every 2 week', 'Every month'] | |
], | |
txt: ['', ''] | |
}, | |
'language': { | |
sel: [['Ru', 'En'], ['Ru', 'En']], | |
txt: ['', ''] | |
} | |
}, | |
txtBtn: [ | |
['Жирный', 'Bold'], | |
['Наклонный', 'Italic'], | |
['Подчеркнутый', 'Underlined'], | |
['Зачеркнутый', 'Strike'], | |
['Спойлер', 'Spoiler'], | |
['Код', 'Code'], | |
['Верхний индекс', 'Superscript'], | |
['Нижний индекс', 'Subscript'], | |
['Цитировать выделенное', 'Quote selected'] | |
], | |
cfgTab: { | |
'filters': ['Фильтры', 'Filters'], | |
'posts': ['Посты', 'Posts'], | |
'images': ['Картинки', 'Images'], | |
'links': ['Ссылки', 'Links'], | |
'form': ['Форма', 'Form'], | |
'common': ['Общее', 'Common'], | |
'info': ['Инфо', 'Info'] | |
}, | |
panelBtn: { | |
'attach': ['Прикрепить/Открепить', 'Attach/Detach'], | |
'settings': ['Настройки', 'Settings'], | |
'hidden': ['Скрытое', 'Hidden'], | |
'favor': ['Избранное', 'Favorites'], | |
'video': ['Видео-ссылки', 'Video links'], | |
'refresh': ['Обновить', 'Refresh'], | |
'goback': ['Назад', 'Go back'], | |
'gonext': ['Следующая', 'Next'], | |
'goup': ['Наверх', 'To the top'], | |
'godown': ['В конец', 'To the bottom'], | |
'expimg': ['Раскрыть картинки', 'Expand images'], | |
'preimg': [ | |
'Предзагрузка картинок ([Ctrl+Click] только для новых постов)', | |
'Preload images ([Ctrl+Click] for new posts only)' | |
], | |
'maskimg': ['Маскировать картинки', 'Mask images'], | |
'upd-on': ['Выключить автообновление треда', 'Disable thread autoupdate'], | |
'upd-off': ['Включить автообновление треда', 'Enable thread autoupdate'], | |
'audio-off': ['Звуковое оповещение о новых постах', 'Sound notification about new posts'], | |
'catalog': ['Каталог', 'Catalog'], | |
'counter': ['Постов/картинок в треде', 'Posts/Images in thread'], | |
'savethr': ['Сохранить на диск', 'Save to disk'], | |
'enable': ['Включить/выключить скрипт', 'Turn on/off the script'] | |
}, | |
selHiderMenu: { | |
'sel': ['Скрывать выделенное', 'Hide selected text'], | |
'name': ['Скрывать имя', 'Hide name'], | |
'trip': ['Скрывать трип-код', 'Hide with trip-code'], | |
'img': ['Скрывать картинку', 'Hide with image'], | |
'ihash': ['Скрывать схожие картинки', 'Hide similar images'], | |
'text': ['Скрыть схожий текст', 'Hide similar text'], | |
'noimg': ['Скрывать без картинок', 'Hide without images'], | |
'notext': ['Скрывать без текста', 'Hide without text'] | |
}, | |
selExpandThr: [ | |
['5 постов', '15 постов', '30 постов', '50 постов', '100 постов'], | |
['5 posts', '15 posts', '30 posts', '50 posts', '100 posts'] | |
], | |
selAjaxPages: [ | |
['1 страница', '2 страницы', '3 страницы', '4 страницы', '5 страниц'], | |
['1 page', '2 pages', '3 pages', '4 pages', '5 pages'] | |
], | |
selSaveThr: [ | |
['Скачать весь тред', 'Скачать картинки'], | |
['Download thread', 'Download images'] | |
], | |
selAudioNotif: [ | |
['Каждые 30 сек.', 'Каждую минуту', 'Каждые 2 мин.', 'Каждые 5 мин.'], | |
['Every 30 sec.', 'Every minute', 'Every 2 min.', 'Every 5 min.'] | |
], | |
hotKeyEdit: [[ | |
'%l%i24 – предыдущая страница/картинка%/l', | |
'%l%i217 – следующая страница/картинка%/l', | |
'%l%i23 – скрыть текущий пост/тред%/l', | |
'%l%i33 – раскрыть текущий тред%/l', | |
'%l%i22 – быстрый ответ%/l', | |
'%l%i25t – отправить пост%/l', | |
'%l%i21 – тред (на доске)/пост (в треде) ниже%/l', | |
'%l%i20 – тред (на доске)/пост (в треде) выше%/l', | |
'%l%i31 – пост (на доске) ниже%/l', | |
'%l%i30 – пост (на доске) выше%/l', | |
'%l%i32 – открыть тред%/l', | |
'%l%i210 – открыть/закрыть настройки%/l', | |
'%l%i26 – открыть/закрыть избранное%/l', | |
'%l%i27 – открыть/закрыть скрытые посты%/l', | |
'%l%i28 – открыть/закрыть панель%/l', | |
'%l%i29 – включить/выключить маскировку картинок%/l', | |
'%l%i40 – обновить тред%/l', | |
'%l%i211 – раскрыть картинку в текущем посте%/l', | |
'%l%i212t – жирный%/l', | |
'%l%i213t – курсив%/l', | |
'%l%i214t – зачеркнутый%/l', | |
'%l%i215t – спойлер%/l', | |
'%l%i216t – код%/l'], [ | |
'%l%i24 – previous page/image%/l', | |
'%l%i217 – next page/image%/l', | |
'%l%i23 – hide current post/thread%/l', | |
'%l%i33 – expand current thread%/l', | |
'%l%i22 – quick reply%/l', | |
'%l%i25t – send post%/l', | |
'%l%i21 – thread (on board)/post (in thread) below%/l', | |
'%l%i20 – thread (on board)/post (in thread) above%/l', | |
'%l%i31 – on board post below%/l', | |
'%l%i30 – on board post above%/l', | |
'%l%i32 – open thread%/l', | |
'%l%i210 – open/close Settings%/l', | |
'%l%i26 – open/close Favorites%/l', | |
'%l%i27 – open/close Hidden Posts Table%/l', | |
'%l%i28 – open/close the main panel%/l', | |
'%l%i29 – turn on/off masking images%/l', | |
'%l%i40 – update thread%/l', | |
'%l%i211 – expand current post\'s images%/l', | |
'%l%i212t – bold%/l', | |
'%l%i213t – italic%/l', | |
'%l%i214t – strike%/l', | |
'%l%i215t – spoiler%/l', | |
'%l%i216t – code%/l' | |
]], | |
month: [ | |
['янв', 'фев', 'мар', 'апр', 'мая', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'], | |
['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] | |
], | |
fullMonth: [ | |
['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря'], | |
['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] | |
], | |
week: [ | |
['Вск', 'Пнд', 'Втр', 'Срд', 'Чтв', 'Птн', 'Сбт'], | |
['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] | |
], | |
editor: { | |
cfg: ['Редактирование настроек:', 'Edit settings:'], | |
hidden: ['Редактирование скрытых тредов:', 'Edit hidden threads:'], | |
favor: ['Редактирование избранного:', 'Edit favorites:'], | |
css: ['Редактирование CSS', 'Edit CSS'] | |
}, | |
newPost: [ | |
[' новый пост', ' новых поста', ' новых постов', '. Последний:'], | |
[' new post', ' new posts', ' new posts', '. Latest: '] | |
], | |
add: ['Добавить', 'Add'], | |
apply: ['Применить', 'Apply'], | |
clear: ['Очистить', 'Clear'], | |
refresh: ['Обновить', 'Refresh'], | |
load: ['Загрузить', 'Load'], | |
save: ['Сохранить', 'Save'], | |
edit: ['Правка', 'Edit'], | |
reset: ['Сброс', 'Reset'], | |
remove: ['Удалить', 'Remove'], | |
info: ['Инфо', 'Info'], | |
undo: ['Отмена', 'Undo'], | |
change: ['Сменить', 'Change'], | |
reply: ['Ответ', 'Reply'], | |
loading: ['Загрузка...', 'Loading...'], | |
checking: ['Проверка...', 'Checking...'], | |
deleting: ['Удаление...', 'Deleting...'], | |
error: ['Ошибка', 'Error'], | |
noConnect: ['Ошибка подключения', 'Connection failed'], | |
thrNotFound: ['Тред недоступен (№', 'Thread is unavailable (№'], | |
succDeleted: ['Успешно удалено!', 'Succesfully deleted!'], | |
errDelete: ['Не могу удалить:\n', 'Can\'t delete:\n'], | |
cTimeError: ['Неправильные настройки времени', 'Invalid time settings'], | |
noGlobalCfg: ['Глобальные настройки не найдены', 'Global config not found'], | |
postNotFound: ['Пост не найден', 'Post not found'], | |
dontShow: ['Скрыть: ', 'Hide: '], | |
checkNow: ['Проверить сейчас', 'Check now'], | |
updAvail: ['Доступно обновление!', 'Update available!'], | |
haveLatest: ['У вас стоит самая последняя версия!', 'You have latest version!'], | |
storage: ['Хранение: ', 'Storage: '], | |
thrViewed: ['Тредов просмотрено: ', 'Threads viewed: '], | |
thrCreated: ['Тредов создано: ', 'Threads created: '], | |
thrHidden: ['Тредов скрыто: ', 'Threads hidden: '], | |
postsSent: ['Постов отправлено: ', 'Posts sent: '], | |
total: ['Всего: ', 'Total: '], | |
debug: ['Отладка', 'Debug'], | |
infoDebug: ['Информация для отладки', 'Information for debugging'], | |
loadGlobal: ['Загрузить глобальные настройки', 'Load global settings'], | |
saveGlobal: ['Сохранить настройки как глобальные', 'Save settings as global'], | |
editInTxt: ['Правка в текстовом формате', 'Edit in text format'], | |
resetCfg: ['Сбросить в настройки по умолчанию', 'Reset settings to defaults'], | |
conReset: [ | |
'Данное действие удалит все ваши настройки и закладки. Продолжить?', | |
'This will delete all your preferences and favourites. Continue?' | |
], | |
clrSelected: ['Удалить выделенные записи', 'Remove selected notes'], | |
saveChanges: ['Сохранить внесенные изменения', 'Save your changes'], | |
infoCount: ['Обновить счетчики постов', 'Refresh posts counters'], | |
infoPage: ['Проверить актуальность тредов (до 5 страницы)', 'Check for threads actuality (up to 5 page)'], | |
clrDeleted: ['Очистить недоступные (404) треды', 'Clear inaccessible (404) threads'], | |
oldPosts: ['Постов при последнем посещении', 'Posts at the last visit'], | |
newPosts: ['Количество новых постов', 'Number of new posts'], | |
thrPage: ['Тред на @странице', 'Thread on @page'], | |
findThrd: ['Найти/Загрузить тред', 'Find/Load thread'], | |
hiddenPosts: ['Скрытые посты на странице', 'Hidden posts on the page'], | |
hiddenThrds: ['Скрытые треды', 'Hidden threads'], | |
noHidPosts: ['На этой странице нет скрытых постов...', 'No hidden posts on this page...'], | |
noHidThrds: ['Нет скрытых тредов...', 'No hidden threads...'], | |
expandAll: ['Раскрыть все', 'Expand all'], | |
invalidData: ['Некорректный формат данных', 'Incorrect data format'], | |
favThrds: ['Избранные треды:', 'Favorite threads:'], | |
noFavThrds: ['Нет избранных тредов...', 'Favorites is empty...'], | |
noVideoLinks: ['Нет ссылок на видео...', 'No video links...'], | |
hideLnkList: ['Скрыть/Показать список ссылок', 'Hide/Unhide list of links'], | |
prevVideo: ['Предыдущее видео', 'Previous video'], | |
nextVideo: ['Следующее видео', 'Next video'], | |
toggleQReply: ['Поместить под пост / Открепить', 'Move under post / Unattach'], | |
closeQReply: ['Закрыть форму', 'Close form'], | |
replies: ['Ответы:', 'Replies:'], | |
postsOmitted: ['Пропущено ответов: ', 'Posts omitted: '], | |
collapseThrd: ['Свернуть тред', 'Collapse thread'], | |
deleted: ['удалён', 'deleted'], | |
getNewPosts: ['Получить новые посты', 'Get new posts'], | |
page: ['Страница', 'Page'], | |
hiddenThrd: ['Скрытый тред:', 'Hidden thread:'], | |
makeThrd: ['Создать тред', 'Create thread'], | |
makeReply: ['Ответить', 'Make reply'], | |
hideForm: ['Скрыть форму', 'Hide form'], | |
search: ['Искать в ', 'Search in '], | |
wait: ['Ждите', 'Wait'], | |
noFile: ['Нет файла', 'No file'], | |
clickToAdd: ['Выберите, либо перетащите файл', 'Select or drag and drop file'], | |
removeFile: ['Удалить файл', 'Remove file'], | |
helpAddFile: ['Встроить .ogg, .rar, .zip или .7z в картинку', 'Pack .ogg, .rar, .zip or .7z into image'], | |
downloadFile: ['Скачать содержащийся в картинке файл', 'Download existing file from image'], | |
fileCorrupt: ['Файл повреждён: ', 'File is corrupted: '], | |
subjHasTrip: ['Поле "Тема" содержит трипкод', '"Subject" field contains a tripcode'], | |
loadImage: ['Загружаются картинки: ', 'Loading images: '], | |
loadFile: ['Загружаются файлы: ', 'Loading files: '], | |
cantLoad: ['Не могу загрузить ', 'Can\'t load '], | |
willSavePview: ['Будет сохранено превью', 'Thumbnail will be saved'], | |
loadErrors: ['Во время загрузки произошли ошибки:', 'An error occurred during the loading:'], | |
errCorruptData: ['Ошибка: сервер отправил повреждённые данные', 'Error: server sent corrupted data'], | |
expImgInline: ['[Click] открыть в посте, [Ctrl+Click] в центре', '[Click] expand in post, [Ctrl+Click] by center'], | |
expImgFull: ['[Click] открыть в центре, [Ctrl+Click] в посте', '[Click] expand by center, [Ctrl+Click] in post'], | |
nextImg: ['Следующая картинка', 'Next image'], | |
prevImg: ['Предыдущая картинка', 'Previous image'], | |
togglePost: ['Скрыть/Раскрыть пост', 'Hide/Unhide post'], | |
replyToPost: ['Ответить на пост', 'Reply to post'], | |
expandThrd: ['Раскрыть весь тред', 'Expand all thread'], | |
addFav: ['Добавить тред в Избранное', 'Add thread to Favorites'], | |
delFav: ['Убрать тред из Избранного', 'Remove thread from Favorites'], | |
attachPview: ['Закрепить превью', 'Attach preview'], | |
author: ['автор: ', 'author: '], | |
views: ['просмотров: ', 'views: '], | |
published: ['опубликовано: ', 'published: '], | |
seSyntaxErr: ['синтаксическая ошибка в аргументе спелла: %s', 'syntax error in argument of spell: %s'], | |
seUnknown: ['неизвестный спелл: %s', 'unknown spell: %s'], | |
seMissOp: ['пропущен оператор', 'missing operator'], | |
seMissArg: ['пропущен аргумент спелла: %s', 'missing argument of spell: %s'], | |
seMissSpell: ['пропущен спелл', 'missing spell'], | |
seErrRegex: ['синтаксическая ошибка в регулярном выражении: %s', 'syntax error in regular expression: %s'], | |
seUnexpChar: ['неожиданный символ: %s', 'unexpected character: %s'], | |
seMissClBkt: ['пропущена закрывающаяся скобка', 'missing ) in parenthetical'], | |
seRepsInParens: ['спелл $s не должен располагаться в скобках', 'spell %s shouldn\'t be in parens'], | |
seOpInReps: [ | |
'недопустимо использовать оператор %s со спеллами #rep и #outrep', | |
'don\'t use operator %s with spells #rep & #outrep' | |
], | |
seRow: [' (строка ', ' (row '], | |
seCol: [', столбец ', ', column '] | |
}, | |
doc = window.document, aProto = Array.prototype, locStorage, sesStorage, | |
Cfg, comCfg, hThr, pByNum, sVis, bUVis, needScroll, | |
aib, nav, brd, TNum, pageNum, updater, hKeys, firstThr, lastThr, visPosts = 2, dTime, | |
YouTube, WebmParser, Logger, | |
pr, dForm, dummy, spells, | |
Images_ = {preloading: false, afterpreload: null, progressId: null, canvas: null}, | |
ajaxInterval, lang, quotetxt = '', liteMode, localRun, isExpImg, isPreImg, chromeCssUpd, | |
$each = Function.prototype.call.bind(aProto.forEach), | |
emptyFn = function () {}; | |
// UTILS | |
// =========================================================================================================== | |
function $Q(path, root) { | |
return root.querySelectorAll(path); | |
} | |
function $q(path, root) { | |
return root.querySelector(path); | |
} | |
function $C(id, root) { | |
return root.getElementsByClassName(id); | |
} | |
function $c(id, root) { | |
return root.getElementsByClassName(id)[0]; | |
} | |
function $id(id) { | |
return doc.getElementById(id); | |
} | |
function $T(id, root) { | |
return root.getElementsByTagName(id); | |
} | |
function $t(id, root) { | |
return root.getElementsByTagName(id)[0]; | |
} | |
function $parent(el, tagName) { | |
do { | |
el = el.parentElement; | |
} while (el && el.tagName !== tagName); | |
return el; | |
} | |
function $before(el, node) { | |
el.parentNode.insertBefore(node, el); | |
} | |
function $after(el, node) { | |
el.parentNode.insertBefore(node, el.nextSibling); | |
} | |
function $add(html) { | |
dummy.innerHTML = html; | |
return dummy.firstChild; | |
} | |
function $new(tag, attr, events) { | |
var key, el = doc.createElement(tag); | |
if (attr) { | |
for (key in attr) { | |
if (key === 'text') { | |
el.textContent = attr[key]; | |
} else if (key === 'value') { | |
el.value = attr[key]; | |
} else if (attr.hasOwnProperty(key)) { | |
el.setAttribute(key, attr[key]); | |
} | |
} | |
} | |
if (events) { | |
for (key in events) { | |
if (events.hasOwnProperty(key)) { | |
el.addEventListener(key, events[key], false); | |
} | |
} | |
} | |
return el; | |
} | |
function $New(tag, attr, nodes) { | |
var el = $new(tag, attr, null); | |
for (var i = 0, len = nodes.length; i < len; i++) { | |
if (nodes[i]) { | |
el.appendChild(nodes[i]); | |
} | |
} | |
return el; | |
} | |
function $txt(el) { | |
return doc.createTextNode(el); | |
} | |
function $btn(val, ttl, Fn) { | |
return $new('input', {'type': 'button', 'value': val, 'title': ttl}, {'click': Fn}); | |
} | |
function $script(text) { | |
$del(doc.head.appendChild($new('script', {'type': 'text/javascript', 'text': text}, null))); | |
} | |
function $css(text) { | |
return doc.head.appendChild($new('style', {'type': 'text/css', 'text': text}, null)); | |
} | |
function $if(cond, el) { | |
return cond ? el : null; | |
} | |
function $disp(el) { | |
el.style.display = el.style.display === 'none' ? '' : 'none'; | |
} | |
function $del(el) { | |
if (el) { | |
el.parentNode.removeChild(el); | |
} | |
} | |
function $DOM(html) { | |
var myDoc = doc.implementation.createHTMLDocument(''); | |
myDoc.documentElement.innerHTML = html; | |
return myDoc; | |
} | |
function $pd(e) { | |
e.preventDefault(); | |
} | |
function $txtInsert(el, txt) { | |
var scrtop = el.scrollTop, | |
start = el.selectionStart; | |
el.value = el.value.substr(0, start) + txt + el.value.substr(el.selectionEnd); | |
el.setSelectionRange(start + txt.length, start + txt.length); | |
el.focus(); | |
el.scrollTop = scrtop; | |
} | |
function $txtSelect() { | |
return (nav.Presto ? doc.getSelection() : window.getSelection()).toString(); | |
} | |
function $isEmpty(obj) { | |
for (var i in obj) { | |
if (obj.hasOwnProperty(i)) { | |
return false; | |
} | |
} | |
return true; | |
} | |
Logger = new function () { | |
var instance, oldTime, initTime, timeLog; | |
function LoggerSingleton() { | |
if (instance) { | |
return instance; | |
} | |
instance = this; | |
} | |
LoggerSingleton.prototype = { | |
finish: function () { | |
timeLog.push(Lng.total[lang] + (Date.now() - initTime) + 'ms'); | |
}, | |
get: function () { | |
return timeLog; | |
}, | |
init: function () { | |
oldTime = initTime = Date.now(); | |
timeLog = []; | |
}, | |
log: function realLog(text) { | |
var newTime = Date.now(), | |
time = newTime - oldTime; | |
if (time > 1) { | |
timeLog.push(text + ': ' + time + 'ms'); | |
oldTime = newTime; | |
} | |
} | |
}; | |
return LoggerSingleton; | |
}; | |
function $xhr(obj) { | |
var h, xhr = new XMLHttpRequest(); | |
if (obj.onreadystatechange) { | |
xhr.onreadystatechange = obj.onreadystatechange.bind(window, xhr); | |
} | |
if (obj.onload) { | |
xhr.onload = obj.onload.bind(window, xhr); | |
} | |
xhr.open(obj.method, obj.url, true); | |
if (obj.responseType) { | |
xhr.responseType = obj.responseType; | |
} | |
for (h in obj.headers) { | |
xhr.setRequestHeader(h, obj.headers[h]); | |
} | |
xhr.send(obj.data || null); | |
return xhr; | |
} | |
function $queue(maxNum, Fn, endFn) { | |
this.array = []; | |
this.length = this.index = this.running = 0; | |
this.num = 1; | |
this.fn = Fn; | |
this.endFn = endFn; | |
this.max = maxNum; | |
this.freeSlots = []; | |
while (maxNum--) { | |
this.freeSlots.push(maxNum); | |
} | |
this.completed = this.paused = false; | |
} | |
$queue.prototype = { | |
run: function (data) { | |
if (this.paused || this.running === this.max) { | |
this.array.push(data); | |
this.length++; | |
} else { | |
this.fn(this.freeSlots.pop(), this.num++, data); | |
this.running++; | |
} | |
}, | |
end: function (qIdx) { | |
if (!this.paused && this.index < this.length) { | |
this.fn(qIdx, this.num++, this.array[this.index++]); | |
return; | |
} | |
this.running--; | |
this.freeSlots.push(qIdx); | |
if (!this.paused && this.completed && this.running === 0) { | |
this.endFn(); | |
} | |
}, | |
complete: function () { | |
if (this.index >= this.length && this.running === 0) { | |
this.endFn(); | |
} else { | |
this.completed = true; | |
} | |
}, | |
pause: function () { | |
this.paused = true; | |
}, | |
'continue': function () { | |
this.paused = false; | |
if (this.index >= this.length) { | |
if (this.completed) { | |
this.endFn(); | |
} | |
return; | |
} | |
while (this.index < this.length && this.running !== this.max) { | |
this.fn(this.freeSlots.pop(), this.num++, this.array[this.index++]); | |
this.running++; | |
} | |
} | |
}; | |
function $tar() { | |
this._data = []; | |
} | |
$tar.prototype = { | |
addFile: function (filepath, input) { | |
var i, checksum, nameLen, fileSize = input.length, | |
header = new Uint8Array(512); | |
for (i = 0, nameLen = Math.min(filepath.length, 100); i < nameLen; ++i) { | |
header[i] = filepath.charCodeAt(i) & 0xFF; | |
} | |
// fileMode | |
this._padSet(header, 100, '100777', 8); | |
// uid | |
this._padSet(header, 108, '0', 8); | |
// gid | |
this._padSet(header, 116, '0', 8); | |
// fileSize | |
this._padSet(header, 124, fileSize.toString(8), 13); | |
// mtime | |
this._padSet(header, 136, Math.floor(Date.now() / 1000).toString(8), 12); | |
// checksum | |
this._padSet(header, 148, ' ', 8); | |
// type ('0') | |
header[156] = 0x30; | |
for (i = checksum = 0; i < 157; i++) { | |
checksum += header[i]; | |
} | |
// checksum | |
this._padSet(header, 148, checksum.toString(8), 8); | |
this._data.push(header); | |
this._data.push(input); | |
if ((i = Math.ceil(fileSize / 512) * 512 - fileSize) !== 0) { | |
this._data.push(new Uint8Array(i)); | |
} | |
}, | |
addString: function (filepath, str) { | |
var i, len, data, sDat = unescape(encodeURIComponent(str)); | |
for (i = 0, len = sDat.length, data = new Uint8Array(len); i < len; ++i) { | |
data[i] = sDat.charCodeAt(i) & 0xFF; | |
} | |
this.addFile(filepath, data); | |
}, | |
get: function () { | |
this._data.push(new Uint8Array(1024)); | |
return new Blob(this._data, {'type': 'application/x-tar'}); | |
}, | |
_padSet: function (data, offset, num, len) { | |
var i = 0, nLen = num.length; | |
len -= 2; | |
while (nLen < len) { | |
data[offset++] = 0x20; // ' ' | |
len--; | |
} | |
while (i < nLen) { | |
data[offset++] = num.charCodeAt(i++); | |
} | |
data[offset] = 0x20; // ' ' | |
} | |
}; | |
function $workers(source, count) { | |
var i, wrk, wUrl; | |
if (nav.Firefox) { | |
wUrl = 'data:text/javascript,' + source; | |
wrk = unsafeWindow.Worker; | |
} else { | |
wUrl = window.URL.createObjectURL(new Blob([source], {'type': 'text/javascript'})); | |
this.url = wUrl; | |
wrk = Worker; | |
} | |
for (i = 0; i < count; ++i) { | |
this[i] = new wrk(wUrl); | |
} | |
} | |
$workers.prototype = { | |
url: null, | |
clear: function () { | |
if (this.url !== null) { | |
window.URL.revokeObjectURL(this.url); | |
} | |
} | |
}; | |
function regQuote(str) { | |
return (str + '').replace(/([.?*+^$[\]\\(){}|\-])/g, '\\$1'); | |
} | |
function fixBrd(b) { | |
return '/' + b + (b ? '/' : ''); | |
} | |
function getAbsLink(url) { | |
return url[1] === '/' ? aib.prot + url : | |
url[0] === '/' ? aib.prot + '//' + aib.host + url : url; | |
} | |
function getErrorMessage(eCode, eMsg) { | |
return eCode === 0 ? eMsg || Lng.noConnect[lang] : 'HTTP [' + eCode + '] ' + eMsg; | |
} | |
function getPrettyErrorMessage(e) { | |
return e.stack ? (nav.WebKit ? e.stack : | |
e.name + ': ' + e.message + '\n' + | |
(nav.Firefox ? e.stack.replace(/^([^@]*).*\/(.+)$/gm, function (str, fName, line) { | |
return ' at ' + (fName ? fName + ' (' + line + ')' : line); | |
}) : e.stack) | |
) : e.name + ': ' + e.message; | |
} | |
function toRegExp(str, noG) { | |
var l = str.lastIndexOf('/'), | |
flags = str.substr(l + 1); | |
return new RegExp(str.substr(1, l - 1), noG ? flags.replace('g', '') : flags); | |
} | |
function setImageSize(size, idx, nVal) { | |
size[idx] = nVal; | |
if (idx === 0) { | |
size[1] = nVal / size[2]; | |
} else { | |
size[0] = nVal * size[2]; | |
} | |
} | |
function resizeImage(size, minSize, maxSize) { | |
var idx = size[2] > 1 ? 1 : 0; | |
if (+size[idx] < +minSize) { | |
setImageSize(size, idx, minSize); | |
} | |
if (maxSize) { | |
idx = size[2] > maxSize[2] ? 0 : 1; | |
if (+size[idx] > +maxSize[idx]) { | |
setImageSize(size, idx, +maxSize[idx]); | |
} | |
} | |
return size; | |
} | |
// STORAGE | |
// =========================================================================================================== | |
function getStored(id, Fn) { | |
if (nav.isGM) { | |
Fn(GM_getValue(id)); | |
} else if (nav.isChromeStorage) { | |
chrome.storage.local.get(id, function (obj) { | |
if (Object.keys(obj).length) { | |
// console.log('Read local ' + id); | |
Fn(obj[id]); | |
} else { | |
chrome.storage.sync.get(id, function (obj) { | |
// console.log('Read sync ' + id); | |
Fn(obj[id]); | |
}); | |
} | |
}); | |
} else if (nav.isScriptStorage) { | |
Fn(scriptStorage.getItem(id)); | |
} else { | |
Fn(locStorage.getItem(id)); | |
} | |
} | |
function setStored(id, value) { | |
if (nav.isGM) { | |
GM_setValue(id, value); | |
} else if (nav.isChromeStorage) { | |
var obj = {}; | |
obj[id] = value; | |
if (value.toString().length < 4095) { | |
chrome.storage.sync.set(obj, emptyFn); | |
chrome.storage.local.remove(id, emptyFn); | |
} else { | |
chrome.storage.local.set(obj, emptyFn); | |
chrome.storage.sync.remove(id, emptyFn); | |
} | |
} else if (nav.isScriptStorage) { | |
scriptStorage.setItem(id, value); | |
} else { | |
locStorage.setItem(id, value); | |
} | |
} | |
function delStored(id) { | |
if (nav.isGM) { | |
GM_deleteValue(id); | |
} else if (nav.isChromeStorage) { | |
chrome.storage.sync.remove(id, emptyFn); | |
} else if (nav.isScriptStorage) { | |
scriptStorage.removeItem(id); | |
} else { | |
locStorage.removeItem(id); | |
} | |
} | |
function getStoredObj(id, Fn) { | |
getStored(id, function (Fn, val) { | |
var data; | |
try { | |
data = JSON.parse(val || '{}'); | |
} finally { | |
Fn(data || {}); | |
} | |
}.bind(null, Fn)); | |
} | |
function saveComCfg(dm, obj) { | |
getStoredObj('DESU_Config', function (dm, obj, val) { | |
comCfg = val; | |
if (obj) { | |
comCfg[dm] = obj; | |
} else { | |
delete comCfg[dm]; | |
} | |
setStored('DESU_Config', JSON.stringify(comCfg) || ''); | |
}.bind(null, dm, obj)); | |
} | |
function saveCfg(id, val) { | |
if (Cfg[id] !== val) { | |
Cfg[id] = val; | |
saveComCfg(aib.dm, Cfg); | |
} | |
} | |
function Config(obj) { | |
for (var i in obj) { | |
this[i] = obj[i]; | |
} | |
} | |
Config.prototype = defaultCfg; | |
function readCfg(Fn) { | |
getStoredObj('DESU_Config', function (Fn, val) { | |
var obj; | |
comCfg = val; | |
if (!(aib.dm in comCfg) || $isEmpty(obj = comCfg[aib.dm])) { | |
if (nav.isChromeStorage && (obj = locStorage.getItem('DESU_Config'))) { | |
obj = JSON.parse(obj)[aib.dm]; | |
locStorage.removeItem('DESU_Config'); | |
} else { | |
obj = nav.isGlobal ? comCfg.global || {} : {}; | |
} | |
obj.captchaLang = aib.ru ? 2 : 1; | |
obj.correctTime = 0; | |
} | |
Cfg = new Config(obj); | |
if (!Cfg.timeOffset) { | |
Cfg.timeOffset = '+0'; | |
} | |
if (!Cfg.timePattern) { | |
Cfg.timePattern = aib.timePattern; | |
} | |
if ((nav.Opera11 || aib.fch || aib.tiny) && Cfg.ajaxReply === 2) { | |
Cfg.ajaxReply = 1; | |
} | |
if (aib.tiny) { | |
Cfg.fileThumb = 0; | |
} | |
if (!('Notification' in window)) { | |
Cfg.desktNotif = 0; | |
} | |
if (nav.Presto) { | |
if (nav.Opera11) { | |
if (!nav.isGM) { | |
Cfg.YTubeTitles = 0; | |
} | |
Cfg.animation = 0; | |
} | |
if (Cfg.YTubeType === 2) { | |
Cfg.YTubeType = 1; | |
} | |
Cfg.preLoadImgs = 0; | |
Cfg.findImgFile = 0; | |
if (!nav.isGM) { | |
Cfg.updScript = 0; | |
} | |
Cfg.fileThumb = 0; | |
} | |
if (nav.isChromeStorage) { | |
Cfg.updScript = 0; | |
} | |
if (Cfg.updThrDelay < 10) { | |
Cfg.updThrDelay = 10; | |
} | |
if (!Cfg.saveSage) { | |
Cfg.sageReply = 0; | |
} | |
if (!Cfg.passwValue) { | |
Cfg.passwValue = Math.round(Math.random() * 1e15).toString(32); | |
} | |
if (!Cfg.stats) { | |
Cfg.stats = {'view': 0, 'op': 0, 'reply': 0}; | |
} | |
if (TNum) { | |
Cfg.stats.view++; | |
} | |
if (aib.dobr) { | |
aib.hDTFix = new dateTime( | |
'yyyy-nn-dd-hh-ii-ss', | |
'_d _M _Y (_w) _h:_i ', | |
Cfg.timeOffset || 0, | |
Cfg.correctTime ? lang : 1, | |
null | |
); | |
} | |
if (aib.synch) { | |
Cfg.timePattern = 'w+dd+m+yyyy+hh+ii+ss'; | |
Cfg.timeOffset = 4; | |
Cfg.correctTime = 1; | |
} | |
saveComCfg(aib.dm, Cfg); | |
lang = Cfg.language; | |
if (Cfg.correctTime) { | |
dTime = new dateTime(Cfg.timePattern, Cfg.timeRPattern, Cfg.timeOffset, lang, function (rp) { | |
saveCfg('timeRPattern', rp); | |
}); | |
} | |
Fn(); | |
}.bind(null, Fn)); | |
} | |
function toggleCfg(id) { | |
saveCfg(id, +!Cfg[id]); | |
} | |
function readPosts() { | |
var data, str = TNum ? sesStorage['de-hidden-' + brd + TNum] : null; | |
if (typeof str === 'string') { | |
data = str.split(','); | |
if (data.length === 4 && +data[0] === (Cfg.hideBySpell ? spells.hash : 0) && | |
(data[1] in pByNum) && pByNum[data[1]].count === +data[2]) | |
{ | |
sVis = data[3].split(''); | |
return; | |
} | |
} | |
sVis = []; | |
} | |
function readUserPosts() { | |
getStoredObj('DESU_Posts_' + aib.dm, function (val) { | |
bUVis = val; | |
getStoredObj('DESU_Threads_' + aib.dm, function (val) { | |
hThr = val; | |
if (nav.isChromeStorage && (val = locStorage.getItem('DESU_Posts_' + aib.dm))) { | |
bUVis = JSON.parse(val); | |
val = locStorage.getItem('DESU_Threads_' + aib.dm); | |
hThr = JSON.parse(val); | |
locStorage.removeItem('DESU_Posts_' + aib.dm); | |
locStorage.removeItem('DESU_Threads_' + aib.dm); | |
} | |
var uVis, vis, num, post, date = Date.now(), | |
update = false; | |
if (brd in bUVis) { | |
uVis = bUVis[brd]; | |
} else { | |
uVis = bUVis[brd] = {}; | |
} | |
if (!(brd in hThr)) { | |
hThr[brd] = {}; | |
} | |
if (!firstThr) { | |
return; | |
} | |
for (post = firstThr.op; post; post = post.next) { | |
num = post.num; | |
if (num in uVis) { | |
if (post.isOp) { | |
uVis[num][0] = +!(num in hThr[brd]); | |
} | |
if (uVis[num][0] === 0) { | |
post.setUserVisib(true, date, false); | |
} else { | |
uVis[num][1] = date; | |
post.btns.firstChild.className = 'de-btn-hide-user'; | |
post.userToggled = true; | |
} | |
} else { | |
vis = sVis[post.count]; | |
if (post.isOp) { | |
if (num in hThr[brd]) { | |
vis = '0'; | |
} else if (vis === '0') { | |
vis = null; | |
} | |
} | |
if (vis === '0') { | |
if (!post.hidden) { | |
post.setVisib(true); | |
post.hideRefs(); | |
} | |
post.spellHidden = true; | |
} else if (vis !== '1') { | |
spells.check(post); | |
} | |
} | |
} | |
spells.end(savePosts); | |
if (update) { | |
bUVis[brd] = uVis; | |
saveUserPosts(false); | |
} | |
}); | |
}); | |
} | |
function savePosts() { | |
if (TNum) { | |
var lPost = firstThr.lastNotDeleted; | |
sesStorage['de-hidden-' + brd + TNum] = (Cfg.hideBySpell ? spells.hash : '0') + | |
',' + lPost.num + ',' + lPost.count + ',' + sVis.join(''); | |
} | |
saveHiddenThreads(false); | |
toggleContent('hid', true); | |
} | |
function saveUserPosts(clear) { | |
var minDate, b, vis, key, str = JSON.stringify(bUVis); | |
if (clear && str.length > 1e6) { | |
minDate = Date.now() - 5 * 24 * 3600 * 1000; | |
for (b in bUVis) { | |
if (bUVis.hasOwnProperty(b)) { | |
vis = bUVis[b]; | |
for (key in vis) { | |
if (vis.hasOwnProperty(key) && vis[key][1] < minDate) { | |
delete vis[key]; | |
} | |
} | |
} | |
} | |
str = JSON.stringify(bUVis); | |
} | |
setStored('DESU_Posts_' + aib.dm, str); | |
toggleContent('hid', true); | |
} | |
function saveHiddenThreads(updContent) { | |
setStored('DESU_Threads_' + aib.dm, JSON.stringify(hThr)); | |
if (updContent) { | |
toggleContent('hid', true); | |
} | |
} | |
function readFavoritesPosts() { | |
getStoredObj('DESU_Favorites', function (fav) { | |
var thr, temp, num, update = false; | |
if (nav.isChromeStorage && (temp = locStorage.getItem('DESU_Favorites'))) { | |
temp = JSON.parse(temp); | |
locStorage.removeItem('DESU_Favorites'); | |
if ($isEmpty(temp)) { | |
return; | |
} | |
temp = temp[aib.host]; | |
fav[aib.host] = temp; | |
temp = temp[brd]; | |
} else { | |
if (!(aib.host in fav)) { | |
return; | |
} | |
temp = fav[aib.host]; | |
if (!(brd in temp)) { | |
return; | |
} | |
temp = temp[brd]; | |
} | |
for (thr = firstThr; thr; thr = thr.next) { | |
if ((num = thr.num) in temp) { | |
thr.setFavBtn(true); | |
if (TNum) { | |
temp[num].cnt = thr.pcount; | |
temp[num]['new'] = 0; | |
} else { | |
temp[num]['new'] = thr.pcount - temp[num].cnt; | |
} | |
update = true; | |
} | |
} | |
if (update) { | |
saveFavorites(fav); | |
} | |
}); | |
} | |
function saveFavorites(fav) { | |
setStored('DESU_Favorites', JSON.stringify(fav)); | |
toggleContent('fav', true, fav); | |
} | |
function removeFavoriteEntry(fav, h, b, num, clearPage) { | |
function _isEmpty(f) { | |
for (var i in f) { | |
if (i !== 'url' && f.hasOwnProperty(i)) { | |
return false; | |
} | |
} | |
return true; | |
} | |
if ((h in fav) && (b in fav[h]) && (num in fav[h][b])) { | |
delete fav[h][b][num]; | |
if (_isEmpty(fav[h][b])) { | |
delete fav[h][b]; | |
if ($isEmpty(fav[h])) { | |
delete fav[h]; | |
} | |
} | |
} | |
if (clearPage && h === aib.host && b === brd && (num in pByNum)) { | |
pByNum[num].thr.setFavBtn(false); | |
} | |
} | |
function readViewedPosts() { | |
if (Cfg.markViewed) { | |
var data = sesStorage['de-viewed']; | |
if (data) { | |
data.split(',').forEach(function (pNum) { | |
var post = pByNum[pNum]; | |
if (post) { | |
post.el.classList.add('de-viewed'); | |
post.viewed = true; | |
} | |
}); | |
} | |
} | |
} | |
// PANEL | |
// =========================================================================================================== | |
function pButton(id, href, hasHotkey) { | |
return '<li><a id="de-btn-' + id + '" class="de-abtn" ' + (hasHotkey ? 'de-' : '') + 'title="' + | |
Lng.panelBtn[id][lang] +'" href="' + href + '"></a></li>'; | |
} | |
function addPanel() { | |
var panel, evtObject, imgLen = $Q(aib.qThumbImages, dForm).length; | |
(pr && pr.pArea[0] || dForm).insertAdjacentHTML('beforebegin', | |
'<div id="darude-sandstorm" lang="' + getThemeLang() + '">' + | |
'<div id="de-panel">' + | |
'<span id="de-btn-logo" title="' + Lng.panelBtn.attach[lang] + '"></span>' + | |
'<ul id="de-panel-btns"' + (Cfg.expandPanel ? '>' : ' style="display: none">') + | |
(Cfg.disabled ? pButton('enable', '#', false) : | |
pButton('settings', '#', true) + | |
pButton('hidden', '#', true) + | |
pButton('favor', '#', true) + | |
(!Cfg.addYouTube ? '' : pButton('video', '#', false)) + | |
(aib.arch || localRun ? '' : | |
pButton('refresh', '#', false) + | |
(!TNum && (pageNum === aib.firstPage) ? '' : | |
pButton('goback', aib.getPageUrl(brd, pageNum - 1), true)) + | |
(TNum || pageNum === aib.lastPage ? '' : | |
pButton('gonext', aib.getPageUrl(brd, pageNum + 1), true)) | |
) + pButton('goup', '#', false) + | |
pButton('godown', '#', false) + | |
(imgLen === 0 ? '' : | |
pButton('expimg', '#', false) + | |
pButton('maskimg', '#', true) + | |
(nav.Presto || localRun ? '' : | |
(Cfg.preLoadImgs ? '' : pButton('preimg', '#', false)) + | |
(!TNum && !aib.arch ? '' : pButton('savethr', '#', false)))) + | |
(!TNum || localRun ? '' : | |
pButton(Cfg.ajaxUpdThr ? 'upd-on' : 'upd-off', '#', false) + | |
(nav.Safari ? '' : pButton('audio-off', '#', false))) + | |
(!aib.abu && !aib.mak && (!aib.fch || aib.arch) ? '' : | |
pButton('catalog', aib.prot + '//' + aib.host + '/' + (aib.mak ? | |
'makaba/makaba.fcgi?task=catalog&board=' + brd : brd + '/catalog.html'), false)) + | |
pButton('enable', '#', false) + | |
(!TNum && !aib.arch ? '' : | |
'<span id="de-panel-info" title="' + Lng.panelBtn.counter[lang] + '">' + | |
firstThr.pcount + '/' + imgLen + '</span>') | |
) + | |
'</ul>' + | |
'</div><div class="de-content"></div>' + | |
(Cfg.disabled ? '' : '<div id="de-alert"></div><hr style="clear: both;">') + | |
'</div>' | |
); | |
panel = $id('de-panel'); | |
evtObject = { | |
attach: false, | |
odelay: 0, | |
panel: panel, | |
handleEvent: function (e) { | |
switch (e.type) { | |
case 'click': | |
switch (e.target.id) { | |
case 'de-btn-logo': | |
if (Cfg.expandPanel) { | |
this.panel.lastChild.style.display = 'none'; | |
this.attach = false; | |
} else { | |
this.attach = true; | |
} | |
toggleCfg('expandPanel'); | |
return; | |
case 'de-btn-settings': this.attach = toggleContent('cfg', false); break; | |
case 'de-btn-hidden': this.attach = toggleContent('hid', false); break; | |
case 'de-btn-favor': this.attach = toggleContent('fav', false); break; | |
case 'de-btn-video': this.attach = toggleContent('vid', false); break; | |
case 'de-btn-refresh': window.location.reload(); break; | |
case 'de-btn-goup': scrollTo(0, 0); break; | |
case 'de-btn-godown': scrollTo(0, doc.body.scrollHeight || doc.body.offsetHeight); break; | |
case 'de-btn-expimg': | |
isExpImg = !isExpImg; | |
$del($c('de-img-center', doc)); | |
for (var post = firstThr.op; post; post = post.next) { | |
post.toggleImages(isExpImg); | |
} | |
break; | |
case 'de-btn-preimg': | |
isPreImg = !isPreImg; | |
if (!e.ctrlKey) { | |
preloadImages(null); | |
} | |
break; | |
case 'de-btn-maskimg': | |
toggleCfg('maskImgs'); | |
updateCSS(); | |
break; | |
case 'de-btn-upd-on': | |
case 'de-btn-upd-off': | |
case 'de-btn-upd-warn': | |
if (updater.enabled) { | |
updater.disable(); | |
} else { | |
updater.enable(); | |
} | |
break; | |
case 'de-btn-audio-on': | |
case 'de-btn-audio-off': | |
if (updater.toggleAudio(0)) { | |
updater.enable(); | |
e.target.id = 'de-btn-audio-on'; | |
} else { | |
e.target.id = 'de-btn-audio-off'; | |
} | |
$del($c('de-menu', doc)); | |
break; | |
case 'de-btn-savethr': break; | |
case 'de-btn-enable': | |
toggleCfg('disabled'); | |
window.location.reload(); | |
break; | |
default: return; | |
} | |
$pd(e); | |
return; | |
case 'mouseover': | |
if (!Cfg.expandPanel) { | |
clearTimeout(this.odelay); | |
this.panel.lastChild.style.display = ''; | |
} | |
switch (e.target.id) { | |
case 'de-btn-settings': KeyEditListener.setTitle(e.target, 10); break; | |
case 'de-btn-hidden': KeyEditListener.setTitle(e.target, 7); break; | |
case 'de-btn-favor': KeyEditListener.setTitle(e.target, 6); break; | |
case 'de-btn-goback': KeyEditListener.setTitle(e.target, 4); break; | |
case 'de-btn-gonext': KeyEditListener.setTitle(e.target, 17); break; | |
case 'de-btn-maskimg': KeyEditListener.setTitle(e.target, 9); break; | |
case 'de-btn-refresh': | |
if (TNum) { | |
return; | |
} | |
case 'de-btn-savethr': | |
case 'de-btn-audio-off': addMenu(e); | |
} | |
return; | |
default: // mouseout | |
if (!Cfg.expandPanel && !this.attach) { | |
this.odelay = setTimeout(function (obj) { | |
obj.panel.lastChild.style.display = 'none'; | |
obj.attach = false; | |
}, 500, this); | |
} | |
switch (e.target.id) { | |
case 'de-btn-refresh': | |
case 'de-btn-savethr': | |
case 'de-btn-audio-off': removeMenu(e); break; | |
} | |
} | |
} | |
}; | |
panel.addEventListener('click', evtObject, true); | |
panel.addEventListener('mouseover', evtObject, false); | |
panel.addEventListener('mouseout', evtObject, false); | |
} | |
function toggleContent(name, isUpd, data) { | |
if (liteMode) { | |
return false; | |
} | |
var remove, el = $c('de-content', doc), | |
id = 'de-content-' + name; | |
if (!el) { | |
return false; | |
} | |
if (isUpd && el.id !== id) { | |
return true; | |
} | |
remove = !isUpd && el.id === id; | |
if (el.hasChildNodes() && Cfg.animation) { | |
nav.animEvent(el, function (node) { | |
showContent(node, id, name, remove, data); | |
id = name = remove = data = null; | |
}); | |
el.className = 'de-content de-cfg-close'; | |
return !remove; | |
} else { | |
showContent(el, id, name, remove, data); | |
return !remove; | |
} | |
} | |
function addContentBlock(parent, title) { | |
return parent.appendChild($New('div', {'class': 'de-content-block'}, [ | |
$new('input', {'type': 'checkbox'}, {'click': function () { | |
var el, res = this.checked, i = 0, els = $Q('.de-entry > input', this.parentNode); | |
for (; el = els[i++];) { | |
el.checked = res; | |
} | |
}}), | |
title | |
])); | |
} | |
function showContent(cont, id, name, remove, data) { | |
var tNum, i, b, els, el, post, cln, block, temp, cfgTabId; | |
if (name === 'cfg' && !remove && (temp = $q('.de-cfg-tab-back[selected="true"] > .de-cfg-tab', cont))) { | |
cfgTabId = temp.getAttribute('info'); | |
} | |
cont.innerHTML = cont.style.backgroundColor = ''; | |
if (remove) { | |
cont.removeAttribute('id'); | |
return; | |
} | |
cont.id = id; | |
if (name === 'cfg') { | |
addSettings(cont, cfgTabId); | |
} else if (Cfg.attachPanel) { | |
cont.style.backgroundColor = getComputedStyle(doc.body).getPropertyValue('background-color'); | |
} | |
if (name === 'fav') { | |
if (data) { | |
showFavoriteTable(cont, data); | |
} else { | |
// TODO: show load message | |
getStoredObj('DESU_Favorites', function (fav) { | |
showFavoriteTable(this, fav); | |
}.bind(cont)); | |
} | |
return; | |
} | |
if (name === 'hid') { | |
for (i = 0, els = $C('de-post-hide', dForm); post = els[i++];) { | |
if (post.isOp) { | |
continue; | |
} | |
(cln = post.cloneNode(true)).removeAttribute('id'); | |
cln.style.display = ''; | |
if (cln.classList.contains(aib.cRPost)) { | |
cln.classList.add('de-cloned-post'); | |
} else { | |
cln.className = aib.cReply + ' de-cloned-post'; | |
} | |
cln.post = Object.create(cln.clone = post.post); | |
cln.post.el = cln; | |
cln.btn = $q('.de-btn-hide, .de-btn-hide-user', cln); | |
cln.btn.parentNode.className = 'de-post-btns'; | |
cln.btn.onclick = function () { // doesn't work properly. TODO: Fix | |
this.hideContent(this.hidden = !this.hidden); | |
}.bind(cln); | |
(block || (block = cont.appendChild( | |
$add('<div class="de-content-block"><b>' + Lng.hiddenPosts[lang] + ':</b></div>') | |
))).appendChild($New('div', {'class': 'de-entry'}, [cln])); | |
} | |
if (block) { | |
cont.appendChild($btn(Lng.expandAll[lang], '', function () { | |
$each($Q('.de-cloned-post', this.parentNode), function (el) { | |
var post = el.post; | |
post.hideContent(post.hidden = !post.hidden); | |
}); | |
this.value = this.value === Lng.undo[lang] ? Lng.expandAll[lang] : Lng.undo[lang]; | |
})); | |
cont.appendChild($btn(Lng.save[lang], '', function () { | |
$each($Q('.de-cloned-post', this.parentNode), function (date, el) { | |
if (!el.post.hidden) { | |
el.clone.setUserVisib(false, date, true); | |
} | |
}.bind(null, Date.now())); | |
saveUserPosts(true); | |
})); | |
} else { | |
cont.insertAdjacentHTML('beforeend', '<b>' + Lng.noHidPosts[lang] + '</b>'); | |
} | |
cont.insertAdjacentHTML('beforeend', '<hr><b>' + | |
($isEmpty(hThr) ? Lng.noHidThrds[lang] : Lng.hiddenThrds[lang] + ':') + '</b>'); | |
for (b in hThr) { | |
if (!$isEmpty(hThr[b])) { | |
block = addContentBlock(cont, $new('b', {'text': '/' + b}, null)); | |
for (tNum in hThr[b]) { | |
block.insertAdjacentHTML('beforeend', '<div class="de-entry ' + aib.cReply + | |
'" info="' + b + ';' + tNum + '"><input type="checkbox"><a href="' + | |
aib.getThrdUrl(b, tNum) + '" target="_blank">№' + tNum + '</a> - ' + | |
hThr[b][tNum] + '</div>'); | |
} | |
} | |
} | |
cont.insertAdjacentHTML('beforeend', '<hr>'); | |
cont.appendChild(addEditButton('hidden', function (Fn) { | |
Fn(hThr, true, function (data) { | |
hThr = data; | |
if (!(brd in hThr)) { | |
hThr[brd] = {}; | |
} | |
firstThr.updateHidden(hThr[brd]); | |
saveHiddenThreads(true); | |
locStorage['__de-threads'] = JSON.stringify(hThr); | |
locStorage.removeItem('__de-threads'); | |
}); | |
})); | |
cont.appendChild($btn(Lng.clear[lang], Lng.clrDeleted[lang], function () { | |
$each($Q('.de-entry[info]', this.parentNode), function (el) { | |
var arr = el.getAttribute('info').split(';'); | |
ajaxLoad(aib.getThrdUrl(arr[0], arr[1]), false, null, function (eCode, eMsg, xhr) { | |
if (eCode === 404) { | |
delete hThr[this[0]][this[1]]; | |
saveHiddenThreads(true); | |
} | |
}.bind(arr)); | |
}); | |
})); | |
cont.appendChild($btn(Lng.remove[lang], Lng.clrSelected[lang], function () { | |
$each($Q('.de-entry[info]', this.parentNode), function (date, el) { | |
var post, arr = el.getAttribute('info').split(';'); | |
if ($t('input', el).checked) { | |
if (arr[1] in pByNum) { | |
pByNum[arr[1]].setUserVisib(false, date, true); | |
} else { | |
locStorage['__de-post'] = JSON.stringify({ | |
'brd': arr[0], | |
'date': date, | |
'isOp': true, | |
'num': arr[1], | |
'hide': false | |
}); | |
locStorage.removeItem('__de-post'); | |
} | |
delete hThr[arr[0]][arr[1]]; | |
} | |
}.bind(null, Date.now())); | |
saveHiddenThreads(true); | |
})); | |
} | |
if (name === 'vid') { | |
els = $C('de-video-link', dForm); | |
if (els.length) { | |
!$id('de-ytube-api') && doc.head.appendChild( | |
$new('script', {'id': 'de-ytube-api', 'src': aib.prot + '//www.youtube.com/player_api'}, null)); | |
cont.insertAdjacentHTML('beforeend', '<div class="de-video-obj"></div><center>' + | |
'<a class="de-abtn" id="de-video-btn-prev" href="#" title="' + Lng.prevVideo[lang] + | |
'">◀</a> <a class="de-abtn" id="de-video-btn-hide" href="#" title="' + Lng.hideLnkList[lang] + | |
'">▲</a> <a class="de-abtn" id="de-video-btn-next" href="#" title="' + Lng.nextVideo[lang] + | |
'">▶</a></center><div id="de-video-list"></div>'); | |
post = {}; | |
post.ytInfo = null; | |
post.ytObj = cont.firstChild; | |
post.msg = cont.lastChild; | |
post.el = cont; | |
post.ytObj.nextSibling.onclick = function (e) { | |
$pd(e); | |
var node; | |
switch (e.target.id) { | |
case 'de-video-btn-hide': | |
node = this.el.lastChild; | |
if (node.style.display === 'none') { | |
node.style.display = ''; | |
e.target.textContent = '\u25B2'; | |
} else { | |
node.style.display = 'none'; | |
e.target.textContent = '\u25BC'; | |
} | |
return; | |
case 'de-video-btn-prev': | |
node = this.ytLink.parentNode, | |
(node.previousSibling || node.parentNode.lastChild).firstChild.click(); | |
break; | |
case 'de-video-btn-next': | |
node = this.ytLink.parentNode, | |
(node.nextSibling || node.parentNode.firstChild).firstChild.click(); | |
} | |
}.bind(post); | |
post.msg.onclick = function (e) { | |
$pd(e); | |
var c = e.target.classList; | |
if (!c.contains('de-video-link')) { | |
return; | |
} | |
if (c.contains('de-current')) { | |
post.ytInfo = null; | |
} | |
new YouTube().clickLink(this, e.target, 2); | |
if (!c.contains('de-ytube')) { | |
return; | |
} | |
this.ytObj.firstChild.id = 'de-ytplayer'; | |
$script( | |
'if ("YT" in window && "Player" in window.YT) {\ | |
initPlayer();\ | |
}\ | |
function onYouTubePlayerAPIReady() {\ | |
initPlayer();\ | |
}\ | |
function initPlayer() {\ | |
var ytplayer = new YT.Player("de-ytplayer", { events: {\ | |
"onError": gotoNextVideo,\ | |
"onReady": function (e) {\ | |
' + (post.firstCall ? '' : 'e.target.playVideo();') + '\ | |
},\ | |
"onStateChange": function (e) {\ | |
if (e.data === 0) {\ | |
gotoNextVideo();\ | |
}\ | |
}\ | |
}});\ | |
}\ | |
function gotoNextVideo() {\ | |
document.getElementById("de-video-btn-next").click();\ | |
}' | |
); | |
post.firstCall = false; | |
}.bind(post); | |
temp = new YouTube(); | |
for (i = 0; el = els[i++];) { | |
el = el.cloneNode(true); | |
post.msg.insertAdjacentHTML('beforeend', '<div class="de-entry ' + aib.cReply + '"></div>'); | |
post.msg.lastChild.appendChild(el); | |
b = el.classList.contains('de-ytube'); | |
el.ytInfo = el.href.match(b ? temp.ytReg : temp.vimReg); | |
if (i === 1) { | |
post.ytLink = el; | |
post.firstCall = true; | |
el.click(); | |
} else { | |
el.classList.remove('de-current'); | |
} | |
} | |
} else { | |
cont.insertAdjacentHTML('beforeend', '<b>' + Lng.noVideoLinks[lang] + '</b>'); | |
} | |
} | |
if (Cfg.animation) { | |
cont.className = 'de-content de-cfg-open'; | |
} | |
} | |
function clearFavoriteTable() { | |
var els = $Q('.de-entry[de-removed]', doc), | |
len = els.length; | |
if (len > 0) { | |
getStoredObj('DESU_Favorites', function (fav) { | |
for (var el, i = 0; i < len; ++i) { | |
el = els[i]; | |
removeFavoriteEntry(fav, el.getAttribute('de-host'), el.getAttribute('de-board'), | |
el.getAttribute('de-num'), true); | |
} | |
saveFavorites(fav); | |
}); | |
} | |
} | |
function showFavoriteTable(cont, data) { | |
var h, b, i, block, tNum; | |
for (h in data) { | |
for (b in data[h]) { | |
i = data[h][b]; | |
block = addContentBlock(cont, i.url ? | |
$new('a', {'href': i.url, 'text': h + '/' + b}, null) : | |
$new('b', {'text': h + '/' + b}, null)); | |
if (h === aib.host && b === brd) { | |
block.classList.add('de-fav-current'); | |
} | |
for (tNum in data[h][b]) { | |
if (tNum === 'url') { | |
continue; | |
} | |
i = data[h][b][tNum]; | |
if (!i.url.startsWith('http')) { | |
i.url = (h === aib.host ? aib.prot + '//' : 'http://') + h + i.url; | |
} | |
block.insertAdjacentHTML('beforeend', '<div class="de-entry ' + aib.cReply + | |
'" de-host="' + h + '" de-board="' + b + '" de-num="' + tNum + '" de-url="' + i.url + | |
'"><input type="checkbox"><span class="de-btn-expthr" title="' + Lng.findThrd[lang] + | |
'"></span><a href="' + i.url + '">№' + tNum + '</a><span class="de-fav-title"> - ' + | |
i.txt + '</span><span class="de-fav-inf-posts">[<span class="de-fav-inf-old" title="' + | |
Lng.oldPosts[lang] + '">' + i.cnt + '</span>] <span class="de-fav-inf-new" title="' + | |
Lng.newPosts[lang] + '"' + (i['new'] ? '>' : ' style="display: none;">') + | |
(i['new'] || 0) + '</span> <span class="de-fav-inf-page" title="' + | |
Lng.thrPage[lang] + '"></span></span></div>'); | |
block.lastChild.firstChild.nextSibling.onclick = loadFavorThread; | |
} | |
} | |
} | |
cont.insertAdjacentHTML('afterbegin', '<b>' + (Lng[block ? 'favThrds' : 'noFavThrds'][lang]) + '</b>'); | |
cont.insertAdjacentHTML('beforeend', '<hr>'); | |
cont.appendChild(addEditButton('favor', function (Fn) { | |
getStoredObj('DESU_Favorites', function (Fn, val) { | |
Fn(val, true, saveFavorites); | |
}.bind(null, Fn)); | |
})); | |
cont.appendChild($btn(Lng.refresh[lang], Lng.infoCount[lang], function () { | |
getStoredObj('DESU_Favorites', function (fav) { | |
var i, els, len, update = false; | |
var queue = new $queue(4, function (qIdx, num, el) { | |
var c, host = el.getAttribute('de-host'), | |
b = el.getAttribute('de-board'), | |
num = el.getAttribute('de-num'), | |
f = fav[host][b][num]; | |
if (host !== aib.host) { | |
queue.end(qIdx); | |
return; | |
} | |
el = $c('de-fav-inf-new', el); | |
el.style.display = ''; | |
el.textContent = ''; | |
el.className = 'de-wait'; | |
ajaxLoad(aib.getThrdUrl(b, num), true, function (form, xhr) { | |
var cnt = aib.getPosts(form).length + 1 - this.previousElementSibling.textContent; | |
this.textContent = cnt; | |
this.className = 'de-fav-inf-new'; | |
if (cnt === 0) { | |
this.style.display = 'none'; | |
} else { | |
f['new'] = cnt; | |
update = true; | |
} | |
queue.end(qIdx); | |
f = qIdx = null; | |
}.bind(el), function (eCode, eMsg, xhr) { | |
this.textContent = getErrorMessage(eCode, eMsg); | |
this.classList.remove('de-wait'); | |
queue.end(qIdx); | |
qIdx = null; | |
}.bind(el)); | |
}, function () { | |
if (update) { | |
setStored('DESU_Favorites', JSON.stringify(fav)); | |
} | |
fav = queue = update = null; | |
}); | |
for (i = 0, els = $C('de-entry', doc), len = els.length; i < len; ++i) { | |
queue.run(els[i]); | |
} | |
queue.complete(); | |
}); | |
})); | |
cont.appendChild($btn(Lng.page[lang], Lng.infoPage[lang], function () { | |
var els = $C('de-entry', doc), | |
i = 6, | |
loaded = 0; | |
$alert(Lng.loading[lang], 'load-pages', true); | |
while (i--) { | |
ajaxLoad(aib.getPageUrl(brd, i), true, function (idx, form, xhr) { | |
for (var inf, el, len = this.length, i = 0; i < len; ++i) { | |
el = this[i]; | |
if (el.getAttribute('de-host') === aib.host && el.getAttribute('de-board') === brd) { | |
inf = $c('de-fav-inf-page', el); | |
if ((new RegExp('(?:№|No.|>)\\s*' + el.getAttribute('de-num') + '\\s*<')) | |
.test(form.innerHTML)) | |
{ | |
inf.innerHTML = '@' + idx; | |
} else if (loaded === 5 && !inf.textContent.contains('@')) { | |
inf.innerHTML = '@?'; | |
} | |
} | |
} | |
if (loaded === 5) { | |
closeAlert($id('de-alert-load-pages')); | |
} | |
loaded++; | |
}.bind(els, i), function (eCode, eMsg, xhr) { | |
if (loaded === 5) { | |
closeAlert($id('de-alert-load-pages')); | |
} | |
loaded++; | |
}); | |
} | |
})); | |
cont.appendChild($btn(Lng.clear[lang], Lng.clrDeleted[lang], function () { | |
var i, len, els, queue = new $queue(4, function (qIdx, num, el) { | |
var node = $c('de-fav-inf-page', el); | |
node.classList.add('de-wait'); | |
ajaxLoad(el.getAttribute('de-url'), false, function () { | |
this.classList.remove('de-wait'); | |
queue.end(qIdx); | |
qIdx = null; | |
}.bind(node), function (eCode, eMsg, xhr) { | |
if (eCode === 404) { | |
this.textContent = getErrorMessage(eCode, eMsg); | |
this.classList.remove('de-wait'); | |
el.setAttribute('de-removed', ''); | |
} | |
queue.end(qIdx); | |
qIdx = el = null; | |
}.bind(node)); | |
}, function () { | |
queue = null; | |
clearFavoriteTable(); | |
}); | |
for (i = 0, els = $C('de-entry', doc), len = els.length; i < len; ++i) { | |
queue.run(els[i]); | |
} | |
queue.complete(); | |
})); | |
cont.appendChild($btn(Lng.remove[lang], Lng.clrSelected[lang], function () { | |
$each($C('de-entry', doc), function (el) { | |
if ($t('input', el).checked) { | |
el.setAttribute('de-removed', ''); | |
} | |
}); | |
clearFavoriteTable(); | |
})); | |
if (Cfg.animation) { | |
cont.className = 'de-content de-cfg-open'; | |
} | |
} | |
// SETTINGS | |
// =========================================================================================================== | |
function fixSettings() { | |
function toggleBox(state, arr) { | |
var i = arr.length, | |
nState = !state; | |
while (i--) { | |
($q(arr[i], doc) || {}).disabled = nState; | |
} | |
} | |
toggleBox(Cfg.ajaxUpdThr, [ | |
'input[info="noErrInTitle"]', 'input[info="favIcoBlink"]', | |
'input[info="markNewPosts"]', 'input[info="desktNotif"]' | |
]); | |
toggleBox(Cfg.expandImgs, [ | |
'input[info="imgNavBtns"]', 'input[info="resizeDPI"]', 'input[info="resizeImgs"]', | |
'input[info="minImgSize"]', 'input[info="zoomFactor"]', | |
'input[info="webmControl"]', 'input[info="webmVolume"]' | |
]); | |
toggleBox(Cfg.preLoadImgs, ['input[info="findImgFile"]']); | |
toggleBox(Cfg.openImgs, ['input[info="openGIFs"]']); | |
toggleBox(Cfg.linksNavig, [ | |
'input[info="linksOver"]', 'input[info="linksOut"]', 'input[info="markViewed"]', | |
'input[info="strikeHidd"]', 'input[info="noNavigHidd"]' | |
]); | |
toggleBox(Cfg.addYouTube && Cfg.addYouTube !== 4, [ | |
'select[info="YTubeType"]', 'input[info="YTubeHD"]', 'input[info="addVimeo"]' | |
]); | |
toggleBox(Cfg.addYouTube, [ | |
'input[info="YTubeWidth"]', 'input[info="YTubeHeigh"]', 'input[info="YTubeTitles"]' | |
]); | |
toggleBox(Cfg.ajaxReply, ['input[info="sendErrNotif"]', 'input[info="scrAfterRep"]']); | |
toggleBox(Cfg.ajaxReply === 2, [ | |
'input[info="postSameImg"]', 'input[info="removeEXIF"]', 'input[info="removeFName"]' | |
]); | |
toggleBox(Cfg.addTextBtns, ['input[info="txtBtnsLoc"]']); | |
toggleBox(Cfg.updScript, ['select[info="scrUpdIntrv"]']); | |
toggleBox(Cfg.hotKeys, ['input[info="loadPages"]']); | |
} | |
function lBox(id, isBlock, Fn) { | |
var el = $new('input', {'info': id, 'type': 'checkbox'}, {'click': function () { | |
toggleCfg(this.getAttribute('info')); | |
fixSettings(); | |
if (Fn) { | |
Fn(this); | |
} | |
}}); | |
el.checked = Cfg[id]; | |
return $New('label', isBlock ? {'class': 'de-block'} : null, [el, $txt(' ' + Lng.cfg[id][lang])]); | |
} | |
function inpTxt(id, size, Fn) { | |
return $new('input', {'info': id, 'type': 'text', 'size': size, 'value': Cfg[id]}, { | |
'keyup': Fn ? Fn : function () { | |
saveCfg(this.getAttribute('info'), this.value); | |
} | |
}); | |
} | |
function optSel(id, isBlock, Fn) { | |
for (var i = 0, x = Lng.cfg[id], len = x.sel[lang].length, el, opt = ''; i < len; i++) { | |
opt += '<option value="' + i + '">' + x.sel[lang][i] + '</option>'; | |
} | |
el = $add('<select info="' + id + '">' + opt + '</select>'); | |
el.addEventListener('change', Fn || function () { | |
saveCfg(this.getAttribute('info'), this.selectedIndex); | |
fixSettings(); | |
}, false); | |
el.selectedIndex = Cfg[id]; | |
return $New('label', isBlock ? {'class': 'de-block'} : null, [el, $txt(' ' + x.txt[lang])]); | |
} | |
function cfgTab(name) { | |
return $New('div', {'class': aib.cReply + ' de-cfg-tab-back', 'selected': false}, [$new('div', { | |
'class': 'de-cfg-tab', | |
'text': Lng.cfgTab[name][lang], | |
'info': name}, { | |
'click': function () { | |
var el, id, pN = this.parentNode; | |
if (pN.getAttribute('selected') === 'true') { | |
return; | |
} | |
if (el = $c('de-cfg-body', doc)) { | |
el.className = 'de-cfg-unvis'; | |
$q('.de-cfg-tab-back[selected="true"]', doc).setAttribute('selected', false); | |
} | |
pN.setAttribute('selected', true); | |
if (!(el = $id('de-cfg-' + (id = this.getAttribute('info'))))) { | |
$after($id('de-cfg-bar'), el = | |
id === 'filters' ? getCfgFilters() : | |
id === 'posts' ? getCfgPosts() : | |
id === 'images' ? getCfgImages() : | |
id === 'links' ? getCfgLinks() : | |
id === 'form' ? getCfgForm() : | |
id === 'common' ? getCfgCommon() : | |
getCfgInfo() | |
); | |
if (id === 'filters') { | |
updRowMeter.call($id('de-spell-edit')); | |
} | |
} | |
el.className = 'de-cfg-body'; | |
if (id === 'filters') { | |
$id('de-spell-edit').value = spells.list; | |
} | |
fixSettings(); | |
} | |
})]); | |
} | |
function updRowMeter() { | |
var str, top = this.scrollTop, | |
el = this.parentNode.previousSibling.firstChild, | |
num = el.numLines || 1, | |
i = 15; | |
if (num - i < ((top / 12) | 0 + 1)) { | |
str = ''; | |
while (i--) { | |
str += num++ + '<br>'; | |
} | |
el.insertAdjacentHTML('beforeend', str); | |
el.numLines = num; | |
} | |
el.scrollTop = top; | |
} | |
function getCfgFilters() { | |
return $New('div', {'class': 'de-cfg-unvis', 'id': 'de-cfg-filters'}, [ | |
lBox('hideBySpell', false, toggleSpells), | |
$New('div', {'id': 'de-spell-panel'}, [ | |
$new('a', { | |
'id': 'de-btn-addspell', | |
'text': Lng.add[lang], | |
'href': '#', | |
'class': 'de-abtn'}, { | |
'click': $pd, | |
'mouseover': addMenu, | |
'mouseout': removeMenu | |
}), | |
$new('a', {'text': Lng.apply[lang], 'href': '#', 'class': 'de-abtn'}, {'click': function (e) { | |
$pd(e); | |
saveCfg('hideBySpell', 1); | |
$q('input[info="hideBySpell"]', doc).checked = true; | |
toggleSpells(); | |
}}), | |
$new('a', {'text': Lng.clear[lang], 'href': '#', 'class': 'de-abtn'}, {'click': function (e) { | |
$pd(e); | |
$id('de-spell-edit').value = ''; | |
toggleSpells(); | |
}}), | |
$add('<a href="https://github.com/SthephanShinkufag/Dollchan-Extension-Tools/wiki/Spells-' + | |
(lang ? 'en' : 'ru') + '" class="de-abtn" target="_blank">[?]</a>') | |
]), | |
$New('div', {'id': 'de-spell-div'}, [ | |
$add('<div><div id="de-spell-rowmeter"></div></div>'), | |
$New('div', null, [$new('textarea', {'id': 'de-spell-edit', 'wrap': 'off'}, { | |
'keydown': updRowMeter, | |
'scroll': updRowMeter | |
})]) | |
]), | |
lBox('sortSpells', true, function () { | |
if (Cfg.sortSpells) { | |
toggleSpells(); | |
} | |
}), | |
lBox('menuHiddBtn', true, null), | |
lBox('hideRefPsts', true, null), | |
lBox('delHiddPost', true, function () { | |
$each($C('de-post-hide', dForm), function (el) { | |
var wrap = el.post.wrap, | |
hide = !wrap.classList.contains('de-hidden'); | |
if (hide) { | |
wrap.insertAdjacentHTML('beforebegin', | |
'<span style="counter-increment: de-cnt 1;"></span>'); | |
} else { | |
$del(wrap.previousSibling); | |
} | |
wrap.classList.toggle('de-hidden'); | |
}); | |
updateCSS(); | |
}) | |
]); | |
} | |
function getCfgPosts() { | |
return $New('div', {'class': 'de-cfg-unvis', 'id': 'de-cfg-posts'}, [ | |
lBox('ajaxUpdThr', false, TNum ? function () { | |
if (Cfg.ajaxUpdThr) { | |
updater.enable(); | |
} else { | |
updater.disable(); | |
} | |
} : null), | |
$New('label', null, [ | |
inpTxt('updThrDelay', 2, null), | |
$txt(Lng.cfg.updThrDelay[lang]) | |
]), | |
$New('div', {'class': 'de-cfg-depend'}, [ | |
lBox('noErrInTitle', true, null), | |
lBox('favIcoBlink', true, null), | |
lBox('markNewPosts', true, function () { | |
firstThr.clearPostsMarks(); | |
}), | |
$if('Notification' in window, lBox('desktNotif', true, function () { | |
if (Cfg.desktNotif) { | |
Notification.requestPermission(); | |
} | |
})) | |
]), | |
optSel('expandPosts', true, null), | |
optSel('postBtnsCSS', true, null), | |
lBox('noSpoilers', true, updateCSS), | |
lBox('noPostNames', true, updateCSS), | |
lBox('noPostScrl', true, updateCSS), | |
$New('div', null, [ | |
lBox('correctTime', false, dateTime.toggleSettings), | |
$add('<a href="https://github.com/SthephanShinkufag/Dollchan-Extension-Tools/wiki/Settings-time-' + | |
(lang ? 'en' : 'ru') + '" class="de-abtn" target="_blank">[?]</a>') | |
]), | |
$New('div', {'class': 'de-cfg-depend'}, [ | |
$New('div', null, [ | |
inpTxt('timeOffset', 2, null), | |
$txt(Lng.cfg.timeOffset[lang]) | |
]), | |
$New('div', null, [ | |
inpTxt('timePattern', 25, null), | |
$txt(Lng.cfg.timePattern[lang]) | |
]), | |
$New('div', null, [ | |
inpTxt('timeRPattern', 25, null), | |
$txt(Lng.cfg.timeRPattern[lang]) | |
]) | |
]) | |
]); | |
} | |
function getCfgImages() { | |
return $New('div', {'class': 'de-cfg-unvis', 'id': 'de-cfg-images'}, [ | |
optSel('expandImgs', true, null), | |
$New('div', {'style': 'padding-left: 25px;'}, [ | |
lBox('imgNavBtns', true, updateCSS), | |
lBox('resizeImgs', true, null), | |
$if(Post.sizing.dPxRatio > 1, lBox('resizeDPI', true, null)), | |
$New('div', null, [ | |
inpTxt('minImgSize', 4, function () { | |
saveCfg('minImgSize', Math.max(+this.value, 1)); | |
}), | |
$txt(Lng.cfg.minImgSize[lang]) | |
]), | |
inpTxt('zoomFactor', 4, function () { | |
saveCfg('zoomFactor', Math.min(Math.max(+this.value, 1), 100)); | |
}), | |
$txt(Lng.cfg.zoomFactor[lang]), | |
lBox('webmControl', true, null), | |
$New('div', null, [ | |
inpTxt('webmVolume', 4, function () { | |
saveCfg('webmVolume', Math.min(+this.value, 100)); | |
}), | |
$txt(Lng.cfg.webmVolume[lang]) | |
]) | |
]), | |
$if(!nav.Presto, lBox('preLoadImgs', true, null)), | |
$if(!nav.Presto, $New('div', {'class': 'de-cfg-depend'}, [ | |
lBox('findImgFile', true, null) | |
])), | |
lBox('openImgs', true, null), | |
$New('div', {'class': 'de-cfg-depend'}, [ lBox('openGIFs', false, null)]), | |
lBox('imgSrcBtns', true, null) | |
]); | |
} | |
function getCfgLinks() { | |
return $New('div', {'class': 'de-cfg-unvis', 'id': 'de-cfg-links'}, [ | |
optSel('linksNavig', true, null), | |
$New('div', {'class': 'de-cfg-depend'}, [ | |
$New('div', null, [ | |
inpTxt('linksOver', 4, function () { | |
saveCfg('linksOver', +this.value | 0); | |
}), | |
$txt(Lng.cfg.linksOver[lang]) | |
]), | |
$New('div', null, [ | |
inpTxt('linksOut', 4, function () { | |
saveCfg('linksOut', +this.value | 0); | |
}), | |
$txt(Lng.cfg.linksOut[lang]) | |
]), | |
lBox('markViewed', true, null), | |
lBox('strikeHidd', true, null), | |
lBox('noNavigHidd', true, null) | |
]), | |
lBox('crossLinks', true, null), | |
lBox('insertNum', true, null), | |
lBox('addMP3', true, null), | |
lBox('addImgs', true, null), | |
optSel('addYouTube', true, null), | |
$New('div', {'class': 'de-cfg-depend'}, [ | |
$New('div', null, [ | |
optSel('YTubeType', false, null), | |
inpTxt('YTubeWidth', 4, null), | |
$txt('×'), | |
inpTxt('YTubeHeigh', 4, null), | |
$txt(' '), | |
lBox('YTubeHD', false, null) | |
]), | |
$if(!nav.Opera11 || nav.isGM, lBox('YTubeTitles', false, null)), | |
lBox('addVimeo', true, null) | |
]) | |
]); | |
} | |
function getCfgForm() { | |
return $New('div', {'class': 'de-cfg-unvis', 'id': 'de-cfg-form'}, [ | |
optSel('ajaxReply', true, null), | |
$if(pr.form, $New('div', {'class': 'de-cfg-depend'}, [ | |
$if(!nav.Opera11, $New('div', null, [ | |
lBox('postSameImg', true, null), | |
lBox('removeEXIF', false, null), | |
lBox('removeFName', false, null), | |
lBox('sendErrNotif', true, null) | |
])), | |
lBox('scrAfterRep', true, null) | |
])), | |
$if(pr.form, optSel('addPostForm', true, function() { | |
saveCfg('addPostForm', this.selectedIndex); | |
pr.isTopForm = Cfg.addPostForm !== 0; | |
pr.setReply(false, !TNum || Cfg.addPostForm > 1); | |
})), | |
lBox('favOnReply', true, null), | |
$if(pr.subj, lBox('warnSubjTrip', false, null)), | |
$if(pr.file && !nav.Presto, lBox('fileThumb', true, function () { | |
for (var inp = pr.fileObj; true; inp = inp.next) { | |
inp.updateUtils(); | |
if (!inp.next) { | |
break; | |
} | |
} | |
if (inp.empty) { | |
inp.hideInputs(); | |
} | |
})), | |
$if(!aib.mak && pr.mail, $New('div', null, [ | |
lBox('addSageBtn', false, null), | |
lBox('saveSage', false, null) | |
])), | |
$if(pr.capTr, optSel('captchaLang', true, null)), | |
$if(pr.txta, $New('div', null, [ | |
optSel('addTextBtns', false, function () { | |
saveCfg('addTextBtns', this.selectedIndex); | |
pr.addTextPanel(); | |
}), | |
lBox('txtBtnsLoc', false, pr.addTextPanel.bind(pr)) | |
])), | |
$if(pr.passw, $New('div', null, [ | |
inpTxt('passwValue', 15, PostForm.setUserPassw), | |
$txt(Lng.cfg.userPassw[lang]), | |
$btn(Lng.change[lang], '', function () { | |
$q('input[info="passwValue"]', doc).value = Math.round(Math.random() * 1e15).toString(32); | |
PostForm.setUserPassw(); | |
}) | |
])), | |
$if(pr.name, $New('div', null, [ | |
inpTxt('nameValue', 15, PostForm.setUserName), | |
lBox('userName', false, PostForm.setUserName) | |
])), | |
$New('div', null, [ | |
$txt(Lng.dontShow[lang]), | |
lBox('noBoardRule', false, updateCSS), | |
$if(pr.gothr, lBox('noGoto', false, function () { | |
$disp(pr.gothr); | |
})), | |
$if(pr.passw, lBox('noPassword', false, function () { | |
$disp(pr.passw.parentNode.parentNode); | |
})) | |
]) | |
]); | |
} | |
function getCfgCommon() { | |
return $New('div', {'class': 'de-cfg-unvis', 'id': 'de-cfg-common'}, [ | |
optSel('scriptStyle', true, function () { | |
saveCfg('scriptStyle', this.selectedIndex); | |
var lang = getThemeLang(); | |
$id('darude-sandstorm').lang = lang; | |
$id('de-qarea').lang = lang; | |
}), | |
$New('div', null, [ | |
lBox('userCSS', false, updateCSS), | |
addEditButton('css', function (Fn) { | |
Fn(Cfg.userCSSTxt, false, function () { | |
saveCfg('userCSSTxt', this.value); | |
updateCSS(); | |
toggleContent('cfg', true); | |
}); | |
}) | |
]), | |
lBox('attachPanel', true, function () { | |
toggleContent('cfg', false); | |
updateCSS(); | |
}), | |
lBox('panelCounter', true, updateCSS), | |
lBox('rePageTitle', true, null), | |
$if(nav.Anim, lBox('animation', true, null)), | |
lBox('closePopups', true, null), | |
$New('div', null, [ | |
lBox('hotKeys', false, function () { | |
if (Cfg.hotKeys) { | |
if (hKeys) { | |
hKeys.enable(); | |
} else { | |
hKeys = new HotKeys(); | |
} | |
} else if (hKeys) { | |
hKeys.disable(); | |
} | |
}), | |
$btn(Lng.edit[lang], '', function (e) { | |
$pd(e); | |
if ($id('de-alert-edit-hotkeys')) { | |
return; | |
} | |
HotKeys.readKeys(function (keys) { | |
var aEl, evtListener, temp = KeyEditListener.getEditMarkup(keys); | |
$alert(temp[1], 'edit-hotkeys', false); | |
aEl = $id('de-alert-edit-hotkeys'); | |
evtListener = new KeyEditListener(aEl, keys, temp[0]); | |
aEl.addEventListener('focus', evtListener, true); | |
aEl.addEventListener('blur', evtListener, true); | |
aEl.addEventListener('click', evtListener, true); | |
aEl.addEventListener('keydown', evtListener, true); | |
aEl.addEventListener('keyup', evtListener, true); | |
}); | |
}) | |
]), | |
$New('div', {'class': 'de-cfg-depend'}, [ | |
inpTxt('loadPages', 2, null), | |
$txt(Lng.cfg.loadPages[lang]) | |
]), | |
$if(!nav.isChromeStorage && !nav.Presto || nav.isGM, $New('div', null, [ | |
lBox('updScript', true, null), | |
$New('div', {'class': 'de-cfg-depend'}, [ | |
optSel('scrUpdIntrv', false, null), | |
$btn(Lng.checkNow[lang], '', function () { | |
$alert(Lng.loading[lang], 'updavail', true); | |
checkForUpdates(true, function (html) { | |
$alert(html, 'updavail', false); | |
}); | |
}) | |
]) | |
])), | |
lBox('turnOff', true, function () { | |
for (var dm in comCfg) { | |
if (dm !== aib.dm && dm !== 'global' && dm !== 'lastUpd') { | |
comCfg[dm].disabled = Cfg.turnOff; | |
} | |
} | |
setStored('DESU_Config', JSON.stringify(comCfg) || ''); | |
}) | |
]); | |
} | |
function getCfgInfo() { | |
function getHiddenThrCount() { | |
var b, tNum, count = 0; | |
for (b in hThr) { | |
for (tNum in hThr[b]) { | |
count++; | |
} | |
} | |
return count; | |
} | |
return $New('div', {'class': 'de-cfg-unvis', 'id': 'de-cfg-info'}, [ | |
$add('<div style="padding-bottom: 10px;">' + | |
'<a href="https://github.com/SthephanShinkufag/Dollchan-Extension-Tools/wiki/versions" ' + | |
'target="_blank">v' + version + '</a> | ' + | |
'<a href="http://www.freedollchan.org/scripts/" target="_blank">Freedollchan</a> | ' + | |
'<a href="https://github.com/SthephanShinkufag/Dollchan-Extension-Tools/wiki/' + | |
(lang ? 'home-en/' : '') + '" target="_blank">Github</a></div>'), | |
$add('<div><div style="display: inline-block; vertical-align: top; width: 186px; height: 230px;">' + | |
Lng.thrViewed[lang] + Cfg.stats.view + '<br>' + | |
Lng.thrCreated[lang] + Cfg.stats.op + '<br>' + | |
Lng.thrHidden[lang] + getHiddenThrCount() + '<br>' + | |
Lng.postsSent[lang] + Cfg.stats.reply + '</div>' + | |
'<div style="display: inline-block; padding-left: 7px; height: 230px; ' + | |
'border-left: 1px solid grey;">' + new Logger().get().join('<br>') + '</div></div>'), | |
$btn(Lng.debug[lang], Lng.infoDebug[lang], function () { | |
$alert(Lng.infoDebug[lang] + | |
':<textarea readonly id="de-debug-info" class="de-editor"></textarea>', 'help-debug', false); | |
$id('de-debug-info').value = JSON.stringify({ | |
'version': version, | |
'location': String(window.location), | |
'nav': nav, | |
'cfg': Cfg, | |
'sSpells': spells.list.split('\n'), | |
'oSpells': sesStorage['de-spells-' + brd + TNum], | |
'perf': new Logger().get() | |
}, function (key, value) { | |
if (key in defaultCfg) { | |
if (value === defaultCfg[key] || key === 'nameValue' || key === 'passwValue') { | |
return void 0; | |
} | |
} | |
return key === 'stats' ? void 0 : value; | |
}, '\t'); | |
}) | |
]); | |
} | |
function addEditButton(name, getDataFn) { | |
return $btn(Lng.edit[lang], Lng.editInTxt[lang], function (getData) { | |
getData(function (val, isJSON, saveFn) { | |
var el, ta = $new('textarea', { | |
'class': 'de-editor', | |
'value': isJSON ? JSON.stringify(val, null, '\t') : val | |
}, null); | |
$alert('', 'edit-' + name, false); | |
el = $c('de-alert-msg', $id('de-alert-edit-' + name)); | |
el.appendChild($txt(Lng.editor[name][lang])); | |
el.appendChild(ta); | |
el.appendChild($btn(Lng.save[lang], Lng.saveChanges[lang], isJSON ? function (fun) { | |
var data; | |
try { | |
data = JSON.parse(this.value.trim().replace(/[\n\r\t]/g, '') || '{}'); | |
} finally { | |
if (data) { | |
fun(data); | |
closeAlert($id('de-alert-edit-' + name)); | |
closeAlert($id('de-alert-err-invaliddata')); | |
} else { | |
$alert(Lng.invalidData[lang], 'err-invaliddata', false); | |
} | |
} | |
}.bind(ta, saveFn) : saveFn.bind(ta))); | |
}); | |
}.bind(null, getDataFn)); | |
} | |
function addSettings(Set, id) { | |
Set.appendChild($New('div', {'class': aib.cReply}, [ | |
$new('div', {'class': 'de-cfg-head', 'text': 'Dollchan Extension Tools'}, null), | |
$New('div', {'id': 'de-cfg-bar'}, [ | |
cfgTab('filters'), | |
cfgTab('posts'), | |
cfgTab('images'), | |
cfgTab('links'), | |
$if(pr.form || pr.oeForm, cfgTab('form')), | |
cfgTab('common'), | |
cfgTab('info') | |
]), | |
$New('div', {'id': 'de-cfg-btns'}, [ | |
optSel('language', false, function () { | |
saveCfg('language', lang = this.selectedIndex); | |
$del($id('darude-sandstorm')); | |
$del($id('de-css')); | |
$del($id('de-css-dynamic')); | |
scriptCSS(); | |
addPanel(); | |
toggleContent('cfg', false); | |
}), | |
$New('div', {'style': 'float: right;'}, [ | |
addEditButton('cfg', function (Fn) { | |
Fn(Cfg, true, function (data) { | |
saveComCfg(aib.dm, data); | |
window.location.reload(); | |
}); | |
}), | |
$if(nav.isGlobal, $btn(Lng.load[lang], Lng.loadGlobal[lang], function () { | |
if (('global' in comCfg) && !$isEmpty(comCfg.global)) { | |
saveComCfg(aib.dm, null); | |
window.location.reload(); | |
} else { | |
$alert(Lng.noGlobalCfg[lang], 'err-noglobalcfg', false); | |
} | |
})), | |
$if(nav.isGlobal, $btn(Lng.save[lang], Lng.saveGlobal[lang], function () { | |
var i, obj = {}, | |
com = comCfg[aib.dm]; | |
for (i in com) { | |
if (com[i] !== defaultCfg[i] && i !== 'stats') { | |
obj[i] = com[i]; | |
} | |
} | |
saveComCfg('global', obj); | |
toggleContent('cfg', true); | |
})), | |
$btn(Lng.reset[lang], Lng.resetCfg[lang], function () { | |
if (confirm(Lng.conReset[lang])) { | |
delStored('DESU_Config'); | |
delStored('DESU_Favorites'); | |
delStored('DESU_Posts_' + aib.dm); | |
delStored('DESU_Threads_' + aib.dm); | |
delStored('DESU_keys'); | |
window.location.reload(); | |
} | |
}) | |
]), | |
$new('div', {'style': 'clear: both;'}, null) | |
]) | |
])); | |
$q('.de-cfg-tab[info="' + (id || 'filters') + '"]', Set).click(); | |
} | |
// MENU & POPUP | |
// =========================================================================================================== | |
function closeAlert(el) { | |
if (el) { | |
el.closeTimeout = null; | |
if (Cfg.animation) { | |
nav.animEvent(el, function (node) { | |
var p = node && node.parentNode; | |
if (p) { | |
p.removeChild(node); | |
} | |
}); | |
el.classList.add('de-close'); | |
} else { | |
$del(el); | |
} | |
} | |
} | |
function $alert(txt, id, wait) { | |
var node, el = $id('de-alert-' + id), | |
cBtn = 'de-alert-btn' + (wait ? ' de-wait' : ''), | |
tBtn = wait ? '' : '\u2716 '; | |
if (el) { | |
$t('div', el).innerHTML = txt.trim(); | |
node = $t('span', el); | |
node.className = cBtn; | |
node.textContent = tBtn; | |
clearTimeout(el.closeTimeout); | |
if (!wait && Cfg.animation) { | |
nav.animEvent(el, function (node) { | |
node.classList.remove('de-blink'); | |
}); | |
el.classList.add('de-blink'); | |
} | |
} else { | |
el = $id('de-alert').appendChild($New('div', {'class': aib.cReply, 'id': 'de-alert-' + id}, [ | |
$new('span', {'class': cBtn, 'text': tBtn}, {'click': function () { | |
closeAlert(this.parentNode); | |
}}), | |
$add('<div class="de-alert-msg">' + txt.trim() + '</div>') | |
])); | |
if (Cfg.animation) { | |
nav.animEvent(el, function (node) { | |
node.classList.remove('de-open'); | |
}); | |
el.classList.add('de-open'); | |
} | |
} | |
if (Cfg.closePopups && !wait && !id.contains('help') && !id.contains('edit')) { | |
el.closeTimeout = setTimeout(closeAlert, 4e3, el); | |
} | |
} | |
function showMenu(el, html, inPanel, onclick) { | |
var y, pos, menu, cr = el.getBoundingClientRect(); | |
if (Cfg.attachPanel && inPanel) { | |
pos = 'fixed'; | |
y = 'bottom: 25'; | |
} else { | |
pos = 'absolute'; | |
y = 'top: ' + (window.pageYOffset + cr.bottom); | |
} | |
doc.body.insertAdjacentHTML('beforeend', '<div class="' + aib.cReply + ' de-menu" style="position: ' + | |
pos + '; right: ' + (doc.documentElement.clientWidth - cr.right - window.pageXOffset) + | |
'px; ' + y + 'px;">' + html + '</div>'); | |
menu = doc.body.lastChild; | |
menu.addEventListener('mouseover', function (e) { | |
clearTimeout(e.currentTarget.odelay); | |
}, true); | |
menu.addEventListener('mouseout', removeMenu, true); | |
menu.addEventListener('click', function (e) { | |
var el = e.target; | |
if (el.className === 'de-menu-item') { | |
setTimeout(this, 10, el); | |
do { | |
el = el.parentElement; | |
} while (!el.classList.contains('de-menu')); | |
$del(el); | |
} | |
}.bind(onclick), false); | |
} | |
function addMenu(e) { | |
e.target.odelay = setTimeout(function (el) { | |
switch (el.id) { | |
case 'de-btn-addspell': addSpellMenu(el); return; | |
case 'de-btn-refresh': addAjaxPagesMenu(el); return; | |
case 'de-btn-savethr': addSaveThreadMenu(el); return; | |
case 'de-btn-audio-off': addAudioNotifMenu(el); return; | |
} | |
}, Cfg.linksOver, e.target); | |
} | |
function removeMenu(e) { | |
var el = $c('de-menu', doc), | |
rt = e.relatedTarget; | |
clearTimeout(e.target.odelay); | |
if (el && (!rt || (rt !== el && !el.contains(rt)))) { | |
el.odelay = setTimeout($del, 75, el); | |
} | |
} | |
function addSpellMenu(el) { | |
showMenu(el, '<div style="display: inline-block; border-right: 1px solid grey;">' + | |
'<span class="de-menu-item">' + ('#words,#exp,#exph,#imgn,#ihash,#subj,#name,#trip,#img,<br>') | |
.split(',').join('</span><span class="de-menu-item">') + | |
'</span></div><div style="display: inline-block;"><span class="de-menu-item">' + | |
('#sage,#op,#tlen,#all,#video,#vauthor,#num,#wipe,#rep,#outrep') | |
.split(',').join('</span><span class="de-menu-item">') + '</span></div>', false, | |
function (el) { | |
var exp = el.textContent, | |
idx = Spells.names.indexOf(exp.substr(1)); | |
$txtInsert($id('de-spell-edit'), exp + ( | |
TNum && exp !== '#op' && exp !== '#rep' && exp !== '#outrep' ? '[' + brd + ',' + TNum + ']' : '' | |
) + (Spells.needArg[idx] ? '(' : '')); | |
}); | |
} | |
function addAjaxPagesMenu(el) { | |
showMenu(el, '<span class="de-menu-item">' + | |
Lng.selAjaxPages[lang].join('</span><span class="de-menu-item">') + '</span>', true, | |
function (el) { | |
loadPages(aProto.indexOf.call(el.parentNode.children, el) + 1); | |
}); | |
} | |
function addSaveThreadMenu(el) { | |
showMenu(el, '<span class="de-menu-item">' + | |
Lng.selSaveThr[lang].join('</span><span class="de-menu-item">') + '</span>', true, | |
function (el) { | |
if (!$id('de-alert-savethr')) { | |
var imgOnly = !!aProto.indexOf.call(el.parentNode.children, el); | |
if (Images_.preloading) { | |
$alert(Lng.loading[lang], 'savethr', true); | |
Images_.afterpreload = loadDocFiles.bind(null, imgOnly); | |
Images_.progressId = 'savethr'; | |
} else { | |
loadDocFiles(imgOnly); | |
} | |
} | |
}); | |
} | |
function addAudioNotifMenu(el) { | |
showMenu(el, '<span class="de-menu-item">' + | |
Lng.selAudioNotif[lang].join('</span><span class="de-menu-item">') + '</span>', true, | |
function (el) { | |
var i = aProto.indexOf.call(el.parentNode.children, el); | |
updater.enable(); | |
updater.toggleAudio(i === 0 ? 3e4 : i === 1 ? 6e4 : i === 2 ? 12e4 : 3e5); | |
$id('de-btn-audio-off').id = 'de-btn-audio-on'; | |
}); | |
} | |
// HOTKEYS | |
// =========================================================================================================== | |
function HotKeys() { | |
HotKeys.readKeys(this._init.bind(this)); | |
} | |
HotKeys.version = 6; | |
HotKeys.readKeys = function (Fn) { | |
getStored('DESU_keys', function (str) { | |
var tKeys, keys; | |
if (!str) { | |
this(HotKeys.getDefaultKeys()); | |
return; | |
} | |
try { | |
keys = JSON.parse(str); | |
} finally { | |
if (!keys) { | |
this(HotKeys.getDefaultKeys()); | |
return; | |
} | |
if (keys[0] !== HotKeys.version) { | |
tKeys = HotKeys.getDefaultKeys(); | |
switch (keys[0]) { | |
case 1: | |
keys[2][11] = tKeys[2][11]; | |
keys[4] = tKeys[4]; | |
case 2: | |
keys[2][12] = tKeys[2][12]; | |
keys[2][13] = tKeys[2][13]; | |
keys[2][14] = tKeys[2][14]; | |
keys[2][15] = tKeys[2][15]; | |
keys[2][16] = tKeys[2][16]; | |
case 3: | |
keys[2][17] = keys[3][3]; | |
keys[3][3] = keys[3].splice(4, 1)[0]; | |
case 4: | |
case 5: | |
if (keys[2][18]) { | |
delete keys[2][18]; | |
} | |
} | |
keys[0] = HotKeys.version; | |
setStored('DESU_keys', JSON.stringify(keys)); | |
} | |
if (keys[1] ^ !!nav.Firefox) { | |
var mapFunc = nav.Firefox ? function mapFuncFF(key) { | |
switch (key) { | |
case 189: return 173; | |
case 187: return 61; | |
case 186: return 59; | |
default: return key; | |
} | |
} : function mapFuncNonFF(key) { | |
switch (key) { | |
case 173: return 189; | |
case 61: return 187; | |
case 59: return 186; | |
default: return key; | |
} | |
}; | |
keys[1] = !!nav.Firefox; | |
keys[2] = keys[2].map(mapFunc); | |
keys[3] = keys[3].map(mapFunc); | |
setStored('DESU_keys', JSON.stringify(keys)); | |
} | |
this(keys); | |
} | |
}.bind(Fn)); | |
}; | |
HotKeys.getDefaultKeys = function () { | |
var isFirefox = !!nav.Firefox; | |
var globKeys = [ | |
/* One post/thread above */ 0x004B /* = K */, | |
/* One post/thread below */ 0x004A /* = J */, | |
/* Reply or create thread */ 0x0052 /* = R */, | |
/* Hide selected thread/post */ 0x0048 /* = H */, | |
/* Open previous page/picture */ 0x1025 /* = Ctrl+Left */, | |
/* Send post (txt) */ 0xC00D /* = Alt+Enter */, | |
/* Open/close favorites posts */ 0x4046 /* = Alt+F */, | |
/* Open/close hidden posts */ 0x4048 /* = Alt+H */, | |
/* Open/close panel */ 0x0050 /* = P */, | |
/* Mask/unmask images */ 0x0042 /* = B */, | |
/* Open/close settings */ 0x4053 /* = Alt+S */, | |
/* Expand current image */ 0x0049 /* = I */, | |
/* Bold text */ 0xC042 /* = Alt+B */, | |
/* Italic text */ 0xC049 /* = Alt+I */, | |
/* Strike text */ 0xC054 /* = Alt+T */, | |
/* Spoiler text */ 0xC050 /* = Alt+P */, | |
/* Code text */ 0xC043 /* = Alt+C */, | |
/* Open next page/picture */ 0x1027 /* = Ctrl+Right */ | |
]; | |
var nonThrKeys = [ | |
/* One post above */ 0x004D /* = M */, | |
/* One post below */ 0x004E /* = N */, | |
/* Open thread */ 0x0056 /* = V */, | |
/* Expand thread */ 0x0045 /* = E */ | |
]; | |
var thrKeys = [ | |
/* Update thread */ 0x0055 /* = U */ | |
]; | |
return [HotKeys.version, isFirefox, globKeys, nonThrKeys, thrKeys]; | |
}; | |
HotKeys.prototype = { | |
cPost: null, | |
enabled: false, | |
gKeys: null, | |
lastPage: 0, | |
lastPageOffset: 0, | |
ntKeys: null, | |
paused: false, | |
tKeys: null, | |
clear: function (lastPage) { | |
this.cPost = null; | |
this.lastPage = lastPage; | |
this.lastPageOffset = 0; | |
}, | |
disable: function () { | |
if (this.enabled) { | |
if (this.cPost) { | |
this.cPost.unselect(); | |
} | |
doc.removeEventListener('keydown', this, true); | |
this.enabled = false; | |
} | |
}, | |
enable: function () { | |
if (!this.enabled) { | |
this.clear(pageNum); | |
doc.addEventListener('keydown', this, true); | |
this.enabled = true; | |
} | |
}, | |
handleEvent: function (e) { | |
if (this.paused) { | |
return; | |
} | |
var temp, post, scrollToThread, globIdx, idx, curTh = e.target.tagName, | |
kc = e.keyCode | (e.ctrlKey ? 0x1000 : 0) | (e.shiftKey ? 0x2000 : 0) | | |
(e.altKey ? 0x4000 : 0) | (curTh === 'TEXTAREA' || | |
(curTh === 'INPUT' && e.target.type === 'text') ? 0x8000 : 0); | |
if (kc === 0x74 || kc === 0x8074) { // F5 | |
if (TNum || $id('de-alert-load-pages')) { | |
return; | |
} | |
if (Attachment.viewer) { | |
Attachment.viewer.close(null); | |
Attachment.viewer = null; | |
} | |
loadPages(+Cfg.loadPages); | |
} else if (kc === 0x1B) { // ESC | |
if (Attachment.viewer) { | |
Attachment.viewer.close(null); | |
Attachment.viewer = null; | |
return; | |
} | |
if (this.cPost) { | |
this.cPost.unselect(); | |
this.cPost = null; | |
} | |
if (TNum) { | |
firstThr.clearPostsMarks(); | |
} | |
this.lastPageOffset = 0; | |
} else if (kc === 0x801B) { // ESC (txt) | |
e.target.blur(); | |
} else { | |
globIdx = this.gKeys.indexOf(kc); | |
switch (globIdx) { | |
case 2: // Quick reply | |
if (pr.form) { | |
post = this.cPost || this._getFirstVisPost(false, true) || firstThr.op; | |
this.cPost = post; | |
pr.showQuickReply(post, post.num, true, false); | |
post.select(); | |
} | |
break; | |
case 3: // Hide selected thread/post | |
post = this._getFirstVisPost(false, true) || this._getNextVisPost(null, true, false); | |
if (post) { | |
post.toggleUserVisib(); | |
this._scroll(post, false, post.isOp); | |
} | |
break; | |
case 4: // Open previous page/picture | |
if (Attachment.viewer) { | |
Attachment.viewer.navigate(false); | |
} else if (TNum || pageNum !== aib.firstPage) { | |
window.location.pathname = aib.getPageUrl(brd, TNum ? 0 : pageNum - 1); | |
} | |
break; | |
case 5: // Send post (txt) | |
if (e.target !== pr.txta && e.target !== pr.cap) { | |
return; | |
} | |
pr.subm.click(); | |
break; | |
case 6: // Open/close favorites posts | |
toggleContent('fav', false); | |
break; | |
case 7: // Open/close hidden posts | |
toggleContent('hid', false); | |
break; | |
case 8: // Open/close panel | |
$disp($id('de-panel').lastChild); | |
break; | |
case 9: // Mask/unmask images | |
toggleCfg('maskImgs'); | |
updateCSS(); | |
break; | |
case 10: // Open/close settings | |
toggleContent('cfg', false); | |
break; | |
case 11: // Expand current image | |
post = this._getFirstVisPost(false, true) || this._getNextVisPost(null, true, false); | |
if (post) { | |
post.toggleImages(!post.imagesExpanded); | |
} | |
break; | |
case 12: // Bold text (txt) | |
if (e.target !== pr.txta) { | |
return; | |
} | |
$id('de-btn-bold').click(); | |
break; | |
case 13: // Italic text (txt) | |
if (e.target !== pr.txta) { | |
return; | |
} | |
$id('de-btn-italic').click(); | |
break; | |
case 14: // Strike text (txt) | |
if (e.target !== pr.txta) { | |
return; | |
} | |
$id('de-btn-strike').click(); | |
break; | |
case 15: // Spoiler text (txt) | |
if (e.target !== pr.txta) { | |
return; | |
} | |
$id('de-btn-spoil').click(); | |
break; | |
case 16: // Code text (txt) | |
if (e.target !== pr.txta) { | |
return; | |
} | |
$id('de-btn-code').click(); | |
break; | |
case 17: // Open next page/picture | |
if (Attachment.viewer) { | |
Attachment.viewer.navigate(true); | |
} else if (!TNum && this.lastPage !== aib.lastPage) { | |
window.location.pathname = aib.getPageUrl(brd, this.lastPage + 1); | |
} | |
break; | |
case -1: | |
if (TNum) { | |
idx = this.tKeys.indexOf(kc); | |
if (idx === 0) { // Update thread | |
Thread.loadNewPosts(null); | |
break; | |
} | |
return; | |
} | |
idx = this.ntKeys.indexOf(kc); | |
if (idx === -1) { | |
return; | |
} else if (idx === 2) { // Open thread | |
post = this._getFirstVisPost(false, true) || this._getNextVisPost(null, true, false); | |
if (post) { | |
if (nav.Firefox) { | |
GM_openInTab(aib.getThrdUrl(brd, post.tNum), false, true); | |
} else { | |
window.open(aib.getThrdUrl(brd, post.tNum), '_blank'); | |
} | |
} | |
break; | |
} else if (idx === 3) { // Expand/collapse thread | |
post = this._getFirstVisPost(false, true) || this._getNextVisPost(null, true, false); | |
if (post) { | |
if (post.thr.loadedOnce && post.thr.op.next.count === 1) { | |
temp = post.thr.nextNotHidden; | |
post.thr.load(visPosts, !!temp, null); | |
post = (temp || post.thr).op; | |
} else { | |
post.thr.load(1, false, null); | |
post = post.thr.op; | |
} | |
scrollTo(0, pageYOffset + post.topCoord); | |
if (this.cPost && this.cPost !== post) { | |
this.cPost.unselect(); | |
this.cPost = post; | |
} | |
} | |
break; | |
} | |
default: | |
scrollToThread = !TNum && (globIdx === 0 || globIdx === 1); | |
this._scroll(this._getFirstVisPost(scrollToThread, false), globIdx === 0 || idx === 0, | |
scrollToThread); | |
} | |
} | |
e.stopPropagation(); | |
$pd(e); | |
}, | |
pause: function () { | |
this.paused = true; | |
}, | |
resume: function (keys) { | |
this.gKeys = keys[2]; | |
this.ntKeys = keys[3]; | |
this.tKeys = keys[4]; | |
this.paused = false; | |
}, | |
_getFirstVisPost: function (getThread, getFull) { | |
var post, tPost; | |
if (this.lastPageOffset !== pageYOffset) { | |
post = getThread ? firstThr : firstThr.op; | |
while (post.topCoord < 1) { | |
tPost = post.next; | |
if (!tPost) { | |
break; | |
} | |
post = tPost; | |
} | |
if (this.cPost) { | |
this.cPost.unselect(); | |
} | |
this.cPost = getThread ? getFull ? post.op : post.op.prev : getFull ? post : post.prev; | |
this.lastPageOffset = pageYOffset; | |
} | |
return this.cPost; | |
}, | |
_getNextVisPost: function (cPost, isOp, toUp) { | |
var thr; | |
if (isOp) { | |
thr = cPost ? toUp ? cPost.thr.prevNotHidden : cPost.thr.nextNotHidden : | |
firstThr.hidden ? firstThr.nextNotHidden : firstThr; | |
return thr ? thr.op : null; | |
} | |
return cPost ? cPost.getAdjacentVisPost(toUp) : firstThr.hidden || | |
firstThr.op.hidden ? firstThr.op.getAdjacentVisPost(toUp) : firstThr.op; | |
}, | |
_init: function (keys) { | |
this.enabled = true; | |
this.lastPage = pageNum; | |
this.gKeys = keys[2]; | |
this.ntKeys = keys[3]; | |
this.tKeys = keys[4]; | |
doc.addEventListener('keydown', this, true); | |
}, | |
_scroll: function (post, toUp, toThread) { | |
var next = this._getNextVisPost(post, toThread, toUp); | |
if (!next) { | |
if (!TNum && (toUp ? pageNum > aib.firstPage : this.lastPage < aib.lastPage)) { | |
window.location.pathname = aib.getPageUrl(brd, toUp ? pageNum - 1 : this.lastPage + 1); | |
} | |
return; | |
} | |
if (post) { | |
post.unselect(); | |
} | |
if (toThread) { | |
next.el.scrollIntoView(); | |
} else { | |
scrollTo(0, pageYOffset + next.el.getBoundingClientRect().top - | |
Post.sizing.wHeight / 2 + next.el.clientHeight / 2); | |
} | |
this.lastPageOffset = pageYOffset; | |
next.select(); | |
this.cPost = next; | |
} | |
} | |
function KeyEditListener(alertEl, keys, allKeys) { | |
var j, k, i, len, aInputs = aProto.slice.call($C('de-input-key', alertEl)); | |
for (i = 0, len = allKeys.length; i < len; ++i) { | |
k = allKeys[i]; | |
if (k !== 0) { | |
for (j = i + 1; j < len; ++j) { | |
if (k === allKeys[j]) { | |
aInputs[i].classList.add('de-error-key'); | |
aInputs[j].classList.add('de-error-key'); | |
break; | |
} | |
} | |
} | |
} | |
this.aEl = alertEl; | |
this.keys = keys; | |
this.initKeys = JSON.parse(JSON.stringify(keys)); | |
this.allKeys = allKeys; | |
this.allInputs = aInputs; | |
this.errCount = $C('de-error-key', alertEl).length; | |
if (this.errCount !== 0) { | |
this.saveButton.disabled = true; | |
} | |
} | |
// Browsers have different codes for these keys (see HotKeys.readKeys): | |
// Firefox - '-' - 173, '=' - 61, ';' - 59 | |
// Chrome/Opera: '-' - 189, '=' - 187, ';' - 186 | |
KeyEditListener.keyCodes = ['',,,,,,,,'Backspace','Tab',,,,'Enter',,,'Shift','Ctrl','Alt', | |
/* Pause/Break */,/* Caps Lock */,,,,,,,/* Escape */,,,,,'Space',/* Page Up */, | |
/* Page Down */,/* End */,/* Home */,'←','↑','→','↓',,,,,/* Insert */,/* Delete */,,'0','1','2', | |
'3','4','5','6','7','8','9',,';',,'=',,,,'A','B','C','D','E','F','G','H','I','J','K','L','M', | |
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',/* Left WIN Key */,/* Right WIN Key */, | |
/* Select key */,,,'Numpad 0','Numpad 1','Numpad 2','Numpad 3','Numpad 4','Numpad 5','Numpad 6', | |
'Numpad 7','Numpad 8','Numpad 9','Numpad *','Numpad +',,'Numpad -','Numpad .','Numpad /', | |
/* F1 */,/* F2 */,/* F3 */,/* F4 */,/* F5 */,/* F6 */,/* F7 */,/* F8 */,/* F9 */,/* F10 */, | |
/* F11 */,/* F12 */,,,,,,,,,,,,,,,,,,,,,/* Num Lock */,/* Scroll Lock */,,,,,,,,,,,,,,,,,,,,,,,, | |
,,,,'-',,,,,,,,,,,,,';','=',',','-','.','/','`',,,,,,,,,,,,,,,,,,,,,,,,,,,'[','\\',']','\'' | |
]; | |
KeyEditListener.getStrKey = function (key) { | |
var str = ''; | |
if (key & 0x1000) { | |
str += 'Ctrl+'; | |
} | |
if (key & 0x2000) { | |
str += 'Shift+'; | |
} | |
if (key & 0x4000) { | |
str += 'Alt+'; | |
} | |
str += KeyEditListener.keyCodes[key & 0xFFF]; | |
return str; | |
}; | |
KeyEditListener.getEditMarkup = function (keys) { | |
var allKeys = []; | |
var html = Lng.hotKeyEdit[lang].join('') | |
.replace(/%l/g, '<label class="de-block">') | |
.replace(/%\/l/g, '</label>') | |
.replace(/%i([2-4])([0-9]+)(t)?/g, function (aKeys, all, id1, id2, isText) { | |
var key = this[+id1][+id2]; | |
aKeys.push(key); | |
return '<input class="de-input-key" type="text" de-id1="' + id1 + '" de-id2="' + id2 + | |
'" size="26" value="' + KeyEditListener.getStrKey(key) + | |
(isText ? '" de-text' : '"' ) + ' readonly></input>'; | |
}.bind(keys, allKeys)) + | |
'<input type="button" id="de-keys-save" value="' + Lng.save[lang] + '"></input>' + | |
'<input type="button" id="de-keys-reset" value="' + Lng.reset[lang] + '"></input>'; | |
return [allKeys, html]; | |
}; | |
KeyEditListener.setTitle = function (el, idx) { | |
var title = el.getAttribute('de-title'); | |
if (hKeys && idx !== -1) { | |
title += ' [' + KeyEditListener.getStrKey(hKeys.gKeys[idx]) + ']'; | |
} | |
el.title = title; | |
}; | |
KeyEditListener.prototype = { | |
cEl: null, | |
cKey: -1, | |
errorInput: false, | |
get saveButton() { | |
var val = $id('de-keys-save'); | |
Object.defineProperty(this, 'saveButton', { value: val, configurable: true }); | |
return val; | |
}, | |
handleEvent: function (e) { | |
var key, keyStr, keys, str, id, temp, el = e.target; | |
switch (e.type) { | |
case 'blur': | |
if (hKeys && this.errCount === 0) { | |
hKeys.resume(this.keys); | |
} | |
this.cEl = null; | |
return; | |
case 'focus': | |
if (hKeys) { | |
hKeys.pause(); | |
} | |
this.cEl = el; | |
return; | |
case 'click': | |
if (el.id === 'de-keys-reset') { | |
this.keys = HotKeys.getDefaultKeys(); | |
this.initKeys = HotKeys.getDefaultKeys(); | |
if (hKeys) { | |
hKeys.resume(this.keys); | |
} | |
temp = KeyEditListener.getEditMarkup(this.keys); | |
this.allKeys = temp[0]; | |
$c('de-alert-msg', this.aEl).innerHTML = temp[1]; | |
this.allInputs = aProto.slice.call($C('de-input-key', this.aEl)); | |
this.errCount = 0; | |
delete this.saveButton; | |
break; | |
} else if (el.id === 'de-keys-save') { | |
keys = this.keys; | |
setStored('DESU_keys', JSON.stringify(keys)); | |
} else if (el.className === 'de-alert-btn') { | |
keys = this.initKeys; | |
} else { | |
return; | |
} | |
if (hKeys) { | |
hKeys.resume(keys); | |
} | |
closeAlert($id('de-alert-edit-hotkeys')); | |
break; | |
case 'keydown': | |
if (!this.cEl) { | |
return; | |
} | |
key = e.keyCode; | |
if (key === 0x1B || key === 0x2E) { // ESC, DEL | |
this.cEl.value = ''; | |
this.cKey = 0; | |
this.errorInput = false; | |
break; | |
} | |
keyStr = KeyEditListener.keyCodes[key]; | |
if (keyStr == null) { | |
this.cKey = -1; | |
return; | |
} | |
str = ''; | |
if (e.ctrlKey) { | |
str += 'Ctrl+'; | |
} | |
if (e.shiftKey) { | |
str += 'Shift+'; | |
} | |
if (e.altKey) { | |
str += 'Alt+'; | |
} | |
if (key === 16 || key === 17 || key === 18) { | |
this.errorInput = true; | |
} else { | |
this.cKey = key | (e.ctrlKey ? 0x1000 : 0) | (e.shiftKey ? 0x2000 : 0) | | |
(e.altKey ? 0x4000 : 0) | (this.cEl.hasAttribute('de-text') ? 0x8000 : 0); | |
this.errorInput = false; | |
str += keyStr; | |
} | |
this.cEl.value = str; | |
break; | |
case 'keyup': | |
var idx, rIdx, oKey, rEl, isError, el = this.cEl, | |
key = this.cKey; | |
if (!el || key === -1) { | |
return; | |
} | |
isError = el.classList.contains('de-error-key'); | |
if (!this.errorInput && key !== -1) { | |
idx = this.allInputs.indexOf(el); | |
oKey = this.allKeys[idx]; | |
if (oKey === key) { | |
this.errorInput = false; | |
break; | |
} | |
rIdx = key === 0 ? -1 : this.allKeys.indexOf(key); | |
this.allKeys[idx] = key; | |
if (isError) { | |
idx = this.allKeys.indexOf(oKey); | |
if (idx !== -1 && this.allKeys.indexOf(oKey, idx + 1) === -1) { | |
rEl = this.allInputs[idx]; | |
if (rEl.classList.contains('de-error-key')) { | |
this.errCount--; | |
rEl.classList.remove('de-error-key'); | |
} | |
} | |
if (rIdx === -1) { | |
this.errCount--; | |
el.classList.remove('de-error-key'); | |
} | |
} | |
if (rIdx === -1) { | |
this.keys[+el.getAttribute('de-id1')][+el.getAttribute('de-id2')] = key; | |
if (this.errCount === 0) { | |
this.saveButton.disabled = false; | |
} | |
this.errorInput = false; | |
break; | |
} | |
rEl = this.allInputs[rIdx]; | |
if (!rEl.classList.contains('de-error-key')) { | |
this.errCount++; | |
rEl.classList.add('de-error-key'); | |
} | |
} | |
if (!isError) { | |
this.errCount++; | |
el.classList.add('de-error-key'); | |
} | |
if (this.errCount !== 0) { | |
this.saveButton.disabled = true; | |
} | |
} | |
$pd(e); | |
} | |
}; | |
// CONTENT FEATURES | |
// =========================================================================================================== | |
function initMessageFunctions() { | |
window.addEventListener('message', function (e) { | |
var temp, data = e.data.substring(1); | |
switch (e.data[0]) { | |
case 'A': | |
if (data.substr(10, 5) === 'pform') { | |
checkUpload($DOM(data.substr(15))); | |
$q('iframe[name="de-iframe-pform"]', doc).src = 'about:blank'; | |
} else { | |
checkDelete($DOM(data.substr(15))); | |
$q('iframe[name="de-iframe-dform"]', doc).src = 'about:blank'; | |
} | |
return; | |
case 'B': | |
closeAlert($id('de-alert-load-favthr')); | |
$id('de-iframe-fav').style.height = data + 'px'; | |
return; | |
} | |
}, false); | |
} | |
function detectImgFile(ab) { | |
var i, j, dat = new Uint8Array(ab), | |
len = dat.length; | |
/* JPG [ff d8 ff e0] = [яШяа] */ | |
if (dat[0] === 0xFF && dat[1] === 0xD8) { | |
for (i = 0, j = 0; i < len - 1; i++) { | |
if (dat[i] === 0xFF) { | |
/* Built-in JPG */ | |
if (dat[i + 1] === 0xD8) { | |
j++; | |
/* JPG end [ff d9] */ | |
} else if (dat[i + 1] === 0xD9 && --j === 0) { | |
i += 2; | |
break; | |
} | |
} | |
} | |
/* PNG [89 50 4e 47] = [‰PNG] */ | |
} else if (dat[0] === 0x89 && dat[1] === 0x50) { | |
for (i = 0; i < len - 7; i++) { | |
/* PNG end [49 45 4e 44 ae 42 60 82] */ | |
if (dat[i] === 0x49 && dat[i + 1] === 0x45 && dat[i + 2] === 0x4E && dat[i + 3] === 0x44) { | |
i += 8; | |
break; | |
} | |
} | |
} else { | |
return {}; | |
} | |
/* Ignore small files */ | |
if (i !== len && len - i > 60) { | |
for (len = i + 90; i < len; i++) { | |
/* 7Z [37 7a bc af] = [7zјЇ] */ | |
if (dat[i] === 0x37 && dat[i + 1] === 0x7A && dat[i + 2] === 0xBC) { | |
return {'type': 0, 'idx': i, 'data': ab}; | |
/* ZIP [50 4b 03 04] = [PK..] */ | |
} else if (dat[i] === 0x50 && dat[i + 1] === 0x4B && dat[i + 2] === 0x03) { | |
return {'type': 1, 'idx': i, 'data': ab}; | |
/* RAR [52 61 72 21] = [Rar!] */ | |
} else if (dat[i] === 0x52 && dat[i + 1] === 0x61 && dat[i + 2] === 0x72) { | |
return {'type': 2, 'idx': i, 'data': ab}; | |
/* OGG [4f 67 67 53] = [OggS] */ | |
} else if (dat[i] === 0x4F && dat[i + 1] === 0x67 && dat[i + 2] === 0x67) { | |
return {'type': 3, 'idx': i, 'data': ab}; | |
/* MP3 [0x49 0x44 0x33] = [ID3] */ | |
} else if (dat[i] === 0x49 && dat[i + 1] === 0x44 && dat[i + 2] === 0x33) { | |
return {'type': 4, 'idx': i, 'data': ab}; | |
} | |
} | |
} | |
return {}; | |
} | |
function workerQueue(mReqs, wrkFn, errFn) { | |
if (!nav.hasWorker) { | |
this.run = this._runSync.bind(wrkFn); | |
return; | |
} | |
this.queue = new $queue(mReqs, this._createWrk.bind(this), null); | |
this.run = this._runWrk; | |
this.wrks = new $workers('self.onmessage = function (e) {\ | |
var info = (' + String(wrkFn) + ')(e.data[1]);\ | |
if (info.data) {\ | |
self.postMessage([e.data[0], info], [info.data]);\ | |
} else {\ | |
self.postMessage([e.data[0], info]);\ | |
}\ | |
}', mReqs); | |
this.errFn = errFn; | |
} | |
workerQueue.prototype = { | |
_runSync: function (data, transferObjs, Fn) { | |
Fn(this(data)); | |
}, | |
onMess: function (Fn, e) { | |
this.queue.end(e.data[0]); | |
Fn(e.data[1]); | |
}, | |
onErr: function (qIdx, e) { | |
this.queue.end(qIdx); | |
this.errFn(e); | |
}, | |
_runWrk: function (data, transObjs, Fn) { | |
this.queue.run([data, transObjs, this.onMess.bind(this, Fn)]); | |
}, | |
_createWrk: function (qIdx, num, data) { | |
var w = this.wrks[qIdx]; | |
w.onmessage = data[2]; | |
w.onerror = this.onErr.bind(this, qIdx); | |
w.postMessage([qIdx, data[0]], data[1]); | |
}, | |
clear: function () { | |
this.wrks && this.wrks.clear(); | |
this.wrks = null; | |
} | |
}; | |
function addImgFileIcon(fName, info) { | |
var app, ext, type = info.type; | |
if (typeof type !== 'undefined') { | |
if (type === 2) { | |
app = 'application/x-rar-compressed'; | |
ext = 'rar'; | |
} else if (type === 1) { | |
app = 'application/zip'; | |
ext = 'zip'; | |
} else if (type === 0) { | |
app = 'application/x-7z-compressed'; | |
ext = '7z'; | |
} else if (type === 3) { | |
app = 'audio/ogg'; | |
ext = 'ogg'; | |
} else { | |
app = 'audio/mpeg'; | |
ext = 'mp3'; | |
} | |
this.insertAdjacentHTML('afterend', '<a href="' + window.URL.createObjectURL( | |
new Blob([new Uint8Array(info.data).subarray(info.idx)], {'type': app}) | |
) + '" class="de-img-' + (type > 2 ? 'audio' : 'arch') + '" title="' + Lng.downloadFile[lang] + | |
'" download="' + fName.substring(0, fName.lastIndexOf('.')) + '.' + ext + '">.' + ext + '</a>' | |
); | |
} | |
} | |
function downloadImgData(url, Fn) { | |
downloadObjInfo(Fn, { | |
'method': 'GET', | |
'url': url, | |
'onreadystatechange': function onDownloaded(url, e) { | |
if (e.readyState !== 4) { | |
return; | |
} | |
var isAb = e.responseType === 'arraybuffer'; | |
if (e.status === 0 && isAb) { | |
Fn(new Uint8Array(e.response)); | |
} else if (e.status !== 200) { | |
if (e.status === 404 || !url) { | |
Fn(null); | |
} else { | |
downloadObjInfo(Fn, { | |
'method': 'GET', | |
'url': url, | |
'onreadystatechange': onDownloaded.bind(null, null) | |
}); | |
} | |
} else if (isAb) { | |
Fn(new Uint8Array(e.response)); | |
} else { | |
for (var len, i = 0, txt = e.responseText, rv = new Uint8Array(len = txt.length); i < len; ++i) { | |
rv[i] = txt.charCodeAt(i) & 0xFF; | |
} | |
Fn(rv); | |
} | |
}.bind(null, url) | |
}); | |
} | |
function downloadObjInfo(Fn, obj) { | |
if (aib.fch && nav.Firefox && !obj.url.startsWith('blob')) { | |
obj.overrideMimeType = 'text/plain; charset=x-user-defined'; | |
GM_xmlhttpRequest(obj); | |
} else { | |
obj.responseType = 'arraybuffer'; | |
try { | |
$xhr(obj); | |
} catch(e) { | |
Fn(null); | |
} | |
} | |
} | |
function preloadImages(post) { | |
if (!Cfg.preLoadImgs && !Cfg.openImgs && !isPreImg) { | |
return; | |
} | |
var lnk, url, iType, nExp, el, i, len, els, queue, mReqs = post ? 1 : 4, cImg = 1, | |
rjf = (isPreImg || Cfg.findImgFile) && new workerQueue(mReqs, detectImgFile, function (e) { | |
console.error("FILE DETECTOR ERROR, line: " + e.lineno + " - " + e.message); | |
}); | |
if (isPreImg || Cfg.preLoadImgs) { | |
queue = new $queue(mReqs, function (qIdx, num, dat) { | |
downloadImgData(dat[0], function (idx, data) { | |
if (data) { | |
var a = this[1], | |
fName = this[0].substring(this[0].lastIndexOf("/") + 1), | |
aEl = $q(aib.qImgLink, aib.getImgWrap(a)); | |
aEl.setAttribute('download', fName); | |
a.href = window.URL.createObjectURL(new Blob([data], {'type': this[2]})); | |
a.setAttribute('de-name', fName); | |
if (this[2] === 'video/webm') { | |
this[4].setAttribute('de-video', ''); | |
} | |
if (this[3]) { | |
this[4].src = a.href; | |
} | |
if (rjf) { | |
rjf.run(data.buffer, [data.buffer], addImgFileIcon.bind(aEl, fName)); | |
} | |
} | |
queue.end(idx); | |
if (Images_.progressId) { | |
$alert(Lng.loadImage[lang] + cImg + '/' + len, Images_.progressId, true); | |
} | |
cImg++; | |
}.bind(dat, qIdx)); | |
}, function () { | |
Images_.preloading = false; | |
if (Images_.afterpreload) { | |
Images_.afterpreload(); | |
Images_.afterpreload = Images_.progressId = null; | |
} | |
rjf && rjf.clear(); | |
rjf = queue = cImg = len = null; | |
}); | |
Images_.preloading = true; | |
} | |
for (i = 0, els = $Q(aib.qThumbImages, post || dForm), len = els.length; i < len; i++) { | |
if (lnk = $parent(el = els[i], 'A')) { | |
url = lnk.href; | |
nExp = !!Cfg.openImgs; | |
if (/\.gif$/i.test(url)) { | |
iType = 'image/gif'; | |
} else { | |
if (/\.jpe?g$/i.test(url)) { | |
iType = 'image/jpeg'; | |
} else if (/\.png$/i.test(url)) { | |
iType = 'image/png'; | |
} else if (/\.webm$/i.test(url)) { | |
iType = 'video/webm'; | |
nExp = false; | |
} else { | |
continue; | |
} | |
nExp &= !Cfg.openGIFs; | |
} | |
if (queue) { | |
queue.run([url, lnk, iType, nExp, el]); | |
} else if (nExp) { | |
el.src = url; // ! | |
} | |
} | |
} | |
queue && queue.complete(); | |
} | |
function getDataFromImg(img) { | |
var cnv = Images_.canvas || (Images_.canvas = doc.createElement('canvas')); | |
cnv.width = img.width; | |
cnv.height = img.height; | |
cnv.getContext('2d').drawImage(img, 0, 0); | |
return new Uint8Array(atob(cnv.toDataURL("image/png").split(',')[1]).split('').map(function (a) { | |
return a.charCodeAt(); | |
})); | |
} | |
function loadDocFiles(imgOnly) { | |
var els, files, progress, counter, count = 0, | |
current = 1, | |
warnings = '', | |
tar = new $tar(), | |
dc = imgOnly ? doc : doc.documentElement.cloneNode(true); | |
Images_.queue = new $queue(4, function (qIdx, num, dat) { | |
downloadImgData(dat[0], function (idx, data) { | |
var name = this[1].replace(/[\\\/:*?"<>|]/g, '_'), el = this[2]; | |
progress.value = current; | |
counter.innerHTML = current; | |
current++; | |
if (this[3]) { | |
if (!data) { | |
warnings += '<br>' + Lng.cantLoad[lang] + '<a href="' + this[0] + '">' + | |
this[0] + '</a><br>' + Lng.willSavePview[lang]; | |
$alert(Lng.loadErrors[lang] + warnings, 'floadwarn', false); | |
name = 'thumb-' + name.replace(/\.[a-z]+$/, '.png'); | |
data = getDataFromImg(this[2]); | |
} | |
if (!imgOnly) { | |
el.classList.add('de-thumb'); | |
el.src = this[3].href = | |
$q(aib.qImgLink, aib.getImgWrap(this[3])).href = | |
name = 'images/' + name; | |
} | |
tar.addFile(name, data); | |
} else if (data && data.length > 0) { | |
tar.addFile(el.href = el.src = 'data/' + name, data); | |
} else { | |
$del(el); | |
} | |
Images_.queue.end(idx); | |
}.bind(dat, qIdx)); | |
}, function () { | |
var u, a, dt, name = aib.dm + '-' + brd.replace(/[\\\/:*?"<>|]/g, '') + '-' + TNum; | |
if (!imgOnly) { | |
dt = doc.doctype; | |
$t('head', dc).insertAdjacentHTML('beforeend', | |
'<script type="text/javascript" src="data/dollscript.js"></script>'); | |
tar.addString('data/dollscript.js', '(' + String(de_main_func) + ')(null, true);'); | |
tar.addString( | |
name + '.html', '<!DOCTYPE ' + dt.name + | |
(dt.publicId ? ' PUBLIC "' + dt.publicId + '"' : dt.systemId ? ' SYSTEM' : '') + | |
(dt.systemId ? ' "' + dt.systemId + '"' : '') + '>' + dc.outerHTML | |
); | |
} | |
u = window.URL.createObjectURL(tar.get()); | |
a = $new('a', {'href': u, 'download': name + (imgOnly ? '-images.tar' : '.tar')}, null); | |
doc.body.appendChild(a); | |
a.click(); | |
setTimeout(function (el, url) { | |
window.URL.revokeObjectURL(url); | |
$del(el); | |
}, 0, a, u); | |
$del($id('de-alert-filesload')); | |
Images_.queue = tar = warnings = count = current = imgOnly = progress = counter = null; | |
}); | |
els = aProto.slice.call($Q(aib.qThumbImages, $q('[de-form]', dc))); | |
count += els.length; | |
els.forEach(function (el) { | |
var lnk, url; | |
if (lnk = $parent(el, 'A')) { | |
url = lnk.href; | |
if (aib.tiny) { | |
url = url.replace(/^.*?\?v=|&.*?$/g, ''); | |
} | |
Images_.queue.run([url, lnk.getAttribute('de-name') || | |
url.substring(url.lastIndexOf("/") + 1), el, lnk]); | |
} | |
}); | |
if (!imgOnly) { | |
files = []; | |
$each($Q('#darude-sandstorm, .de-parea, .de-post-btns, #de-qarea, .de-refmap, #de-updater-div, .de-video-obj,' + | |
' link[rel="alternate stylesheet"], script, ' + aib.qPostForm, dc), $del); | |
$each($T('a', dc), function (el) { | |
var num, tc = el.textContent; | |
if (tc[0] === '>' && tc[1] === '>' && (num = +tc.substr(2)) && (num in pByNum)) { | |
el.href = aib.anchor + num; | |
} else { | |
el.href = getAbsLink(el.href); | |
} | |
if (!el.classList.contains('de-preflink')) { | |
el.className = 'de-preflink ' + el.className; | |
} | |
}); | |
$each($Q('.' + aib.cRPost, dc), function (post, i) { | |
post.setAttribute('de-num', i === 0 ? TNum : aib.getPNum(post)); | |
}); | |
$each($Q('link, *[src]', dc), function (el) { | |
if (els.indexOf(el) !== -1) { | |
return; | |
} | |
var temp, i, ext, name, url = el.tagName === 'LINK' ? el.href : el.src; | |
if (!this.test(url)) { | |
$del(el); | |
return; | |
} | |
name = url.substring(url.lastIndexOf("/") + 1).replace(/[\\\/:*?"<>|]/g, '_') | |
.toLowerCase(); | |
if (files.indexOf(name) !== -1) { | |
temp = url.lastIndexOf('.'); | |
ext = url.substring(temp); | |
url = url.substring(0, temp); | |
name = name.substring(0, name.lastIndexOf('.')); | |
for (i = 0; ; ++i) { | |
temp = name + '(' + i + ')' + ext; | |
if (files.indexOf(temp) === -1) { | |
break; | |
} | |
} | |
name = temp; | |
} | |
files.push(name); | |
Images_.queue.run([url, name, el, null]); | |
count++; | |
}.bind(new RegExp('^\\/\\/?|^https?:\\/\\/([^\\/]*\.)?' + regQuote(aib.dm) + '\\/', 'i'))); | |
} | |
$alert((imgOnly ? Lng.loadImage[lang] : Lng.loadFile[lang]) + | |
'<br><progress id="de-loadprogress" value="0" max="' + count + '"></progress> <span>1</span>/' + | |
count, 'filesload', true); | |
progress = $id('de-loadprogress'); | |
counter = progress.nextElementSibling; | |
Images_.queue.complete(); | |
els = null; | |
} | |
// TIME CORRECTION | |
// =========================================================================================================== | |
function dateTime(pattern, rPattern, diff, dtLang, onRPat) { | |
if (dateTime.checkPattern(pattern)) { | |
this.disabled = true; | |
return; | |
} | |
this.regex = pattern | |
.replace(/(?:[sihdny]\?){2,}/g, function () { | |
return '(?:' + arguments[0].replace(/\?/g, '') + ')?'; | |
}) | |
.replace(/\-/g, '[^<]') | |
.replace(/\+/g, '[^0-9]') | |
.replace(/([sihdny]+)/g, '($1)') | |
.replace(/[sihdny]/g, '\\d') | |
.replace(/m|w/g, '([a-zA-Zа-яА-Я]+)'); | |
this.pattern = pattern.replace(/[\?\-\+]+/g, '').replace(/([a-z])\1+/g, '$1'); | |
this.diff = parseInt(diff, 10); | |
this.sDiff = (this.diff < 0 ? '' : '+') + this.diff; | |
this.arrW = Lng.week[dtLang]; | |
this.arrM = Lng.month[dtLang]; | |
this.arrFM = Lng.fullMonth[dtLang]; | |
this.rPattern = rPattern; | |
this.onRPat = onRPat; | |
} | |
dateTime.toggleSettings = function (el) { | |
if (el.checked && (!/^[+-]\d{1,2}$/.test(Cfg.timeOffset) || dateTime.checkPattern(Cfg.timePattern))) { | |
$alert(Lng.cTimeError[lang], 'err-correcttime', false); | |
saveCfg('correctTime', 0); | |
el.checked = false; | |
} | |
}; | |
dateTime.checkPattern = function (val) { | |
return !val.contains('i') || !val.contains('h') || !val.contains('d') || !val.contains('y') || | |
!(val.contains('n') || val.contains('m')) || | |
/[^\?\-\+sihdmwny]|mm|ww|\?\?|([ihdny]\?)\1+/.test(val); | |
}; | |
dateTime.prototype = { | |
getRPattern: function (txt) { | |
var k, p, a, str, i = 1, | |
j = 0, | |
m = txt.match(new RegExp(this.regex)); | |
if (!m) { | |
this.disabled = true; | |
return false; | |
} | |
this.rPattern = ''; | |
str = m[0]; | |
while (a = m[i++]) { | |
p = this.pattern[i - 2]; | |
if ((p === 'm' || p === 'y') && a.length > 3) { | |
p = p.toUpperCase(); | |
} | |
k = str.indexOf(a, j); | |
this.rPattern += str.substring(j, k) + '_' + p; | |
j = k + a.length; | |
} | |
this.onRPat && this.onRPat(this.rPattern); | |
return true; | |
}, | |
pad2: function (num) { | |
return num < 10 ? '0' + num : num; | |
}, | |
fix: function (txt) { | |
if (this.disabled || (!this.rPattern && !this.getRPattern(txt))) { | |
return txt; | |
} | |
return txt.replace(new RegExp(this.regex, 'g'), function () { | |
var i, a, t, second, minute, hour, day, month, year, dtime; | |
for (i = 1; i < 8; i++) { | |
a = arguments[i]; | |
t = this.pattern[i - 1]; | |
t === 's' ? second = a : | |
t === 'i' ? minute = a : | |
t === 'h' ? hour = a : | |
t === 'd' ? day = a : | |
t === 'n' ? month = a - 1 : | |
t === 'y' ? year = a : | |
t === 'm' && ( | |
month = | |
/^янв|^jan/i.test(a) ? 0 : | |
/^фев|^feb/i.test(a) ? 1 : | |
/^мар|^mar/i.test(a) ? 2 : | |
/^апр|^apr/i.test(a) ? 3 : | |
/^май|^may/i.test(a) ? 4 : | |
/^июн|^jun/i.test(a) ? 5 : | |
/^июл|^jul/i.test(a) ? 6 : | |
/^авг|^aug/i.test(a) ? 7 : | |
/^сен|^sep/i.test(a) ? 8 : | |
/^окт|^oct/i.test(a) ? 9 : | |
/^ноя|^nov/i.test(a) ? 10 : | |
/^дек|^dec/i.test(a) && 11 | |
); | |
} | |
dtime = new Date(year.length === 2 ? '20' + year : year, month, day, hour, minute, second || 0); | |
dtime.setHours(dtime.getHours() + this.diff); | |
return this.rPattern | |
.replace('_o', this.sDiff) | |
.replace('_s', this.pad2(dtime.getSeconds())) | |
.replace('_i', this.pad2(dtime.getMinutes())) | |
.replace('_h', this.pad2(dtime.getHours())) | |
.replace('_d', this.pad2(dtime.getDate())) | |
.replace('_w', this.arrW[dtime.getDay()]) | |
.replace('_n', this.pad2(dtime.getMonth() + 1)) | |
.replace('_m', this.arrM[dtime.getMonth()]) | |
.replace('_M', this.arrFM[dtime.getMonth()]) | |
.replace('_y', ('' + dtime.getFullYear()).substring(2)) | |
.replace('_Y', dtime.getFullYear()); | |
}.bind(this)); | |
} | |
}; | |
// PLAYER | |
// =========================================================================================================== | |
YouTube = new function () { | |
var instance, vData, embedType, videoType, width, height, isHD, loadTitles; | |
function addThumb(el, m, isYtube) { | |
var wh = ' width="' + width + '" height="' + height + '"></a>'; | |
if (isYtube) { | |
el.innerHTML = '<a href="' + aib.prot + '//www.youtube.com/watch?v=' + m[1] + '" target="_blank">' + | |
'<img class="de-video-thumb de-ytube" src="https://i.ytimg.com/vi/' + m[1] + '/0.jpg"' + wh; | |
} else { | |
el.innerHTML = '<a href="' + aib.prot + '//vimeo.com/' + m[1] + '" target="_blank">' + | |
'<img class="de-video-thumb de-vimeo" src=""' + wh; | |
GM_xmlhttpRequest({ | |
'method': 'GET', | |
'url': aib.prot + '//vimeo.com/api/v2/video/' + m[1] + '.json', | |
'onload': function (xhr){ | |
this.setAttribute('src', JSON.parse(xhr.responseText)[0].thumbnail_large); | |
}.bind(el.firstChild.firstChild) | |
}); | |
} | |
} | |
function addPlayer(el, m, isYtube) { | |
var time, list, id = m[1], | |
wh = ' width="' + width + '" height="' + height + '">'; | |
if (isYtube) { | |
time = (m[2] ? m[2] * 3600 : 0) + (m[3] ? m[3] * 60 : 0) + (m[4] ? +m[4] : 0); | |
list = m[0].match(/list=[^&#]+/); | |
el.innerHTML = '<iframe frameborder="0" allowfullscreen="1" src="' + aib.prot + '//www.youtube.com/embed/' + | |
id + '?' + (el.parentNode.id === 'de-content-vid' ? 'enablejsapi=1&' : '') + | |
(isHD ? 'hd=1&' : '') + (list ? list[0] + '&' : '') + 'start=' + time + (videoType === 1 ? | |
'&html5=1&rel=0" type="text/html"' : '" type="application/x-shockwave-flash"') + wh; | |
} else { | |
time = m[2] ? m[2] : ''; | |
el.innerHTML = videoType === 1 ? | |
'<iframe src="' + aib.prot + '//player.vimeo.com/video/' + id + time + | |
'" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen' + wh : | |
'<embed type="application/x-shockwave-flash" src="' + aib.prot + '//vimeo.com/moogaloop.swf' + | |
'?clip_id=' + id + time + '&server=vimeo.com&color=00adef&fullscreen=1" ' + | |
'allowscriptaccess="always" allowfullscreen="true"' + wh; | |
} | |
} | |
function addLink(post, m, loader, link, isYtube) { | |
var msg, src, time, dataObj; | |
if (!post) { | |
return; | |
} | |
post.hasYTube = true; | |
if (post.ytInfo === null) { | |
if (embedType === 2) { | |
addPlayer(post.ytObj, post.ytInfo = m, isYtube); | |
} else if (embedType > 2) { | |
addThumb(post.ytObj, post.ytInfo = m, isYtube); | |
} | |
} else if (!link && $q('.de-video-link[href*="' + m[1] + '"]', post.msg)) { | |
return; | |
} | |
if (loader && (dataObj = vData[m[1]])) { | |
post.ytData.push(dataObj); | |
} | |
if (m[4] || m[3] || m[2]) { | |
if (m[4] >= 60) { | |
m[3] = (m[3] || 0) + Math.floor(m[4] / 60); | |
m[4] %= 60; | |
} | |
if (m[3] >= 60) { | |
m[2] = (m[2] || 0) + Math.floor(m[3] / 60); | |
m[3] %= 60; | |
} | |
time = (m[2] ? m[2] + 'h' : '') + (m[3] ? m[3] + 'm' : '') + (m[4] ? m[4] + 's' : ''); | |
} | |
if (link) { | |
link.href = link.href.replace(/^http:/, 'https:'); | |
if (time) { | |
link.setAttribute('de-time', time); | |
} | |
if (dataObj) { | |
link.textContent = dataObj[0]; | |
link.className = 'de-video-link de-ytube de-video-title'; | |
link.setAttribute('de-author', dataObj[1]); | |
link.title = Lng.author[lang] + dataObj[1] + ', ' + | |
Lng.views[lang] + dataObj[2] + ', ' + Lng.published[lang] + dataObj[3]; | |
} else { | |
link.className = 'de-video-link ' + (isYtube ? 'de-ytube' : 'de-vimeo'); | |
if (!isYtube && Cfg.YTubeTitles) { | |
getVimeoTitle(link, m); | |
} | |
} | |
} else { | |
src = isYtube ? aib.prot + '//www.youtube.com/watch?v=' + m[1] + (time ? '#t=' + time : '') | |
: aib.prot + '//vimeo.com/' + m[1]; | |
post.msg.insertAdjacentHTML('beforeend', | |
'<p class="de-video-ext"><a class="de-video-link ' + (isYtube ? 'de-ytube' : 'de-vimeo') + | |
(dataObj ? ' de-video-title" title="' + Lng.author[lang] + dataObj[1] + ', ' + | |
Lng.views[lang] + dataObj[2] + ', ' + Lng.published[lang] + dataObj[3] + | |
'" de-author="' + dataObj[1] : '') + (time ? '" de-time="' + time : '') + | |
'" href="' + src + '">' + (dataObj ? dataObj[0] : src) + '</a></p>'); | |
link = post.msg.lastChild.firstChild; | |
} | |
if (!post.ytInfo || post.ytInfo === m) { | |
post.ytLink = link; | |
} | |
link.ytInfo = m; | |
if (loader && !dataObj) { | |
post.ytLinksLoading++; | |
loader.run([post, link, m[1]]); | |
} | |
} | |
function clickLink(post, el, mode) { | |
var m = el.ytInfo; | |
if (post.ytInfo === m) { | |
if (mode === 3) { | |
if ($c('de-video-thumb', post.ytObj)) { | |
el.classList.add('de-current'); | |
addPlayer(post.ytObj, post.ytInfo = m, el.classList.contains('de-ytube')); | |
} else { | |
el.classList.remove('de-current'); | |
addThumb(post.ytObj, post.ytInfo = m, el.classList.contains('de-ytube')); | |
} | |
} else { | |
el.classList.remove('de-current'); | |
post.ytObj.innerHTML = ''; | |
post.ytInfo = null; | |
} | |
} else if (mode > 2) { | |
post.ytLink.classList.remove('de-current'); | |
post.ytLink = el; | |
addThumb(post.ytObj, post.ytInfo = m, el.classList.contains('de-ytube')); | |
} else { | |
post.ytLink.classList.remove('de-current'); | |
post.ytLink = el; | |
el.classList.add('de-current'); | |
addPlayer(post.ytObj, post.ytInfo = m, el.classList.contains('de-ytube')); | |
} | |
} | |
function getVimeoTitle(link, m) { | |
GM_xmlhttpRequest({ | |
'method': 'GET', | |
'url': aib.prot + '//vimeo.com/api/v2/video/' + m[1] + '.json', | |
'onload': function (xhr) { | |
var json = JSON.parse(xhr.responseText)[0], | |
date = new RegExp (/(.*)\s(.*)?/).exec(json["upload_date"]); | |
link.textContent = json["title"]; | |
link.title = Lng.author[lang] + json["user_name"] + ', ' + | |
Lng.views[lang] + json["stats_number_of_plays"] + ', ' + Lng.published[lang] + date[1]; | |
} | |
}); | |
} | |
function getYtubeTitleLoader() { | |
var queueEnd, queue = new $queue(4, function (qIdx, num, data) { | |
if (num % 30 === 0) { | |
queue.pause(); | |
setTimeout(queue.continue.bind(queue), 3e3); | |
} | |
GM_xmlhttpRequest({ | |
'method': 'GET', | |
'url': aib.prot + '//gdata.youtube.com/feeds/api/videos/' + data[2] + | |
'?alt=json&fields=title/text(),author/name,yt:statistics/@viewCount,published', | |
'onreadystatechange': function (idx, xhr) { | |
if (xhr.readyState !== 4) { | |
return; | |
} | |
var entry, title, author, views, publ, data, post = this[0], link = this[1]; | |
try { | |
if (xhr.status === 200) { | |
entry = JSON.parse(xhr.responseText).entry; | |
title = entry.title.$t; | |
author = entry.author[0].name.$t; | |
views = entry.yt$statistics.viewCount; | |
publ = entry.published.$t.substr(0, 10); | |
} | |
} finally { | |
if (title) { | |
link.textContent = title; | |
link.setAttribute('de-author', author); | |
link.classList.add('de-video-title'); | |
link.title = Lng.author[lang] + author + ', ' + Lng.views[lang] + views + ', ' + | |
Lng.published[lang] + publ; | |
vData[this[2]] = data = [title, author, views, publ]; | |
post.ytData.push(data); | |
post.ytLinksLoading--; | |
if (post.ytHideFun !== null) { | |
post.ytHideFun(data); | |
} | |
} | |
setTimeout(queueEnd, 250, idx); | |
} | |
}.bind(data, qIdx) | |
}); | |
}, function () { | |
sesStorage['de-ytube-data'] = JSON.stringify(vData); | |
queue = queueEnd = null; | |
}); | |
queueEnd = queue.end.bind(queue); | |
return queue; | |
} | |
function YouTubeSingleton() { | |
if (instance) { | |
return instance; | |
} | |
instance = this; | |
embedType = Cfg.addYouTube; | |
if (embedType === 0) { | |
this.parseLinks = emptyFn; | |
this.updatePost = emptyFn; | |
} | |
loadTitles = Cfg.YTubeTitles; | |
if (loadTitles) { | |
vData = JSON.parse(sesStorage['de-ytube-data'] || '{}'); | |
} | |
videoType = Cfg.YTubeType; | |
width = Cfg.YTubeWidth; | |
height = Cfg.YTubeHeigh; | |
isHD = Cfg.YTubeHD; | |
} | |
YouTubeSingleton.prototype = { | |
embedType: embedType, | |
ytReg: /^https?:\/\/(?:www\.|m\.)?youtu(?:be\.com\/(?:watch\?.*?v=|v\/|embed\/)|\.be\/)([a-zA-Z0-9-_]+).*?(?:t(?:ime)?=(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s?)?)?$/, | |
vimReg: /^https?:\/\/(?:www\.)?vimeo\.com\/(?:[^\?]+\?clip_id=|.*?\/)?(\d+).*?(#t=\d+)?$/, | |
vData: vData, | |
addPlayer: addPlayer, | |
addLink: addLink, | |
clickLink: clickLink, | |
parseLinks: function (post) { | |
var i, len, els, el, src, m, embedTube = [], | |
loader = loadTitles && getYtubeTitleLoader(); | |
for (i = 0, els = $Q('embed, object, iframe', post ? post.el : dForm), len = els.length; i < len; ++i) { | |
el = els[i]; | |
src = el.src || el.data; | |
if (m = src.match(this.ytReg)) { | |
embedTube.push(post || aib.getPostEl(el).post, m, true); | |
$del(el); | |
} | |
if (Cfg.addVimeo && (m = src.match(this.vimReg))) { | |
embedTube.push(post || aib.getPostEl(el).post, m, false); | |
$del(el); | |
} | |
} | |
for (i = 0, els = $Q('a[href*="youtu"]', post ? post.el : dForm), len = els.length; i < len; ++i) { | |
el = els[i]; | |
if (m = el.href.match(this.ytReg)) { | |
addLink(post || aib.getPostEl(el).post, m, loader, el, true); | |
} | |
} | |
if (Cfg.addVimeo) { | |
for (i = 0, els = $Q('a[href*="vimeo.com"]', post ? post.el : dForm), len = els.length; i < len; ++i) { | |
el = els[i]; | |
if (m = el.href.match(this.vimReg)) { | |
addLink(post || aib.getPostEl(el).post, m, null, el, false); | |
} | |
} | |
} | |
for (i = 0, len = embedTube.length; i < len; i += 3) { | |
addLink(embedTube[i], embedTube[i + 1], loader, null, embedTube[i + 2]); | |
} | |
loader && loader.complete(); | |
}, | |
updatePost: function (post, oldLinks, newLinks, cloned) { | |
var i, j, el, link, m, loader = !cloned && loadTitles && getYtubeTitleLoader(), | |
len = newLinks.length; | |
for (i = 0, j = 0; i < len; i++) { | |
el = newLinks[i]; | |
link = oldLinks[j]; | |
if (link && link.classList.contains('de-current')) { | |
post.ytLink = el; | |
} | |
if (cloned) { | |
el.ytInfo = link.ytInfo; | |
j++; | |
} else if (m = el.href.match(this.ytReg)) { | |
addLink(post, m, loader, el, true); | |
j++; | |
} | |
} | |
post.ytLink = post.ytLink || newLinks[0]; | |
loader && loader.complete(); | |
} | |
}; | |
return YouTubeSingleton; | |
}; | |
function embedMP3Links(post) { | |
var el, link, src, i, els, len; | |
if (!Cfg.addMP3) { | |
return; | |
} | |
for (i = 0, els = $Q('a[href*=".mp3"]', post ? post.el : dForm), len = els.length; i < len; ++i) { | |
link = els[i]; | |
if (link.target !== '_blank' && link.rel !== 'nofollow') { | |
continue; | |
} | |
src = link.href; | |
el = (post || aib.getPostEl(link).post).mp3Obj; | |
if (nav.canPlayMP3) { | |
if (!$q('audio[src="' + src + '"]', el)) { | |
el.insertAdjacentHTML('beforeend', | |
'<p><audio src="' + src + '" preload="none" controls></audio></p>'); | |
link = el.lastChild.firstChild; | |
link.addEventListener('play', updater.addPlayingTag, false); | |
link.addEventListener('pause', updater.removePlayingTag, false); | |
} | |
} else if (!$q('object[FlashVars*="' + src + '"]', el)) { | |
el.insertAdjacentHTML('beforeend', '<object data="http://junglebook2007.narod.ru/audio/player.swf" type="application/x-shockwave-flash" wmode="transparent" width="220" height="16" FlashVars="playerID=1&bg=0x808080&leftbg=0xB3B3B3&lefticon=0x000000&rightbg=0x808080&rightbghover=0x999999&rightcon=0x000000&righticonhover=0xffffff&text=0xffffff&slider=0x222222&track=0xf5f5dc&border=0x666666&loader=0x7fc7ff&loop=yes&autostart=no&soundFile=' + src + '"><br>'); | |
} | |
} | |
} | |
// AJAX | |
// =========================================================================================================== | |
function ajaxLoad(url, loadForm, Fn, errFn) { | |
return GM_xmlhttpRequest({ | |
'method': 'GET', | |
'url': nav.fixLink(url), | |
'onreadystatechange': function (xhr) { | |
if (xhr.readyState !== 4) { | |
return; | |
} | |
if (xhr.status !== 200) { | |
if (errFn) { | |
errFn(xhr.status, xhr.statusText, this); | |
} | |
} else if (Fn) { | |
do { | |
var el, text = xhr.responseText; | |
if ((aib.futa ? /<!--gz-->$/ : /<\/html?>[\s\n\r]*$/).test(text)) { | |
el = $DOM(text); | |
if (!loadForm || (el = $q(aib.qDForm, el))) { | |
Fn(el, this); | |
break; | |
} | |
} | |
if (errFn) { | |
errFn(0, Lng.errCorruptData[lang], this); | |
} | |
} while (false); | |
} | |
loadForm = Fn = errFn = null; | |
} | |
});; | |
} | |
function getJsonPosts(url, Fn) { | |
GM_xmlhttpRequest({ | |
'method': 'GET', | |
'url': nav.fixLink(url), | |
'onreadystatechange': function (xhr) { | |
if (xhr.readyState !== 4) { | |
return; | |
} | |
if (xhr.status === 304) { | |
closeAlert($id('de-alert-newposts')); | |
} else { | |
try { | |
var json = JSON.parse(xhr.responseText); | |
} catch(e) { | |
Fn(1, e.toString(), null, this); | |
} finally { | |
if (json) { | |
Fn(xhr.status, xhr.statusText, json, this); | |
} | |
Fn = null; | |
} | |
} | |
} | |
}); | |
} | |
function loadFavorThread() { | |
var post, el = this.parentNode, | |
ifrm = $t('iframe', el), | |
cont = $c('de-content', doc); | |
if (ifrm) { | |
$del(ifrm); | |
cont.style.overflowY = 'auto'; | |
return; | |
} | |
if ((post = pByNum[el.getAttribute('de-num')]) && !post.hidden) { | |
scrollTo(0, pageYOffset + post.el.getBoundingClientRect().top); | |
return; | |
} | |
$del($id('de-iframe-fav')); | |
$c('de-content', doc).style.overflowY = 'scroll'; | |
$alert(Lng.loading[lang], 'load-favthr', true); | |
el.insertAdjacentHTML('beforeend', '<iframe name="de-iframe-fav" id="de-iframe-fav" src="' + | |
$t('a', el).href + '" scrolling="no" style="display: block; border: none; width: ' + | |
(doc.documentElement.clientWidth - 55) + 'px; height: 1px;">'); | |
} | |
function loadPages(count) { | |
var fun, i = pageNum, | |
len = Math.min(aib.lastPage + 1, i + count), | |
pages = [], | |
loaded = 1; | |
count = len - i; | |
function onLoadOrError(idx, eCodeOrForm, eMsgOrXhr, maybeXhr) { | |
if (typeof eCodeOrForm === 'number') { | |
pages[idx] = $add('<div><center style="font-size: 2em">' + | |
getErrorMessage(eCodeOrForm, eMsgOrXhr) + '</center><hr></div>'); | |
} else { | |
pages[idx] = replacePost(eCodeOrForm); | |
} | |
if (loaded === count) { | |
var el, df, j, parseThrs = Thread.parsed, | |
threads = parseThrs ? [] : null; | |
for (j in pages) { | |
if (!pages.hasOwnProperty(j)) { | |
continue; | |
} | |
if (j != pageNum) { | |
dForm.insertAdjacentHTML('beforeend', '<center style="font-size: 2em">' + | |
Lng.page[lang] + ' ' + j + '</center><hr>'); | |
} | |
df = pages[j]; | |
if (parseThrs) { | |
threads = parseThreadNodes(df, threads); | |
} | |
while (el = df.firstChild) { | |
dForm.appendChild(el); | |
} | |
} | |
if (!parseThrs) { | |
threads = $Q(aib.qThread, dForm); | |
} | |
do { | |
if (threads.length !== 0) { | |
try { | |
parseDelform(dForm, threads); | |
} catch(e) { | |
$alert(getPrettyErrorMessage(e), 'load-pages', true); | |
break; | |
} | |
initDelformAjax(); | |
addDelformStuff(false); | |
readUserPosts(); | |
readFavoritesPosts(); | |
$each($Q('input[type="password"]', dForm), function (pEl) { | |
pr.dpass = pEl; | |
pEl.value = Cfg.passwValue; | |
}); | |
if (hKeys) { | |
hKeys.clear(pageNum + count - 1); | |
} | |
} | |
closeAlert($id('de-alert-load-pages')); | |
} while (false); | |
dForm.style.display = ''; | |
loaded = pages = count = null; | |
} else { | |
loaded++; | |
} | |
} | |
$alert(Lng.loading[lang], 'load-pages', true); | |
$each($Q('a[href^="blob:"]', dForm), function (a) { | |
window.URL.revokeObjectURL(a.href); | |
}); | |
Pview.clearCache(); | |
isExpImg = false; | |
pByNum = Object.create(null); | |
Thread.tNums = []; | |
Post.hiddenNums = []; | |
if (Attachment.viewer) { | |
Attachment.viewer.close(null); | |
Attachment.viewer = null; | |
} | |
dForm.style.display = 'none'; | |
dForm.innerHTML = ''; | |
if (pr.isQuick) { | |
if (pr.file) { | |
pr.delFilesUtils(); | |
} | |
pr.txta.value = ''; | |
} | |
while (i < len) { | |
fun = onLoadOrError.bind(null, i); | |
ajaxLoad(aib.getPageUrl(brd, i++), true, fun, fun); | |
} | |
} | |
function infoLoadErrors(eCode, eMsg, newPosts) { | |
if (eCode === 200 || eCode === 304) { | |
closeAlert($id('de-alert-newposts')); | |
} else if (eCode === 0) { | |
$alert(eMsg || Lng.noConnect[lang], 'newposts', false); | |
} else { | |
$alert(Lng.thrNotFound[lang] + TNum + '): \n' + getErrorMessage(eCode, eMsg), 'newposts', false); | |
if (newPosts !== -1) { | |
doc.title = '{' + eCode + '} ' + doc.title; | |
} | |
} | |
} | |
// SPELLS | |
// =========================================================================================================== | |
function Spells(read) { | |
if (read) { | |
this._read(true); | |
} else { | |
this.disable(false); | |
} | |
} | |
Spells.names = [ | |
'words', 'exp', 'exph', 'imgn', 'ihash', 'subj', 'name', 'trip', 'img', 'sage', 'op', 'tlen', | |
'all', 'video', 'wipe', 'num', 'vauthor' | |
]; | |
Spells.needArg = [ | |
/* words */ true, /* exp */ true, /* exph */ true, /* imgn */ true, /* ihash */ true, | |
/* subj */ false, /* name */ true, /* trip */ false, /* img */ false, /* sage */ false, | |
/* op */ false, /* tlen */ false, /* all */ false, /* video */ false, /* wipe */ false, | |
/* num */ true, /* vauthor */ true | |
]; | |
Spells.decompileSpell = function (type, neg, val, scope) { | |
var temp, temp_, spell = (neg ? '!#' : '#') + Spells.names[type] + (scope ? '[' + | |
scope[0] + (scope[1] ? ',' + (scope[1] === -1 ? '' : scope[1]) : '') + ']' : ''); | |
if (!val) { | |
return spell; | |
} | |
// #img | |
if (type === 8) { | |
return spell + '(' + (val[0] === 2 ? '>' : val[0] === 1 ? '<' : '=') + | |
(val[1] ? val[1][0] + (val[1][1] === val[1][0] ? '' : '-' + val[1][1]) : '') + | |
(val[2] ? '@' + val[2][0] + (val[2][0] === val[2][1] ? '' : '-' + val[2][1]) + 'x' + | |
val[2][2] + (val[2][2] === val[2][3] ? '' : '-' + val[2][3]) : '') + ')'; | |
} | |
// #wipe | |
else if (type === 14) { | |
if (val === 0x3F) { | |
return spell; | |
} | |
temp = []; | |
(val & 1) && temp.push('samelines'); | |
(val & 2) && temp.push('samewords'); | |
(val & 4) && temp.push('longwords'); | |
(val & 8) && temp.push('symbols'); | |
(val & 16) && temp.push('capslock'); | |
(val & 32) && temp.push('numbers'); | |
(val & 64) && temp.push('whitespace'); | |
return spell + '(' + temp.join(',') + ')'; | |
} | |
// #num, #tlen | |
else if (type === 15 || type === 11) { | |
if ((temp = val[1].length - 1) !== -1) { | |
for (temp_ = []; temp >= 0; temp--) { | |
temp_.push(val[1][temp][0] + '-' + val[1][temp][1]); | |
} | |
temp_.reverse(); | |
} | |
spell += '('; | |
if (val[0].length !== 0) { | |
spell += val[0].join(',') + (temp_ ? ',' : ''); | |
} | |
if (temp_) { | |
spell += temp_.join(','); | |
} | |
return spell + ')'; | |
} | |
// #words, #name, #trip, #vauthor | |
else if (type === 0 || type === 6 || type === 7 || type === 16) { | |
return spell + '(' + val.replace(/\)/g, '\\)') + ')'; | |
} else { | |
return spell + '(' + String(val) + ')'; | |
} | |
}; | |
Spells.prototype = { | |
_optimizeSpells: function (spells) { | |
var i, j, len, flags, type, spell, scope, neg, parensSpells, lastSpell = -1, | |
newSpells = []; | |
for (i = 0, len = spells.length; i < len; ++i) { | |
spell = spells[i]; | |
flags = spell[0]; | |
type = flags & 0xFF; | |
neg = (flags & 0x100) !== 0; | |
if (type === 0xFF) { | |
parensSpells = this._optimizeSpells(spell[1]); | |
if (parensSpells) { | |
if (parensSpells.length !== 1) { | |
newSpells.push([flags, parensSpells]); | |
lastSpell++; | |
continue; | |
} else if ((parensSpells[0][0] & 0xFF) !== 12) { | |
newSpells.push([(parensSpells[0][0] | (flags & 0x200)) ^ (flags & 0x100), | |
parensSpells[0][1]]); | |
lastSpell++; | |
continue; | |
} | |
flags = parensSpells[0][0]; | |
neg = !(neg ^ ((flags & 0x100) !== 0)); | |
} | |
} else { | |
scope = spell[2]; | |
if (!scope || (scope[0] === brd && | |
(scope[1] === -1 ? !TNum : (!scope[1] || scope[1] === TNum)))) | |
{ | |
if (type === 12) { | |
neg = !neg; | |
} else { | |
newSpells.push([flags, spell[1]]); | |
lastSpell++; | |
continue; | |
} | |
} | |
} | |
for (j = lastSpell; j >= 0 && (((newSpells[j][0] & 0x200) !== 0) ^ neg); --j) {} | |
if (j !== lastSpell) { | |
newSpells = newSpells.slice(0, j + 1); | |
lastSpell = j; | |
} | |
if (neg && j !== -1) { | |
newSpells[j][0] &= 0x1FF; | |
} | |
if (((flags & 0x200) !== 0) ^ neg) { | |
break; | |
} | |
} | |
return lastSpell === -1 ? neg ? [[12, '']] : null : newSpells; | |
}, | |
_initSpells: function (data) { | |
if (data) { | |
data.forEach(function initExps(item) { | |
var val = item[1]; | |
if (val) { | |
switch (item[0] & 0xFF) { | |
case 1: | |
case 2: | |
case 3: | |
case 5: | |
case 13: item[1] = toRegExp(val, true); break; | |
case 0xFF: val.forEach(initExps); | |
} | |
} | |
}); | |
} | |
return data; | |
}, | |
_decompileScope: function (scope, indent) { | |
var spell, type, temp, str, dScope = [], hScope = false, i = 0, j = 0, len = scope.length; | |
for (; i < len; i++, j++) { | |
spell = scope[i]; | |
type = spell[0] & 0xFF; | |
if (type === 0xFF) { | |
hScope = true; | |
temp = this._decompileScope(spell[1], indent + ' '); | |
if (temp[1]) { | |
str = ((spell[0] & 0x100) ? '!(\n' : '(\n') + indent + ' ' + | |
temp[0].join('\n' + indent + ' ') + '\n' + indent + ')'; | |
if (j === 0) { | |
dScope[0] = str; | |
} else { | |
dScope[--j] += ' ' + str; | |
} | |
} else { | |
dScope[j] = ((spell[0] & 0x100) ? '!(' : '(') + temp[0].join(' ') + ')'; | |
} | |
} else { | |
dScope[j] = Spells.decompileSpell(type, spell[0] & 0x100, spell[1], spell[2]); | |
} | |
if (i !== len - 1) { | |
dScope[j] += (spell[0] & 0x200) ? ' &' : ' |'; | |
} | |
} | |
return [dScope, dScope.length > 2 || hScope]; | |
}, | |
_decompileSpells: function () { | |
var str, reps, oreps, data = this._data; | |
if (!data) { | |
this._read(false); | |
if (!(data = this._data)) { | |
return this._list = ''; | |
} | |
} | |
str = data[1] ? this._decompileScope(data[1], '')[0].join('\n') : ''; | |
reps = data[2]; | |
oreps = data[3]; | |
if (reps || oreps) { | |
if (str) { | |
str += '\n\n'; | |
} | |
reps && reps.forEach(function (rep) { | |
str += this._decompileRep(rep, false) + '\n'; | |
}.bind(this)); | |
oreps && oreps.forEach(function (orep) { | |
str += this._decompileRep(orep, true) + '\n'; | |
}.bind(this)); | |
str = str.substr(0, str.length - 1); | |
} | |
this._data = null; | |
return this._list = str; | |
}, | |
_decompileRep: function (rep, isOrep) { | |
return (isOrep ? '#outrep' : '#rep') + | |
(rep[0] ? '[' + rep[0] + (rep[1] ? ',' + (rep[1] === -1 ? '' : rep[1]) : '') + ']' : '') + | |
'(' + rep[2] + ',' + rep[3].replace(/\)/g, '\\)') + ')'; | |
}, | |
_optimizeReps: function (data) { | |
if (data) { | |
var nData = []; | |
data.forEach(function (temp) { | |
if (!temp[0] || (temp[0] === brd && (temp[1] === -1 ? !TNum : !temp[1] || temp[1] === TNum))) { | |
nData.push([temp[2], temp[3]]); | |
} | |
}); | |
return nData.length === 0 ? false : nData; | |
} | |
return false; | |
}, | |
_initReps: function (data) { | |
if (data) { | |
for (var i = data.length - 1; i >= 0; i--) { | |
data[i][0] = toRegExp(data[i][0], false); | |
} | |
} | |
return data; | |
}, | |
_init: function (spells, reps, outreps) { | |
this._spells = this._initSpells(spells); | |
this._sLength = spells && spells.length; | |
this._reps = this._initReps(reps); | |
this._outreps = this._initReps(outreps); | |
this.enable = !!this._spells; | |
this.haveReps = !!reps; | |
this.haveOutreps = !!outreps; | |
}, | |
_read: function (init) { | |
var spells, data; | |
try { | |
spells = JSON.parse(Cfg.spells); | |
data = JSON.parse(sesStorage['de-spells-' + brd + TNum]); | |
} catch(e) {} | |
if (data && spells && data[0] === spells[0]) { | |
this._data = spells; | |
if (init) { | |
this.hash = data[0]; | |
this._init(data[1], data[2], data[3]); | |
} | |
return; | |
} | |
if (!spells) { | |
spells = this.parseText('#wipe(samelines,samewords,longwords,numbers,whitespace)'); | |
} | |
if (init) { | |
this.update(spells, false, false); | |
} else { | |
this._data = spells; | |
} | |
}, | |
_asyncSpellComplete: function (interp) { | |
this.hasNumSpell |= interp.hasNumSpell; | |
this._asyncJobs--; | |
this.end(null); | |
}, | |
_asyncJobs: 0, | |
_completeFns: [], | |
_hasComplFns: false, | |
_data: null, | |
_list: '', | |
hash: 0, | |
hasNumSpell: false, | |
enable: false, | |
get list() { | |
return this._list || this._decompileSpells(); | |
}, | |
addCompleteFunc: function (Fn) { | |
this._completeFns.push(Fn); | |
this._hasComplFns = true; | |
}, | |
parseText: function (str) { | |
var codeGen = new SpellsCodegen(str), | |
data = codeGen.generate(); | |
if (codeGen.hasError) { | |
$alert(Lng.error[lang] + ': ' + codeGen.error, 'help-err-spell', false); | |
} else if (data) { | |
if (data[0] && Cfg.sortSpells) { | |
this.sort(data[0]); | |
} | |
return [Date.now(), data[0], data[1], data[2]]; | |
} | |
return null; | |
}, | |
sort: function (sp) { | |
// Wraps AND-spells with brackets for proper sorting | |
for (var i = 0, len = sp.length-1; i < len; i++) { | |
if (sp[i][0] > 0x200) { | |
var temp = [0xFF, []]; | |
do { | |
temp[1].push(sp.splice(i, 1)[0]); | |
len--; | |
} while (sp[i][0] > 0x200); | |
temp[1].push(sp.splice(i, 1)[0]); | |
sp.splice(i, 0, temp); | |
} | |
} | |
sp = sp.sort(); | |
for (var i = 0, len = sp.length-1; i < len; i++) { | |
// Removes duplicates and weaker spells | |
if (sp[i][0] === sp[i+1][0] && sp[i][1] <= sp[i+1][1] && sp[i][1] >= sp[i+1][1] && | |
(sp[i][2] === null || // Stronger spell with 3 parameters | |
sp[i][2] === undefined || // Equal spells with 2 parameters | |
(sp[i][2] <= sp[i+1][2] && sp[i][2] >= sp[i+1][2]))) | |
{ // Equal spells with 3 parameters | |
sp.splice(i+1, 1); | |
i--; | |
len--; | |
// Moves brackets to the end of the list | |
} else if (sp[i][0] === 0xFF) { | |
sp.push(sp.splice(i, 1)[0]); | |
i--; | |
len--; | |
} | |
} | |
}, | |
update: function (data, sync, isHide) { | |
var spells = data[1] ? this._optimizeSpells(data[1]) : false, | |
reps = this._optimizeReps(data[2]), | |
outreps = this._optimizeReps(data[3]); | |
saveCfg('spells', JSON.stringify(data)); | |
sesStorage['de-spells-' + brd + TNum] = JSON.stringify([data[0], spells, reps, outreps]); | |
this._data = data; | |
this._list = ''; | |
this.hash = data[0]; | |
if (sync) { | |
locStorage['__de-spells'] = JSON.stringify({ | |
'hide': (!!this.list && !!isHide), | |
'data': data | |
}); | |
locStorage.removeItem('__de-spells'); | |
} | |
this._init(spells, reps, outreps); | |
}, | |
setSpells: function (spells, sync) { | |
this.update(spells, sync, Cfg.hideBySpell); | |
if (Cfg.hideBySpell) { | |
for (var post = firstThr.op; post; post = post.next) { | |
this.check(post); | |
} | |
this.end(savePosts); | |
} else { | |
this.enable = false; | |
} | |
}, | |
disable: function (sync) { | |
this.enable = false; | |
this._list = ''; | |
this._data = null; | |
this.haveReps = this.haveOutreps = false; | |
saveCfg('hideBySpell', false); | |
}, | |
end: function (Fn) { | |
if (this._asyncJobs === 0) { | |
Fn && Fn(); | |
if (this._hasComplFns) { | |
for (var i = 0, len = this._completeFns.length; i < len; ++i) { | |
this._completeFns[i](); | |
} | |
this._completeFns = []; | |
this._hasComplFns = false; | |
} | |
} else if (Fn) { | |
this.addCompleteFunc(Fn); | |
} | |
}, | |
check: function (post) { | |
if (!this.enable) { | |
return 0; | |
} | |
var interp = new SpellsInterpreter(post, this._spells, this._sLength); | |
if (interp.run()) { | |
this.hasNumSpell |= interp.hasNumSpell; | |
return interp.postHidden ? 1 : 0; | |
} | |
interp.setEndFn(this._asyncSpellComplete.bind(this)); | |
this._asyncJobs++; | |
return 0; | |
}, | |
replace: function (txt) { | |
for (var i = 0, len = this._reps.length; i < len; i++) { | |
txt = txt.replace(this._reps[i][0], this._reps[i][1]); | |
} | |
return txt; | |
}, | |
outReplace: function (txt) { | |
for (var i = 0, len = this._outreps.length; i < len; i++) { | |
txt = txt.replace(this._outreps[i][0], this._outreps[i][1]); | |
} | |
return txt; | |
}, | |
addSpell: function (type, arg, scope, isNeg, spells) { | |
if (!spells) { | |
if (!this._data) { | |
this._read(false); | |
} | |
spells = this._data || [Date.now(), [], false, false]; | |
} | |
var idx, sScope = String(scope), | |
sArg = String(arg); | |
if (spells[1]) { | |
spells[1].some(scope && isNeg ? function (spell, i) { | |
var data; | |
if (spell[0] === 0xFF && ((data = spell[1]) instanceof Array) && data.length === 2 && | |
data[0][0] === 0x20C && data[1][0] === type && data[1][2] == null && | |
String(data[1][1]) === sArg && String(data[0][2]) === sScope) | |
{ | |
idx = i; | |
return true; | |
} | |
return (spell[0] & 0x200) !== 0; | |
} : function (spell, i) { | |
if (spell[0] === type && String(spell[1]) === sArg && String(spell[2]) === sScope) { | |
idx = i; | |
return true; | |
} | |
return (spell[0] & 0x200) !== 0; | |
}); | |
} else { | |
spells[1] = []; | |
} | |
if (typeof idx !== 'undefined') { | |
spells[1].splice(idx, 1); | |
} else if (scope && isNeg) { | |
spells[1].splice(0, 0, [0xFF, [[0x20C, '', scope], [type, arg, void 0]], void 0]); | |
} else { | |
spells[1].splice(0, 0, [type, arg, scope]); | |
} | |
this.update(spells, true, true); | |
idx = null; | |
} | |
}; | |
function SpellsCodegen(sList) { | |
this._line = 1; | |
this._col = 1; | |
this._sList = sList; | |
this.hasError = false; | |
} | |
SpellsCodegen.prototype = { | |
TYPE_UNKNOWN: 0, | |
TYPE_ANDOR: 1, | |
TYPE_NOT: 2, | |
TYPE_SPELL: 3, | |
TYPE_PARENTHESES: 4, | |
TYPE_REPLACER: 5, | |
generate: function () { | |
return this._sList ? this._generate(this._sList, false) : null; | |
}, | |
get error() { | |
if (!this.hasError) { | |
return ''; | |
} | |
return (this._errMsgArg ? this._errMsg.replace('%s', this._errMsgArg) : this._errMsg) + | |
Lng.seRow[lang] + this._line + Lng.seCol[lang] + this._col + ')'; | |
}, | |
_errMsg: '', | |
_errMsgArg: null, | |
_generate: function (sList, inParens) { | |
var res, name, i = 0, | |
len = sList.length, | |
spells = [], | |
reps = [], | |
outreps = [], | |
lastType = this.TYPE_UNKNOWN, | |
hasReps = false; | |
for (; i < len; i++, this._col++) { | |
switch (sList[i]) { | |
case '\n': | |
this._line++; | |
this._col = 0; | |
case '\r': | |
case ' ': continue; | |
case '#': | |
name = ''; | |
i++; | |
this._col++; | |
while ((sList[i] >= 'a' && sList[i] <= 'z') || (sList[i] >= 'A' && sList[i] <= 'Z')) { | |
name += sList[i].toLowerCase(); | |
i++; | |
this._col++; | |
} | |
if (name === 'rep' || name === 'outrep') { | |
if (!hasReps) { | |
if (inParens) { | |
this._col -= 1 + name.length; | |
this._setError(Lng.seRepsInParens[lang], '#' + name); | |
return null; | |
} | |
if (lastType === this.TYPE_ANDOR || lastType === this.TYPE_NOT) { | |
i -= 1 + name.length; | |
this._col -= 1 + name.length; | |
lookBack: | |
while (i >= 0) { | |
switch (sList[i]) { | |
case '\n': | |
case '\r': | |
case ' ': | |
i--; | |
this._col--; | |
break; | |
default: | |
break lookBack; | |
} | |
} | |
this._setError(Lng.seOpInReps[lang], sList[i]); | |
return null; | |
} | |
hasReps = true; | |
} | |
res = this._doRep(name, sList.substr(i)); | |
if (!res) { | |
return null; | |
} | |
if (name === 'rep') { | |
reps.push(res[1]); | |
} else { | |
outreps.push(res[1]); | |
} | |
i += res[0] - 1; | |
this._col += res[0] - 1; | |
lastType = this.TYPE_REPLACER; | |
} else { | |
if (lastType === this.TYPE_SPELL || lastType === this.TYPE_PARENTHESES) { | |
this._setError(Lng.seMissOp[lang], null); | |
return null; | |
} | |
res = this._doSpell(name, sList.substr(i), lastType === this.TYPE_NOT) | |
if (!res) { | |
return null; | |
} | |
i += res[0] - 1; | |
this._col += res[0] - 1; | |
spells.push(res[1]); | |
lastType = this.TYPE_SPELL; | |
} | |
break; | |
case '(': | |
if (hasReps) { | |
this._setError(Lng.seUnexpChar[lang], '('); | |
return null; | |
} | |
if (lastType === this.TYPE_SPELL || lastType === this.TYPE_PARENTHESES) { | |
this._setError(Lng.seMissOp[lang], null); | |
return null; | |
} | |
res = this._generate(sList.substr(i + 1), true); | |
if (!res) { | |
return null; | |
} | |
i += res[0] + 1; | |
spells.push([lastType === this.TYPE_NOT ? 0x1FF : 0xFF, res[1]]); | |
lastType = this.TYPE_PARENTHESES; | |
break; | |
case '|': | |
case '&': | |
if (hasReps) { | |
this._setError(Lng.seUnexpChar[lang], sList[i]); | |
return null; | |
} | |
if (lastType !== this.TYPE_SPELL && lastType !== this.TYPE_PARENTHESES) { | |
this._setError(Lng.seMissSpell[lang], null); | |
return null; | |
} | |
if (sList[i] === '&') { | |
spells[spells.length - 1][0] |= 0x200; | |
} | |
lastType = this.TYPE_ANDOR; | |
break; | |
case '!': | |
if (hasReps) { | |
this._setError(Lng.seUnexpChar[lang], '!'); | |
return null; | |
} | |
if (lastType !== this.TYPE_ANDOR && lastType !== this.TYPE_UNKNOWN) { | |
this._setError(Lng.seMissOp[lang], null); | |
return null; | |
} | |
lastType = this.TYPE_NOT; | |
break; | |
case ')': | |
if (hasReps) { | |
this._setError(Lng.seUnexpChar[lang], ')'); | |
return null; | |
} | |
if (lastType === this.TYPE_ANDOR || lastType === this.TYPE_NOT) { | |
this._setError(Lng.seMissSpell[lang], null); | |
return null; | |
} | |
if (inParens) { | |
return [i, spells]; | |
} | |
default: | |
this._setError(Lng.seUnexpChar[lang], sList[i]); | |
return null; | |
} | |
} | |
if (inParens) { | |
this._setError(Lng.seMissClBkt[lang], null); | |
return null; | |
} | |
if (lastType !== this.TYPE_SPELL && lastType !== this.TYPE_PARENTHESES && | |
lastType !== this.TYPE_REPLACER) | |
{ | |
this._setError(Lng.seMissSpell[lang], null); | |
return null; | |
} | |
if (reps.length === 0) { | |
reps = false; | |
} | |
if (outreps.length === 0) { | |
outreps = false; | |
} | |
return [spells, reps, outreps]; | |
}, | |
_getScope: function (str) { | |
var scope, m = str.match(/^\[([a-z0-9\/]+)(?:(,)|,(\s*[0-9]+))?\]/); | |
if (m) { | |
return [m[0].length, [m[1], m[3] ? m[3] : m[2] ? -1 : false]]; | |
} | |
return null; | |
}, | |
_getRegex: function (str, haveComma) { | |
var val, m = str.match(/^\((\/.*?[^\\]\/[igm]*)(?:\)|\s*(,))/); | |
if (m) { | |
if (haveComma !== !!m[2]) { | |
return null; | |
} | |
val = m[1]; | |
try { | |
toRegExp(val, true); | |
} catch(e) { | |
this._setError(Lng.seErrRegex[lang], val); | |
return null; | |
} | |
return [m[0].length, val]; | |
} | |
return null; | |
}, | |
_getText: function (str, haveBracket) { | |
var m = str.match(/^(\()?(.*?[^\\])\)/); | |
if (m) { | |
if (haveBracket !== !!m[1]) { | |
return null; | |
} | |
return [m[0].length, m[2].replace(/\\\)/g, ')')]; | |
} | |
return null; | |
}, | |
_doRep: function (name, str) { | |
var regex, val, scope = this._getScope(str); | |
if (scope) { | |
str = str.substring(scope[0]); | |
} else { | |
scope = [0, ['', '']]; | |
} | |
regex = this._getRegex(str, true); | |
if (regex) { | |
str = str.substring(regex[0]); | |
if (str[0] === ')') { | |
return [regex[0] + scope[0] + 1, [scope[1][0], scope[1][1], regex[1], '']]; | |
} | |
val = this._getText(str, false); | |
if (val) { | |
return [val[0] + regex[0] + scope[0], [scope[1][0], scope[1][1], regex[1], val[1]]]; | |
} | |
} | |
this._setError(Lng.seSyntaxErr[lang], name); | |
return null; | |
}, | |
_doSpell: function (name, str, isNeg) { | |
var scope, m, spellType, val, temp, i = 0, | |
scope = null, | |
spellIdx = Spells.names.indexOf(name); | |
if (spellIdx === -1) { | |
this._setError(Lng.seUnknown[lang], name); | |
return null; | |
} | |
temp = this._getScope(str); | |
if (temp) { | |
i += temp[0]; | |
str = str.substring(temp[0]); | |
scope = temp[1]; | |
} | |
spellType = isNeg ? spellIdx | 0x100 : spellIdx; | |
if (str[0] !== '(' || str[1] === ')') { | |
if (Spells.needArg[spellIdx]) { | |
this._setError(Lng.seMissArg[lang], name); | |
return null; | |
} | |
return [str[0] === '(' ? i + 2 : i, [spellType, spellIdx === 14 ? 0x3F : '', scope]]; | |
} | |
switch (spellIdx) { | |
// #ihash | |
case 4: | |
m = str.match(/^\((\d+)\)/); | |
if (+m[1] === +m[1]) { | |
return [i + m[0].length, [spellType, +m[1], scope]]; | |
} | |
break; | |
// #img | |
case 8: | |
m = str.match(/^\(([><=])(?:(\d+(?:\.\d+)?)(?:-(\d+(?:\.\d+)?))?)?(?:@(\d+)(?:-(\d+))?x(\d+)(?:-(\d+))?)?\)/); | |
if (m && (m[2] || m[4])) { | |
return [i + m[0].length, [spellType, [ | |
m[1] === '=' ? 0 : m[1] === '<' ? 1 : 2, | |
m[2] && [+m[2], m[3] ? +m[3] : +m[2]], | |
m[4] && [+m[4], m[5] ? +m[5] : +m[4], +m[6], m[7] ? +m[7] : +m[6]] | |
], scope]]; | |
} | |
break; | |
// #wipe | |
case 14: | |
m = str.match(/^\(([a-z, ]+)\)/); | |
if (m) { | |
val = m[1].split(/, */).reduce(function (val, str) { | |
switch (str) { | |
case 'samelines': return val |= 1; | |
case 'samewords': return val |= 2; | |
case 'longwords': return val |= 4; | |
case 'symbols': return val |= 8; | |
case 'capslock': return val |= 16; | |
case 'numbers': return val |= 32; | |
case 'whitespace': return val |= 64; | |
default: return -1; | |
} | |
}, 0); | |
if (val !== -1) { | |
return [i + m[0].length, [spellType, val, scope]]; | |
} | |
} | |
break; | |
// #tlen, #num | |
case 11: | |
case 15: | |
m = str.match(/^\(([\d-, ]+)\)/); | |
if (m) { | |
m[1].split(/, */).forEach(function (v) { | |
if (v.contains('-')) { | |
var nums = v.split('-'); | |
nums[0] = +nums[0]; | |
nums[1] = +nums[1]; | |
this[1].push(nums); | |
} else { | |
this[0].push(+v); | |
} | |
}, val = [[], []]); | |
return [i + m[0].length, [spellType, val, scope]]; | |
} | |
break; | |
// #exp, #exph, #imgn, #subj, #video | |
case 1: | |
case 2: | |
case 3: | |
case 5: | |
case 13: | |
temp = this._getRegex(str, false); | |
if (temp) { | |
return [i + temp[0], [spellType, temp[1], scope]]; | |
} | |
break; | |
// #sage, #op, #all, #trip, #name, #words, #vauthor | |
default: | |
temp = this._getText(str, true); | |
if (temp) { | |
return [i + temp[0], [spellType, spellIdx === 0 ? temp[1].toLowerCase() : temp[1], scope]]; | |
} | |
} | |
this._setError(Lng.seSyntaxErr[lang], name); | |
return null; | |
}, | |
_setError: function (msg, arg) { | |
this.hasError = true; | |
this._errMsg = msg; | |
this._errMsgArg = arg; | |
} | |
}; | |
function SpellsInterpreter(post, spells, length) { | |
this._post = post; | |
this._ctx = [length, spells, 0]; | |
this._deep = 0; | |
} | |
SpellsInterpreter.prototype = { | |
hasNumSpell: false, | |
postHidden: false, | |
run: function () { | |
var rv, type, val, i = this._ctx.pop(), | |
scope = this._ctx.pop(), | |
len = this._ctx.pop(); | |
while (true) { | |
if (i < len) { | |
type = scope[i][0] & 0xFF; | |
if (type === 0xFF) { | |
this._deep++; | |
this._ctx.push(len, scope, i); | |
scope = scope[i][1]; | |
len = scope.length; | |
i = 0; | |
continue; | |
} | |
val = this._runSpell(type, scope[i][1]); | |
if (this._asyncWait) { | |
this._ctx.push(len, scope, i, scope[i][0]); | |
return false; | |
} | |
rv = this._checkRes(scope[i][0], val); | |
if (rv === null) { | |
i++; | |
continue; | |
} | |
this._lastSpellIdx = i; | |
} else { | |
this._lastSpellIdx = i -= 1; | |
rv = false; | |
} | |
if (this._deep !== 0) { | |
this._deep--; | |
i = this._ctx.pop(); | |
scope = this._ctx.pop(); | |
len = this._ctx.pop(); | |
rv = this._checkRes(scope[i][0], rv); | |
if (rv === null) { | |
i++; | |
continue; | |
} | |
} | |
if (rv) { | |
this._post.spellHide(this._getMsg(scope[i])); | |
this.postHidden = true; | |
} else if (!this._post.deleted) { | |
sVis[this._post.count] = 1; | |
} | |
return true; | |
} | |
}, | |
setEndFn: function (Fn) { | |
this._endFn = Fn; | |
}, | |
_asyncWait: false, | |
_endFn: null, | |
_lastSpellIdx: 0, | |
_wipeMsg: '', | |
_asyncContinue: function (val) { | |
this._asyncWait = false; | |
var temp, rv = this._checkRes(this._ctx.pop(), val); | |
if (rv === null) { | |
if (!this.run()) { | |
return; | |
} | |
} else if (rv) { | |
temp = this._ctx.pop(); | |
this._post.spellHide(this._getMsg(this._ctx.pop()[temp - 1])); | |
this.postHidden = true; | |
} else if (!this._post.deleted) { | |
sVis[this._post.count] = 1; | |
} | |
if (this._endFn) { | |
this._endFn(this); | |
} | |
}, | |
_checkRes: function (flags, val) { | |
if ((flags & 0x100) !== 0) { | |
val = !val; | |
} | |
if ((flags & 0x200) !== 0) { | |
if (!val) { | |
return false; | |
} | |
} else if (val) { | |
return true; | |
} | |
return null; | |
}, | |
_getMsg: function (spell) { | |
var neg = spell[0] & 0x100, | |
type = spell[0] & 0xFF, | |
val = spell[1]; | |
if (type === 0xFF) { | |
return this._getMsg(val[this._lastSpellIdx]); | |
} | |
if (type === 14) { | |
return (neg ? '!#wipe' : '#wipe') + (Spells._lastWipeMsg ? ': ' + Spells._lastWipeMsg : ''); | |
} else { | |
return Spells.decompileSpell(type, neg, val, spell[2]); | |
} | |
}, | |
_runSpell: function (spellId, val) { | |
switch (spellId) { | |
case 0: return this._words(val); | |
case 1: return this._exp(val); | |
case 2: return this._exph(val); | |
case 3: return this._imgn(val); | |
case 4: return this._ihash(val); | |
case 5: return this._subj(val); | |
case 6: return this._name(val); | |
case 7: return this._trip(val); | |
case 8: return this._img(val); | |
case 9: return this._sage(val); | |
case 10: return this._op(val); | |
case 11: return this._tlen(val); | |
case 12: return this._all(val); | |
case 13: return this._video(val); | |
case 14: return this._wipe(val); | |
case 15: | |
this.hasNumSpell = true; | |
return this._num(val); | |
case 16: return this._vauthor(val); | |
} | |
}, | |
_words: function (val) { | |
return this._post.text.toLowerCase().contains(val) || this._post.subj.toLowerCase().contains(val); | |
}, | |
_exp: function (val) { | |
return val.test(this._post.text); | |
}, | |
_exph: function (val) { | |
return val.test(this._post.html); | |
}, | |
_imgn: function (val) { | |
for (var i = 0, imgs = this._post.images, len = imgs.length; i < len; ++i) { | |
if (val.test(imgs[i].info)) { | |
return true; | |
} | |
} | |
return false; | |
}, | |
_ihash: function (val) { | |
for (var i = 0, imgs = this._post.images, len = imgs.length; i < len; ++i) { | |
if (imgs[i].hash === val) { | |
return true; | |
} | |
} | |
if (this._post.hashImgsBusy === 0) { | |
return false; | |
} | |
this._post.hashHideFun = this._ihash_helper.bind(this, val); | |
this._asyncWait = true; | |
return false; | |
}, | |
_ihash_helper: function (val, hash) { | |
if (val === hash) { | |
this._post.hashHideFun = null; | |
this._asyncContinue(true); | |
} else if (this._post.hashImgsBusy === 0) { | |
this.hashHideFun = null; | |
this._asyncContinue(false); | |
} | |
}, | |
_subj: function (val) { | |
var pSubj = this._post.subj; | |
return pSubj ? !val || val.test(pSubj) : false; | |
}, | |
_name: function (val) { | |
var pName = this._post.posterName; | |
return pName ? !val || pName.contains(val) : false; | |
}, | |
_trip: function (val) { | |
var pTrip = this._post.posterTrip; | |
return pTrip ? !val || pTrip.contains(val) : false; | |
}, | |
_img: function (val) { | |
var temp, w, h, hide, img, i, imgs = this._post.images, | |
len = imgs.length; | |
if (!val) { | |
return len !== 0; | |
} | |
for (i = 0; i < len; ++i) { | |
img = imgs[i]; | |
if (temp = val[1]) { | |
w = img.weight; | |
switch (val[0]) { | |
case 0: hide = w >= temp[0] && w <= temp[1]; break; | |
case 1: hide = w < temp[0]; break; | |
case 2: hide = w > temp[0]; | |
} | |
if (!hide) { | |
continue; | |
} else if (!val[2]) { | |
return true; | |
} | |
} | |
if (temp = val[2]) { | |
w = img.width; | |
h = img.height; | |
switch (val[0]) { | |
case 0: | |
if (w >= temp[0] && w <= temp[1] && h >= temp[2] && h <= temp[3]) { | |
return true | |
} | |
break; | |
case 1: | |
if (w < temp[0] && h < temp[3]) { | |
return true | |
} | |
break; | |
case 2: | |
if (w > temp[0] && h > temp[3]) { | |
return true | |
} | |
} | |
} | |
} | |
return false; | |
}, | |
_sage: function (val) { | |
return this._post.sage; | |
}, | |
_op: function (val) { | |
return this._post.isOp; | |
}, | |
_tlen: function (val) { | |
var text = this._post.text; | |
return !val ? !!text : this._tlenNum_helper(val, text.replace(/\n/g, '').length); | |
}, | |
_all: function (val) { | |
return true; | |
}, | |
_video: function (val) { | |
return this._videoVauthor(val, false); | |
}, | |
_wipe: function (val) { | |
var arr, len, i, j, n, x, keys, pop, capsw, casew, _txt, txt = this._post.text; | |
// (1 << 0): samelines | |
if (val & 1) { | |
arr = txt.replace(/>/g, '').split(/\s*\n\s*/); | |
if ((len = arr.length) > 5) { | |
arr.sort(); | |
for (i = 0, n = len / 4; i < len;) { | |
x = arr[i]; | |
j = 0; | |
while (arr[i++] === x) { | |
j++; | |
} | |
if (j > 4 && j > n && x) { | |
this._wipeMsg = 'same lines: "' + x.substr(0, 20) + '" x' + (j + 1); | |
return true; | |
} | |
} | |
} | |
} | |
// (1 << 1): samewords | |
if (val & 2) { | |
arr = txt.replace(/[\s\.\?\!,>]+/g, ' ').toUpperCase().split(' '); | |
if ((len = arr.length) > 3) { | |
arr.sort(); | |
for (i = 0, n = len / 4, keys = 0, pop = 0; i < len; keys++) { | |
x = arr[i]; | |
j = 0; | |
while (arr[i++] === x) { | |
j++; | |
} | |
if (len > 25) { | |
if (j > pop && x.length > 2) { | |
pop = j; | |
} | |
if (pop >= n) { | |
this._wipeMsg = 'same words: "' + x.substr(0, 20) + '" x' + (pop + 1); | |
return true; | |
} | |
} | |
} | |
x = keys / len; | |
if (x < 0.25) { | |
this._wipeMsg = 'uniq words: ' + (x * 100).toFixed(0) + '%'; | |
return true; | |
} | |
} | |
} | |
// (1 << 2): longwords | |
if (val & 4) { | |
arr = txt.replace(/https*:\/\/.*?(\s|$)/g, '').replace(/[\s\.\?!,>:;-]+/g, ' ').split(' '); | |
if (arr[0].length > 50 || ((len = arr.length) > 1 && arr.join('').length / len > 10)) { | |
this._wipeMsg = 'long words'; | |
return true; | |
} | |
} | |
// (1 << 3): symbols | |
if (val & 8) { | |
_txt = txt.replace(/\s+/g, ''); | |
if ((len = _txt.length) > 30 && | |
(x = _txt.replace(/[0-9a-zа-я\.\?!,]/ig, '').length / len) > 0.4) | |
{ | |
this._wipeMsg = 'specsymbols: ' + (x * 100).toFixed(0) + '%'; | |
return true; | |
} | |
} | |
// (1 << 4): capslock | |
if (val & 16) { | |
arr = txt.replace(/[\s\.\?!;,-]+/g, ' ').trim().split(' '); | |
if ((len = arr.length) > 4) { | |
for (i = 0, n = 0, capsw = 0, casew = 0; i < len; i++) { | |
x = arr[i]; | |
if ((x.match(/[a-zа-я]/ig) || []).length < 5) { | |
continue; | |
} | |
if ((x.match(/[A-ZА-Я]/g) || []).length > 2) { | |
casew++; | |
} | |
if (x === x.toUpperCase()) { | |
capsw++; | |
} | |
n++; | |
} | |
if (capsw / n >= 0.3 && n > 4) { | |
this._wipeMsg = 'CAPSLOCK: ' + capsw / arr.length * 100 + '%'; | |
return true; | |
} else if (casew / n >= 0.3 && n > 8) { | |
this._wipeMsg = 'cAsE words: ' + casew / arr.length * 100 + '%'; | |
return true; | |
} | |
} | |
} | |
// (1 << 5): numbers | |
if (val & 32) { | |
_txt = txt.replace(/\s+/g, ' ').replace(/>>\d+|https*:\/\/.*?(?: |$)/g, ''); | |
if ((len = _txt.length) > 30 && (x = (len - _txt.replace(/\d/g, '').length) / len) > 0.4) { | |
this._wipeMsg = 'numbers: ' + Math.round(x * 100) + '%'; | |
return true; | |
} | |
} | |
// (1 << 5): whitespace | |
if (val & 64) { | |
if (/(?:\n\s*){5}/i.test(txt)) { | |
this._wipeMsg = 'whitespace'; | |
return true; | |
} | |
} | |
return false; | |
}, | |
_num: function (val) { | |
return this._tlenNum_helper(val, this._post.count + 1); | |
}, | |
_tlenNum_helper: function (val, num) { | |
var i, arr; | |
for (arr = val[0], i = arr.length - 1; i >= 0; --i) { | |
if (arr[i] === num) { | |
return true; | |
} | |
} | |
for (arr = val[1], i = arr.length - 1; i >= 0; --i) { | |
if (num >= arr[i][0] && num <= arr[i][1]) { | |
return true; | |
} | |
} | |
return false; | |
}, | |
_vauthor: function (val) { | |
return this._videoVauthor(val, true); | |
}, | |
_videoVauthor: function (val, isAuthorSpell) { | |
if (!val) { | |
return !!this._post.hasYTube; | |
} | |
if (!this._post.hasYTube || !Cfg.YTubeTitles) { | |
return false; | |
} | |
var i, data, len; | |
for (i = 0, data = this._post.ytData, len = data.length; i < len; ++i) { | |
if (isAuthorSpell ? val === data[i][1] : val.test(data[i][0])) { | |
return true; | |
} | |
} | |
if (this._post.ytLinksLoading === 0) { | |
return false; | |
} | |
this._post.ytHideFun = this._videoVauthor_helper.bind(this, isAuthorSpell, val); | |
this._asyncWait = true; | |
return false; | |
}, | |
_videoVauthor_helper: function (isAuthorSpell, val, data) { | |
if (isAuthorSpell ? val === data[1] : val.test(data[0])) { | |
this._post.ytHideFun = null; | |
this._asyncContinue(true); | |
} else if (this._post.ytLinksLoading === 0) { | |
this._post.ytHideFun = null; | |
this._asyncContinue(false); | |
} | |
} | |
} | |
function disableSpells() { | |
closeAlert($id('de-alert-help-err-spell')); | |
if (spells.enable) { | |
sVis = TNum ? '1'.repeat(firstThr.pcount).split('') : []; | |
for (var post = firstThr.op; post; post = post.next) { | |
if (post.spellHidden && !post.userToggled) { | |
post.spellUnhide(); | |
} | |
} | |
} | |
} | |
function toggleSpells() { | |
var temp, fld = $id('de-spell-edit'), | |
val = fld.value; | |
if (val && (temp = spells.parseText(val))) { | |
disableSpells(); | |
spells.setSpells(temp, true); | |
fld.value = spells.list; | |
} else { | |
if (val) { | |
locStorage['__de-spells'] = '{"hide": false, "data": null}'; | |
} else { | |
disableSpells(); | |
spells.disable(); | |
saveCfg('spells', ''); | |
locStorage['__de-spells'] = '{"hide": false, "data": ""}'; | |
} | |
locStorage.removeItem('__de-spells'); | |
$q('input[info="hideBySpell"]', doc).checked = spells.enable = false; | |
} | |
} | |
function addSpell(type, arg, isNeg) { | |
var temp, fld = $id('de-spell-edit'), | |
val = fld && fld.value, | |
chk = $q('input[info="hideBySpell"]', doc); | |
if (!val || (temp = spells.parseText(val))) { | |
disableSpells(); | |
spells.addSpell(type, arg, TNum ? [brd, TNum] : null, isNeg, temp); | |
val = spells.list; | |
saveCfg('hideBySpell', !!val); | |
if (val) { | |
for (var post = firstThr.op; post; post = post.next) { | |
spells.check(post); | |
} | |
spells.end(savePosts); | |
} else { | |
saveCfg('spells', ''); | |
spells.enable = false; | |
} | |
if (fld) { | |
chk.checked = !!(fld.value = val); | |
} | |
return; | |
} | |
spells.enable = false; | |
if (chk) { | |
chk.checked = false; | |
} | |
} | |
// POSTFORM | |
// =========================================================================================================== | |
function PostForm(form, ignoreForm, init, dc) { | |
this.oeForm = $q('form[name="oeform"], form[action*="paint"]', dc); | |
if (!ignoreForm && !form) { | |
if (this.oeForm) { | |
ajaxLoad(aib.getThrdUrl(brd, aib.getTNum(dForm)), false, function (dc, xhr) { | |
pr = new PostForm($q(aib.qPostForm, dc), true, init, dc); | |
}, function (eCode, eMsg, xhr) { | |
pr = new PostForm(null, true, init, dc); | |
}); | |
} else { | |
this.form = null; | |
} | |
return; | |
} | |
function $x(path, root) { | |
return dc.evaluate(path, root, null, 8, null).singleNodeValue; | |
} | |
var p = './/tr[not(contains(@style,"none"))]//input[not(@type="hidden") and '; | |
this.tNum = TNum; | |
this.form = form; | |
this.cap = $q('input[type="text"][name*="aptcha"], div[id*="captcha"]', form); | |
this.txta = $q('tr:not([style*="none"]) textarea:not([style*="display:none"])', form); | |
this.subm = $q('tr input[type="submit"]', form); | |
this.file = $q('tr input[type="file"]', form); | |
if (this.file) { | |
this.fileTd = $parent(this.file, 'TD'); | |
} | |
this.passw = $q('tr input[type="password"]', form); | |
this.dpass = $q('input[type="password"], input[name="password"]', dForm); | |
this.name = $x(p + '(@name="field1" or @name="name" or @name="internal_n" or @name="nya1" or @name="akane")]', form); | |
this.mail = $x(p + ( | |
aib._410 ? '@name="sage"]' : | |
'(@name="field2" or @name="em" or @name="sage" or @name="email" or @name="nabiki" or @name="dont_bump")]' | |
), form); | |
this.subj = $x(p + '(@name="field3" or @name="sub" or @name="subject" or @name="internal_s" or @name="nya3" or @name="kasumi")]', form); | |
this.video = $q('tr input[name="video"], tr input[name="embed"]', form); | |
this.gothr = aib.qPostRedir && (p = $q(aib.qPostRedir, form)) && $parent(p, 'TR'); | |
if (init) { | |
this._init(); | |
} | |
} | |
PostForm.setUserName = function () { | |
var el = $q('input[info="nameValue"]', doc); | |
if (el) { | |
saveCfg('nameValue', el.value); | |
} | |
pr.name.value = Cfg.userName ? Cfg.nameValue : ''; | |
}; | |
PostForm.setUserPassw = function () { | |
var el = $q('input[info="passwValue"]', doc); | |
if (el) { | |
saveCfg('passwValue', el.value); | |
} | |
(pr.dpass || {}).value = pr.passw.value = Cfg.passwValue; | |
}; | |
PostForm.prototype = { | |
fileObj: null, | |
isHidden: false, | |
isQuick: false, | |
isTopForm: false, | |
lastQuickPNum: -1, | |
pForm: null, | |
pArea: [], | |
qArea: null, | |
get fileImageTD() { | |
var val = $t(aib.tiny ? 'th' : 'td', $parent(this.txta, 'TR')); | |
val.innerHTML = ''; | |
Object.defineProperty(this, 'fileImageTD', { value: val }); | |
return val; | |
}, | |
get rarInput() { | |
var val = doc.body.appendChild($new('input', {'type': 'file', 'style': 'display: none;'}, null)) | |
Object.defineProperty(this, 'rarInput', { value: val }); | |
return val; | |
}, | |
addTextPanel: function () { | |
var i, len, tag, html, btns, tPanel = $id('de-txt-panel'); | |
if (!Cfg.addTextBtns) { | |
$del(tPanel); | |
return; | |
} | |
if (!tPanel) { | |
tPanel = $new('span', {'id': 'de-txt-panel'}, { | |
'click': this, | |
'mouseover': this | |
}); | |
} | |
tPanel.style.cssFloat = Cfg.txtBtnsLoc ? 'none' : 'right'; | |
$after(Cfg.txtBtnsLoc ? $id('de-txt-resizer') || this.txta : | |
aib._420 ? $c('popup', this.form) : this.subm, tPanel); | |
for (html = '', i = 0, btns = aib.formButtons, len = btns.id.length; i < len; ++i) { | |
tag = btns.tag[i]; | |
if (tag === '') { | |
continue; | |
} | |
html += '<span id="de-btn-' + btns.id[i] + '" de-title="' + Lng.txtBtn[i][lang] + | |
'" de-tag="' + tag + '"' + (btns.bb[i] ? 'de-bb' : '') + '>' + ( | |
Cfg.addTextBtns === 2 ? | |
(i === 0 ? '[ ' : '') + '<a class="de-abtn" href="#">' + btns.val[i] + | |
'</a>' + (i === len - 1 ? ' ]' : ' / ') : | |
Cfg.addTextBtns === 3 ? | |
'<input type="button" value="' + btns.val[i] + '" style="font-weight: bold;">' : '' | |
) + '</span>'; | |
} | |
tPanel.innerHTML = html; | |
}, | |
delFilesUtils: function () { | |
for (var inp = this.fileObj; inp; inp = inp.next) { | |
inp.delUtils(); | |
} | |
}, | |
eventFiles: function (clear) { | |
var i, len, inp, els, el, last = null; | |
for (i = 0, els = $Q('input[type="file"]', this.fileTd), len = els.length; i < len; ++i) { | |
el = els[i]; | |
inp = el.obj; | |
if (inp) { | |
inp.prev = last; | |
if (last) { | |
last.next = inp; | |
} | |
last = inp; | |
} else { | |
el.obj = last = new FileInput(this, el, last); | |
last.init(false); | |
if (clear && el.files && el.files.length !== 0) { | |
last.clear(); | |
} | |
} | |
} | |
this.fileObj = els[0].obj; | |
}, | |
handleEvent: function (e) { | |
var x, start, end, scrtop, id, len, val, el = e.target; | |
if (el.tagName !== 'SPAN') { | |
el = el.parentNode; | |
} | |
id = el.id; | |
if (id.startsWith('de-btn')) { | |
if (e.type === 'mouseover') { | |
if (id === 'de-btn-quote') { | |
quotetxt = $txtSelect(); | |
} | |
x = -1; | |
if (hKeys) { | |
switch (id.substr(7)) { | |
case 'bold': x = 12; break; | |
case 'italic': x = 13; break; | |
case 'strike': x = 14; break; | |
case 'spoil': x = 15; break; | |
case 'code': x = 16; break; | |
} | |
} | |
KeyEditListener.setTitle(el, x); | |
return; | |
} | |
x = pr.txta; | |
start = x.selectionStart; | |
end = x.selectionEnd; | |
if (id === 'de-btn-quote') { | |
$txtInsert(x, '> ' + (start === end ? quotetxt : x.value.substring(start, end)) | |
.replace(/\n/gm, '\n> ')); | |
} else { | |
scrtop = x.scrollTop; | |
val = this._wrapText(el.hasAttribute('de-bb'), el.getAttribute('de-tag'), | |
x.value.substring(start, end)); | |
len = start + val[0]; | |
x.value = x.value.substr(0, start) + val[1] + x.value.substr(end); | |
x.setSelectionRange(len, len); | |
x.focus(); | |
x.scrollTop = scrtop; | |
} | |
$pd(e); | |
e.stopPropagation(); | |
} | |
}, | |
get isVisible() { | |
if (!this.isHidden && this.isTopForm && $q(':focus', this.pForm)) { | |
var cr = this.pForm.getBoundingClientRect(); | |
return cr.bottom > 0 && cr.top < window.innerHeight; | |
} | |
return false; | |
}, | |
get topCoord() { | |
return this.pForm.getBoundingClientRect().top; | |
}, | |
showQuickReply: function (post, pNum, closeReply, isNumClick) { | |
var temp, tNum = post.tNum; | |
if (!this.isQuick) { | |
this.isQuick = true; | |
this.setReply(true, false); | |
$t('a', this._pBtn[+this.isTopForm]).className = | |
'de-abtn de-parea-btn-' + (TNum ? 'reply' : 'thrd'); | |
if (!TNum && !aib.kus && !aib.dobr && !aib.mak) { | |
if (this.oeForm) { | |
$del($q('input[name="oek_parent"]', this.oeForm)); | |
this.oeForm.insertAdjacentHTML('afterbegin', '<input type="hidden" value="' + | |
tNum + '" name="oek_parent">'); | |
} | |
if (this.form) { | |
$del($q('#thr_id, input[name="parent"]', this.form)); | |
this.form.insertAdjacentHTML('afterbegin', | |
'<input type="hidden" id="thr_id" value="' + tNum + '" name="' + ( | |
aib.fch || aib.futa ? 'resto' : | |
aib.tiny ? 'thread' : | |
'parent' | |
) + '">' | |
); | |
} | |
} | |
} else if (closeReply && !quotetxt && post.wrap.nextElementSibling === this.qArea) { | |
this.closeQReply(); | |
return; | |
} | |
$after(post.wrap, this.qArea); | |
if (!TNum) { | |
this._toggleQuickReply(tNum); | |
} | |
if (!this.form) { | |
return; | |
} | |
if (this._lastCapUpdate && ((!TNum && this.tNum !== tNum) || (Date.now() - this._lastCapUpdate > 3e5))) { | |
this.tNum = tNum; | |
this.refreshCapImg(false); | |
} | |
this.tNum = tNum; | |
if (aib._420 && this.txta.value === 'Comment') { | |
this.txta.value = ''; | |
} | |
temp = this.txta.value; | |
if (!TNum && post.isOp && !isNumClick) { | |
this.txta.focus(); | |
} else { | |
$txtInsert(this.txta, ( | |
isNumClick ? '>>' + pNum : | |
(temp !== '' && temp.slice(-1) !== '\n' ? '\n' : '') + | |
(this.lastQuickPNum === pNum && temp.contains('>>' + pNum) ? '' : '>>' + pNum + '\n')) + | |
(quotetxt ? quotetxt.replace(/^\n|\n$/g, '').replace(/(^|\n)(.)/gm, '$1> $2') + '\n': '')); | |
} | |
temp = pByNum[pNum].thr.op.title; | |
if (temp.length > 30) { | |
temp = temp.substr(0, 30) + '\u2026'; | |
} | |
this.qArea.firstChild.firstChild.textContent = temp || '#' + pNum; | |
this.lastQuickPNum = pNum; | |
}, | |
showMainReply: function (isTop, evt) { | |
this.closeQReply(); | |
if (this.isTopForm === isTop) { | |
this.pForm.style.display = this.isHidden ? '' : 'none'; | |
this.isHidden = !this.isHidden; | |
this.updatePAreaBtns(); | |
} else { | |
this.isTopForm = isTop; | |
this.setReply(false, false); | |
} | |
if (evt) { | |
$pd(evt); | |
} | |
}, | |
closeQReply: function () { | |
if (this.isQuick) { | |
this.isQuick = false; | |
this.lastQuickPNum = -1; | |
if (!TNum) { | |
this._toggleQuickReply(0); | |
$del($id('thr_id')); | |
} | |
this.setReply(false, !TNum || Cfg.addPostForm > 1); | |
} | |
}, | |
refreshCapImg: function (focus) { | |
var src, img; | |
if (aib.abu && (img = $id('captcha_div')) && img.hasAttribute('onclick')) { | |
src = {'isCustom': true, 'focus': focus}; | |
img.dispatchEvent(new CustomEvent('click', { | |
'bubbles': true, | |
'cancelable': true, | |
'detail': (nav.Firefox ? cloneInto(src, document.defaultView) : src) | |
})); | |
return; | |
} | |
if (aib.mak) { | |
aib.updateCaptcha(focus); | |
} else { | |
if (!this.cap || (aib.krau && !$q('input[name="captcha_name"]', this.form).hasAttribute('value'))) { | |
return; | |
} | |
img = this.recap ? $id('recaptcha_image') : $t('img', this.capTr); | |
if (aib.dobr || aib.krau || aib.dvachnet || this.recap) { | |
img.click(); | |
} else if (img) { | |
src = img.getAttribute('src'); | |
if (aib.tire) { | |
src = '/' + brd + '/captcha.fpl?' + Math.random(); | |
} else if (aib.kus || aib.tinyIb) { | |
src = src.replace(/\?[^?]+$|$/, (aib._410 ? '?board=' + brd + '&' : '?') + Math.random()); | |
} else { | |
src = src.replace(/pl$/, 'pl?key=mainpage&dummy=') | |
.replace(/dummy=[\d\.]*/, 'dummy=' + Math.random()); | |
src = this.tNum ? src.replace(/mainpage|res\d+/, 'res' + this.tNum) : | |
src.replace(/res\d+/, 'mainpage'); | |
} | |
img.src = ''; | |
img.src = src; | |
} | |
} | |
this.cap.value = ''; | |
if (focus) { | |
this.cap.focus(); | |
} | |
if (this._lastCapUpdate) { | |
this._lastCapUpdate = Date.now(); | |
} | |
}, | |
setReply: function (quick, hide) { | |
if (quick) { | |
this.qArea.appendChild(this.pForm); | |
} else { | |
$after(this.pArea[+this.isTopForm], this.qArea); | |
$after(this._pBtn[+this.isTopForm], this.pForm); | |
} | |
this.isHidden = hide; | |
this.qArea.style.display = quick ? '' : 'none'; | |
this.pForm.style.display = hide ? 'none' : ''; | |
this.updatePAreaBtns(); | |
}, | |
updatePAreaBtns: function () { | |
var txt = 'de-abtn de-parea-btn-', | |
rep = TNum ? 'reply' : 'thrd'; | |
$t('a', this._pBtn[+this.isTopForm]).className = txt + (this.pForm.style.display === '' ? 'close' : rep); | |
$t('a', this._pBtn[+!this.isTopForm]).className = txt + rep; | |
}, | |
_lastCapUpdate: 0, | |
_pBtn: [], | |
_init: function () { | |
var btn, el; | |
this.pForm = $New('div', {'id': 'de-pform'}, [this.form, this.oeForm]); | |
dForm.insertAdjacentHTML('beforebegin', '<div class="de-parea"><div>[<a href="#"></a>]</div><hr></div>'); | |
this.pArea[0] = dForm.previousSibling; | |
this._pBtn[0] = this.pArea[0].firstChild; | |
this._pBtn[0].firstElementChild.onclick = this.showMainReply.bind(this, false); | |
el = aib.fch ? $c('board', dForm) : dForm; | |
el.insertAdjacentHTML('afterend', '<div class="de-parea"><div>[<a href="#"></a>]</div><hr></div>'); | |
this.pArea[1] = el.nextSibling; | |
this._pBtn[1] = this.pArea[1].firstChild; | |
this._pBtn[1].firstElementChild.onclick = this.showMainReply.bind(this, true); | |
this.qArea = $add('<div style="display: none;" id="de-qarea" class="' + aib.cReply + | |
(Cfg.hangQReply ? ' de-qarea-hanging' : ' de-qarea-inline') + '"></div>'); | |
this.isTopForm = Cfg.addPostForm !== 0; | |
this.setReply(false, !TNum || Cfg.addPostForm > 1); | |
el = this.qArea; | |
el.style.right = Cfg.qreplyRight + 'px'; | |
el.style.bottom = Cfg.qreplyBottom + 'px'; | |
el.lang = getThemeLang(); | |
el.insertAdjacentHTML('beforeend', | |
'<div' + (Cfg.hangQReply ? ' class="de-cfg-head"' : '') + '><span id="de-qarea-target"' + | |
(Cfg.hangQReply ? '': ' style="display: none;"') + '></span><span id="de-qarea-utils">' + | |
'<span id="de-qarea-toggle" title="' + Lng.toggleQReply[lang] + '">\u2750</span>' + | |
'<span id="de-qarea-close" title="' + Lng.closeQReply[lang] + '">\u2716</span></span></div>'); | |
el = el.firstChild; | |
el.addEventListener('mousedown', { | |
_el: this.qArea, | |
_elStyle: this.qArea.style, | |
_oldX: 0, | |
_oldY: 0, | |
handleEvent: function (e) { | |
if (!Cfg.hangQReply) { | |
return; | |
} | |
var right, bottom, curX = e.clientX, | |
curY = e.clientY; | |
switch (e.type) { | |
case 'mousedown': | |
this._oldX = curX; | |
this._oldY = curY; | |
doc.body.addEventListener('mousemove', this, false); | |
doc.body.addEventListener('mouseup', this, false); | |
$pd(e); | |
return; | |
case 'mousemove': | |
right = parseInt(this._elStyle.right, 10) - curX + this._oldX; | |
bottom = parseInt(this._elStyle.bottom, 10) - curY + this._oldY; | |
this._elStyle.right = (right < 0 ? 0 : | |
Math.min(right, Post.sizing.wWidth - this._el.offsetWidth)) + 'px'; | |
this._elStyle.bottom = (bottom < 25 ? 25 : | |
Math.min(bottom, Post.sizing.wHeight - this._el.offsetHeight)) + 'px'; | |
this._oldX = curX; | |
this._oldY = curY; | |
return; | |
default: // mouseup | |
doc.body.removeEventListener('mousemove', this, false); | |
doc.body.removeEventListener('mouseup', this, false); | |
saveCfg('qreplyRight', parseInt(this._elStyle.right, 10)); | |
saveCfg('qreplyBottom', parseInt(this._elStyle.bottom, 10)); | |
} | |
} | |
}, false); | |
el = el.lastChild; | |
el.firstChild.onclick = function() { | |
var node = this.qArea; | |
toggleCfg('hangQReply') | |
if (Cfg.hangQReply) { | |
node.className = aib.cReply + ' de-qarea-hanging'; | |
node = node.firstChild; | |
node.className = 'de-cfg-head'; | |
node.firstChild.style.display = ''; | |
} else { | |
node.className = aib.cReply + ' de-qarea-inline'; | |
node = node.firstChild; | |
node.removeAttribute('class'); | |
node.firstChild.style.display = 'none'; | |
this.txta.focus(); | |
} | |
}.bind(this); | |
el.lastChild.onclick = this.closeQReply.bind(this); | |
if (aib.tire) { | |
$each($Q('input[type="hidden"]', dForm), $del); | |
dForm.appendChild($c('userdelete', doc.body)); | |
this.dpass = $q('input[type="password"]', dForm); | |
} | |
if (!this.form || !this.txta) { | |
return; | |
} | |
aib.disableRedirection(this.form); | |
this.form.style.display = 'inline-block'; | |
this.form.style.textAlign = 'left'; | |
if (nav.Firefox) { | |
this.txta.addEventListener('mouseup', function () { | |
saveCfg('textaWidth', parseInt(this.style.width, 10)); | |
saveCfg('textaHeight', parseInt(this.style.height, 10)); | |
}, false); | |
} else { | |
this.txta.insertAdjacentHTML('afterend', '<div id="de-txt-resizer"></div>'); | |
this.txta.nextSibling.addEventListener('mousedown', { | |
el: this.txta, | |
elStyle: this.txta.style, | |
handleEvent: function (e) { | |
switch (e.type) { | |
case 'mousedown': | |
doc.body.addEventListener('mousemove', this, false); | |
doc.body.addEventListener('mouseup', this, false); | |
$pd(e); | |
return; | |
case 'mousemove': | |
var cr = this.el.getBoundingClientRect(); | |
this.elStyle.width = (e.pageX - cr.left - window.pageXOffset) + 'px'; | |
this.elStyle.height = (e.pageY - cr.top - window.pageYOffset) + 'px'; | |
return; | |
default: // mouseup | |
doc.body.removeEventListener('mousemove', this, false); | |
doc.body.removeEventListener('mouseup', this, false); | |
saveCfg('textaWidth', parseInt(this.elStyle.width, 10)); | |
saveCfg('textaHeight', parseInt(this.elStyle.height, 10)); | |
} | |
} | |
}, false); | |
} | |
if (aib.kus) { | |
while (this.subm.nextSibling) { | |
$del(this.subm.nextSibling); | |
} | |
} | |
if (Cfg.addSageBtn && this.mail) { | |
btn = $new('span', {'id': 'de-sagebtn'}, {'click': function (e) { | |
e.stopPropagation(); | |
$pd(e); | |
toggleCfg('sageReply'); | |
this._setSage(); | |
}.bind(this)}); | |
el = $parent(this.mail, 'LABEL') || this.mail; | |
if (el.nextElementSibling || el.previousElementSibling) { | |
el.style.display = 'none'; | |
$after(this.subm, btn); | |
} else { | |
$parent(this.mail, 'TR').style.display = 'none'; | |
$after(this.name || this.subm, btn); | |
} | |
setTimeout(this._setSage.bind(this), 0); | |
if (aib._2chru) { | |
while (btn.nextSibling) { | |
$del(btn.nextSibling); | |
} | |
} | |
} | |
this.addTextPanel(); | |
this.txta.style.cssText = 'display: inline-block; padding: 0; resize: both; width: ' + | |
Cfg.textaWidth + 'px; height: ' + Cfg.textaHeight + 'px; min-width: 0;'; | |
this.txta.addEventListener('keypress', function (e) { | |
var code = e.charCode || e.keyCode; | |
if ((code === 33 || code === 34) && e.which === 0) { | |
e.target.blur(); | |
window.focus(); | |
} | |
}, false); | |
if (!aib.tiny) { | |
this.subm.value = Lng.reply[lang]; | |
} | |
this.subm.addEventListener('click', function (e) { | |
var temp, val = this.txta.value; | |
if (aib._2chru && !aib.reqCaptcha) { | |
GM_xmlhttpRequest({ | |
'method': 'GET', | |
'url': '/' + brd + '/api/requires-captcha', | |
'onreadystatechange': function (xhr) { | |
if (xhr.readyState !== 4 || xhr.status !== 200) { | |
return; | |
} | |
aib.reqCaptcha = true; | |
if (JSON.parse(xhr.responseText)['requires-captcha'] !== '1') { | |
this.subm.click(); | |
return; | |
} | |
$id('captcha_tr').style.display = 'table-row'; | |
$id('captchaimage').src = '/' + brd + '/captcha?' + Math.random(); | |
$after(this.cap, $new('span', { | |
'class': 'shortened', | |
'style': 'margin: 0px 0.5em;', | |
'text': 'проверить капчу'}, { | |
'click': function () { GM_xmlhttpRequest({ | |
'method': 'POST', | |
'url': '/' + brd + '/api/validate-captcha', | |
'onreadystatechange': function (str) { | |
if (str.readyState === 4 && str.status === 200) { | |
if (JSON.parse(str.responseText).status === 'ok') { | |
this.innerHTML = 'можно постить'; | |
} else { | |
this.innerHTML = 'неверная капча'; | |
setTimeout(function (el) { | |
el.innerHTML = 'проверить капчу'; | |
}, 1000, this); | |
} | |
} | |
}.bind(this) | |
}) } | |
})) | |
}.bind(this) | |
}); | |
$pd(e); | |
return; | |
} | |
if (Cfg.warnSubjTrip && this.subj && /#.|##./.test(this.subj.value)) { | |
$pd(e); | |
$alert(Lng.subjHasTrip[lang], 'upload', false); | |
return; | |
} | |
if (spells.haveOutreps) { | |
val = spells.outReplace(val); | |
} | |
if (this.tNum && pByNum[this.tNum].subj === 'Dollchan Extension Tools') { | |
temp = '\n\n' + this._wrapText(aib.formButtons.bb[5], aib.formButtons.tag[5], | |
'-'.repeat(50) + '\n' + nav.ua + '\nv' + version + ' [' + nav.scriptInstall + ']')[1]; | |
if (!val.contains(temp)) { | |
val += temp; | |
} | |
} | |
this.txta.value = val; | |
if (Cfg.ajaxReply) { | |
$alert(Lng.checking[lang], 'upload', true); | |
} | |
if (Cfg.favOnReply && this.tNum) { | |
pByNum[this.tNum].thr.setFavorState(true); | |
} | |
if (this.video && (val = this.video.value) && (val = val.match(new YouTube().ytReg))) { | |
this.video.value = 'http://www.youtube.com/watch?v=' + val[1]; | |
} | |
if (this.isQuick) { | |
this.pForm.style.display = 'none'; | |
this.qArea.style.display = 'none'; | |
$after(this._pBtn[+this.isTopForm], this.pForm); | |
} | |
}.bind(this), false); | |
$each($Q('input[type="text"], input[type="file"]', this.form), function (node) { | |
node.size = 30; | |
}); | |
if (Cfg.noGoto && this.gothr) { | |
this.gothr.style.display = 'none'; | |
} | |
if (Cfg.noPassword && this.passw) { | |
$parent(this.passw, 'TR').style.display = 'none'; | |
} | |
window.addEventListener('load', function () { | |
if (Cfg.userName && this.name) { | |
setTimeout(PostForm.setUserName, 1e3); | |
} | |
if (this.passw) { | |
setTimeout(PostForm.setUserPassw, 1e3); | |
} | |
}.bind(this), false); | |
if (this.cap) { | |
if (!(aib.fch && doc.cookie.indexOf('pass_enabled=1') > -1)) { | |
this.capTr = $parent(this.cap, 'TR'); | |
this.txta.addEventListener('focus', this._captchaInit.bind(this, this.capTr.innerHTML), false); | |
if (this.file) { | |
this.file.addEventListener('click', this._captchaInit.bind(this, this.capTr.innerHTML), false); | |
} | |
if (!aib.krau) { | |
this.capTr.style.display = 'none'; | |
} | |
this.capTr.innerHTML = ''; | |
} | |
this.cap = null; | |
} | |
if (Cfg.ajaxReply === 2) { | |
if (aib.krau) { | |
this.form.removeAttribute('onsubmit'); | |
} | |
setTimeout(function () { | |
this.form.onsubmit = function (e) { | |
$pd(e); | |
if (aib.krau) { | |
aib.addProgressTrack.click(); | |
} | |
if (aib._2chru) { | |
doc.body.insertAdjacentHTML('beforeend', '<iframe class="ninja" id="csstest" src="/' + | |
brd + '/csstest.foo"></iframe>'); | |
doc.body.lastChild.onload = function (e) { | |
$del(e.target); | |
new html5Submit(this.form, this.subm, checkUpload); | |
}.bind(this); | |
return; | |
} | |
new html5Submit(this.form, this.subm, checkUpload); | |
}.bind(this); | |
}.bind(this), 0); | |
} else if (Cfg.ajaxReply === 1) { | |
this.form.target = 'de-iframe-pform'; | |
this.form.onsubmit = null; | |
} | |
if (el = this.file) { | |
aib.fixFileInputs(el); | |
this.eventFiles(true); | |
} | |
}, | |
_setSage: function () { | |
var c = Cfg.sageReply; | |
$id('de-sagebtn').innerHTML = ' ' + ( | |
c ? '<span class="de-btn-sage"></span><b style="color: red;">SAGE</b>' : | |
'<span>(no sage)</span>' | |
); | |
if (this.mail.type === 'text') { | |
this.mail.value = c ? 'sage' : aib.fch ? 'noko' : ''; | |
} else { | |
this.mail.checked = c; | |
} | |
}, | |
_toggleQuickReply: function (tNum) { | |
if (this.oeForm) { | |
$q('input[name="oek_parent"], input[name="replyto"]', this.oeForm).value = tNum; | |
} | |
if (this.form) { | |
$q('#thr_id, input[name*="thread"]', this.form).value = tNum; | |
if (aib.pony) { | |
$q('input[name="quickreply"]', this.form).value = tNum || ''; | |
} | |
} | |
}, | |
_captchaInit: function (html) { | |
if (this.capInited) { | |
return; | |
} | |
this.capTr.innerHTML = html; | |
this.cap = $q('input[type="text"][name*="aptcha"]:not([name="recaptcha_challenge_field"])', this.capTr); | |
if (aib.fch) { | |
$script('loadRecaptcha()'); | |
} | |
if (aib.tire) { | |
$script('show_captcha()'); | |
} | |
if (aib.krau) { | |
aib.initCaptcha.click(); | |
$id('captcha_image').setAttribute('onclick', 'requestCaptcha(true);'); | |
} | |
if (aib.dvachnet) { | |
$script('get_captcha()'); | |
} | |
if (aib.mak) { | |
aib.updateCaptcha(false); | |
pr.txta.tabIndex = 999; | |
this.capInited = true; | |
return; | |
} | |
setTimeout(this._captchaUpd.bind(this), 100); | |
}, | |
_captchaUpd: function () { | |
var img, a; | |
if ((this.recap = $id('recaptcha_response_field')) && (img = $id('recaptcha_image'))) { | |
this.cap = this.recap; | |
img.setAttribute('onclick', 'Recaptcha.reload()'); | |
img.style.cssText = 'width: 300px; cursor: pointer;'; | |
} else if (aib.fch) { | |
setTimeout(this._captchaUpd.bind(this), 100); | |
return; | |
} | |
this.capInited = true; | |
this.cap.autocomplete = 'off'; | |
this.cap.onkeypress = (function () { | |
var ru = 'йцукенгшщзхъфывапролджэячсмитьбюё', | |
en = 'qwertyuiop[]asdfghjkl;\'zxcvbnm,.`'; | |
return function (e) { | |
if (!Cfg.captchaLang || e.which === 0) { | |
return; | |
} | |
var i, code = e.charCode || e.keyCode, | |
chr = String.fromCharCode(code).toLowerCase(); | |
if (Cfg.captchaLang === 1) { | |
if (code < 0x0410 || code > 0x04FF || (i = ru.indexOf(chr)) === -1) { | |
return; | |
} | |
chr = en[i]; | |
} else { | |
if (code < 0x0021 || code > 0x007A || (i = en.indexOf(chr)) === -1) { | |
return; | |
} | |
chr = ru[i]; | |
} | |
$pd(e); | |
$txtInsert(e.target, chr); | |
}; | |
})(); | |
if (aib.krau) { | |
return; | |
} | |
if (aib.abu || aib.dobr || aib.dvachnet || this.recap || !(img = $q('img', this.capTr))) { | |
this.capTr.style.display = ''; | |
return; | |
} | |
if (!aib.kus && !aib.tinyIb) { | |
this._lastCapUpdate = Date.now(); | |
this.cap.onfocus = function () { | |
if (this._lastCapUpdate && (Date.now() - this._lastCapUpdate > 3e5)) { | |
this.refreshCapImg(false); | |
} | |
}.bind(this); | |
if (!TNum && this.isQuick) { | |
this.refreshCapImg(false); | |
} | |
} | |
img.title = Lng.refresh[lang]; | |
img.alt = Lng.loading[lang]; | |
img.style.cssText = 'vertical-align: bottom; border: none; cursor: pointer;'; | |
img.onclick = this.refreshCapImg.bind(this, true); | |
if ((a = img.parentNode).tagName === 'A') { | |
$after(a, img); | |
$del(a); | |
} | |
this.capTr.style.display = ''; | |
}, | |
_wrapText: function (isBB, tag, text) { | |
var str, m; | |
if (isBB) { | |
if (text.contains('\n')) { | |
str = '[' + tag + ']' + text + '[/' + tag + ']'; | |
return [str.length, str]; | |
} | |
m = text.match(/^(\s*)(.*?)(\s*)$/); | |
str = m[1] + '[' + tag + ']' + m[2] + '[/' + tag + ']' + m[3]; | |
return [m[2].length === 0 ? m[1].length + tag.length + 2 : str.length, str]; | |
} | |
for (var rv = '', i = 0, arr = text.split('\n'), len = arr.length; i < len; ++i) { | |
m = arr[i].match(/^(\s*)(.*?)(\s*)$/); | |
rv += '\n' + m[1] + (tag === '^H' ? m[2] + '^H'.repeat(m[2].length) : | |
tag + m[2] + tag) + m[3]; | |
} | |
return [i === 1 && m[2].length === 0 && tag !== '^H' ? m[1].length + tag.length : | |
rv.length - 1, rv.slice(1)]; | |
} | |
} | |
function FileInput(form, el, prev) { | |
this.el = el; | |
this.place = el.parentNode; | |
this.form = form; | |
this.prev = prev; | |
if (prev) { | |
prev.next = this; | |
} | |
} | |
FileInput.prototype = { | |
empty: true, | |
next: null, | |
imgFile: null, | |
thumb: null, | |
clear: function () { | |
var newEl, form = this.form, | |
oldEl = this.el; | |
oldEl.insertAdjacentHTML('afterend', oldEl.outerHTML); | |
newEl = this.el.nextSibling; | |
newEl.obj = this; | |
newEl.addEventListener('change', this, false); | |
if (form.file === oldEl) { | |
form.file = newEl; | |
} | |
this.el = newEl; | |
$del(oldEl); | |
this.empty = true; | |
this.hideInputs(); | |
}, | |
delUtils: function () { | |
var mParent; | |
if (Cfg.fileThumb) { | |
this.thumb.classList.add('de-file-off'); | |
if (this._mediaEl) { | |
window.URL.revokeObjectURL(this._mediaEl.src); | |
mParent = this._mediaEl.parentNode; | |
mParent.title = Lng.clickToAdd[lang]; | |
$del(this._mediaEl); | |
this._mediaEl = null; | |
} | |
} | |
$del(this._delUtil); | |
$del(this._rjUtil); | |
this.imgFile = this._delUtil = this._rjUtil = null; | |
this._changeFilesCount(-1); | |
this.clear(); | |
}, | |
updateUtils: function () { | |
this.init(true); | |
if (this._delUtil) { | |
$after(this._buttonsPlace, this._delUtil); | |
} | |
if (this._rjUtil) { | |
$after(this._buttonsPlace, this._rjUtil); | |
} | |
}, | |
handleEvent: function (e) { | |
switch (e.type) { | |
case 'change': this._onFileChange(); break; | |
case 'click': | |
if (e.target === this._delUtil) { | |
this.delUtils(); | |
} else if (e.target === this._rjUtil) { | |
this._addRarJpeg(); | |
} else if (e.target.className === 'de-file-img') { | |
this.el.click(); | |
} | |
e.stopPropagation(); | |
$pd(e); | |
break; | |
case 'dragover': | |
this.thumb.classList.add('de-file-drag'); | |
$after(this.thumb, this.el); | |
break; | |
case 'dragleave': | |
case 'drop': | |
setTimeout(function () { | |
this.thumb.classList.remove('de-file-drag'); | |
var el = this.place.firstChild; | |
if (el) { | |
$before(el, this.el); | |
} else { | |
this.place.appendChild(this.el); | |
} | |
}.bind(this), 10); | |
break; | |
case 'mouseover': this.thumb.classList.add('de-file-hover'); break; | |
case 'mouseout': this.thumb.classList.remove('de-file-hover'); | |
} | |
}, | |
hideInputs: function () { | |
var hideThumbs = Cfg.fileThumb, inp = this.next; | |
while (inp && inp.empty) { | |
inp = inp.next; | |
} | |
if (!inp) { | |
inp = this; | |
while (inp.prev && inp.prev.empty) { | |
inp = inp.prev; | |
} | |
while (inp = inp.next) { | |
if (hideThumbs) { | |
inp.thumb.style.display = 'none'; | |
} else { | |
inp._wrap.style.display = 'none'; | |
} | |
} | |
} | |
}, | |
init: function (update) { | |
var imgTD; | |
if (Cfg.fileThumb) { | |
this.form.fileTd.parentNode.style.display = 'none'; | |
imgTD = this.form.fileImageTD; | |
imgTD.insertAdjacentHTML('beforeend', '<div class="de-file de-file-off"><div class="de-file-img">' + | |
'<div class="de-file-img" title="' + Lng.clickToAdd[lang] + '"></div></div></div>'); | |
this.thumb = imgTD.lastChild; | |
this.thumb.addEventListener('mouseover', this, false); | |
this.thumb.addEventListener('mouseout', this, false); | |
this.thumb.addEventListener('click', this, false); | |
this.thumb.addEventListener('dragover', this, false); | |
this.el.addEventListener('dragleave', this, false); | |
this.el.addEventListener('drop', this, false); | |
if (update) { | |
this._showPviewImage(); | |
} else if (this.prev) { | |
this.thumb.style.display = 'none'; | |
} | |
} else if (update) { | |
this._wrap.style.display = ''; | |
this.form.fileTd.parentNode.style.display = ''; | |
if (this._mediaE) { | |
window.URL.revokeObjectURL(this._mediaE.src); | |
} | |
$del(this.thumb); | |
this.thumb = this._mediaEl = null; | |
} | |
if (!update) { | |
this.el.addEventListener('change', this, false); | |
} | |
}, | |
_mediaEl: null, | |
_delUtil: null, | |
_rjUtil: null, | |
get _buttonsPlace() { | |
return Cfg.fileThumb ? this.thumb.firstChild : this.el; | |
}, | |
get _wrap() { | |
return aib.getFileWrap(this.el); | |
}, | |
_addRarJpeg: function () { | |
var el = this.form.rarInput; | |
el.onchange = function (e) { | |
$del(this._rjUtil); | |
var file = e.target.files[0], | |
fr = new FileReader(), | |
btnsPlace = this._buttonsPlace; | |
btnsPlace.insertAdjacentHTML('afterend', | |
'<span><span class="de-wait"></span>' + Lng.wait[lang] + '</span>'); | |
this._rjUtil = btnsPlace.nextSibling; | |
fr.onload = function (file, node, e) { | |
if (this._buttonsPlace.nextSibling === node) { | |
node.className = 'de-file-rarmsg de-file-utils'; | |
node.title = this.el.files[0].name + ' + ' + file.name; | |
node.textContent = this.el.files[0].name.replace(/^.+\./, '') + ' + ' + | |
file.name.replace(/^.+\./, '') | |
this.imgFile = e.target.result; | |
} | |
}.bind(this, file, btnsPlace.nextSibling); | |
fr.readAsArrayBuffer(file); | |
}.bind(this); | |
el.click(); | |
}, | |
_changeFilesCount: function (val) { | |
if (aib.dobr) { | |
var el = this.form.fileTd.firstElementChild, | |
val = +el.value + val; | |
el.value = val < 1 ? 1 : val; | |
} | |
}, | |
_onFileChange: function () { | |
if (Cfg.fileThumb) { | |
this._showPviewImage(); | |
} else { | |
this.form.eventFiles(false); | |
} | |
if (this.empty) { | |
this.empty = false; | |
this._changeFilesCount(+1); | |
$after(this._buttonsPlace, this._delUtil = $new('span', { | |
'class': 'de-file-del de-file-utils', | |
'title': Lng.removeFile[lang]}, { | |
'click': this | |
})); | |
} else if (this.imgFile) { | |
this.imgFile = null; | |
} | |
if (this.next) { | |
if (Cfg.fileThumb) { | |
this.next.thumb.style.display = ''; | |
} else { | |
this.next._wrap.style.display = ''; | |
} | |
} | |
if (aib.fch || nav.Presto || !/^image\/(?:png|jpeg)$/.test(this.el.files[0].type)) { | |
return; | |
} | |
if (this._rjUtil) { | |
$del(this._rjUtil); | |
this._rjUtil = null; | |
} | |
$after(this._buttonsPlace, this._rjUtil = $new('span', { | |
'class': 'de-file-rar de-file-utils', | |
'title': Lng.helpAddFile[lang]}, { | |
'click': this | |
})); | |
}, | |
_showPviewImage: function () { | |
var fr, files = this.el.files; | |
if (files && files[0]) { | |
fr = new FileReader(); | |
fr.onload = function (e) { | |
this.form.eventFiles(false); | |
var file = this.el.files[0], | |
thumb = this.thumb; | |
if (this.empty) { | |
return; | |
} | |
thumb.classList.remove('de-file-off'); | |
thumb = thumb.firstChild.firstChild; | |
thumb.title = file.name + ', ' + (file.size/1024).toFixed(2) + 'KB'; | |
thumb.insertAdjacentHTML('afterbegin', file.type === 'video/webm' ? | |
'<video class="de-file-img" loop autoplay muted src=""></video>' : | |
'<img class="de-file-img" src="">'); | |
this._mediaEl = thumb = thumb.firstChild; | |
thumb.src = window.URL.createObjectURL(new Blob([e.target.result])); | |
thumb = thumb.nextSibling; | |
if (thumb) { | |
window.URL.revokeObjectURL(thumb.src); | |
$del(thumb); | |
} | |
}.bind(this); | |
fr.readAsArrayBuffer(files[0]); | |
} | |
} | |
} | |
// SUBMIT | |
// =========================================================================================================== | |
function getSubmitError(dc) { | |
var i, els, el, err = '', form = $q(aib.qDForm, dc); | |
if (dc.body.hasChildNodes() && !form) { | |
for (i = 0, els = $Q(aib.qError, dc); el = els[i++];) { | |
err += el.innerHTML + '\n'; | |
} | |
if (!(err = err.replace(/<a [^>]+>Назад.+|<br.+/, ''))) { | |
err = Lng.error[lang] + ':\n' + dc.body.innerHTML; | |
} | |
err = /:null|successful|uploaded|updating|обновл|удален[о\.]/i.test(err) ? '' : err.replace(/"/g, "'"); | |
} | |
return err; | |
} | |
function checkUpload(dc) { | |
if (aib.krau) { | |
pr.form.action = pr.form.action.split('?')[0]; | |
$id('postform_row_progress').style.display = 'none'; | |
aib.btnZeroLUTime.click(); | |
} | |
var el, err = getSubmitError(dc); | |
if (err) { | |
if (pr.isQuick) { | |
pr.setReply(true, false); | |
} | |
if (/captch|капч|подтвер|verifizie/i.test(err)) { | |
pr.refreshCapImg(true); | |
} | |
$alert(err, 'upload', false); | |
updater.sendErrNotif(); | |
return; | |
} | |
pr.txta.value = ''; | |
if (pr.file) { | |
pr.delFilesUtils(); | |
} | |
if (pr.video) { | |
pr.video.value = ''; | |
} | |
Cfg.stats[pr.tNum ? 'reply' : 'op']++; | |
saveComCfg(aib.dm, Cfg); | |
if (!pr.tNum) { | |
window.location = aib.getThrdUrl(brd, aib.getTNum($q(aib.qDForm, dc))); | |
return; | |
} | |
el = !aib.tiny && !aib.kus && | |
(aib.qPostRedir === null || $q(aib.qPostRedir, dc)) ? $q(aib.qDForm, dc) : null; | |
if (TNum) { | |
firstThr.clearPostsMarks(); | |
if (el) { | |
firstThr.loadNewFromForm(el); | |
closeAlert($id('de-alert-upload')); | |
if (Cfg.scrAfterRep) { | |
scrollTo(0, pageYOffset + firstThr.last.el.getBoundingClientRect().top); | |
} | |
} else { | |
firstThr.loadNew(function (eCode, eMsg, np, xhr) { | |
infoLoadErrors(eCode, eMsg, 0); | |
closeAlert($id('de-alert-upload')); | |
if (Cfg.scrAfterRep) { | |
scrollTo(0, pageYOffset + firstThr.last.el.getBoundingClientRect().top); | |
} | |
}, true); | |
} | |
} else { | |
if (el) { | |
pByNum[pr.tNum].thr.loadFromForm(visPosts, false, el); | |
closeAlert($id('de-alert-upload')); | |
} else { | |
pByNum[pr.tNum].thr.load(visPosts, false, closeAlert.bind(window, $id('de-alert-upload'))); | |
} | |
} | |
pr.closeQReply(); | |
pr.refreshCapImg(false); | |
} | |
function endDelete() { | |
var el = $id('de-alert-deleting'); | |
if (el) { | |
closeAlert(el); | |
$alert(Lng.succDeleted[lang], 'deleted', false); | |
} | |
} | |
function checkDelete(dc) { | |
var el, i, els, len, post, tNums, num, err = getSubmitError(dc); | |
if (err) { | |
$alert(Lng.errDelete[lang] + err, 'deleting', false); | |
updater.sendErrNotif(); | |
return; | |
} | |
tNums = []; | |
num = (doc.location.hash.match(/\d+/) || [null])[0]; | |
if (num && (post = pByNum[num])) { | |
if (!post.isOp) { | |
post.el.className = aib.cReply; | |
} | |
doc.location.hash = ''; | |
} | |
for (i = 0, els = $Q('.' + aib.cRPost + ' input:checked', dForm), len = els.length; i < len; ++i) { | |
el = els[i]; | |
el.checked = false; | |
if (!TNum && tNums.indexOf(num = aib.getPostEl(el).post.tNum) === -1) { | |
tNums.push(num); | |
} | |
} | |
if (TNum) { | |
firstThr.clearPostsMarks(); | |
firstThr.loadNew(function (eCode, eMsg, np, xhr) { | |
infoLoadErrors(eCode, eMsg, 0); | |
endDelete(); | |
}, false); | |
} else { | |
tNums.forEach(function (tNum) { | |
pByNum[tNum].thr.load(visPosts, false, endDelete); | |
}); | |
} | |
} | |
function html5Submit(form, button, fn) { | |
this.boundary = '---------------------------' + Math.round(Math.random() * 1e11); | |
this.data = []; | |
this.busy = 0; | |
this.error = false; | |
this.url = form.action; | |
this.fn = fn; | |
$each($Q('input:not([type="submit"]):not([type="button"]), textarea, select', form), | |
this.append.bind(this)); | |
this.append(button); | |
this.submit(); | |
} | |
html5Submit.prototype = { | |
append: function (el) { | |
var file, fName, idx, fr, | |
pre = '--' + this.boundary + '\r\nContent-Disposition: form-data; name="' + el.name + '"'; | |
if (el.type === 'file' && el.files.length > 0) { | |
file = el.files[0]; | |
fName = file.name; | |
this.data.push(pre + '; filename="' + ( | |
!Cfg.removeFName ? fName : ' ' + fName.substring(fName.lastIndexOf('.')) | |
) + '"\r\nContent-type: ' + file.type + '\r\n\r\n', null, '\r\n'); | |
idx = this.data.length - 2; | |
if (!/^image\/(?:png|jpeg)$|^video\/webm$/.test(file.type)) { | |
this.data[idx] = file; | |
return; | |
} | |
fr = new FileReader(); | |
fr.onload = function (name, e) { | |
var dat = this.clearImage(e.target.result, el.obj.imgFile, | |
Cfg.postSameImg && String(Math.round(Math.random() * 1e6))); | |
if (dat) { | |
this.data[idx] = new Blob(dat); | |
this.busy--; | |
this.submit(); | |
} else { | |
this.error = true; | |
$alert(Lng.fileCorrupt[lang] + name, 'upload', false); | |
} | |
}.bind(this, fName); | |
fr.readAsArrayBuffer(file); | |
this.busy++; | |
} else if ((el.type !== 'checkbox' && el.type !== 'radio') || el.checked) { | |
this.data.push(pre + '\r\n\r\n' + el.value + '\r\n'); | |
} | |
}, | |
submit: function () { | |
if (this.error || this.busy !== 0) { | |
return; | |
} | |
this.data.push('--' + this.boundary + '--\r\n'); | |
$xhr({ | |
'method': 'POST', | |
'headers': {'Content-type': 'multipart/form-data; boundary=' + this.boundary}, | |
'data': new Blob(this.data), | |
'url': nav.fixLink(this.url), | |
'onreadystatechange': function (xhr) { | |
if (xhr.readyState === 4) { | |
if (xhr.status === 200) { | |
this($DOM(xhr.responseText)); | |
} else { | |
$alert(xhr.status === 0 ? Lng.noConnect[lang] : | |
'HTTP [' + xhr.status + '] ' + xhr.statusText, 'upload', false); | |
} | |
} | |
}.bind(this.fn) | |
}); | |
}, | |
readExif: function (data, off, len) { | |
var i, j, dE, tag, tgLen, xRes = 0, | |
yRes = 0, | |
resT = 0, | |
dv = new DataView(data, off), | |
le = String.fromCharCode(dv.getUint8(0), dv.getUint8(1)) !== 'MM'; | |
if (dv.getUint16(2, le) !== 0x2A) { | |
return null; | |
} | |
i = dv.getUint32(4, le); | |
if (i > len) { | |
return null; | |
} | |
for (tgLen = dv.getUint16(i, le), j = 0; j < tgLen; j++) { | |
tag = dv.getUint16(dE = i + 2 + 12 * j, le); | |
if (tag === 0x0128) { | |
resT = dv.getUint16(dE + 8, le) - 1; | |
} else if (tag === 0x011A || tag === 0x011B) { | |
dE = dv.getUint32(dE + 8, le); | |
if (dE > len) { | |
return null; | |
} | |
if (tag === 0x11A) { | |
xRes = Math.round(dv.getUint32(dE, le) / dv.getUint32(dE + 4, le)); | |
} else { | |
yRes = Math.round(dv.getUint32(dE, le) / dv.getUint32(dE + 4, le)); | |
} | |
} | |
} | |
xRes = xRes || yRes; | |
yRes = yRes || xRes; | |
return new Uint8Array([resT & 0xFF, xRes >> 8, xRes & 0xFF, yRes >> 8, yRes & 0xFF]); | |
}, | |
clearImage: function (data, extraData, rand) { | |
var tmp, i, len, deep, val, lIdx, jpgDat, img = new Uint8Array(data), | |
rExif = !!Cfg.removeEXIF, | |
rv = extraData ? rand ? [img, extraData, rand] : [img, extraData] : rand ? | |
[img, rand] : [img]; | |
if (!Cfg.postSameImg && !rExif && !extraData) { | |
return rv; | |
} | |
// JPG | |
if (img[0] === 0xFF && img[1] === 0xD8) { | |
for (i = 2, deep = 1, len = img.length - 1, val = [null, null], lIdx = 2, jpgDat = null; i < len; ) { | |
if (img[i] === 0xFF) { | |
if (rExif) { | |
if (!jpgDat && deep === 1) { | |
if (img[i + 1] === 0xE1 && img[i + 4] === 0x45) { | |
jpgDat = this.readExif (data, i + 10, (img[i + 2] << 8) + img[i + 3]); | |
} else if (img[i + 1] === 0xE0 && img[i + 7] === 0x46 && | |
(img[i + 2] !== 0 || img[i + 3] >= 0x0E || | |
img[i + 15] !== 0xFF)) | |
{ | |
jpgDat = img.subarray(i + 11, i + 16); | |
} | |
} | |
if ((img[i + 1] >> 4) === 0xE || img[i + 1] === 0xFE) { | |
if (lIdx !== i) { | |
val.push(img.subarray(lIdx, i)); | |
} | |
i += 2 + (img[i + 2] << 8) + img[i + 3]; | |
lIdx = i; | |
continue; | |
} | |
} else if (img[i + 1] === 0xD8) { | |
deep++; | |
i++; | |
continue; | |
} | |
if (img[i + 1] === 0xD9 && --deep === 0) { | |
break; | |
} | |
} | |
i++; | |
} | |
i += 2; | |
if (!extraData && len - i > 75) { | |
i = len; | |
} | |
if (lIdx === 2) { | |
if (i !== len) { | |
rv[0] = new Uint8Array(data, 0, i); | |
} | |
return rv; | |
} | |
val[0] = new Uint8Array([0xFF, 0xD8, 0xFF, 0xE0, 0, 0x0E, 0x4A, 0x46, 0x49, 0x46, 0, 1, 1]); | |
val[1] = jpgDat || new Uint8Array([0, 0, 1, 0, 1]); | |
val.push(img.subarray(lIdx, i)); | |
if (extraData) { | |
val.push(extraData); | |
} | |
if (rand) { | |
val.push(rand); | |
} | |
return val; | |
} | |
// PNG | |
if (img[0] === 0x89 && img[1] === 0x50) { | |
for (i = 0, len = img.length - 7; i < len && (img[i] !== 0x49 || | |
img[i + 1] !== 0x45 || img[i + 2] !== 0x4E || img[i + 3] !== 0x44); i++) {} | |
i += 8; | |
if (i !== len && (extraData || len - i <= 75)) { | |
rv[0] = new Uint8Array(data, 0, i); | |
} | |
return rv; | |
} | |
// WEBM | |
if (img[0] === 0x1a && img[1] === 0x45 && img[2] === 0xDF && img[3] === 0xA3) { | |
return new WebmParser(data).addData(rand).getData(); | |
} | |
return null; | |
} | |
}; | |
WebmParser = function (data) { | |
var EBMLId = 0x1A45DFA3, | |
segmentId = 0x18538067, | |
voidId = 0xEC; | |
function WebmElement(data, dataLength, offset) { | |
var num, clz, id, size, headSize = 0; | |
if (offset + 4 >= dataLength) { | |
return; | |
} | |
num = data.getUint32(offset); | |
clz = Math.clz32(num); | |
if (clz > 3) { | |
this.error = true; | |
return; | |
} | |
id = num >>> (8 * (3 - clz)); | |
headSize += clz + 1; | |
offset += clz + 1; | |
if (offset + 4 >= dataLength) { | |
this.error = true; | |
return; | |
} | |
num = data.getUint32(offset); | |
clz = Math.clz32(num); | |
if (clz > 3) { | |
if ((num & (0xFFFFFFFF >>> (clz + 1))) !== 0) { | |
this.error = true; | |
return; // We cannot handle webm-files with size greater than 4Gb :( | |
} | |
if (offset + 8 >= dataLength) { | |
this.error = true; | |
return; | |
} | |
headSize += 4; | |
offset += 4; | |
num = data.getUint32(offset); | |
clz -= 4; | |
} | |
size = num >>> (8 * (3 - clz)); | |
headSize += clz + 1; | |
offset += clz + 1; | |
if (offset + size > dataLength) { | |
this.error = true; | |
return; | |
} | |
this.data = data; | |
this.offset = offset; | |
this.endOffset = offset + size; | |
this.id = id; | |
this.headSize = headSize; | |
this.size = size; | |
} | |
WebmElement.prototype = { | |
error: false, | |
id: 0 | |
}; | |
function Parser(data) { | |
var dv = new DataView(data), | |
len = data.byteLength, | |
el = new WebmElement(dv, len, 0), | |
offset = 0, | |
voids = []; | |
error: do { | |
if (el.error || el.id !== EBMLId) { | |
break; | |
} | |
this.EBML = el; | |
offset += el.headSize + el.size; | |
while (true) { | |
el = new WebmElement(dv, len, offset); | |
if (el.error) { | |
break error; | |
} | |
if (el.id === segmentId) { | |
this.segment = el; | |
break; // Ignore everything after first segment | |
} else if (el.id === voidId) { | |
voids.push(el); | |
} else { | |
break error; | |
} | |
offset += el.headSize + el.size; | |
} | |
this.voids = voids; | |
this.data = data; | |
this.length = len; | |
this.rv = [null]; | |
this.error = false; | |
return; | |
} while (false); | |
this.error = true; | |
} | |
Parser.prototype = { | |
addData: function (data) { | |
if (this.error || !data) { | |
return this; | |
} | |
var size = typeof data === 'string' ? data.length : data.byteLength; | |
if (size > 127) { | |
this.error = true; | |
return; | |
} | |
this.rv.push(new Uint8Array([voidId, 0x80 | size]), data); | |
return this; | |
}, | |
getData: function () { | |
if (this.error) { | |
return null; | |
} | |
var len = this.segment.endOffset; | |
this.rv[0] = len === this.length ? this.data : new Uint8Array(this.data, 0, len); | |
return this.rv; | |
} | |
}; | |
WebmParser = Parser; | |
return new Parser(data); | |
} | |
// IMAGES | |
// =========================================================================================================== | |
function genImgHash(data) { | |
var i, j, l, c, t, u, g, buf = new Uint8Array(data[0]), | |
oldw = data[1], | |
oldh = data[2], | |
tmp = oldw * oldh, | |
newh = 8, | |
neww = 8, | |
levels = 3, | |
areas = 256 / levels, | |
values = 256 / (levels - 1), | |
hash = 0; | |
for (i = 0, j = 0; i < tmp; i++, j += 4) { | |
buf[i] = buf[j] * 0.3 + buf[j + 1] * 0.59 + buf[j + 2] * 0.11; | |
} | |
for (i = 0; i < newh; i++) { | |
for (j = 0; j < neww; j++) { | |
tmp = i / (newh - 1) * (oldh - 1); | |
l = Math.min(tmp | 0, oldh - 2); | |
u = tmp - l; | |
tmp = j / (neww - 1) * (oldw - 1); | |
c = Math.min(tmp | 0, oldw - 2); | |
t = tmp - c; | |
hash = (hash << 4) + Math.min(values * (((buf[l * oldw + c] * ((1 - t) * (1 - u)) + | |
buf[l * oldw + c + 1] * (t * (1 - u)) + | |
buf[(l + 1) * oldw + c + 1] * (t * u) + | |
buf[(l + 1) * oldw + c] * ((1 - t) * u)) / areas) | 0), 255); | |
if (g = hash & 0xF0000000) { | |
hash ^= g >>> 24; | |
} | |
hash &= ~g; | |
} | |
} | |
return {hash: hash}; | |
} | |
function ImgBtnsShowHider(nextFn, prevFn) { | |
dForm.insertAdjacentHTML('beforeend', '<div style="display: none;">' + | |
'<div id="de-img-btn-next" de-title="' + Lng.nextImg[lang] + '"><div></div></div>' + | |
'<div id="de-img-btn-prev" de-title="' + Lng.prevImg[lang] + '"><div></div></div></div>'); | |
var btns = dForm.lastChild; | |
this._btns = btns; | |
this._btnsStyle = btns.style; | |
this._nextFn = nextFn; | |
this._prevFn = prevFn; | |
window.addEventListener('mousemove', this, false); | |
btns.addEventListener('mouseover', this, false); | |
} | |
ImgBtnsShowHider.prototype = { | |
handleEvent: function (e) { | |
switch (e.type) { | |
case 'mousemove': | |
var curX = e.clientX, | |
curY = e.clientY; | |
if (this._oldX !== curX || this._oldY !== curY) { | |
this._oldX = curX; | |
this._oldY = curY; | |
this.show(); | |
} | |
break; | |
case 'mouseover': | |
if (!this.hasEvents) { | |
this.hasEvents = true; | |
this._btns.addEventListener('mouseout', this, false); | |
this._btns.addEventListener('click', this, false); | |
} | |
if (!this._hidden) { | |
clearTimeout(this._hideTmt); | |
KeyEditListener.setTitle(this._btns.firstChild, 17); | |
KeyEditListener.setTitle(this._btns.lastChild, 4); | |
} | |
break; | |
case 'mouseout': | |
this._setHideTmt(); | |
break; | |
case 'click': | |
switch (e.target.parentNode.id) { | |
case 'de-img-btn-next': this._nextFn(); return; | |
case 'de-img-btn-prev': this._prevFn(); return; | |
default: return; | |
} | |
} | |
}, | |
hide: function () { | |
this._btnsStyle.display = 'none'; | |
this._hidden = true; | |
this._oldX = this._oldY = -1; | |
}, | |
remove: function () { | |
$del(this._btns); | |
window.removeEventListener('mousemove', this, false); | |
clearTimeout(this._hideTmt); | |
}, | |
show: function () { | |
if (this._hidden) { | |
this._btnsStyle.display = ''; | |
this._hidden = false; | |
this._setHideTmt(); | |
} | |
}, | |
_hasEvents: false, | |
_hideTmt: 0, | |
_hidden: true, | |
_oldX: -1, | |
_oldY: -1, | |
_setHideTmt: function () { | |
clearTimeout(this._hideTmt); | |
this._hideTmt = setTimeout(this.hide.bind(this), 2000); | |
} | |
}; | |
function AttachmentViewer(data) { | |
this._show(data); | |
} | |
AttachmentViewer.prototype = { | |
data: null, | |
close: function (e) { | |
if (this.hasOwnProperty('_btns')) { | |
this._btns.remove(); | |
} | |
this._remove(e); | |
}, | |
handleEvent: function (e) { | |
var temp, isOverEvent = false; | |
switch (e.type) { | |
case 'mousedown': | |
if (this.data.isVideo && this.data.isControlClick(e, this._elStyle.height)) { | |
return; | |
} | |
this._oldX = e.clientX; | |
this._oldY = e.clientY; | |
doc.body.addEventListener('mousemove', this, true); | |
doc.body.addEventListener('mouseup', this, true); | |
break; | |
case 'mousemove': | |
var curX = e.clientX, | |
curY = e.clientY; | |
if (curX !== this._oldX || curY !== this._oldY) { | |
this._elStyle.left = (this._oldL = parseInt(this._elStyle.left, 10) + curX - this._oldX) + 'px'; | |
this._elStyle.top = (this._oldT = parseInt(this._elStyle.top, 10) + curY - this._oldY) + 'px'; | |
this._oldX = curX; | |
this._oldY = curY; | |
this._moved = true; | |
} | |
return; | |
case 'mouseup': | |
doc.body.removeEventListener('mousemove', this, true); | |
doc.body.removeEventListener('mouseup', this, true); | |
return; | |
case 'click': | |
if (this.data.isVideo && this.data.isControlClick(e, this._elStyle.height)) { | |
return; | |
} | |
if (e.button === 0) { | |
if (this._moved) { | |
this._moved = false; | |
} else { | |
this.close(e); | |
Attachment.viewer = null; | |
} | |
e.stopPropagation(); | |
break; | |
} | |
return; | |
case 'mouseover': isOverEvent = true; | |
case 'mouseout': | |
temp = e.relatedTarget; | |
if (!temp || (temp !== this._obj && !this._obj.contains(temp))) { | |
if (isOverEvent) { | |
Pview.mouseEnter(this.data.post); | |
} else if (Pview.top && this.data.post.el !== temp && !this.data.post.el.contains(temp)) { | |
Pview.top.markToDel(); | |
} | |
} | |
return; | |
default: // wheel event | |
var tmp, curX = e.clientX, | |
curY = e.clientY, | |
oldW = this._curW, | |
oldH = this._curH, | |
d = nav.Firefox ? -e.detail : nav.Presto ? e.wheelDelta : e.wheelDeltaY, | |
width = d > 0 ? oldW * this._zoomFactor : oldW / this._zoomFactor, | |
height = d > 0 ? oldH * this._zoomFactor : oldH / this._zoomFactor; | |
if (d < 0) { | |
tmp = resizeImage([width, height, this._ar], Cfg.minImgSize, this._maxSize); | |
width = tmp[0]; | |
height = tmp[1]; | |
} | |
this._curW = width; | |
this._curH = height; | |
this._elStyle.width = width + 'px'; | |
this._elStyle.height = height + 'px'; | |
this._elStyle.left = (this._oldL = parseInt(curX - (width/oldW) * (curX - this._oldL), 10)) + 'px'; | |
this._elStyle.top = (this._oldT = parseInt(curY - (height/oldH) * (curY - this._oldT), 10)) + 'px'; | |
} | |
$pd(e); | |
}, | |
navigate: function (isForward) { | |
var data = this.data; | |
do { | |
data = this._navigateHelper(data, isForward); | |
} while (!data.isVideo && !data.isImage); | |
this.update(data, null); | |
}, | |
update: function (data, showButtons, e) { | |
this._remove(e); | |
this._show(data, showButtons); | |
}, | |
_ar: 0, | |
_data: null, | |
_elStyle: null, | |
_fullEl: null, | |
_obj: null, | |
_oldL: 0, | |
_oldT: 0, | |
_curH: 0, | |
_curW: 0, | |
_oldX: 0, | |
_oldY: 0, | |
_maxSize: null, | |
_moved: false, | |
get _btns() { | |
var val = new ImgBtnsShowHider(this.navigate.bind(this, true), this.navigate.bind(this, false)); | |
Object.defineProperty(this, '_btns', { value: val }); | |
return val; | |
}, | |
get _zoomFactor() { | |
var val = 1 + (Cfg.zoomFactor / 100); | |
Object.defineProperty(this, '_zoomFactor', { value: val }); | |
return val; | |
}, | |
_getHolder: function (el, data) { | |
var obj, html, size = data.computeFullSize(false), | |
screenWidth = Post.sizing.wWidth, | |
screenHeight = Post.sizing.wHeight; | |
this._ar = size[0] / size[1]; | |
this._curW = size[0]; | |
this._curH = size[1]; | |
this._maxSize = !size[2] ? null : | |
Cfg.minImgSize > (size[2][2] > 1 ? size[2][0]: size[2][1]) ? size[2] : null; | |
this._oldL = (screenWidth - size[0]) / 2 - 1; | |
this._oldT = (screenHeight - size[1]) / 2 - 1; | |
html = '<div class="de-img-center" style="top:' + this._oldT + 'px; left:' + | |
this._oldL + 'px; width:' + size[0] + 'px; height:' + size[1] + 'px; display: block"></div>'; | |
obj = $add(html); | |
if (data.isImage) { | |
obj.insertAdjacentHTML('afterbegin', '<a href="' + data.src + '"></a>'); | |
obj.firstChild.appendChild(el); | |
} else { | |
obj.appendChild(el); | |
} | |
return obj; | |
}, | |
_navigateHelper: function (data, isForward) { | |
var post = data.post, | |
imgs = post.allImages; | |
if (isForward ? data.idx + 1 === imgs.length : data.idx === 0) { | |
do { | |
post = post.getAdjacentVisPost(!isForward); | |
if (!post) { | |
post = isForward ? firstThr.op : lastThr.last; | |
if (post.hidden || post.thr.hidden) { | |
post = post.getAdjacentVisPost(!isForward); | |
} | |
} | |
imgs = post.allImages; | |
} while (imgs.length === 0); | |
return imgs[isForward ? 0 : imgs.length - 1]; | |
} | |
return imgs[isForward ? data.idx + 1 : data.idx - 1] | |
}, | |
_show: function (data) { | |
var el = data.getFullObject(), | |
obj = this._getHolder(el, data), | |
style = obj.style; | |
this._elStyle = style; | |
this.data = data; | |
this._fullEl = el; | |
this._obj = obj; | |
obj.addEventListener(nav.Firefox ? 'DOMMouseScroll' : 'mousewheel', this, true); | |
obj.addEventListener('mousedown', this, true); | |
obj.addEventListener('click', this, true); | |
if (data.inPview) { | |
obj.addEventListener('mouseover', this, true); | |
obj.addEventListener('mouseout', this, true); | |
} | |
if (!data.inPview) { | |
this._btns.show(); | |
} else if (this.hasOwnProperty('_btns')) { | |
this._btns.hide(); | |
} | |
dForm.appendChild(obj); | |
}, | |
_remove: function (e) { | |
if (this.data.isVideo && this._fullEl.tagName === 'VIDEO') { | |
this._fullEl.pause(); | |
this._fullEl.src = ''; | |
} | |
this._obj.style.display = 'none'; | |
setTimeout($del, 0, this._obj); | |
if (e && this.data.inPview) { | |
this.data.sendCloseEvent(e, false); | |
} | |
} | |
}; | |
function IAttachmentData() {} | |
IAttachmentData.prototype = { | |
expanded: false, | |
get inPview() { | |
var val = this.post.isPview; | |
Object.defineProperty(this, 'inPview', { value: val }); | |
return val; | |
}, | |
get isImage() { | |
var val = /\.jpe?g|\.png|\.gif/i.test(this.src) || | |
(this.src.startsWith('blob:') && !this.el.hasAttribute('de-video')); | |
Object.defineProperty(this, 'isImage', { value: val }); | |
return val; | |
}, | |
get isVideo() { | |
var val = /\.webm(?:&|$)/i.test(this.src) || | |
(this.src.startsWith('blob:') && this.el.hasAttribute('de-video')); | |
Object.defineProperty(this, 'isVideo', { value: val }); | |
return val; | |
}, | |
get height() { | |
var dat = this._getImageSize(); | |
Object.defineProperties(this, { | |
'width': { value: dat[0] }, | |
'height': { value: dat[1] } | |
}); | |
return dat[1]; | |
}, | |
get src() { | |
var val = this._getImageSrc(); | |
Object.defineProperty(this, 'src', { value: val }); | |
return val; | |
}, | |
get width() { | |
var dat = this._getImageSize(); | |
Object.defineProperties(this, { | |
'width': { value: dat[0] }, | |
'height': { value: dat[1] } | |
}); | |
return dat[0]; | |
}, | |
collapse: function (e) { | |
if (!this.isVideo || !this.isControlClick(e, this._fullEl.style.height)) { | |
this.expanded = false; | |
$del(this._fullEl); | |
this._fullEl = null; | |
this.el.parentNode.style.display = ''; | |
$del((aib.hasPicWrap ? this._getImageParent() : this.el.parentNode).nextSibling); | |
if (e && this.inPview) { | |
this.sendCloseEvent(e, true); | |
} | |
return true; | |
} | |
return false; | |
}, | |
computeFullSize: function (inPost) { | |
var maxWidth, maxHeight, maxSize, temp, width = this.width, | |
height = this.height; | |
if (Cfg.resizeDPI) { | |
width /= Post.sizing.dPxRatio; | |
height /= Post.sizing.dPxRatio; | |
} | |
if (Cfg.resizeImgs) { | |
if (inPost) { | |
maxSize = [Post.sizing.wWidth - this._offset - 3, Number.MAX_SAFE_INTEGER, 0]; | |
} else { | |
maxWidth = Post.sizing.wWidth - 2; | |
maxHeight = Post.sizing.wHeight - 2; | |
maxSize = [maxWidth, maxHeight, maxWidth / maxHeight]; | |
} | |
} else { | |
maxSize = null; | |
} | |
temp = resizeImage([width, height, width / height], Cfg.minImgSize, maxSize); | |
return [temp[0], temp[1], maxSize]; | |
}, | |
expand: function (inPost, e) { | |
var size, el = this.el; | |
if (!inPost) { | |
if (Attachment.viewer) { | |
if (Attachment.viewer.data === this) { | |
Attachment.viewer.close(e); | |
Attachment.viewer = null; | |
return; | |
} | |
Attachment.viewer.update(this, e); | |
} else { | |
Attachment.viewer = new AttachmentViewer(this); | |
} | |
return; | |
} | |
this.expanded = true; | |
(aib.hasPicWrap ? this._getImageParent() : el.parentNode).insertAdjacentHTML('afterend', | |
'<div class="de-after-fimg"></div>'); | |
size = this.computeFullSize(inPost); | |
el.parentNode.style.display = 'none'; | |
this._fullEl = this.getFullObject(); | |
this._fullEl.className = 'de-img-full'; | |
this._fullEl.style.width = size[0] + 'px'; | |
this._fullEl.style.height = size[1] + 'px'; | |
$after(el.parentNode, this._fullEl); | |
}, | |
getFullObject: function () { | |
var obj, src = this.src; | |
if (this.isVideo) { | |
if (aib.tiny) { | |
src = src.replace(/^.*?\?v=|&.*?$/g, ''); | |
} | |
if (nav.canPlayWebm) { | |
obj = $add('<video style="width: 100%; height: 100%" src="' + src + | |
'" loop autoplay ' + (Cfg.webmControl ? 'controls ' : '') + | |
(Cfg.webmVolume === 0 ? 'muted ' : '') + '></video>'); | |
if (Cfg.webmVolume !== 0) { | |
obj.oncanplay = function () { | |
this.volume = Cfg.webmVolume / 100; | |
}; | |
} | |
obj.onerror = function () { | |
if (!this.onceLoaded) { | |
this.load(); | |
this.onceLoaded = true; | |
} | |
}; | |
obj.onvolumechange = function () { | |
saveCfg('webmVolume', Math.round(this.volume * 100)); | |
}; | |
} else { | |
obj = $add('<object style="width: 100%; height: 100%" data="' + src + '" type="video/quicktime">' + | |
'<param name="pluginurl" value="http://www.apple.com/quicktime/download/" />' + | |
'<param name="controller" value="' + (Cfg.webmControl ? 'true' : 'false') + '" />' + | |
'<param name="autoplay" value="true" />' + | |
'<param name="scale" value="tofit" />' + | |
'<param name="volume" value="' + Math.round(Cfg.webmVolume * 2.55) + '" />' + | |
'<param name="wmode" value="transparent" /></object>'); | |
} | |
} else { | |
obj = $add('<img style="width: 100%; height: 100%" src="' + src + '" alt="' + src + '"></a>'); | |
obj.onload = obj.onerror = function (e) { | |
if (this.naturalHeight + this.naturalWidth === 0 && !this.onceLoaded) { | |
this.src = this.src; | |
this.onceLoaded = true; | |
} | |
}; | |
} | |
return obj; | |
}, | |
isControlClick: function (e, styleHeight) { | |
return Cfg.webmControl && e.clientY > | |
(e.target.getBoundingClientRect().top + parseInt(styleHeight, 10) - 30); | |
}, | |
sendCloseEvent: function (e, inPost) { | |
var pv = this.post, | |
cr = pv.el.getBoundingClientRect(), | |
x = e.pageX - pageXOffset, | |
y = e.pageY - pageYOffset; | |
if (!inPost) { | |
while (x > cr.right || x < cr.left || y > cr.bottom || y < cr.top) { | |
if (pv = pv.parent) { | |
cr = pv.el.getBoundingClientRect(); | |
} else { | |
if (Pview.top) { | |
Pview.top.markToDel(); | |
} | |
return; | |
} | |
} | |
if (pv.kid) { | |
pv.kid.markToDel(); | |
} else { | |
clearTimeout(Pview.delTO); | |
} | |
} else if (x > cr.right || y > cr.bottom && Pview.top) { | |
Pview.top.markToDel(); | |
} | |
}, | |
_fullEl: null, | |
get _offset() { | |
var val = -1; | |
if (this._useCache) { | |
val = this._glob._offset; | |
} | |
if (val === -1) { | |
if (this.post.hidden) { | |
this.post.hideContent(false); | |
val = this.el.getBoundingClientRect().left + window.pageXOffset; | |
this.post.hideContent(true); | |
} else { | |
val = this.el.getBoundingClientRect().left + window.pageXOffset; | |
} | |
if (this._useCache) { | |
this._glob._offset = val; | |
} | |
} | |
Object.defineProperty(this, '_offset', { value: val }); | |
return val; | |
} | |
}; | |
function EmbeddedImage(post, el, idx) { | |
this.post = post; | |
this.el = el; | |
this.idx = idx; | |
} | |
EmbeddedImage.prototype = Object.create(IAttachmentData.prototype, { | |
_useCache: { value: false }, | |
_getImageSize: { value: function () { | |
var iEl = new Image(); | |
iEl.src = this.el.src; | |
return [iEl.width, iEl.height]; | |
} }, | |
_getImageSrc: { value: function () { | |
return this.el.src; | |
} }, | |
_getImageParent: { value: function () { | |
return this.el.parentNode; | |
} } | |
}); | |
function Attachment(post, el, idx) { | |
this.post = post; | |
this.el = el; | |
this.idx = idx; | |
} | |
Attachment.viewer = null; | |
Attachment.prototype = Object.create(IAttachmentData.prototype, { | |
data: { get: function () { | |
var img = this.el, | |
cnv = this._glob.canvas, | |
w = cnv.width = img.naturalWidth, | |
h = cnv.height = img.naturalHeight, | |
ctx = cnv.getContext('2d'); | |
ctx.drawImage(img, 0, 0); | |
return [ctx.getImageData(0, 0, w, h).data.buffer, w, h]; | |
} }, | |
hash: { configurable: true, get: function () { | |
var hash; | |
if (this._processing) { | |
this._needToHide = true; | |
} else if (aib.fch || this.el.complete) { | |
hash = this._maybeGetHash(null); | |
if (hash !== null) { | |
return hash; | |
} | |
} else { | |
this.el.onload = this.el.onerror = this._onload.bind(this); | |
} | |
this.post.hashImgsBusy++; | |
return null; | |
} }, | |
info: { configurable: true, get: function () { | |
var el = $c(aib.cFileInfo, aib.getImgWrap(this.el.parentNode)), | |
val = el ? el.textContent : ''; | |
Object.defineProperty(this, 'info', { value: val }); | |
return val; | |
} }, | |
weight: { configurable: true, get: function () { | |
var val = aib.getImgWeight(this.info); | |
Object.defineProperty(this, 'weight', { value: val }); | |
return val; | |
} }, | |
getHash: { value: function atGetHash(Fn) { | |
if (this.hasOwnProperty('hash')) { | |
Fn(this.hash); | |
} else { | |
this.callback = Fn; | |
if (!this._processing) { | |
var hash = this._maybeGetHash(); | |
if (hash !== null) { | |
Fn(hash); | |
} | |
} | |
} | |
} }, | |
_glob: { value: { | |
get canvas() { | |
var val = doc.createElement('canvas'); | |
Object.defineProperty(this, 'canvas', { value: val }); | |
return val; | |
}, | |
get storage() { | |
try { | |
var val = JSON.parse(sesStorage['de-imageshash']); | |
} finally { | |
if (!val) { | |
val = {}; | |
} | |
spells.addCompleteFunc(this._saveStorage.bind(this)); | |
Object.defineProperty(this, 'storage', { value: val }); | |
return val; | |
} | |
}, | |
get workers() { | |
var val = new workerQueue(4, genImgHash, function (e) {}); | |
spells.addCompleteFunc(this._clearWorkers.bind(this)); | |
Object.defineProperty(this, 'workers', { value: val, configurable: true }); | |
return val; | |
}, | |
_expAttach: null, | |
_offset: -1, | |
_saveStorage: function () { | |
sesStorage['de-imageshash'] = JSON.stringify(this.storage); | |
}, | |
_clearWorkers: function () { | |
this.workers.clear(); | |
delete this.workers; | |
} | |
} }, | |
_callback: { writable: true, value: null }, | |
_processing: { writable: true, value: false }, | |
_needToHide: { writable: true, value: false }, | |
_useCache: { configurable: true, get: function () { | |
var val = !this.inPview && !this.post.isOp && !this.post.prev.omitted && !this.post.prev.isOp && this.post.count > 4; | |
Object.defineProperty(this, '_useCache', { value: val }); | |
return val; | |
} }, | |
_getImageSize: { value: function atGetImgSize() { | |
return aib.getImgSize(this.info); | |
} }, | |
_getImageSrc: { value: function atGetImageSrc() { | |
return aib.getImgLink(this.el).href; | |
} }, | |
_getImageParent: { value: function atGetImageWrap() { | |
return aib.getImgParent(this.el.parentNode); | |
} }, | |
_endLoad: { value: function atEndLoad(hash) { | |
this.post.hashImgsBusy--; | |
if (this.post.hashHideFun !== null) { | |
this.post.hashHideFun(hash); | |
} | |
} }, | |
_maybeGetHash: { value: function atMaybeGetHash() { | |
var data, val; | |
if (this.src in this._glob.storage) { | |
val = this._glob.storage[this.src]; | |
} else if (aib.fch) { | |
downloadImgData(this.el.src, this._onload4chan.bind(this)); | |
this._callback = null; | |
return null; | |
} else if (this.el.naturalWidth + this.el.naturalHeight === 0) { | |
val = -1; | |
} else { | |
data = this.data; | |
this._glob.workers.run(data, [data[0]], this._wrkEnd.bind(this)); | |
this._callback = null; | |
return null; | |
} | |
Object.defineProperty(this, 'hash', { value: val }); | |
return val; | |
} }, | |
_onload: { value: function atOnLoad() { | |
var hash = this._maybeGetHash(null); | |
if (hash !== null) { | |
this._endLoad(hash); | |
} | |
} }, | |
_onload4chan: { value: function atOnload4chan(maybeData) { | |
if (maybeData === null) { | |
Object.defineProperty(this, 'hash', { value: -1 }); | |
this._endLoad(-1); | |
} else { | |
var buffer = maybeData.buffer, | |
data = [buffer, this.el.naturalWidth, this.el.naturalHeight]; | |
this._glob.workers.run(data, [buffer], this._wrkEnd.bind(this)); | |
} | |
} }, | |
_wrkEnd: { value: function atWrkEnd(data) { | |
var hash = data.hash; | |
Object.defineProperty(this, 'hash', { value: hash }); | |
this._endLoad(hash); | |
if (this.callback) { | |
this.callback(hash); | |
this.callback = null; | |
} | |
this._glob.storage[this.src] = hash; | |
} } | |
}); | |
function addImagesSearch(el) { | |
for (var link, i = 0, els = $Q(aib.qImgLink, el), len = els.length; i < len; i++) { | |
link = els[i]; | |
if (/google\.|tineye\.com|iqdb\.org/.test(link.href)) { | |
$del(link); | |
continue; | |
} | |
if (link.firstElementChild) { | |
continue; | |
} | |
link.insertAdjacentHTML('beforebegin', '<span class="de-btn-src" de-menu="imgsrc"></span>'); | |
} | |
} | |
function embedImagesLinks(el) { | |
for (var a, link, i = 0, els = $Q(aib.qMsgImgLink, el); link = els[i++];) { | |
if (link.parentNode.tagName === 'SMALL') { | |
return; | |
} | |
a = link.cloneNode(false); | |
a.target = '_blank'; | |
a.innerHTML = '<img class="de-img-pre" src="' + a.href + '">'; | |
$before(link, a); | |
} | |
} | |
// POSTS | |
// =========================================================================================================== | |
function Post(el, thr, num, count, isOp, prev) { | |
var refEl, html; | |
this.count = count; | |
this.el = el; | |
this.isOp = isOp; | |
this.num = num; | |
this._pref = refEl = $q(aib.qRef, el); | |
this.prev = prev; | |
this.thr = thr; | |
this.ref = []; | |
if (prev) { | |
prev.next = this; | |
} | |
el.post = this; | |
html = '<span class="de-post-btns' + (isOp ? '' : ' de-post-counter') + | |
'"><span class="de-btn-hide" de-menu="hide"></span><span class="de-btn-rep"></span>'; | |
if (isOp) { | |
if (!TNum && !aib.arch) { | |
html += '<span class="de-btn-expthr" de-menu="expand"></span>'; | |
} | |
html += '<span class="de-btn-fav" title="' + Lng.addFav[lang] + '"></span>'; | |
} | |
if (this.sage = aib.getSage(el)) { | |
html += '<span class="de-btn-sage" title="SAGE"></span>'; | |
} | |
// html += '<span class="de-btn-udolil" style="font-weight: bold; color: red; cursor: pointer;">[УДОЛИЛ!!11]</span>'; | |
refEl.insertAdjacentHTML('afterend', html + '</span>'); | |
this.btns = refEl.nextSibling; | |
if (Cfg.expandPosts === 1 && this.trunc) { | |
this._getFull(this.trunc, true); | |
} | |
el.addEventListener('mouseover', this, true); | |
} | |
Post.hiddenNums = []; | |
Post.getWrds = function (text) { | |
return text.replace(/\s+/g, ' ').replace(/[^a-zа-яё ]/ig, '').substring(0, 800).split(' '); | |
}; | |
Post.findSameText = function (oNum, oHid, oWords, date, post) { | |
var j, words = Post.getWrds(post.text), | |
len = words.length, | |
i = oWords.length, | |
olen = i, | |
_olen = i, | |
n = 0; | |
if (len < olen * 0.4 || len > olen * 3) { | |
return; | |
} | |
while (i--) { | |
if (olen > 6 && oWords[i].length < 3) { | |
_olen--; | |
continue; | |
} | |
j = len; | |
while (j--) { | |
if (words[j] === oWords[i] || oWords[i].match(/>>\d+/) && words[j].match(/>>\d+/)) { | |
n++; | |
} | |
} | |
} | |
if (n < _olen * 0.4 || len > _olen * 3) { | |
return; | |
} | |
if (oHid) { | |
post.note = ''; | |
if (!post.spellHidden) { | |
post.setVisib(false); | |
} | |
if (post.userToggled) { | |
delete bUVis[brd][post.num]; | |
post.userToggled = false; | |
} | |
} else { | |
post.setUserVisib(true, date, true); | |
post.note = 'similar to >>' + oNum; | |
} | |
return false; | |
}; | |
Post.sizing = { | |
get dPxRatio() { | |
var val = window.devicePixelRatio || 1; | |
Object.defineProperty(this, 'dPxRatio', { value: val }); | |
return val; | |
}, | |
get wHeight() { | |
var val = window.innerHeight; | |
if (!this._enabled) { | |
window.addEventListener('resize', this, false); | |
this._enabled = true; | |
} | |
Object.defineProperties(this, { | |
'wWidth': { writable: true, configurable: true, value: doc.documentElement.clientWidth }, | |
'wHeight': { writable: true, configurable: true, value: val } | |
}); | |
return val; | |
}, | |
get wWidth() { | |
var val = doc.documentElement.clientWidth; | |
if (!this._enabled) { | |
window.addEventListener('resize', this, false); | |
this._enabled = true; | |
} | |
Object.defineProperties(this, { | |
'wWidth': { writable: true, configurable: true, value: val }, | |
'wHeight': { writable: true, configurable: true, value: window.innerHeight } | |
}); | |
return val; | |
}, | |
handleEvent: function () { | |
this.wHeight = window.innerHeight; | |
this.wWidth = doc.documentElement.clientWidth; | |
}, | |
_enabled: false | |
}; | |
Post.prototype = { | |
banned: false, | |
deleted: false, | |
hasRef: false, | |
hasYTube: false, | |
hidden: false, | |
hashHideFun: null, | |
hashImgsBusy: 0, | |
imagesExpanded: false, | |
inited: true, | |
isPview: false, | |
kid: null, | |
next: null, | |
omitted: false, | |
parent: null, | |
prev: null, | |
spellHidden: false, | |
sticked: false, | |
userToggled: false, | |
viewed: false, | |
ytHideFun: null, | |
ytInfo: null, | |
ytLinksLoading: 0, | |
addFuncs: function () { | |
updRefMap(this, true); | |
embedMP3Links(this); | |
if (Cfg.addImgs) { | |
embedImagesLinks(this.el); | |
} | |
if (isExpImg) { | |
this.toggleImages(true); | |
} | |
}, | |
handleEvent: function (e) { | |
var temp, el = e.target, | |
type = e.type, | |
isOutEvent = type === 'mouseout'; | |
if (type === 'click') { | |
if (e.button !== 0) { | |
return; | |
} | |
switch (el.tagName) { | |
case 'IMG': | |
if (el.classList.contains('de-video-thumb')) { | |
if (Cfg.addYouTube === 3) { | |
this.ytLink.classList.add('de-current'); | |
new YouTube().addPlayer(this.ytObj, this.ytInfo, el.classList.contains('de-ytube')); | |
$pd(e); | |
} | |
} else if (Cfg.expandImgs !== 0) { | |
this._clickImage(el, e); | |
} | |
return; | |
case 'VIDEO': | |
if (Cfg.expandImgs !== 0 && !(Cfg.webmControl && e.clientY > | |
(el.getBoundingClientRect().top + parseInt(el.style.height, 10) - 30))) | |
{ | |
this._clickImage(el, e); | |
} | |
return; | |
case 'A': | |
if (el.classList.contains('de-video-link')) { | |
new YouTube().clickLink(this, el, Cfg.addYouTube); | |
$pd(e); | |
} else { | |
temp = el.parentNode; | |
if (temp === this.trunc) { | |
this._getFull(temp, false); | |
$pd(e); | |
e.stopPropagation(); | |
} else if (Cfg.insertNum && pr.form && temp === this._pref && | |
!/Reply|Ответ/.test(el.textContent)) | |
{ | |
$pd(e); | |
e.stopPropagation(); | |
if (pr.isQuick || (TNum && pr.isHidden)) { | |
pr.showQuickReply(this, this.num, false, true); | |
} else if (TNum) { | |
$txtInsert(pr.txta, '>>' + this.num); | |
} else { | |
window.location = el.href.replace(/#i/, '#'); | |
} | |
} | |
} | |
return; | |
} | |
switch (el.className) { | |
case 'de-btn-expthr': | |
this.thr.load(1, false, null); | |
$del(this._menu); | |
this._menu = null; | |
return; | |
case 'de-btn-fav': this.thr.setFavorState(true); return; | |
case 'de-btn-fav-sel': this.thr.setFavorState(false); return; | |
case 'de-btn-hide': | |
case 'de-btn-hide-user': | |
if (this.isPview) { | |
pByNum[this.num].toggleUserVisib(); | |
this.btns.firstChild.className = 'de-btn-hide-user'; | |
if (pByNum[this.num].hidden) { | |
this.btns.classList.add('de-post-hide'); | |
} else { | |
this.btns.classList.remove('de-post-hide'); | |
} | |
} else { | |
this.toggleUserVisib(); | |
} | |
$del(this._menu); | |
this._menu = null; | |
return; | |
case 'de-btn-rep': | |
pr.showQuickReply(this.isPview ? this.getTopParent() : this, this.num, !this.isPview, false); | |
return; | |
case 'de-btn-sage': | |
addSpell(9, '', false); | |
return; | |
case 'de-btn-stick': | |
case 'de-btn-stick-on': | |
el.className = this.sticked ? 'de-btn-stick' : 'de-btn-stick-on'; | |
this.sticked = !this.sticked; | |
return; | |
case 'de-btn-udolil': | |
this.thr.deletePost(this, false, true); | |
return; | |
} | |
if (el.classList[0] === 'de-menu-item') { | |
this._clickMenu(el); | |
} | |
return; | |
} | |
if (type === 'mouseover' && Cfg.expandImgs && !el.classList.contains('de-img-full') && this.allImages && | |
el.imgIdx !== undefined && (temp = this.allImages[el.imgIdx]) && (temp.isImage || temp.isVideo)) | |
{ | |
el.title = Cfg.expandImgs === 1 ? Lng.expImgInline[lang] : Lng.expImgFull[lang]; | |
} | |
if (!this._hasEvents) { | |
this._hasEvents = true; | |
this.el.addEventListener('click', this, true); | |
this.el.addEventListener('mouseout', this, true); | |
} else if (this.isPview && isOutEvent) { | |
this._handleMouseEvents(e.relatedTarget, false); | |
} | |
switch (el.classList[0]) { | |
case 'de-btn-expthr': | |
case 'de-btn-hide': | |
case 'de-btn-hide-user': | |
this._addButtonTitle(el); | |
case 'de-btn-src': | |
if (isOutEvent) { | |
this._closeMenu(e.relatedTarget); | |
} else { | |
this._menuDelay = setTimeout(this._addMenu.bind(this, el), Cfg.linksOver); | |
} | |
return; | |
case 'de-btn-rep': | |
this._addButtonTitle(el); | |
if (!isOutEvent) { | |
quotetxt = $txtSelect(); | |
} | |
return; | |
case 'de-menu': | |
case 'de-menu-item': | |
if (isOutEvent) { | |
this._closeMenu(e.relatedTarget); | |
} else { | |
clearTimeout(this._menuDelay); | |
} | |
return; | |
default: | |
if (!Cfg.linksNavig || el.tagName !== 'A' || el.lchecked) { | |
if (this.isPview && !isOutEvent) { | |
this._handleMouseEvents(e.relatedTarget, true); | |
} | |
return; | |
} | |
if (!el.textContent.startsWith('>>')) { | |
el.lchecked = true; | |
return; | |
} | |
// Don't use classList here, 'de-preflink ' should be first | |
el.className = 'de-preflink ' + el.className; | |
// fall through | |
case 'de-reflink': | |
case 'de-preflink': | |
if (Cfg.linksNavig) { | |
if (isOutEvent) { | |
clearTimeout(this._linkDelay); | |
if (this.kid) { | |
this.kid.markToDel(); | |
} else if (!this.isPview && Pview.top) { | |
Pview.top.markToDel(); | |
} | |
} else { | |
clearTimeout(Pview.delTO); | |
this._linkDelay = setTimeout(this._addPview.bind(this, el), Cfg.linksOver); | |
} | |
$pd(e); | |
e.stopPropagation(); | |
} | |
} | |
}, | |
hideContent: function (hide) { | |
if (hide) { | |
this.el.classList.add('de-post-hide'); | |
} else { | |
this.el.classList.remove('de-post-hide'); | |
} | |
if (nav.Chrome) { | |
if (hide) { | |
this.el.classList.remove('de-post-unhide'); | |
} else { | |
this.el.classList.add('de-post-unhide'); | |
} | |
if (!chromeCssUpd) { | |
chromeCssUpd = setTimeout(function () { | |
doc.head.insertAdjacentHTML('beforeend', | |
'<style id="de-csshide" type="text/css">\ | |
.de-post-hide > ' + aib.qHide + ' { display: none !important; }\ | |
.de-post-unhide > ' + aib.qHide + ' { display: !important; }\ | |
</style>'); | |
$del(doc.head.lastChild); | |
chromeCssUpd = null; | |
}, 200); | |
} | |
} | |
}, | |
hideRefs: function () { | |
if (!Cfg.hideRefPsts || !this.hasRef) { | |
return; | |
} | |
this.ref.forEach(function (num) { | |
var pst = pByNum[num]; | |
if (pst && !pst.userToggled) { | |
pst.setVisib(true); | |
pst.note = 'reference to >>' + this.num; | |
pst.hideRefs(); | |
} | |
}, this); | |
}, | |
getAdjacentVisPost: function (toUp) { | |
var post = toUp ? this.prev : this.next; | |
while (post) { | |
if (post.thr.hidden) { | |
post = toUp ? post.thr.op.prev : post.thr.last.next; | |
} else if (post.hidden || post.omitted) { | |
post = toUp ? post.prev : post.next | |
} else { | |
return post; | |
} | |
} | |
return null; | |
}, | |
get html() { | |
var val = this.el.innerHTML; | |
Object.defineProperty(this, 'html', { configurable: true, value: val }); | |
return val; | |
}, | |
get images() { | |
var i, len, el, els = $Q(aib.qThumbImages, this.el), | |
imgs = []; | |
for (i = 0, len = els.length; i < len; ++i) { | |
el = els[i]; | |
el.imgIdx = i; | |
imgs.push(new Attachment(this, el, i)); | |
} | |
Object.defineProperty(this, 'images', { value: imgs }); | |
return imgs; | |
}, | |
get allImages() { | |
var i, len, el, els, val = this.images.slice(), | |
allIdx = val.length; | |
if (Cfg.addImgs) { | |
for (i = 0, els = $C('de-img-pre', this.el), len = els.length; i < len; ++i, ++allIdx) { | |
el = els[i]; | |
el.imgIdx = allIdx; | |
val.push(new EmbeddedImage(this, el, allIdx)); | |
} | |
} | |
Object.defineProperty(this, 'allImages', { value: val }); | |
return val; | |
}, | |
get mp3Obj() { | |
var val = $new('div', {'class': 'de-mp3'}, null); | |
$before(this.msg, val); | |
Object.defineProperty(this, 'mp3Obj', { value: val }); | |
return val; | |
}, | |
get msg() { | |
var val = $q(aib.qMsg, this.el); | |
Object.defineProperty(this, 'msg', { configurable: true, value: val }); | |
return val; | |
}, | |
get nextInThread() { | |
var post = this.next; | |
return !post || post.count === 0 ? null : post; | |
}, | |
get nextNotDeleted() { | |
var post = this.nextInThread; | |
while (post && post.deleted) { | |
post = post.nextInThread; | |
} | |
return post; | |
}, | |
set note(val) { | |
if (this.isOp) { | |
this.noteEl.textContent = val ? '(autohide: ' + val + ')' : '(' + this.title + ')'; | |
} else if (!Cfg.delHiddPost) { | |
this.noteEl.textContent = val ? 'autohide: ' + val : ''; | |
} | |
}, | |
get noteEl() { | |
var val; | |
if (this.isOp) { | |
val = this.thr.el.previousElementSibling.lastChild; | |
} else { | |
this.btns.insertAdjacentHTML('beforeend', '<span class="de-post-note"></span>'); | |
val = this.btns.lastChild; | |
} | |
Object.defineProperty(this, 'noteEl', { value: val }); | |
return val; | |
}, | |
get posterName() { | |
var pName = $q(aib.qName, this.el), val = pName ? pName.textContent : ''; | |
Object.defineProperty(this, 'posterName', { value: val }); | |
return val; | |
}, | |
get posterTrip() { | |
var pTrip = $c(aib.cTrip, this.el), val = pTrip ? pTrip.textContent : ''; | |
Object.defineProperty(this, 'posterTrip', { value: val }); | |
return val; | |
}, | |
select: function () { | |
if (this.isOp) { | |
if (this.hidden) { | |
this.thr.el.previousElementSibling.classList.add('de-selected'); | |
} | |
this.thr.el.classList.add('de-selected'); | |
} else { | |
this.el.classList.add('de-selected'); | |
} | |
}, | |
setUserVisib: function (hide, date, sync) { | |
this.setVisib(hide); | |
this.btns.firstChild.className = 'de-btn-hide-user'; | |
this.userToggled = true; | |
if (hide) { | |
this.note = ''; | |
this.hideRefs(); | |
} else { | |
this.unhideRefs(); | |
} | |
bUVis[brd][this.num] = [+!hide, date]; | |
if (sync) { | |
locStorage['__de-post'] = JSON.stringify({ | |
'brd': brd, | |
'date': date, | |
'isOp': this.isOp, | |
'num': this.num, | |
'hide': hide, | |
'title': this.isOp ? this.title : '' | |
}); | |
locStorage.removeItem('__de-post'); | |
} | |
}, | |
setVisib: function (hide) { | |
var el, tEl; | |
if (this.hidden === hide) { | |
return; | |
} | |
if (this.isOp) { | |
this.hidden = this.thr.hidden = hide; | |
tEl = this.thr.el; | |
tEl.style.display = hide ? 'none' : ''; | |
el = $id('de-thr-hid-' + this.num); | |
if (el) { | |
el.style.display = hide ? '' : 'none'; | |
} else { | |
tEl.insertAdjacentHTML('beforebegin', '<div class="' + aib.cReply + | |
' de-thr-hid" id="de-thr-hid-' + this.num + '">' + Lng.hiddenThrd[lang] + | |
' <a href="#">№' + this.num + '</a> <span class="de-thread-note"></span></div>'); | |
el = $t('a', tEl.previousSibling); | |
el.onclick = el.onmouseover = el.onmouseout = function (e) { | |
switch (e.type) { | |
case 'click': | |
this.toggleUserVisib(); | |
$pd(e); | |
return; | |
case 'mouseover': this.thr.el.style.display = ''; return; | |
default: // mouseout | |
if (this.hidden) { | |
this.thr.el.style.display = 'none'; | |
} | |
} | |
}.bind(this); | |
} | |
return; | |
} | |
if (Cfg.delHiddPost) { | |
if (hide) { | |
this.wrap.classList.add('de-hidden'); | |
this.wrap.insertAdjacentHTML('beforebegin', | |
'<span style="counter-increment: de-cnt 1;"></span>'); | |
} else if (this.hidden) { | |
this.wrap.classList.remove('de-hidden'); | |
$del(this.wrap.previousSibling); | |
} | |
} else { | |
if (!hide) { | |
this.note = ''; | |
} | |
this._pref.onmouseover = this._pref.onmouseout = hide && function (e) { | |
this.hideContent(e.type === 'mouseout'); | |
}.bind(this); | |
} | |
this.hidden = hide; | |
this.hideContent(hide); | |
if (Cfg.strikeHidd) { | |
setTimeout(this._strikePostNum.bind(this, hide), 50); | |
} | |
}, | |
spellHide: function (note) { | |
this.spellHidden = true; | |
if (!this.userToggled) { | |
if (TNum && !this.deleted) { | |
sVis[this.count] = 0; | |
} | |
if (!this.hidden) { | |
this.hideRefs(); | |
} | |
this.setVisib(true); | |
this.note = note; | |
} | |
}, | |
spellUnhide: function () { | |
this.spellHidden = false; | |
if (!this.userToggled) { | |
if (TNum && !this.deleted) { | |
sVis[this.count] = 1; | |
} | |
this.setVisib(false); | |
this.unhideRefs(); | |
} | |
}, | |
get subj() { | |
var subj = $c(aib.cSubj, this.el), val = subj ? subj.textContent : ''; | |
Object.defineProperty(this, 'subj', { value: val }); | |
return val; | |
}, | |
get text() { | |
var val = this.msg.innerHTML | |
.replace(/<\/?(?:br|p|li)[^>]*?>/gi,'\n') | |
.replace(/<[^>]+?>/g,'') | |
.replace(/>/g, '>') | |
.replace(/</g, '<') | |
.replace(/ /g, '\u00A0') | |
.trim(); | |
Object.defineProperty(this, 'text', { configurable: true, value: val }); | |
return val; | |
}, | |
get title() { | |
var val = this.subj || this.text.substring(0, 70).replace(/\s+/g, ' ') | |
Object.defineProperty(this, 'title', { value: val }); | |
return val; | |
}, | |
get tNum() { | |
return this.thr.num; | |
}, | |
toggleImages: function (expand) { | |
for (var dat, i = 0, imgs = this.allImages, len = imgs.length; i < len; ++i) { | |
dat = imgs[i]; | |
if (dat.isImage && (dat.expanded ^ expand)) { | |
if (expand) { | |
dat.expand(true, null); | |
} else { | |
dat.collapse(null); | |
} | |
} | |
} | |
this.imagesExpanded = expand; | |
}, | |
toggleUserVisib: function () { | |
var isOp = this.isOp, | |
hide = !this.hidden, | |
date = Date.now(); | |
this.setUserVisib(hide, date, true); | |
if (isOp) { | |
if (hide) { | |
hThr[brd][this.num] = this.title; | |
} else { | |
delete hThr[brd][this.num]; | |
} | |
saveHiddenThreads(false); | |
} | |
saveUserPosts(true); | |
}, | |
get topCoord() { | |
var el = this.isOp && this.hidden ? this.thr.el.previousElementSibling : this.el; | |
return el.getBoundingClientRect().top; | |
}, | |
get trunc() { | |
var el = aib.qTrunc && $q(aib.qTrunc, this.el), val = null; | |
if (el && /long|full comment|gekürzt|слишком|длинн|мног|полная версия/i.test(el.textContent)) { | |
val = el; | |
} | |
Object.defineProperty(this, 'trunc', { configurable: true, value: val }); | |
return val; | |
}, | |
unhideRefs: function () { | |
if (!Cfg.hideRefPsts || !this.hasRef) { | |
return; | |
} | |
this.ref.forEach(function (num) { | |
var pst = pByNum[num]; | |
if (pst && pst.hidden && !pst.userToggled && !pst.spellHidden) { | |
pst.setVisib(false); | |
pst.unhideRefs(); | |
} | |
}); | |
}, | |
unselect: function () { | |
if (this.isOp) { | |
var el = $id('de-thr-hid-' + this.num); | |
if (el) { | |
el.classList.remove('de-selected'); | |
} | |
this.thr.el.classList.remove('de-selected'); | |
} else { | |
this.el.classList.remove('de-selected'); | |
} | |
}, | |
updateMsg: function (newMsg) { | |
var origMsg = aib.dobr ? this.msg.firstElementChild : this.msg, | |
ytExt = $c('de-video-ext', origMsg), | |
ytLinks = $Q(':not(.de-video-ext) > .de-video-link', origMsg); | |
origMsg.parentNode.replaceChild(newMsg, origMsg); | |
Object.defineProperties(this, { | |
'msg': { configurable: true, value: newMsg }, | |
'trunc': { configurable: true, value: null } | |
}); | |
delete this.html; | |
delete this.text; | |
new YouTube().updatePost(this, ytLinks, $Q('a[href*="youtu"]', newMsg), false); | |
if (ytExt) { | |
newMsg.appendChild(ytExt); | |
} | |
this.addFuncs(); | |
spells.check(this); | |
closeAlert($id('de-alert-load-fullmsg')); | |
}, | |
get wrap() { | |
var val = aib.getWrap(this.el, this.isOp); | |
Object.defineProperty(this, 'wrap', { value: val }); | |
return val; | |
}, | |
get ytData() { | |
var val = []; | |
Object.defineProperty(this, 'ytData', { value: val }); | |
return val; | |
}, | |
get ytObj() { | |
var val = aib.insertYtPlayer(this.msg, '<div class="de-video-obj"></div>'); | |
Object.defineProperty(this, 'ytObj', { value: val }); | |
return val; | |
}, | |
_hasEvents: false, | |
_linkDelay: 0, | |
_menu: null, | |
_menuDelay: 0, | |
_selRange: null, | |
_selText: '', | |
_addButtonTitle: function (el) { | |
if (el.hasTitle) { | |
return; | |
} | |
el.hasTitle = true; | |
switch (el.className) { | |
case 'de-btn-hide': | |
case 'de-btn-hide-user': | |
el.title = Lng.togglePost[lang]; | |
return; | |
case 'de-btn-expthr': | |
el.title = Lng.expandThrd[lang]; | |
return; | |
case 'de-btn-rep': | |
el.title = Lng.replyToPost[lang]; | |
return; | |
} | |
}, | |
_addMenu: function (el) { | |
var html, cr = el.getBoundingClientRect(), | |
isLeft = false, | |
className = 'de-menu ' + aib.cReply, | |
xOffset = window.pageXOffset; | |
switch (el.getAttribute('de-menu')) { | |
case 'hide': | |
if (!Cfg.menuHiddBtn) { | |
return; | |
} | |
html = this._addMenuHide(); | |
break; | |
case 'expand': | |
html = '<span class="de-menu-item" info="thr-exp">' + Lng.selExpandThr[lang] | |
.join('</span><span class="de-menu-item" info="thr-exp">') + '</span>'; | |
break; | |
case 'imgsrc': | |
isLeft = true; | |
className += ' de-imgmenu'; | |
html = this._addMenuImgSrc(el); | |
break; | |
} | |
doc.body.insertAdjacentHTML('beforeend', '<div class="' + className + | |
'" style="position: absolute; ' + ( | |
isLeft ? 'left: ' + (cr.left + xOffset) : | |
'right: ' + (doc.documentElement.clientWidth - cr.right - xOffset) | |
) + 'px; top: ' + (window.pageYOffset + cr.bottom) + 'px;">' + html + '</div>'); | |
if (this._menu) { | |
clearTimeout(this._menuDelay); | |
$del(this._menu); | |
} | |
this._menu = doc.body.lastChild; | |
this._menu.addEventListener('click', this, false); | |
this._menu.addEventListener('mouseover', this, false); | |
this._menu.addEventListener('mouseout', this, false); | |
}, | |
_addMenuHide: function () { | |
var sel, ssel, str = '', addItem = function (name) { | |
str += '<span info="spell-' + name + '" class="de-menu-item">' + | |
Lng.selHiderMenu[name][lang] + '</span>'; | |
}; | |
sel = nav.Presto ? doc.getSelection() : window.getSelection(); | |
if (ssel = sel.toString()) { | |
this._selText = ssel; | |
this._selRange = sel.getRangeAt(0); | |
addItem('sel'); | |
} | |
if (this.posterName) { | |
addItem('name'); | |
} | |
if (this.posterTrip) { | |
addItem('trip'); | |
} | |
if (this.images.length === 0) { | |
addItem('noimg'); | |
} else { | |
addItem('img'); | |
addItem('ihash'); | |
} | |
if (this.text) { | |
addItem('text'); | |
} else { | |
addItem('notext'); | |
} | |
return str; | |
}, | |
_addMenuImgSrc: function (el) { | |
var p = el.nextSibling.href + '" target="_blank">' + Lng.search[lang], | |
c = doc.body.getAttribute('de-image-search'), | |
str = ''; | |
if (c) { | |
c = c.split(';'); | |
c.forEach(function (el) { | |
var info = el.split(','); | |
str += '<a class="de-src' + info[0] + (!info[1] ? | |
'" onclick="de_isearch(event, \'' + info[0] + '\')" de-url="' : | |
'" href="' + info[1] | |
) + p + info[0] + '</a>'; | |
}); | |
} | |
return '<a class="de-menu-item de-imgmenu de-src-iqdb" href="http://iqdb.org/?url=' + p + 'IQDB</a>' + | |
'<a class="de-menu-item de-imgmenu de-src-tineye" href="http://tineye.com/search/?url=' + p + 'TinEye</a>' + | |
'<a class="de-menu-item de-imgmenu de-src-google" href="http://google.com/searchbyimage?image_url=' + p + 'Google</a>' + | |
'<a class="de-menu-item de-imgmenu de-src-saucenao" href="http://saucenao.com/search.php?url=' + p + 'SauceNAO</a>' + str; | |
}, | |
_addPview: function (link) { | |
var tNum = (link.pathname.match(/.+?\/[^\d]*(\d+)/) || [,0])[1], | |
pNum = (link.textContent.trim().match(/\d+$/) || [tNum])[0], | |
pv = this.isPview ? this.kid : Pview.top; | |
if (pv && pv.num === pNum) { | |
Pview.del(pv.kid); | |
setPviewPosition(link, pv.el, Cfg.animation && animPVMove); | |
if (pv.parent.num !== this.num) { | |
$each($C('de-pview-link', pv.el), function (el) { | |
el.classList.remove('de-pview-link'); | |
}); | |
pv._markLink(this.num); | |
} | |
this.kid = pv; | |
pv.parent = this; | |
} else if (!Cfg.noNavigHidd || !pByNum[pNum] || !pByNum[pNum].hidden) { | |
this.kid = new Pview(this, link, tNum, pNum); | |
} | |
}, | |
_clickImage: function (el, e) { | |
// We need to get allImages getter before imgIdx property, do not remove allImgs var | |
var data, allImgs = this.allImages; | |
if (el.classList.contains('de-img-full')) { | |
if (!allImgs[el.previousSibling.firstElementChild.imgIdx].collapse(e)) { | |
return; | |
} | |
} else if (el.imgIdx === undefined || !(data = allImgs[el.imgIdx]) || !(data.isImage || data.isVideo)) { | |
return; | |
} else { | |
data.expand((Cfg.expandImgs === 1) ^ e.ctrlKey, e); | |
} | |
$pd(e); | |
e.stopPropagation(); | |
}, | |
_clickMenu: function (el) { | |
$del(this._menu); | |
this._menu = null; | |
switch (el.getAttribute('info')) { | |
case 'spell-sel': | |
var start = this._selRange.startContainer, | |
end = this._selRange.endContainer; | |
if (start.nodeType === 3) { | |
start = start.parentNode; | |
} | |
if (end.nodeType === 3) { | |
end = end.parentNode; | |
} | |
if ((nav.matchesSelector(start, aib.qMsg + ' *') && nav.matchesSelector(end, aib.qMsg + ' *')) || | |
(nav.matchesSelector(start, '.' + aib.cSubj) && nav.matchesSelector(end, '.' + aib.cSubj)) | |
) { | |
if (this._selText.contains('\n')) { | |
addSpell(1 /* #exp */, '/' + | |
regQuote(this._selText).replace(/\r?\n/g, '\\n') + '/', false); | |
} else { | |
addSpell(0 /* #words */, this._selText.replace(/\)/g, '\\)').toLowerCase(), false); | |
} | |
} else { | |
dummy.innerHTML = ''; | |
dummy.appendChild(this._selRange.cloneContents()); | |
addSpell(2 /* #exph */, '/' + | |
regQuote(dummy.innerHTML.replace(/^<[^>]+>|<[^>]+>$/g, '')) + '/', false); | |
} | |
return; | |
case 'spell-name': addSpell(6 /* #name */, this.posterName.replace(/\)/g, '\\)'), false); return; | |
case 'spell-trip': addSpell(7 /* #trip */, this.posterTrip.replace(/\)/g, '\\)'), false); return; | |
case 'spell-img': | |
var img = this.images[0], | |
w = img.weight, | |
wi = img.width, | |
h = img.height; | |
addSpell(8 /* #img */, [0, [w, w], [wi, wi, h, h]], false); | |
return; | |
case 'spell-ihash': | |
this.images[0].getHash(function (hash) { | |
addSpell(4 /* #ihash */, hash, false); | |
}); | |
return; | |
case 'spell-noimg': addSpell(0x108 /* (#all & !#img) */, '', true); return; | |
case 'spell-text': | |
var num = this.num, | |
hidden = this.hidden, | |
wrds = Post.getWrds(this.text), | |
time = Date.now(); | |
for (var post = firstThr.op; post; post = post.next) { | |
Post.findSameText(num, hidden, wrds, time, post); | |
} | |
saveUserPosts(true); | |
return; | |
case 'spell-notext': addSpell(0x10B /* (#all & !#tlen) */, '', true); return; | |
case 'thr-exp': this.thr.load(parseInt(el.textContent, 10), false, null); return; | |
} | |
}, | |
_closeMenu: function (rt) { | |
clearTimeout(this._menuDelay); | |
if (this._menu && (!rt || rt.className !== 'de-menu-item')) { | |
this._menuDelay = setTimeout(function () { | |
$del(this._menu); | |
this._menu = null; | |
}.bind(this), 75); | |
} | |
}, | |
_getFull: function (node, isInit) { | |
if (aib.dobr) { | |
$del(node.nextSibling); | |
$del(node.previousSibling); | |
$del(node); | |
if (isInit) { | |
this.msg.replaceChild($q('.alternate > div', this.el), this.msg.firstElementChild); | |
} else { | |
this.updateMsg($q('.alternate > div', this.el)); | |
} | |
return; | |
} | |
if (!isInit) { | |
$alert(Lng.loading[lang], 'load-fullmsg', true); | |
} | |
ajaxLoad(aib.getThrdUrl(brd, this.tNum), true, function (node, form, xhr) { | |
if (this.isOp) { | |
this.updateMsg(replacePost($q(aib.qMsg, form))); | |
$del(node); | |
} else { | |
for (var i = 0, els = aib.getPosts(form), len = els.length; i < len; i++) { | |
if (this.num === aib.getPNum(els[i])) { | |
this.updateMsg(replacePost($q(aib.qMsg, els[i]))); | |
$del(node); | |
return; | |
} | |
} | |
} | |
}.bind(this, node), null); | |
}, | |
_markLink: function (pNum) { | |
$each($Q('a[href*="' + pNum + '"]', this.el), function (num, el) { | |
if (el.textContent === '>>' + num) { | |
el.classList.add('de-pview-link'); | |
} | |
}.bind(null, pNum)); | |
}, | |
_strikePostNum: function (isHide) { | |
var idx, num = this.num; | |
if (isHide) { | |
Post.hiddenNums.push(+num); | |
} else { | |
idx = Post.hiddenNums.indexOf(+num); | |
if (idx !== -1) { | |
Post.hiddenNums.splice(idx, 1); | |
} | |
} | |
$each($Q('a[href*="#' + num + '"]', dForm), isHide ? function (el) { | |
el.classList.add('de-ref-hid'); | |
} : function (el) { | |
el.classList.remove('de-ref-hid'); | |
}); | |
} | |
}; | |
// PREVIEWS | |
// =========================================================================================================== | |
function Pview(parent, link, tNum, pNum) { | |
var b, post = pByNum[pNum]; | |
this.parent = parent; | |
this._link = link; | |
this.num = pNum; | |
this.thr = parent.thr; | |
Object.defineProperty(this, 'tNum', { value: tNum }); | |
if (post && (!post.isOp || !parent.isPview || !parent._loaded)) { | |
this._showPost(post); | |
return; | |
} | |
b = link.pathname.match(/^\/?(.+\/)/)[1].replace(aib.res, '').replace(/\/$/, ''); | |
if (post = this._cache && this._cache[b + tNum] && this._cache[b + tNum].getPost(pNum)) { | |
this._loaded = true; | |
this._showPost(post); | |
} else { | |
this._showText('<span class="de-wait">' + Lng.loading[lang] + '</span>'); | |
ajaxLoad(aib.getThrdUrl(b, tNum), true, this._onload.bind(this, b), this._onerror.bind(this)); | |
} | |
} | |
Pview.clearCache = function () { | |
Pview.prototype._cache = {}; | |
}; | |
Pview.del = function (pv) { | |
if (!pv) { | |
return; | |
} | |
var el, vPost = Attachment.viewer && Attachment.viewer.data.post; | |
pv.parent.kid = null; | |
if (!pv.parent.isPview) { | |
Pview.top = null; | |
} | |
do { | |
clearTimeout(pv._readDelay); | |
if (vPost === pv) { | |
Attachment.viewer.close(null); | |
Attachment.viewer = vPost = null; | |
} | |
el = pv.el; | |
if (Cfg.animation) { | |
nav.animEvent(el, $del); | |
el.classList.add('de-pview-anim'); | |
el.style[nav.animName] = 'de-post-close-' + (el.aTop ? 't' : 'b') + (el.aLeft ? 'l' : 'r'); | |
} else { | |
$del(el); | |
} | |
} while (pv = pv.kid); | |
}; | |
Pview.mouseEnter = function (post) { | |
if (post.kid) { | |
post.kid.markToDel(); | |
} else { | |
clearTimeout(Pview.delTO); | |
} | |
}; | |
Pview.delTO = 0; | |
Pview.top = null; | |
Pview.prototype = Object.create(Post.prototype, { | |
isPview: { value: true }, | |
getTopParent: { value: function pvGetBoardParent() { | |
var post = this.parent; | |
while (post.isPview) { | |
post = post.parent; | |
} | |
return post; | |
} }, | |
markToDel: { value: function pvMarkToDel() { | |
clearTimeout(Pview.delTO); | |
var lastSticked, el = this; | |
do { | |
if (el.sticked) { | |
lastSticked = el; | |
} | |
} while (el = el.kid); | |
if (!lastSticked || lastSticked.kid) { | |
Pview.delTO = setTimeout(Pview.del, Cfg.linksOut, lastSticked ? lastSticked.kid : this); | |
} | |
} }, | |
_loaded: { value: false, writable: true }, | |
_cache: { value: {}, writable: true }, | |
_readDelay: { value: 0, writable: true }, | |
_handleMouseEvents: { value: function pvHandleMouseEvents(el, isOverEvent) { | |
if (!el || (el !== this.el && !this.el.contains(el))) { | |
if (isOverEvent) { | |
Pview.mouseEnter(this); | |
} else if (Pview.top && (!this._menu || (this._menu !== el && !this._menu.contains(el)))) { | |
Pview.top.markToDel(); | |
} | |
} | |
} }, | |
_onerror: { value: function (eCode, eMsg, xhr) { | |
Pview.del(this); | |
this._showText(eCode === 404 ? Lng.postNotFound[lang] : getErrorMessage(eCode, eMsg)); | |
} }, | |
_onload: { value: function pvOnload(b, form, xhr) { | |
var rm, parent = this.parent, | |
parentNum = parent.num, | |
cache = this._cache[b + this.tNum] = new PviewsCache(form, b, this.tNum), | |
post = cache.getPost(this.num); | |
if (post && (brd !== b || !post.hasRef || post.ref.indexOf(parentNum) === -1)) { | |
if (post.hasRef) { | |
rm = $c('de-refmap', post.el) | |
} else { | |
post.msg.insertAdjacentHTML('afterend', '<div class="de-refmap"></div>'); | |
rm = post.msg.nextSibling; | |
} | |
rm.insertAdjacentHTML('afterbegin', '<a class="de-reflink" href="' + | |
aib.getThrdUrl(b, parent.tNum) + aib.anchor + | |
parentNum + '">>>' + (brd === b ? '' : '/' + brd + '/') + parentNum + | |
'</a><span class="de-refcomma">, </span>'); | |
} | |
if (parent.kid === this) { | |
Pview.del(this); | |
if (post) { | |
this._loaded = true; | |
this._showPost(post); | |
} else { | |
this._showText(Lng.postNotFound[lang]); | |
} | |
} | |
} }, | |
_showPost: { value: function pvShowPost(post) { | |
var btns, el = this.el = post.el.cloneNode(true), | |
pText = '<span class="de-btn-rep" title="' + Lng.replyToPost[lang] + '"></span>' + | |
(post.sage ? '<span class="de-btn-sage" title="SAGE"></span>' : '') + | |
'<span class="de-btn-stick" title="' + Lng.attachPview[lang] + '"></span>' + | |
(post.deleted ? '' : '<span style="margin-right: 4px; vertical-align: 1px; color: #4f7942; ' + | |
'font: bold 11px tahoma; cursor: default;">' + (post.isOp ? 'OP' : post.count + 1) + '</span>'); | |
el.post = this; | |
el.className = aib.cReply + ' de-pview' + (post.viewed ? ' de-viewed' : ''); | |
el.style.display = ''; | |
if (Cfg.linksNavig === 2) { | |
this._markLink(this.parent.num); | |
} | |
this._pref = $q(aib.qRef, el); | |
if (post.inited) { | |
this.btns = btns = $c('de-post-btns', el); | |
this.isOp = post.isOp; | |
btns.classList.remove('de-post-counter'); | |
if (post.hidden) { | |
btns.classList.add('de-post-hide'); | |
} | |
btns.innerHTML = '<span class="de-btn-hide' + (post.userToggled ? '-user' : '') + | |
'" de-menu="hide" title="' + Lng.togglePost[lang] + '"></span>' + pText; | |
$each($Q((!TNum && post.isOp ? aib.qOmitted + ', ' : '') + | |
'.de-img-full, .de-after-fimg', el), $del); | |
$each($Q(aib.qThumbImages, el), function (el) { | |
el.parentNode.style.display = ''; | |
}); | |
if (post.hasYTube) { | |
if (post.ytInfo !== null) { | |
Object.defineProperty(this, 'ytObj', { value: $c('de-video-obj', el) }); | |
this.ytInfo = post.ytInfo; | |
} | |
new YouTube().updatePost(this, $C('de-video-link', post.el), $C('de-video-link', el), true); | |
} | |
if (Cfg.addImgs) { | |
$each($C('de-img-pre', el), function (el) { | |
el.style.display = ''; | |
}); | |
} | |
if (Cfg.markViewed) { | |
this._readDelay = setTimeout(function (pst) { | |
if (!pst.viewed) { | |
pst.el.classList.add('de-viewed'); | |
pst.viewed = true; | |
} | |
var arr = (sesStorage['de-viewed'] || '').split(','); | |
arr.push(pst.num); | |
sesStorage['de-viewed'] = arr; | |
}, post.text.length > 100 ? 2e3 : 500, post); | |
} | |
} else { | |
this._pref.insertAdjacentHTML('afterend', '<span class="de-post-btns">' + pText + '</span'); | |
embedMP3Links(this); | |
new YouTube().parseLinks(this); | |
if (Cfg.addImgs) { | |
embedImagesLinks(el); | |
} | |
if (Cfg.imgSrcBtns) { | |
addImagesSearch(el); | |
} | |
} | |
el.addEventListener('click', this, true); | |
this._showPview(el); | |
} }, | |
_showPview: { value: function pvShowPview(el, id) { | |
if (this.parent.isPview) { | |
Pview.del(this.parent.kid); | |
} else { | |
Pview.del(Pview.top); | |
Pview.top = this; | |
} | |
this.parent.kid = this; | |
el.addEventListener('mouseover', this, true); | |
el.addEventListener('mouseout', this, true); | |
(aib.arch ? doc.body : dForm).appendChild(el); | |
setPviewPosition(this._link, el, false); | |
if (Cfg.animation) { | |
nav.animEvent(el, function (node) { | |
node.classList.remove('de-pview-anim'); | |
node.style[nav.animName] = ''; | |
}); | |
el.classList.add('de-pview-anim'); | |
el.style[nav.animName] = 'de-post-open-' + (el.aTop ? 't' : 'b') + (el.aLeft ? 'l' : 'r'); | |
} | |
} }, | |
_showText: { value: function pvShowText(txt) { | |
this._showPview(this.el = $add('<div class="' + aib.cReply + ' de-pview-info de-pview">' + | |
txt + '</div>')); | |
} }, | |
}); | |
function PviewsCache(form, b, tNum) { | |
var i, len, post, pBn = {}, | |
pProto = Post.prototype, | |
thr = $q(aib.qThread, form) || form, | |
posts = aib.getPosts(thr); | |
for (i = 0, len = posts.length; i < len; ++i) { | |
post = posts[i]; | |
pBn[aib.getPNum(post)] = Object.create(pProto, { | |
count: { value: i + 1 }, | |
el: { value: post, writable: true }, | |
inited: { value: false }, | |
pvInited: { value: false, writable: true }, | |
ref: { value: [], writable: true } | |
}); | |
} | |
pBn[tNum] = this._opObj = Object.create(pProto, { | |
inited: { value: false }, | |
isOp: { value: true }, | |
msg: { value: $q(aib.qMsg, thr), writable: true }, | |
ref: { value: [], writable: true } | |
}); | |
this._brd = b; | |
this._thr = thr; | |
this._tNum = tNum; | |
this._tUrl = aib.getThrdUrl(b, tNum); | |
this._posts = pBn; | |
if (Cfg.linksNavig === 2) { | |
genRefMap(pBn, this._tUrl); | |
} | |
} | |
PviewsCache.prototype = { | |
getPost: function (num) { | |
if (num === this._tNum) { | |
return this._op; | |
} | |
var pst = this._posts[num]; | |
if (pst && !pst.pvInited) { | |
pst.el = replacePost(pst.el); | |
delete pst.msg; | |
if (pst.hasRef) { | |
addRefMap(pst, this._tUrl); | |
} | |
pst.pvInited = true; | |
} | |
return pst; | |
}, | |
get _op() { | |
var i, j, len, num, nRef, oRef, rRef, oOp, op = this._opObj; | |
op.el = replacePost(aib.getOp(this._thr)); | |
op.msg = $q(aib.qMsg, op.el); | |
if (this._brd === brd && (oOp = pByNum[this._tNum])) { | |
oRef = op.ref; | |
rRef = []; | |
for (i = j = 0, nRef = oOp.ref, len = nRef.length; j < len; ++j) { | |
num = nRef[j]; | |
if (oRef[i] === num) { | |
i++; | |
} else if (oRef.indexOf(num) !== -1) { | |
continue; | |
} | |
rRef.push(num) | |
} | |
for (len = oRef.length; i < len; i++) { | |
rRef.push(oRef[i]); | |
} | |
op.ref = rRef; | |
if (rRef.length !== 0) { | |
op.hasRef = true; | |
addRefMap(op, this._tUrl); | |
} | |
} else if (op.hasRef) { | |
addRefMap(op, this._tUrl); | |
} | |
Object.defineProperty(this, '_op', { value: op }); | |
return op; | |
} | |
}; | |
function PviewMoved() { | |
if (this.style[nav.animName]) { | |
this.classList.remove('de-pview-anim'); | |
this.style.cssText = this.newPos; | |
this.newPos = false; | |
$each($C('de-css-move', doc.head), $del); | |
this.removeEventListener(nav.animEnd, PviewMoved, false); | |
} | |
} | |
function animPVMove(pView, lmw, top, oldCSS) { | |
var uId = 'de-movecss-' + Math.round(Math.random() * 1e3); | |
$css('@' + nav.cssFix + 'keyframes ' + uId + ' {to { ' + lmw + ' top:' + top + '; }}').className = | |
'de-css-move'; | |
if (pView.newPos) { | |
pView.style.cssText = pView.newPos; | |
pView.removeEventListener(nav.animEnd, PviewMoved, false); | |
} else { | |
pView.style.cssText = oldCSS; | |
} | |
pView.newPos = lmw + ' top:' + top + ';'; | |
pView.addEventListener(nav.animEnd, PviewMoved, false); | |
pView.classList.add('de-pview-anim'); | |
pView.style[nav.animName] = uId; | |
} | |
function setPviewPosition(link, pView, animFun) { | |
if (pView.link === link) { | |
return; | |
} | |
pView.link = link; | |
var isTop, top, oldCSS, cr = link.getBoundingClientRect(), | |
offX = cr.left + window.pageXOffset + link.offsetWidth / 2, | |
offY = cr.top + window.pageYOffset, | |
bWidth = doc.documentElement.clientWidth, | |
isLeft = offX < bWidth / 2, | |
tmp = (isLeft ? offX : offX - | |
Math.min(parseInt(pView.offsetWidth, 10), offX - 10)), | |
lmw = 'max-width:' + (bWidth - tmp - 10) + 'px; left:' + tmp + 'px;'; | |
if (animFun) { | |
oldCSS = pView.style.cssText; | |
pView.style.cssText = 'opacity: 0; ' + lmw; | |
} else { | |
pView.style.cssText = lmw; | |
} | |
top = pView.offsetHeight; | |
isTop = top + cr.top + link.offsetHeight < window.innerHeight || cr.top - top < 5; | |
top = (isTop ? offY + link.offsetHeight : offY - top) + 'px'; | |
pView.aLeft = isLeft; | |
pView.aTop = isTop; | |
if (animFun) { | |
animFun(pView, lmw, top, oldCSS); | |
} else { | |
pView.style.top = top; | |
} | |
} | |
function addRefMap(post, tUrl) { | |
var i, ref, len, bStr = '<a ' + aib.rLinkClick + ' href="' + tUrl + aib.anchor, | |
html = ['<div class="de-refmap">']; | |
for (i = 0, ref = post.ref, len = ref.length; i < len; ++i) { | |
html.push(bStr, ref[i], '" class="de-reflink">>>', ref[i], | |
'</a><span class="de-refcomma">, </span>'); | |
} | |
html.push('</div>'); | |
if (aib.dobr) { | |
post.msg.nextElementSibling.insertAdjacentHTML('beforeend', html.join('')); | |
} else { | |
post.msg.insertAdjacentHTML('afterend', html.join('')); | |
} | |
} | |
function genRefMap(posts, thrURL) { | |
var tc, lNum, post, ref, i, len, links, url, pNum, opNums = Thread.tNums; | |
for (pNum in posts) { | |
for (i = 0, links = $T('a', posts[pNum].msg), len = links.length; i < len; ++i) { | |
tc = links[i].textContent; | |
if (tc[0] === '>' && tc[1] === '>' && (lNum = +tc.substr(2)) && (lNum in posts)) { | |
post = posts[lNum]; | |
ref = post.ref; | |
if (ref.indexOf(pNum) === -1) { | |
ref.push(pNum); | |
post.hasRef = true; | |
} | |
if (opNums.indexOf(lNum) !== -1) { | |
links[i].classList.add('de-opref'); | |
} | |
if (thrURL) { | |
url = links[i].getAttribute('href'); | |
if (url[0] === '#') { | |
links[i].setAttribute('href', thrURL + url); | |
} | |
} | |
} | |
} | |
} | |
} | |
function updRefMap(post, add) { | |
var tc, ref, idx, link, lNum, lPost, i, len, links, pNum = post.num, | |
strNums = add && Cfg.strikeHidd && Post.hiddenNums.length !== 0 ? Post.hiddenNums : null, | |
opNums = add && Thread.tNums; | |
for (i = 0, links = $T('a', post.msg), len = links.length; i < len; ++i) { | |
link = links[i]; | |
tc = link.textContent; | |
if (tc[0] === '>' && tc[1] === '>' && (lNum = +tc.substr(2)) && (lNum in pByNum)) { | |
lPost = pByNum[lNum]; | |
if (!TNum) { | |
link.href = '#' + (aib.fch ? 'p' : '') + lNum; | |
} | |
if (add) { | |
if (strNums && strNums.lastIndexOf(lNum) !== -1) { | |
link.classList.add('de-ref-hid'); | |
} | |
if (opNums.indexOf(lNum) !== -1) { | |
link.classList.add('de-opref'); | |
} | |
if (lPost.ref.indexOf(pNum) === -1) { | |
lPost.ref.push(pNum); | |
post.hasRef = true; | |
if (Cfg.hideRefPsts && lPost.hidden) { | |
if (!post.hidden) { | |
post.hideRefs(); | |
} | |
post.setVisib(true); | |
post.note = 'reference to >>' + lNum; | |
} | |
} else { | |
continue; | |
} | |
} else if (lPost.hasRef) { | |
ref = lPost.ref; | |
idx = ref.indexOf(pNum); | |
if (idx === -1) { | |
continue; | |
} | |
ref.splice(idx, 1); | |
if (ref.length === 0) { | |
lPost.hasRef = false; | |
$del($c('de-refmap', lPost.el)); | |
continue; | |
} | |
} | |
$del($c('de-refmap', lPost.el)); | |
addRefMap(lPost, ''); | |
} | |
} | |
} | |
// THREADS | |
// =========================================================================================================== | |
function Thread(el, prev) { | |
if (aib._420 || aib.tiny) { | |
$after(el, el.lastChild); | |
$del($c('clear', el)); | |
} | |
var i, pEl, lastPost, | |
els = aib.getPosts(el), | |
len = els.length, | |
num = aib.getTNum(el), | |
omt = TNum ? 1 : aib.getOmitted($q(aib.qOmitted, el), len); | |
this.num = num; | |
Thread.tNums.push(+num); | |
this.pcount = omt + len; | |
pByNum[num] = lastPost = this.op = el.post = new Post(aib.getOp(el), this, num, 0, true, | |
prev ? prev.last : null); | |
for (i = 0; i < len; i++) { | |
num = aib.getPNum(pEl = els[i]); | |
pByNum[num] = lastPost = new Post(pEl, this, num, omt + i, false, lastPost); | |
} | |
this.last = lastPost; | |
el.style.counterReset = 'de-cnt ' + omt; | |
el.removeAttribute('id'); | |
el.setAttribute('de-thread', null); | |
visPosts = Math.max(visPosts, len); | |
// aib.crimea && aib.crimea(this.op, el); | |
this.el = el; | |
this.prev = prev; | |
if (prev) { | |
prev.next = this; | |
} | |
} | |
Thread.parsed = false; | |
Thread.clearPostsMark = function () { | |
firstThr.clearPostsMarks(); | |
}; | |
Thread.loadNewPosts = function (e) { | |
if (e) { | |
$pd(e); | |
} | |
$alert(Lng.loading[lang], 'newposts', true); | |
firstThr.clearPostsMarks(); | |
updater.forceLoad(); | |
}; | |
Thread.tNums = []; | |
Thread.prototype = { | |
hasNew: false, | |
hidden: false, | |
loadedOnce: false, | |
next: null, | |
get lastNotDeleted() { | |
var post = this.last; | |
while (post.deleted) { | |
post = post.prev; | |
} | |
return post; | |
}, | |
get nextNotHidden() { | |
for (var thr = this.next; thr && thr.hidden; thr = thr.next) {} | |
return thr; | |
}, | |
get prevNotHidden() { | |
for (var thr = this.prev; thr && thr.hidden; thr = thr.prev) {} | |
return thr; | |
}, | |
get topCoord() { | |
return this.op.topCoord; | |
}, | |
clearPostsMarks: function () { | |
if (this.hasNew) { | |
this.hasNew = false; | |
$each($Q('.de-new-post', this.el), function (el) { | |
el.classList.remove('de-new-post'); | |
}); | |
doc.removeEventListener('click', Thread.clearPostsMark, true); | |
} | |
}, | |
deletePost: function (post, delAll, removePost) { | |
var tPost, idx = post.count, count = 0; | |
do { | |
if (removePost) { | |
$del(post.wrap); | |
delete pByNum[post.num]; | |
if (post.hidden) { | |
post.unhideRefs(); | |
} | |
updRefMap(post, false); | |
if (post.prev.next = post.next) { | |
post.next.prev = post.prev; | |
} | |
if (this.last === post) { | |
this.last = post.prev; | |
} | |
} else { | |
post.deleted = true; | |
post.btns.classList.remove('de-post-counter'); | |
post.btns.classList.add('de-post-deleted'); | |
post.wrap.classList.add('de-post-removed'); | |
($q('input[type="checkbox"]', post.el) || {}).disabled = true; | |
} | |
post = post.nextNotDeleted; | |
count++; | |
} while (delAll && post); | |
if (!spells.hasNumSpell) { | |
sVis.splice(idx, count); | |
} | |
for (tPost = post; tPost; tPost = tPost.nextInThread) { | |
tPost.count -= count; | |
} | |
this.pcount -= count; | |
return post; | |
}, | |
load: function (last, smartScroll, Fn) { | |
if (!Fn) { | |
$alert(Lng.loading[lang], 'load-thr', true); | |
} | |
ajaxLoad(aib.getThrdUrl(brd, this.num), true, function threadOnload(last, smartScroll, Fn, form, xhr) { | |
this.loadFromForm(last, smartScroll, form); | |
Fn && Fn(); | |
}.bind(this, last, smartScroll, Fn), function (eCode, eMsg, xhr) { | |
$alert(getErrorMessage(eCode, eMsg), 'load-thr', false); | |
if (typeof this === 'function') { | |
this(); | |
} | |
}.bind(Fn)); | |
}, | |
loadFromForm: function (last, smartScroll, form) { | |
var nextCoord, els = aib.getPosts(form), | |
op = this.op, | |
thrEl = this.el, | |
expEl = $c('de-expand', thrEl), | |
nOmt = last === 1 ? 0 : Math.max(els.length - last, 0); | |
if (smartScroll) { | |
if (this.next) { | |
nextCoord = this.next.topCoord; | |
} else { | |
smartScroll = false; | |
} | |
} | |
pr.closeQReply(); | |
$del($q(aib.qOmitted + ', .de-omitted', thrEl)); | |
if (!this.loadedOnce) { | |
if (op.trunc) { | |
op.updateMsg(replacePost($q(aib.qMsg, form))); | |
} | |
op.ref = []; | |
this.loadedOnce = true; | |
} | |
this._checkBans(op, form); | |
this._parsePosts(els); | |
thrEl.style.counterReset = 'de-cnt ' + (nOmt + 1); | |
if (this._processExpandThread(els, last === 1 ? els.length : last)) { | |
$del(expEl); | |
} else if (!expEl) { | |
thrEl.insertAdjacentHTML('beforeend', '<span class="de-expand">[<a href="' + | |
aib.getThrdUrl(brd, this.num) + aib.anchor + this.last.num + '">' + | |
Lng.collapseThrd[lang] + '</a>]</span>'); | |
thrEl.lastChild.onclick = function (e) { | |
$pd(e); | |
this.load(visPosts, true, null); | |
}.bind(this); | |
} else if (expEl !== thrEl.lastChild) { | |
thrEl.appendChild(expEl); | |
} | |
if (nOmt !== 0) { | |
op.el.insertAdjacentHTML('afterend', '<div class="de-omitted">' + nOmt + '</div>'); | |
} | |
if (smartScroll) { | |
scrollTo(pageXOffset, pageYOffset - (nextCoord - this.next.topCoord)); | |
} | |
closeAlert($id('de-alert-load-thr')); | |
}, | |
loadNew: function (Fn, useAPI) { | |
if (aib.dobr && useAPI) { | |
return getJsonPosts('/api/thread/' + brd + '/' + TNum + '.json', | |
function checkNewPosts(status, sText, json, xhr) { | |
if (status !== 200 || json.error) { | |
Fn(status, sText || json.message, 0, xhr); | |
} else { | |
if (this._lastModified !== json.last_modified || this.pcount !== json.posts_count) { | |
this._lastModified = json.last_modified; | |
updater.updateXHR(this.loadNew(Fn, false)); | |
} else { | |
Fn(200, '', 0, xhr); | |
} | |
Fn = null; | |
} | |
}.bind(this) | |
); | |
} | |
return ajaxLoad(aib.getThrdUrl(brd, TNum), true, function parseNewPosts(form, xhr) { | |
Fn(200, '', this.loadNewFromForm(form), xhr); | |
Fn = null; | |
}.bind(this), function (eCode, eMsg, xhr) { | |
Fn(eCode, eMsg, 0, xhr); | |
Fn = null; | |
}); | |
}, | |
loadNewFromForm: function (form) { | |
this._checkBans(firstThr.op, form); | |
var lastOffset = pr.isVisible ? pr.topCoord : null, | |
info = this._parsePosts(aib.getPosts(form)); | |
if (lastOffset !== null) { | |
scrollTo(pageXOffset, pageYOffset - (lastOffset - pr.topCoord)); | |
} | |
if (info[0] !== 0) { | |
$id('de-panel-info').firstChild.textContent = this.pcount + '/' + | |
$Q(aib.qThumbImages, dForm).length; | |
} | |
return info[1]; | |
}, | |
setFavBtn: function (state) { | |
var el = $c(state ? 'de-btn-fav' : 'de-btn-fav-sel', this.op.btns); | |
if (el) { | |
el.className = state ? 'de-btn-fav-sel' : 'de-btn-fav'; | |
el.title = state ? Lng.delFav[lang] : Lng.addFav[lang]; | |
} | |
}, | |
setFavorState: function (val) { | |
this.setFavBtn(val); | |
getStoredObj('DESU_Favorites', function (fav) { | |
var h = aib.host, | |
b = brd, | |
num = this.num; | |
if (val) { | |
if (!fav[h]) { | |
fav[h] = {}; | |
} | |
if (!fav[h][brd]) { | |
fav[h][brd] = {}; | |
} | |
fav[h][brd].url = aib.prot + '//' + aib.host + aib.getPageUrl(brd, 0); | |
fav[h][brd][num] = { | |
'cnt': this.pcount, | |
'new': 0, | |
'txt': this.op.title, | |
'url': aib.getThrdUrl(brd, num) | |
}; | |
} else { | |
removeFavoriteEntry(fav, h, b, num, false); | |
} | |
saveFavorites(fav); | |
}.bind(this)); | |
}, | |
updateHidden: function (data) { | |
var realHid, date = Date.now(), | |
thr = this; | |
do { | |
realHid = thr.num in data; | |
if (thr.hidden ^ realHid) { | |
if (realHid) { | |
thr.op.setUserVisib(true, date, false); | |
data[thr.num] = thr.op.title; | |
} else if (thr.hidden) { | |
thr.op.setUserVisib(false, date, false); | |
} | |
} | |
} while (thr = thr.next); | |
}, | |
_lastModified: '', | |
_addPost: function (parent, el, i, prev) { | |
var post, num = aib.getPNum(el), | |
wrap = aib.getWrap(el, false); | |
el = replacePost(el); | |
pByNum[num] = post = new Post(el, this, num, i, false, prev); | |
Object.defineProperty(post, 'wrap', { value: wrap }); | |
parent.appendChild(wrap); | |
if (TNum && Cfg.animation) { | |
nav.animEvent(post.el, function (node) { | |
node.classList.remove('de-post-new'); | |
}); | |
post.el.classList.add('de-post-new'); | |
} | |
new YouTube().parseLinks(post); | |
if (Cfg.imgSrcBtns) { | |
addImagesSearch(el); | |
} | |
post.addFuncs(); | |
preloadImages(el); | |
if (TNum && Cfg.markNewPosts) { | |
this._addPostMark(el); | |
} | |
return post; | |
}, | |
_addPostMark: function (postEl) { | |
if (updater.focused) { | |
this.clearPostsMarks(); | |
} else { | |
if (!this.hasNew) { | |
this.hasNew = true; | |
doc.addEventListener('click', Thread.clearPostsMark, true); | |
} | |
postEl.classList.add('de-new-post'); | |
} | |
}, | |
_checkBans: function (op, thrNode) { | |
var pEl, bEl, post, i, bEls, len; | |
if (aib.qBan) { | |
for (i = 0, bEls = $Q(aib.qBan, thrNode), len = bEls.length; i < len; ++i) { | |
bEl = bEls[i]; | |
pEl = aib.getPostEl(bEl); | |
post = pEl ? pByNum[aib.getPNum(pEl)] : op; | |
if (post && !post.banned) { | |
if (!$q(aib.qBan, post.el)) { | |
post.msg.appendChild(bEl); | |
} | |
post.banned = true; | |
} | |
} | |
} | |
}, | |
_importPosts: function (last, newPosts, begin, end) { | |
var newCount, newVisCount, fragm = doc.createDocumentFragment(), | |
newCount = newVisCount = end - begin; | |
for (; begin < end; ++begin) { | |
last = this._addPost(fragm, newPosts[begin], begin + 1, last); | |
newVisCount -= spells.check(last); | |
} | |
return [newCount, newVisCount, fragm, last]; | |
}, | |
_parsePosts: function (nPosts) { | |
var i, cnt, firstChangedPost, res, temp, saveSpells = false, | |
newPosts = 0, | |
newVisPosts = 0, | |
len = nPosts.length, | |
post = this.lastNotDeleted; | |
if (aib.dobr || (post.count !== 0 && | |
(post.count > len || aib.getPNum(nPosts[post.count - 1]) !== post.num))) | |
{ | |
firstChangedPost = null; | |
post = this.op.nextNotDeleted; | |
for (i = post.count - 1; i < len && post; ) { | |
if (post.num !== aib.getPNum(nPosts[i])) { | |
if (+post.num > +aib.getPNum(nPosts[i])) { | |
if (!firstChangedPost) { | |
firstChangedPost = post.prev; | |
} | |
cnt = 0; | |
do { | |
cnt++; | |
i++; | |
} while (+aib.getPNum(nPosts[i]) < +post.num); | |
res = this._importPosts(post.prev, nPosts, i - cnt, i); | |
newPosts += res[0]; | |
this.pcount += res[0]; | |
newVisPosts += res[1]; | |
$after(post.prev.wrap, res[2]); | |
res[3].next = post; | |
post.prev = res[3]; | |
for (temp = post; temp; temp = temp.nextInThread) { | |
temp.count += cnt; | |
} | |
} else { | |
if (!firstChangedPost) { | |
firstChangedPost = post; | |
} | |
post = this.deletePost(post, false, !TNum); | |
} | |
} else { | |
i++; | |
post = post.nextNotDeleted; | |
} | |
} | |
if (i === len && post) { | |
this.deletePost(post, true, !TNum); | |
} | |
if (firstChangedPost && spells.hasNumSpell) { | |
disableSpells(); | |
for (post = firstChangedPost.nextInThread; post; post = post.nextInThread) { | |
spells.check(post); | |
} | |
saveSpells = true; | |
} | |
if (newPosts !== 0) { | |
for (post = firstChangedPost; post; post = post.nextInThread) { | |
updRefMap(post, true); | |
} | |
} | |
} | |
if (len + 1 > this.pcount) { | |
res = this._importPosts(this.last, nPosts, this.lastNotDeleted.count, len); | |
newPosts += res[0]; | |
newVisPosts += res[1]; | |
this.el.appendChild(res[2]); | |
this.last = res[3]; | |
this.pcount = len + 1; | |
saveSpells = true; | |
} | |
getStoredObj('DESU_Favorites', function (fav) { | |
var el, f, h = aib.host; | |
if (fav[h] && fav[h][brd] && (f = fav[h][brd][this.op.num])) { | |
if (el = $id('de-content-fav')) { | |
el = $q('.de-fav-current > .de-entry[de-num="' + this.op.num + '"] .de-fav-inf-old', el); | |
el.textContent = this.pcount; | |
el = el.nextElementSibling; | |
el.style.display = 'none'; | |
el.textContent = 0; | |
} | |
f.cnt = this.pcount; | |
f['new'] = 0; | |
setStored('DESU_Favorites', JSON.stringify(fav)); | |
} | |
}.bind(this)); | |
if (saveSpells) { | |
spells.end(savePosts); | |
} | |
return [newPosts, newVisPosts]; | |
}, | |
_processExpandThread: function (nPosts, num) { | |
var i, fragm, tPost, len, needRMUpdate, post = this.op.next, | |
vPosts = this.pcount === 1 ? 0 : this.last.count - post.count + 1; | |
if (vPosts > num) { | |
while (vPosts-- !== num) { | |
post.wrap.classList.add('de-hidden'); | |
post.omitted = true; | |
post = post.next; | |
} | |
needRMUpdate = false; | |
} else if (vPosts < num) { | |
fragm = doc.createDocumentFragment(); | |
tPost = this.op; | |
len = nPosts.length; | |
for (i = Math.max(0, len - num), len -= vPosts; i < len; ++i) { | |
tPost = this._addPost(fragm, nPosts[i], i + 1, tPost); | |
spells.check(tPost); | |
} | |
$after(this.op.wrap, fragm); | |
tPost.next = post; | |
if (post) { | |
post.prev = tPost; | |
} | |
needRMUpdate = true; | |
num = Math.min(len + vPosts, num); | |
} else { | |
return num <= visPosts; | |
} | |
while (vPosts-- !== 0) { | |
if (post.trunc) { | |
post.updateMsg(replacePost($q(aib.qMsg, nPosts[post.count - 1]))); | |
} | |
if (post.omitted) { | |
post.wrap.classList.remove('de-hidden'); | |
post.omitted = false; | |
} | |
if (needRMUpdate) { | |
updRefMap(post, true); | |
} | |
post = post.next; | |
} | |
return num <= visPosts; | |
} | |
}; | |
// BROWSER | |
// =========================================================================================================== | |
function getNavFuncs() { | |
if (!('contains' in String.prototype)) { | |
String.prototype.contains = function (s) { | |
return this.indexOf(s) !== -1; | |
}; | |
String.prototype.startsWith = function (s) { | |
return this.indexOf(s) === 0; | |
}; | |
} | |
if (!('repeat' in String.prototype)) { | |
String.prototype.repeat = function (nTimes) { | |
return new Array(nTimes + 1).join(this.valueOf()); | |
}; | |
} | |
if (!('clz32' in Math)) { | |
Math.clz32 = function (x) { | |
return x < 1 ? x === 0 ? 32 : 0 : 31 - ((Math.log(x) / Math.LN2) >> 0); | |
}; | |
} | |
if ('toJSON' in aProto) { | |
delete aProto.toJSON; | |
} | |
if (!('URL' in window)) { | |
window.URL = window.webkitURL; | |
} | |
var ua = window.navigator.userAgent, | |
firefox = ua.contains('Gecko/'), | |
presto = window.opera ? +window.opera.version() : 0, | |
opera11 = presto ? presto < 12.1 : false, | |
webkit = ua.contains('WebKit/'), | |
chrome = webkit && ua.contains('Chrome/'), | |
safari = webkit && !chrome, | |
isGM = typeof GM_setValue === 'function' && | |
(!chrome || !GM_setValue.toString().contains('not supported')), | |
isChromeStorage = window.chrome && !!window.chrome.storage, | |
isScriptStorage = !!scriptStorage && !ua.contains('Opera Mobi'), | |
scriptInstall = | |
firefox ? (typeof Components !== 'undefined' && !!Components.interfaces.nsIFile ? | |
'Greasemonkey' : 'Scriptish') : | |
isChromeStorage ? 'Chrome extension' : | |
isGM ? 'Monkey' : 'Native userscript'; | |
if (!window.GM_xmlhttpRequest) { | |
window.GM_xmlhttpRequest = $xhr; | |
} | |
return { | |
get ua() { | |
return navigator.userAgent + (this.Firefox ? ' [' + navigator.buildID + ']' : ''); | |
}, | |
Firefox: firefox, | |
Opera11: opera11, | |
Presto: presto, | |
WebKit: webkit, | |
Chrome: chrome, | |
Safari: safari, | |
isGM: isGM, | |
isChromeStorage: isChromeStorage, | |
isScriptStorage: isScriptStorage, | |
isGlobal: isGM || isChromeStorage || isScriptStorage, | |
scriptInstall: scriptInstall, | |
cssFix: webkit ? '-webkit-' : opera11 ? '-o-' : '', | |
Anim: !opera11, | |
animName: webkit ? 'webkitAnimationName' : opera11 ? 'OAnimationName' : 'animationName', | |
animEnd: webkit ? 'webkitAnimationEnd' : opera11 ? 'oAnimationEnd' : 'animationend', | |
animEvent: function (el, Fn) { | |
el.addEventListener(this.animEnd, function aEvent() { | |
this.removeEventListener(nav.animEnd, aEvent, false); | |
Fn(this); | |
Fn = null; | |
}, false); | |
}, | |
fixLink: safari ? getAbsLink : function fixLink(url) { | |
return url; | |
}, | |
get hasWorker() { | |
var val = 'Worker' in (this.Firefox ? unsafeWindow : Window); | |
Object.defineProperty(this, 'hasWorker', { value: val }); | |
return val; | |
}, | |
get canPlayMP3() { | |
var val = !!new Audio().canPlayType('audio/mpeg;'); | |
Object.defineProperty(this, 'canPlayMP3', { value: val }); | |
return val; | |
}, | |
get canPlayWebm() { | |
var val = !!new Audio().canPlayType('video/webm; codecs="vp8,vorbis"'); | |
Object.defineProperty(this, 'canPlayWebm', { value: val }); | |
return val; | |
}, | |
get matchesSelector() { | |
var dE = doc.documentElement, | |
fun = dE.matchesSelector || dE.mozMatchesSelector || | |
dE.webkitMatchesSelector || dE.oMatchesSelector, | |
val = Function.prototype.call.bind(fun); | |
Object.defineProperty(this, 'matchesSelector', { value: val }); | |
return val; | |
} | |
}; | |
} | |
// IMAGEBOARD | |
// =========================================================================================================== | |
function getImageBoard(checkDomains, checkOther) { | |
var prot = window.location.protocol; | |
var ibDomains = { | |
'02ch.net': [{ | |
qPostRedir: { value: 'input[name="gb2"][value="thread"]' }, | |
ru: { value: true }, | |
timePattern: { value: 'yyyy+nn+dd++w++hh+ii+ss' } | |
}], | |
'2chru.net': [{ | |
_2chru: { value: true } | |
}, 'form[action*="imgboard.php?delete"]'], | |
get '2-chru.net'() { return this['2chru.net']; }, | |
get '2-ch.su'() { return this['2--ch.ru']; }, | |
'2--ch.ru': [{ | |
tire: { value: true }, | |
qPages: { value: 'table[border="1"] tr:first-of-type > td:first-of-type a' }, | |
qPostRedir: { value: null }, | |
qTable: { value: 'table:not(.postfiles)' }, | |
qThread: { value: '.threadz' }, | |
getFileWrap: { value: function (el) { | |
return el.parentNode; | |
} }, | |
getOmitted: { value: function (el, len) { | |
var txt; | |
return el && (txt = el.textContent) ? +(txt.match(/\d+/) || [0])[0] - len : 1; | |
} }, | |
getPageUrl: { value: function (b, p) { | |
return fixBrd(b) + (p > 0 ? p : 0) + '.memhtml'; | |
} }, | |
css: { value: 'span[id$="_display"], #fastload { display: none !important; }' }, | |
docExt: { value: '.html' }, | |
fixFileInputs: { value: function (el) { | |
var str = '><input name="file" maxlength="4" ' + | |
'accept="|sid|7z|bz2|m4a|flac|lzh|mo3|rar|spc|fla|nsf|jpg|mpp|aac|gz|xm|wav|' + | |
'mp3|png|it|lha|torrent|swf|zip|mpc|ogg|jpeg|gif|mod" type="file"></input></div>'; | |
el.parentNode.innerHTML = '<div' + str + ('<div style="display: none;"' + str).repeat(3); | |
} }, | |
hasPicWrap: { value: true }, | |
isBB: { value: true }, | |
ru: { value: true } | |
}], | |
'410chan.org': [{ | |
_410: { value: true }, | |
qPostRedir: { value: 'input#noko' }, | |
getSage: { value: function (post) { | |
var el = $c('filetitle', post); | |
return el && el.textContent.contains('\u21E9'); | |
} }, | |
formButtons: { get: function () { | |
return Object.create(this._formButtons, { | |
tag: { value: ['**', '*', '__', '^^', '%%', '`', '', '', 'q'] } | |
}); | |
} }, | |
isBB: { value: false }, | |
timePattern: { value: 'dd+nn+yyyy++w++hh+ii+ss' } | |
}, 'script[src*="kusaba"]'], | |
'420chan.org': [{ // Posting doesn't work (antispam protection) | |
_420: { value: true }, | |
qBan: { value: '.ban' }, | |
qError: { value: 'pre' }, | |
qHide: { value: '.replyheader ~ *' }, | |
qPages: { value: '.pagelist > a:last-child' }, | |
qPostRedir: { value: null }, | |
qThread: { value: '[id*="thread"]' }, | |
getTNum: { value: function (op) { | |
return $q('a[id]', op).id.match(/\d+/)[0]; | |
} }, | |
css: { value: '#content > hr, .hidethread, .ignorebtn, .opqrbtn, .qrbtn, noscript { display: none !important; }\ | |
.de-thr-hid { margin: 1em 0; }' }, | |
docExt: { value: '.php' }, | |
formButtons: { get: function () { | |
return Object.create(this._formButtons, { | |
tag: { value: ['**', '*', '', '', '%', 'pre', '', '', 'q'] } | |
}); | |
} }, | |
isBB: { value: true } | |
}], | |
'4chan.org': [{ | |
fch: { value: true }, | |
cFileInfo: { value: 'fileText' }, | |
cOPost: { value: 'op' }, | |
cReply: { value: 'post reply' }, | |
cSubj: { value: 'subject' }, | |
qBan: { value: 'strong[style="color: red;"]' }, | |
qDelBut: { value: '.deleteform > input[type="submit"]' }, | |
qError: { value: '#errmsg' }, | |
qHide: { value: '.postInfo ~ *' }, | |
qImgLink: { value: '.fileText > a' }, | |
qName: { value: '.name' }, | |
qOmitted: { value: '.summary.desktop' }, | |
qPages: { value: '.pagelist > .pages:not(.cataloglink) > a:last-of-type' }, | |
qPostForm: { value: 'form[name="post"]' }, | |
qPostRedir: { value: null }, | |
qRef: { value: '.postInfo > .postNum' }, | |
qTable: { value: '.replyContainer' }, | |
qThumbImages: { value: '.fileThumb > img' }, | |
getPageUrl: { value: function (b, p) { | |
return fixBrd(b) + (p > 1 ? p : ''); | |
} }, | |
getSage: { value: function (post) { | |
return !!$q('.id_Heaven, .useremail[href^="mailto:sage"]', post); | |
} }, | |
getTNum: { value: function (op) { | |
return $q('input[type="checkbox"]', op).name.match(/\d+/)[0]; | |
} }, | |
getWrap: { value: function (el, isOp) { | |
return el.parentNode; | |
} }, | |
anchor: { value: '#p' }, | |
css: { value: '.backlink, .extButton, hr.desktop, .navLinks, .postMenuBtn, #togglePostFormLink { display: none !important; }\ | |
.postForm { display: table !important; }\ | |
textarea { margin-right: 0 !important; }' }, | |
docExt: { value: '' }, | |
firstPage: { value: 1 }, | |
formButtons: { get: function () { | |
return Object.create(this._formButtons, { | |
tag: { value: ['**', '*', '__', '^H', 'spoiler', 'code', '', '', 'q'] }, | |
bb: { value: [false, false, false, false, true, true, false, false, false] } | |
}); | |
} }, | |
rLinkClick: { value: '' }, | |
rep: { value: true }, | |
res: { value: 'thread/' }, | |
timePattern: { value: 'nn+dd+yy+w+hh+ii-?s?s?' } | |
}], | |
'7chan.org': [{ | |
init: { value: function () { return true; } } | |
}], | |
'britfa.gs': [{ | |
init: { value: function () { return true; } } | |
}], | |
get 'dmirrgetyojz735v.onion'() { return this['2chru.net']; }, | |
'dobrochan.com': [{ | |
dobr: { value: true }, | |
anchor: { value: '#i' }, | |
cFileInfo: { value: 'fileinfo' }, | |
cSubj: { value: 'replytitle' }, | |
qDForm: { value: 'form[action*="delete"]' }, | |
qError: { value: '.post-error, h2' }, | |
qMsg: { value: '.postbody' }, | |
qOmitted: { value: '.abbrev > span:first-of-type' }, | |
qPages: { value: '.pages > tbody > tr > td' }, | |
qPostRedir: { value: 'select[name="goto"]' }, | |
qTrunc: { value: '.abbrev > span:nth-last-child(2)' }, | |
getFileWrap: { value: function (el) { | |
return el.parentNode; | |
} }, | |
getImgLink: { value: function (img) { | |
var el = img.parentNode; | |
if (el.tagName === 'A') { | |
return el; | |
} | |
return $q('.fileinfo > a', img.previousElementSibling ? el : el.parentNode); | |
} }, | |
getImgWrap: { value: function (el) { | |
return el.tagName === 'A' ? (el.previousElementSibling ? el : el.parentNode).parentNode : | |
el.firstElementChild.tagName === 'IMG' ? el.parentNode : el; | |
} }, | |
getPageUrl: { value: function (b, p) { | |
return fixBrd(b) + (p > 0 ? p + this.docExt : 'index.xhtml'); | |
} }, | |
getTNum: { value: function (op) { | |
return $q('a[name]', op).name.match(/\d+/)[0]; | |
} }, | |
insertYtPlayer: { value: function (msg, playerHtml) { | |
var prev = msg.previousElementSibling, | |
node = prev.tagName === 'BR' ? prev : msg; | |
node.insertAdjacentHTML('beforebegin', playerHtml); | |
return node.previousSibling; | |
} }, | |
css: { value: '.delete > img, .popup, .reply_, .search_google, .search_iqdb { display: none !important; }\ | |
.delete { background: none; }\ | |
.delete_checkbox { position: static !important; }\ | |
.file + .de-video-obj { float: left; margin: 5px 20px 5px 5px; }\ | |
.de-video-obj + div { clear: left; }' }, | |
disableRedirection: { value: function (el) { | |
($q(this.qPostRedir, el) || {}).selectedIndex = 1; | |
} }, | |
fixFileInputs: { value: function (el) { | |
el = $id('files_parent'); | |
$each($Q('input[type="file"]', el), function (el) { | |
el.removeAttribute('onchange'); | |
}); | |
el.firstElementChild.value = 1; | |
} }, | |
hasPicWrap: { value: true }, | |
init: { value: function () { | |
if (window.location.pathname === '/settings') { | |
nav = getNavFuncs(); | |
$q('input[type="button"]', doc).addEventListener('click', function () { | |
readCfg(function () { | |
saveCfg('__hanarating', $id('rating').value); | |
}); | |
}, false); | |
return true; | |
} | |
} }, | |
rLinkClick: { value: 'onclick="Highlight(event, this.getAttribute(\'de-num\'))"' }, | |
ru: { value: true }, | |
timePattern: { value: 'dd+m+?+?+?+?+?+yyyy++w++hh+ii-?s?s?' } | |
}], | |
get 'dobrochan.org'() { return this['dobrochan.com']; }, | |
'dva-ch.net': [{ | |
dvachnet: { value: true }, | |
}], | |
'hiddenchan.i2p': [{ | |
hid: { value: true } | |
}, 'script[src*="kusaba"]'], | |
get 'honokakawai.com'() { return this['2--ch.ru']; }, | |
'inach.org': [{ | |
qPostRedir: { value: 'input[name="fieldnoko"]' }, | |
css: { value: '#postform > table > tbody > tr:first-child { display: none !important; }' }, | |
init: { value: function () { | |
if (doc.cookie.contains('no_captcha_cook=1') && window.location.pathname.contains('res')) { | |
$id('captcha_field').innerHTML = 'Вам не нужно вводить капчу.'; | |
} | |
} }, | |
isBB: { value: true }, | |
timePattern: { value: 'nn+dd+yyyy++w++hh+ii+ss' } | |
}], | |
'krautchan.net': [{ | |
krau: { value: true }, | |
cFileInfo: { value: 'fileinfo' }, | |
cReply: { value: 'postreply' }, | |
cRPost: { value: 'postreply' }, | |
cSubj: { value: 'postsubject' }, | |
qBan: { value: '.ban_mark' }, | |
qDForm: { value: 'form[action*="delete"]' }, | |
qError: { value: '.message_text' }, | |
qHide: { value: 'div:not(.postheader)' }, | |
qImgLink: { value: '.filename > a' }, | |
qOmitted: { value: '.omittedinfo' }, | |
qPages: { value: 'table[border="1"] > tbody > tr > td > a:nth-last-child(2) + a' }, | |
qPostRedir: { value: 'input#forward_thread' }, | |
qRef: { value: '.postnumber' }, | |
qThread: { value: '.thread_body' }, | |
qThumbImages: { value: 'img[id^="thumbnail_"]' }, | |
qTrunc: { value: 'p[id^="post_truncated"]' }, | |
getFileWrap: { value: function (el) { | |
return el.parentNode; | |
} }, | |
getImgWrap: { value: function (el) { | |
return el.parentNode; | |
} }, | |
getSage: { value: function (post) { | |
return !!$c('sage', post); | |
} }, | |
getTNum: { value: function (op) { | |
return $q('input[type="checkbox"]', op).name.match(/\d+/)[0]; | |
} }, | |
insertYtPlayer: { value: function (msg, playerHtml) { | |
var pMsg = msg.parentNode, | |
prev = pMsg.previousElementSibling, | |
node = prev.hasAttribute('style') ? prev : pMsg; | |
node.insertAdjacentHTML('beforebegin', playerHtml); | |
return node.previousSibling; | |
} }, | |
css: { value: 'img[id^="translate_button"], img[src$="button-expand.gif"], img[src$="button-close.gif"], body > center > hr, form > div:first-of-type > hr, h2, .sage { display: none !important; }\ | |
div[id^="Wz"] { z-index: 10000 !important; }\ | |
.de-thr-hid { margin-bottom: ' + (!TNum ? '7' : '2') + 'px; float: none !important; }\ | |
.file_reply + .de-video-obj, .file_thread + .de-video-obj { margin: 5px 20px 5px 5px; float: left; }\ | |
.de-video-obj + div { clear: left; }' }, | |
fixFileInputs: { value: function (el) { | |
var i, len, node = $id('files_parent'), | |
str = ''; | |
for (i = 0, len = 4; i < len; ++i) { | |
str += '<div' + (i === 0 ? '' : ' style="display: none;"') + | |
'><input type="file" name="file_' + i + '" tabindex="7"></input></div>'; | |
} | |
node.innerHTML = str; | |
node.removeAttribute('id'); | |
} }, | |
formButtons: { get: function () { | |
return Object.create(this._formButtons, { | |
tag: { value: ['b', 'i', 'u', 's', 'spoiler', 'aa', '', '', 'q'] }, | |
}); | |
} }, | |
hasPicWrap: { value: true }, | |
init: { value: function () { | |
doc.body.insertAdjacentHTML('beforeend', '<div style="display: none;">' + | |
'<div onclick="window.lastUpdateTime = 0;"></div>' + | |
'<div onclick="if (boardRequiresCaptcha) { requestCaptcha(true); }"></div>' + | |
'<div onclick="setupProgressTracking();"></div>' + | |
'</div>'); | |
var els = doc.body.lastChild.children; | |
this.btnZeroLUTime = els[0]; | |
this.initCaptcha = els[1]; | |
this.addProgressTrack = els[2]; | |
} }, | |
isBB: { value: true }, | |
rep: { value: true }, | |
res: { value: 'thread-' }, | |
rLinkClick: { value: 'onclick="highlightPost(this.textContent.substr(2)))"' }, | |
timePattern: { value: 'yyyy+nn+dd+hh+ii+ss+--?-?-?-?-?' } | |
}], | |
'mlpg.co': [{ | |
cOPost: { value: 'opContainer' }, | |
getWrap: { value: function (el, isOp) { | |
return el.parentNode; | |
} }, | |
css: { value: '.image-hover, form > div[style="text-align: center;"], form > div[style="text-align: center;"] + hr { display: none !important; }' }, | |
formButtons: { get: function () { | |
return Object.create(this._formButtons, { | |
tag: { value: ['b', 'i', 'u', '-', 'spoiler', 'c', '', '', 'q'] }, | |
}); | |
} }, | |
isBB: { value: true } | |
}, 'form[name*="postcontrols"]'], | |
'ponychan.net': [{ | |
pony: { value: true }, | |
cOPost: { value: 'op' }, | |
qPages: { value: 'table[border="0"] > tbody > tr > td:nth-child(2) > a:last-of-type' }, | |
css: { value: '#bodywrap3 > hr { display: none !important; }' } | |
}, 'script[src*="kusaba"]'], | |
'reptila.ch': [{ | |
qMsg: { value: '.message' }, | |
}, 'form[action*="imgboard.php?delete"]'], | |
'syn-ch.ru': [{ | |
synch: { value: true }, | |
cFileInfo: { value: 'unimportant' }, | |
css: { value: '.fa-sort, .image_id { display: none !important; }\ | |
time:after { content: none; }' }, | |
formButtons: { get: function () { | |
return Object.create(this._formButtons, { | |
tag: { value: ['b', 'i', 'u', 's', 'spoiler', 'code', 'sub', 'sup', 'q'] }, | |
}); | |
} }, | |
init: { value: function () { | |
var val = '{"simpleNavbar":true,"textCountForm":true,"showInfo":true}'; | |
if (locStorage.getItem('settings') !== val) { | |
locStorage.setItem('settings', val); | |
window.location.reload(); | |
} | |
} }, | |
isBB: { value: true } | |
}, 'form[name*="postcontrols"]'], | |
get 'syn-ch.com'() { return this['syn-ch.ru']; }, | |
get 'syn-ch.org'() { return this['syn-ch.ru']; } | |
}; | |
var ibEngines = { | |
'section.posts': { | |
mak: { value: true }, | |
cReply: { value: 'post reply' }, | |
cSubj: { value: 'post-title' }, | |
qBan: { value: 'font[color="#C12267"]' }, // FIXME | |
qDForm: { value: '#posts-form' }, | |
qHide: { value: '.post-details ~ *' }, | |
qImgLink: { value: '.file-attr > .desktop' }, | |
qMsg: { value: '.post-message' }, | |
qName: { value: '.ananimas' }, | |
qOmitted: { value: '.mess-post' }, | |
qPostRedir: { value: null }, | |
qThumbImages: { value: '.preview' }, | |
qTrunc: { value: null }, | |
getImgParent: { value: function (el) { | |
var el = $parent(el, 'FIGURE'), | |
parent = el.parentNode; | |
return parent.lastElementChild === el ? parent : el; | |
} }, | |
getImgWrap: { value: function (el) { | |
return $parent(el, 'FIGURE'); | |
} }, | |
getPNum: { value: function (post) { | |
return post.getAttribute('data-num'); | |
} }, | |
getWrap: { value: function (el) { | |
return el.parentNode; | |
} }, | |
crimea: { value: function (op, el) { | |
brd === 'b' && (this.crimeaReg.test(op.text) || this.crimeaReg.test(op.subj)) && $del(el); | |
} }, | |
crimeaReg: { value: /[^а-я]\u043A\u0440\u044B\u043C|\u043D\u043E\u0432\u043E\u0440\u043E\u0441|[\u043B\u0434]\u043D\u0440/i }, | |
cssEn: { value: '.ABU-refmap, .box[onclick="ToggleSage()"], header > hr, img[alt="webm file"], label[for="name"], .media-expand-button, .norm-reply, .passcode-banner > hr, .postform-hr, .postpanel > :not(img), .posts > hr, .reflink:before, .thread-nav { display: none !important; }\ | |
.captcha-image > img { cursor: pointer; }\ | |
.de-abtn { transition: none; }\ | |
#de-txt-panel { font-size: 16px !important; }' }, | |
formButtons: { get: function () { | |
return Object.create(this._formButtons, { | |
tag: { value: ['B', 'I', 'U', 'S', 'SPOILER', 'CODE', 'SUP', 'SUB', 'q'] } | |
}); | |
} }, | |
hasPicWrap: { value: true }, | |
init: { value: function () { | |
$script('window.FormData = void 0;'); | |
var el = $q('tr:not([class])', doc.body); | |
if (!el) { | |
return; | |
} | |
doc.body.insertAdjacentHTML('beforeend', '<div style="display: none;">' + | |
'<div onclick="loadCaptcha();"></div>' + | |
'</div>'); | |
this.updateCaptcha = function (el, focus) { | |
this.click(); | |
el.style.display = ''; | |
el = $id('captcha-value'); | |
if (el) { | |
pr.cap = el; | |
el.tabIndex = 999; | |
if (focus) { | |
el.focus(); | |
} | |
} | |
}.bind(doc.body.lastChild.firstChild, el); | |
el.addEventListener('click', function (e) { | |
if (e.target.tagName === 'IMG') { | |
this.updateCaptcha(true); | |
} | |
}.bind(this), true); | |
} }, | |
isBB: { value: true }, | |
lastPage: { configurable: true, get: function () { | |
var els = $Q('.pager > a:not([class])', doc), | |
val = els ? els.length : 1; | |
Object.defineProperty(this, 'lastPage', { value: val }); | |
return val; | |
} }, | |
rLinkClick: { value: '' } | |
}, | |
'#ABU_css, #ShowLakeSettings': { | |
abu: { value: true }, | |
qBan: { value: 'font[color="#C12267"]' }, | |
qDForm: { value: '#posts-form, #posts_form, #delform' }, | |
qOmitted: { value: '.mess_post, .omittedposts' }, | |
qPostRedir: { value: null }, | |
getImgWrap: { value: function (el) { | |
return el.parentNode.parentNode; | |
} }, | |
getSage: { writable: true, value: function (post) { | |
if ($c('postertripid', dForm)) { | |
this.getSage = function (post) { | |
return !$c('postertripid', post); | |
}; | |
} else { | |
this.getSage = Object.getPrototypeOf(this).getSage; | |
} | |
return this.getSage(post); | |
} }, | |
cssEn: { value: '#ABU_alert_wait, .ABU_refmap, #captcha_div + font, #CommentToolbar, .postpanel, #usrFlds + tbody > tr:first-child, body > center { display: none !important; }\ | |
.de-abtn { transition: none; }\ | |
#de-txt-panel { font-size: 16px !important; }\ | |
.reflink:before { content: none !important; }' }, | |
formButtons: { get: function () { | |
return Object.create(this._formButtons, { | |
tag: { value: ['b', 'i', 'u', 's', 'spoiler', 'code', 'sup', 'sub', 'q'] } | |
}); | |
} }, | |
init: { value: function () { | |
var cd = $id('captcha_div'), | |
img = cd && $t('img', cd); | |
if (img) { | |
cd.setAttribute('onclick', ['var el, i = 4,', | |
'isCustom = (typeof event.detail === "object") && event.detail.isCustom;', | |
"if (!isCustom && event.target.tagName !== 'IMG') {", | |
'return;', | |
'}', | |
'do {', img.getAttribute('onclick'), '} while (--i > 0 && !/<img|не нужно/i.test(this.innerHTML));', | |
"if (el = this.getElementsByTagName('img')[0]) {", | |
"el.removeAttribute('onclick');", | |
"if ((!isCustom || event.detail.focus) && (el = this.querySelector('input[type=\\'text\\']'))) {", | |
'el.focus();', | |
'}', | |
'}' | |
].join('')); | |
img.removeAttribute('onclick'); | |
} | |
} }, | |
isBB: { value: true } | |
}, | |
'form[action*="futaba.php"]': { | |
futa: { value: true }, | |
qDForm: { value: 'form:not([enctype])' }, | |
qImgLink: { value: 'a[href$=".jpg"], a[href$=".png"], a[href$=".gif"]' }, | |
qOmitted: { value: 'font[color="#707070"]' }, | |
qPostForm: { value: 'form:nth-of-type(1)' }, | |
qPostRedir: { value: null }, | |
qRef: { value: '.del' }, | |
qThumbImages: { value: 'a[href$=".jpg"] > img, a[href$=".png"] > img, a[href$=".gif"] > img' }, | |
getPageUrl: { value: function (b, p) { | |
return fixBrd(b) + (p > 0 ? p + this.docExt : 'futaba.htm'); | |
} }, | |
getPNum: { value: function (post) { | |
return $t('input', post).name; | |
} }, | |
getPostEl: { value: function (el) { | |
while (el && el.tagName !== 'TD' && !el.hasAttribute('de-thread')) { | |
el = el.parentElement; | |
} | |
return el; | |
} }, | |
getPosts: { value: function (thr) { | |
return $Q('td:nth-child(2)', thr); | |
} }, | |
getTNum: { value: function (op) { | |
return $q('input[type="checkbox"]', op).name.match(/\d+/)[0]; | |
} }, | |
cssEn: { value: '.de-cfg-body, .de-content { font-family: arial; }\ | |
.ftbl { width: auto; margin: 0; }\ | |
.reply { background: #f0e0d6; }\ | |
span { font-size: inherit; }' }, | |
docExt: { value: '.htm' } | |
}, | |
'form[action*="imgboard.php?delete"]': { | |
tinyIb: { value: true }, | |
qPostRedir: { value: null }, | |
ru: { value: true } | |
}, | |
'form[name*="postcontrols"]': { | |
tiny: { value: true }, | |
cFileInfo: { value: 'fileinfo' }, | |
cReply: { value: 'post reply' }, | |
cSubj: { value: 'subject' }, | |
cTrip: { value: 'trip' }, | |
qDForm: { value: 'form[name="postcontrols"]' }, | |
qHide: { value: '.intro ~ *'}, | |
qImgLink: { value: 'p.fileinfo > a:first-of-type' }, | |
qMsg: { value: '.body' }, | |
qName: { value: '.name' }, | |
qOmitted: { value: '.omitted' }, | |
qPages: { value: '.pages > a:nth-last-of-type(2)' }, | |
qPostForm: { value: 'form[name="post"]' }, | |
qPostRedir: { value: null }, | |
qRef: { value: '.post_no:nth-of-type(2)' }, | |
qTable: { value: '.post.reply' }, | |
qTrunc: { value: '.toolong' }, | |
firstPage: { value: 1 }, | |
formButtons: { get: function () { | |
return Object.create(this._formButtons, { | |
tag: { value: ["'''", "''", '__', '^H', '**', '`', '', '', 'q'] }, | |
}); | |
} }, | |
timePattern: { value: 'nn+dd+yy++w++hh+ii+ss' }, | |
getPageUrl: { value: function (b, p) { | |
return p > 1 ? fixBrd(b) + p + this.docExt : fixBrd(b); | |
} }, | |
getTNum: { value: function (op) { | |
return $q('input[type="checkbox"]', op).name.match(/\d+/)[0]; | |
} }, | |
cssEn: { get: function () { | |
return '.banner, ' + (TNum ? '' : '.de-btn-rep, ') + '.mentioned, .post-hover { display: none !important; }\ | |
div.post.reply { float: left; clear: left; display: block; }\ | |
form, form table { margin: 0; }'; | |
} } | |
}, | |
'script[src*="kusaba"]': { | |
kus: { value: true }, | |
cOPost: { value: 'postnode' }, | |
qError: { value: 'h1, h2, div[style*="1.25em"]' }, | |
qPostRedir: { value: null }, | |
cssEn: { value: '.extrabtns, #newposts_get, .replymode, .ui-resizable-handle, blockquote + a { display: none !important; }\ | |
.ui-wrapper { display: inline-block; width: auto !important; height: auto !important; padding: 0 !important; }' }, | |
isBB: { value: true }, | |
rLinkClick: { value: 'onclick="highlight(this.textContent.substr(2), true)"' } | |
}, | |
get 'form[action$="board.php"]'() { return this['script[src*="kusaba"]']; }, | |
'link[href$="phutaba.css"]': { | |
cOPost: { value: 'thread_OP' }, | |
cReply: { value: 'post' }, | |
cRPost: { value: 'thread_reply' }, | |
qError: { value: '.error' }, | |
qMsg: { value: '.text' }, | |
cSubj: { value: 'subject' }, | |
cTrip: { value: 'tripcode' }, | |
qHide: { value: '.post > .post_body' }, | |
qPages: { value: '.pagelist > li:nth-last-child(2)' }, | |
qTrunc: { value: '.tldr' }, | |
qImgLink: { value: '.filename > a' }, | |
qPostRedir: { value: 'input[name="gb2"][value="thread"]' }, | |
css: { value: '.content > hr, .de-parea > hr { display: none !important }' }, | |
fixFileInputs: { value: function (el) { | |
var str = '><input name="file" type="file"></input></div>'; | |
el.removeAttribute('onchange'); | |
el.parentNode.parentNode.innerHTML = '<div' + str + ('<div style="display: none;"' + str).repeat(3); | |
} }, | |
getFileWrap: { value: function (el) { | |
return el.parentNode; | |
} }, | |
getImgWrap: { value: function (el) { | |
return el.parentNode.parentNode; | |
} }, | |
getSage: { value: function (post) { | |
return !!$q('.sage', post); | |
} }, | |
docExt: { value: '' }, | |
isBB: { value: true }, | |
res: { value: 'thread/' } | |
} | |
}; | |
var ibBase = { | |
cFileInfo: 'filesize', | |
cOPost: 'oppost', | |
cReply: 'reply', | |
cRPost: 'reply', | |
cSubj: 'filetitle', | |
cTrip: 'postertrip', | |
qBan: '', | |
qDelBut: 'input[type="submit"]', | |
qDForm: '#delform, form[name="delform"]', | |
qError: 'h1, h2, font[size="5"]', | |
qHide: '.de-post-btns ~ *', | |
get qImgLink() { | |
var val = '.' + this.cFileInfo + ' a[href$=".jpg"], ' + | |
'.' + this.cFileInfo + ' a[href$=".jpeg"], ' + | |
'.' + this.cFileInfo + ' a[href$=".png"], ' + | |
'.' + this.cFileInfo + ' a[href$=".gif"], ' + | |
'.' + this.cFileInfo + ' a[href$=".webm"]'; | |
Object.defineProperty(this, 'qImgLink', { value: val }); | |
return val; | |
}, | |
qMsg: 'blockquote', | |
get qMsgImgLink() { | |
var val = this.qMsg + ' a[href*=".jpg"], ' + | |
this.qMsg + ' a[href*=".png"], ' + | |
this.qMsg + ' a[href*=".gif"], ' + | |
this.qMsg + ' a[href*=".jpeg"]'; | |
Object.defineProperty(this, 'qMsgImgLink', { value: val }); | |
return val; | |
}, | |
qName: '.postername, .commentpostername', | |
qOmitted: '.omittedposts', | |
qPages: 'table[border="1"] > tbody > tr > td:nth-child(2) > a:last-of-type', | |
qPostForm: '#postform', | |
qPostRedir: 'input[name="postredir"][value="1"]', | |
qRef: '.reflink', | |
qTable: 'form > table, div > table, div[id^="repl"]', | |
qThumbImages: '.thumb, .de-thumb, .ca_thumb, img[src*="thumb"], img[src*="/spoiler"], img[src^="blob:"]', | |
get qThread() { | |
var val = $c('thread', doc) ? '.thread' : | |
$q('div[id*="_info"][style*="float"]', doc) ? 'div[id^="t"]:not([style])' : | |
'[id^="thread"]'; | |
Object.defineProperty(this, 'qThread', { value: val }); | |
return val; | |
}, | |
qTrunc: '.abbrev, .abbr, .shortened', | |
getFileWrap: function (el) { | |
return el; | |
}, | |
getImgLink: function (img) { | |
var el = img.parentNode; | |
return el.tagName === 'SPAN' ? el.parentNode : el; | |
}, | |
getImgParent: function (el) { | |
return this.getImgWrap(el); | |
}, | |
getImgSize: function (info) { | |
if (info) { | |
var sz = info.match(/(\d+)\s?[x×]\s?(\d+)/); | |
return [sz[1], sz[2]]; | |
} | |
return [-1, -1]; | |
}, | |
getImgWeight: function (info) { | |
var w = info.match(/(\d+(?:[\.,]\d+)?)\s*([mkк])?i?[bб]/i); | |
return w[2] === 'M' ? (w[1] * 1e3) | 0 : !w[2] ? Math.round(w[1] / 1e3) : w[1]; | |
}, | |
getImgWrap: function (el) { | |
var node = (el.tagName === 'SPAN' ? el.parentNode : el).parentNode; | |
return node.tagName === 'SPAN' ? node.parentNode : node; | |
}, | |
getOmitted: function (el, len) { | |
var txt; | |
return el && (txt = el.textContent) ? +(txt.match(/\d+/) || [0])[0] + 1 : 1; | |
}, | |
getOp: function (thr) { | |
var el, op, opEnd; | |
if (op = localRun && $q('div[de-oppost]', thr) || $c(this.cOPost, thr)) { | |
return op; | |
} | |
op = thr.ownerDocument.createElement('div'); | |
op.setAttribute('de-oppost', ''); | |
opEnd = $q(this.qTable, thr); | |
while ((el = thr.firstChild) !== opEnd) { | |
op.appendChild(el); | |
} | |
if (thr.hasChildNodes()) { | |
thr.insertBefore(op, thr.firstChild); | |
} else { | |
thr.appendChild(op); | |
} | |
return op; | |
}, | |
getPNum: function (post) { | |
return post.id.match(/\d+/)[0]; | |
}, | |
getPageUrl: function (b, p) { | |
return fixBrd(b) + (p > 0 ? p + this.docExt : ''); | |
}, | |
getPostEl: function (el) { | |
while (el && !el.classList.contains(this.cRPost) && !el.hasAttribute('de-thread')) { | |
el = el.parentElement; | |
} | |
return el; | |
}, | |
getPosts: function (thr) { | |
return $Q('.' + this.cRPost, thr); | |
}, | |
getSage: function (post) { | |
var a = $q('a[href^="mailto:"], a[href="sage"]', post); | |
return !!a && /sage/i.test(a.href); | |
}, | |
getThrdUrl: function (b, tNum) { | |
return this.prot + '//' + this.host + fixBrd(b) + this.res + tNum + this.docExt; | |
}, | |
getTNum: function (op) { | |
return $q('input[type="checkbox"]', op).value; | |
}, | |
getWrap: function (el, isOp) { | |
if (isOp) { | |
return el; | |
} | |
if (el.tagName === 'TD') { | |
Object.defineProperty(this, 'getWrap', { value: function (el, isOp) { | |
return isOp ? el : $parent(el, 'TABLE'); | |
}}); | |
} else { | |
Object.defineProperty(this, 'getWrap', { value: function (el, isOp) { | |
return el; | |
}}); | |
} | |
return this.getWrap(el, isOp); | |
}, | |
insertYtPlayer: function (msg, playerHtml) { | |
msg.insertAdjacentHTML('beforebegin', playerHtml); | |
return msg.previousSibling; | |
}, | |
anchor: '#', | |
css: '', | |
cssEn: '', | |
disableRedirection: function (el) { | |
if (this.qPostRedir) { | |
($q(this.qPostRedir, el) || {}).checked = true; | |
} | |
}, | |
dm: '', | |
docExt: '.html', | |
firstPage: 0, | |
fixFileInputs: emptyFn, | |
get _formButtons() { | |
var bb = this.isBB; | |
return { | |
id: ['bold', 'italic', 'under', 'strike', 'spoil', 'code', 'sup', 'sub', 'quote'], | |
val: ['B', 'i', 'U', 'S', '%', 'C', 'v', '^', '>'], | |
tag: bb ? ['b', 'i', 'u', 's', 'spoiler', 'code', '', '', 'q'] : | |
['**', '*', '', '^H', '%%', '`', '', '', 'q'], | |
bb: [bb, bb, bb, bb, bb, bb, bb, bb, bb] | |
}; | |
}, | |
get formButtons() { | |
return this._formButtons; | |
}, | |
hasPicWrap: false, | |
host: window.location.hostname, | |
init: null, | |
isBB: false, | |
get lastPage() { | |
var el = $q(this.qPages, doc), | |
val = el && +aProto.pop.call(el.textContent.match(/\d+/g) || []) || 0; | |
if (pageNum === val + 1) { | |
val++; | |
} | |
Object.defineProperty(this, 'lastPage', { value: val }); | |
return val; | |
}, | |
prot: prot, | |
get reCrossLinks() { | |
var val = new RegExp('>https?:\\/\\/[^\\/]*' + this.dm + '\\/([a-z0-9]+)\\/' + | |
regQuote(this.res) + '(\\d+)(?:[^#<]+)?(?:#i?(\\d+))?<', 'g'); | |
Object.defineProperty(this, 'reCrossLinks', { value: val }); | |
return val; | |
}, | |
get rep() { | |
var val = dTime || spells.haveReps || Cfg.crossLinks; | |
Object.defineProperty(this, 'rep', { value: val }); | |
return val; | |
}, | |
res: 'res/', | |
rLinkClick: 'onclick="highlight(this.textContent.substr(2))"', | |
ru: false, | |
timePattern: 'w+dd+m+yyyy+hh+ii+ss' | |
}; | |
localRun = prot === 'file:'; | |
var i, ibObj = null, dm = localRun ? | |
(window.location.pathname.match(/\/([^-]+)-[^-]+-[^\.]+\.[a-z]+$/) || [,''])[1] : | |
window.location.hostname | |
.match(/(?:(?:[^.]+\.)(?=org\.|net\.|com\.))?[^.]+\.[^.]+$|^\d+\.\d+\.\d+\.\d+$|localhost/)[0]; | |
if (checkDomains) { | |
if (dm in ibDomains) { | |
ibObj = (function createBoard(info) { | |
return Object.create( | |
info[2] ? createBoard(ibDomains[info[2]]) : | |
info[1] ? Object.create(ibBase, ibEngines[info[1]]) : | |
ibBase, info[0] | |
); | |
})(ibDomains[dm]); | |
checkOther = false; | |
} | |
} | |
if (checkOther) { | |
for (i in ibEngines) { | |
if ($q(i, doc)) { | |
ibObj = Object.create(ibBase, ibEngines[i]); | |
break; | |
} | |
} | |
if (!ibObj) { | |
ibObj = ibBase; | |
} | |
} | |
if (ibObj) { | |
ibObj.dm = dm; | |
} | |
return ibObj; | |
}; | |
// INITIALIZATION | |
// =========================================================================================================== | |
function Initialization(checkDomains) { | |
if (/^(?:about|chrome|opera|res)/i.test(window.location)) { | |
return false; | |
} | |
try { | |
locStorage = window.localStorage; | |
sesStorage = window.sessionStorage; | |
sesStorage['__de-test'] = 1; | |
} catch(e) { | |
if (typeof unsafeWindow !== 'undefined') { | |
locStorage = unsafeWindow.localStorage; | |
sesStorage = unsafeWindow.sessionStorage; | |
} | |
} | |
if (!(locStorage && typeof locStorage === 'object' && sesStorage)) { | |
console.log('WEBSTORAGE ERROR: please, enable webstorage!'); | |
return false; | |
} | |
var intrv, url; | |
switch (window.name) { | |
case '': break; | |
case 'de-iframe-pform': | |
case 'de-iframe-dform': | |
$script('window.top.postMessage("A' + window.name + '" + document.documentElement.outerHTML, "*");'); | |
return false; | |
case 'de-iframe-fav': | |
intrv = setInterval(function () { | |
$script('window.top.postMessage("B' + (doc.body.offsetHeight + 5) + '", "*");'); | |
}, 1500); | |
window.addEventListener('load', setTimeout.bind(window, clearInterval, 3e4, intrv), false); | |
liteMode = true; | |
pr = {}; | |
} | |
if (!aib) { | |
aib = getImageBoard(checkDomains, true); | |
} | |
if (aib.init && aib.init()) { | |
return false; | |
} | |
dForm = $q(aib.qDForm + ', form[de-form]', doc); | |
if (!dForm || $id('de-panel')) { | |
return false; | |
} | |
nav = getNavFuncs(); | |
window.addEventListener('storage', function (e) { | |
var data, temp, post, val = e.newValue; | |
if (!val) { | |
return; | |
} | |
switch (e.key) { | |
case '__de-post': { | |
try { | |
data = JSON.parse(val); | |
} catch(e) { | |
return; | |
} | |
temp = data.hide; | |
if (data.brd === brd && (post = pByNum[data.num]) && (post.hidden ^ temp)) { | |
post.setUserVisib(temp, data.date, false); | |
} else { | |
if (!(data.brd in bUVis)) { | |
bUVis[data.brd] = {}; | |
} | |
bUVis[data.brd][data.num] = [+!temp, data.date]; | |
} | |
if (data.isOp) { | |
if (!(data.brd in hThr)) { | |
if (temp) { | |
hThr[data.brd] = {}; | |
} else { | |
break; | |
} | |
} | |
if (temp) { | |
hThr[data.brd][data.num] = data.title; | |
} else { | |
delete hThr[data.brd][data.num]; | |
} | |
} | |
break; | |
} | |
case '__de-threads': { | |
try { | |
hThr = JSON.parse(val); | |
} catch(e) { | |
return; | |
} | |
if (!(brd in hThr)) { | |
hThr[brd] = {}; | |
} | |
firstThr.updateHidden(hThr[brd]); | |
break; | |
} | |
case '__de-spells': { | |
try { | |
data = JSON.parse(val); | |
} catch(e) { | |
return; | |
} | |
Cfg.hideBySpell = data.hide; | |
if (temp = $q('input[info="hideBySpell"]', doc)) { | |
temp.checked = data.hide; | |
} | |
doc.body.style.display = 'none'; | |
disableSpells(); | |
if (data.data) { | |
spells.setSpells(data.data, false); | |
if (temp = $id('de-spell-edit')) { | |
temp.value = spells.list; | |
} | |
} else { | |
if (data.data === '') { | |
spells.disable(); | |
if (temp = $id('de-spell-edit')) { | |
temp.value = ''; | |
} | |
saveCfg('spells', ''); | |
} | |
spells.enable = false; | |
} | |
doc.body.style.display = ''; | |
} | |
default: return; | |
} | |
toggleContent('hid', true); | |
}, false); | |
if (localRun) { | |
url = window.location.pathname.match(/\/[^-]+-([^-]+)-([^\.]+)\.[a-z]+$/); | |
aib.prot = 'http:'; | |
aib.host = aib.dm; | |
brd = url ? url[1] : ''; | |
TNum = url ? url[2] : ''; | |
pageNum = 0; | |
aib.docExt = '.html'; | |
} else { | |
url = (window.location.pathname || '').match(new RegExp( | |
'^(?:\\/?([^\\.]*?(?:\\/[^\\/]*?)?)\\/?)?' + '(' + regQuote(aib.res) + ')?' + | |
'(\\d+|index|wakaba|futaba)?' + '(\\.(?:[a-z]+))?(?:\\/|$)' | |
)); | |
brd = url[1].replace(/\/$/, ''); | |
TNum = url[2] ? url[3] : | |
aib.futa ? +(window.location.search.match(/\d+/) || [false])[0] : | |
false; | |
pageNum = url[3] && !TNum ? +url[3] || aib.firstPage : aib.firstPage; | |
if (!aib.hasOwnProperty('docExt') && url[4]) { | |
aib.docExt = url[4]; | |
} | |
} | |
dummy = doc.createElement('div'); | |
return true; | |
} | |
function parseThreadNodes(form, threads) { | |
var el, i, len, node, fNodes = aProto.slice.call(form.childNodes), | |
cThr = doc.createElement('div'); | |
for (i = 0, len = fNodes.length - 1; i < len; ++i) { | |
node = fNodes[i]; | |
if (node.tagName === 'HR') { | |
form.insertBefore(cThr, node); | |
form.insertBefore(cThr.lastElementChild, node); | |
el = cThr.lastElementChild; | |
if (el.tagName === 'BR') { | |
form.insertBefore(el, node); | |
} | |
threads.push(cThr); | |
cThr = doc.createElement('div'); | |
} else { | |
cThr.appendChild(node); | |
} | |
} | |
cThr.appendChild(fNodes[i]); | |
form.appendChild(cThr); | |
return threads; | |
} | |
function parseDelform(node, thrds) { | |
var i, lThr, len = thrds.length; | |
$each($T('script', node), $del); | |
if (len === 0) { | |
Thread.parsed = true; | |
if (localRun) { | |
thrds = $Q('div[de-thread]', doc); | |
len = thrds.length; | |
} | |
if (len === 0) { | |
thrds = parseThreadNodes(dForm, []); | |
len = thrds.length; | |
} | |
} | |
if (len) { | |
firstThr = lThr = new Thread(thrds[0], null); | |
} | |
for (i = 1; i < len; i++) { | |
lThr = new Thread(thrds[i], lThr); | |
} | |
lastThr = lThr; | |
node.setAttribute('de-form', ''); | |
node.removeAttribute('id'); | |
if (aib.abu && TNum) { | |
lThr = firstThr.el; | |
while ((node = lThr.nextSibling) && node.tagName !== 'HR') { | |
$del(node); | |
} | |
} | |
} | |
function replaceString(txt) { | |
if (dTime) { | |
txt = dTime.fix(txt); | |
} | |
if (aib.fch || aib.krau) { | |
if (aib.fch) { | |
txt = txt.replace(/<\/?wbr>/g, '').replace(/ \(OP\)<\/a/g, '</a'); | |
} | |
txt = txt.replace(/(^|>|\s|>)(https*:\/\/[^"<>]*?)(<\/a>)?(?=$|<|\s)/ig, function (x, a, b, c) { | |
return c ? x : a + '<a href="' + b + '">' + b + '</a>'; | |
}); | |
} | |
if (spells.haveReps) { | |
txt = spells.replace(txt); | |
} | |
if (Cfg.crossLinks) { | |
txt = txt.replace(aib.reCrossLinks, function (str, b, tNum, pNum) { | |
return '>>>/' + b + '/' + (pNum || tNum) + '<'; | |
}); | |
} | |
return txt; | |
} | |
function replacePost(el) { | |
if (aib.rep) { | |
el.innerHTML = replaceString(el.innerHTML); | |
} | |
return el; | |
} | |
function replaceDelform() { | |
if (liteMode) { | |
doc.body.insertAdjacentHTML('afterbegin', dForm.outerHTML); | |
dForm = doc.body.firstChild; | |
window.addEventListener('load', function () { | |
while (dForm.nextSibling) { | |
$del(dForm.nextSibling); | |
} | |
}, false); | |
} else if (aib.rep) { | |
dForm.insertAdjacentHTML('beforebegin', replaceString(dForm.outerHTML)); | |
dForm.style.display = 'none'; | |
dForm.id = 'de-dform-old'; | |
dForm = dForm.previousSibling; | |
window.addEventListener('load', function () { | |
$del($id('de-dform-old')); | |
}, false); | |
} | |
} | |
function initDelformAjax() { | |
var btn; | |
if (Cfg.ajaxReply === 2) { | |
dForm.onsubmit = $pd; | |
if (btn = $q(aib.qDelBut, dForm)) { | |
btn.onclick = function (e) { | |
$pd(e); | |
pr.closeQReply(); | |
$alert(Lng.deleting[lang], 'deleting', true); | |
new html5Submit(dForm, e.target, checkDelete); | |
}; | |
} | |
} else if (Cfg.ajaxReply === 1) { | |
dForm.insertAdjacentHTML('beforeend', | |
'<iframe name="de-iframe-pform" src="about:blank" style="display: none;"></iframe>' + | |
'<iframe name="de-iframe-dform" src="about:blank" style="display: none;"></iframe>' | |
); | |
dForm.target = 'de-iframe-dform'; | |
dForm.onsubmit = function () { | |
pr.closeQReply(); | |
$alert(Lng.deleting[lang], 'deleting', true); | |
}; | |
} | |
} | |
function initThreadUpdater(title, enableUpdate) { | |
var focused, delay, checked4XX, loadTO, audioRep, currentXHR, audioEl, stateButton, hasAudio, | |
initDelay, favIntrv, favNorm, favHref, notifGranted, enabled = false, | |
disabledByUser = true, | |
inited = false, | |
lastECode = 200, | |
sendError = false, | |
newPosts = 0, | |
aPlayers = 0; | |
if (('hidden' in doc) || ('webkitHidden' in doc)) { | |
focused = !(doc.hidden || doc.webkitHidden); | |
doc.addEventListener((nav.WebKit ? 'webkit' : '') + 'visibilitychange', function () { | |
if (doc.hidden || doc.webkitHidden) { | |
focused = false; | |
firstThr && firstThr.clearPostsMarks(); | |
} else { | |
onVis(); | |
} | |
}, false); | |
} else { | |
focused = false; | |
window.addEventListener('focus', onVis, false); | |
window.addEventListener('blur', function () { | |
focused = false; | |
firstThr.clearPostsMarks(); | |
}, false); | |
window.addEventListener('mousemove', function mouseMove() { | |
window.removeEventListener('mousemove', mouseMove, false); | |
onVis(); | |
}, false); | |
} | |
if (enableUpdate) { | |
init(); | |
} | |
if (focused && Cfg.desktNotif && ('permission' in Notification)) { | |
switch (Notification.permission.toLowerCase()) { | |
case 'default': requestNotifPermission(); break; | |
case 'denied': saveCfg('desktNotif', 0); | |
} | |
} | |
function init() { | |
audioEl = null; | |
stateButton = null; | |
hasAudio = false; | |
initDelay = Cfg.updThrDelay * 1e3; | |
favIntrv = 0; | |
favNorm = notifGranted = inited = true; | |
favHref = ($q('head link[rel="shortcut icon"]', doc) || {}).href; | |
enable(true); | |
} | |
function enable(startLoading) { | |
enabled = true; | |
checked4XX = false; | |
newPosts = 0; | |
delay = initDelay; | |
if (startLoading) { | |
loadTO = setTimeout(loadPostsFun, delay); | |
} | |
} | |
function disable(byUser) { | |
disabledByUser = byUser; | |
if (enabled) { | |
clearTimeout(loadTO); | |
enabled = hasAudio = false; | |
setState('off'); | |
var btn = $id('de-btn-audio-on'); | |
if (btn) { | |
btn.id = 'de-btn-audio-off'; | |
} | |
} | |
} | |
function toggleAudio(aRep) { | |
if (!audioEl) { | |
audioEl = $new('audio', { | |
'preload': 'auto', | |
'src': 'https://raw.github.com/SthephanShinkufag/Dollchan-Extension-Tools/master/signal.ogg' | |
}, null); | |
} | |
audioRep = aRep; | |
return hasAudio = !hasAudio; | |
} | |
function audioNotif() { | |
if (focused) { | |
hasAudio = false; | |
} else { | |
audioEl.play() | |
setTimeout(audioNotif, audioRep); | |
hasAudio = true; | |
} | |
} | |
function requestNotifPermission() { | |
notifGranted = false; | |
Notification.requestPermission(function (state) { | |
if (state.toLowerCase() === 'denied') { | |
saveCfg('desktNotif', 0); | |
} else { | |
notifGranted = true; | |
} | |
}); | |
} | |
function loadPostsFun() { | |
currentXHR = firstThr.loadNew(onLoaded, true); | |
} | |
function forceLoadPosts() { | |
if (currentXHR) { | |
currentXHR.abort(); | |
} | |
if (!enabled && !disabledByUser) { | |
enable(false); | |
} else { | |
clearTimeout(loadTO); | |
delay = initDelay; | |
} | |
loadPostsFun(); | |
} | |
function favIcoBlink() { | |
$del($q('link[rel="shortcut icon"]', doc.head)); | |
doc.head.insertAdjacentHTML('afterbegin', '<link rel="shortcut icon" href="' + | |
(!favNorm ? favHref : 'data:image/x-icon;base64,' + this) + '">'); | |
favNorm = !favNorm; | |
} | |
function onLoaded(eCode, eMsg, lPosts, xhr) { | |
if (currentXHR !== xhr && eCode === 0) { // Loading aborted | |
return; | |
} | |
currentXHR = null; | |
infoLoadErrors(eCode, eMsg, -1); | |
if (eCode !== 200 && eCode !== 304) { | |
lastECode = eCode; | |
if (Cfg.favIcoBlink && !focused && favHref) { | |
clearInterval(favIntrv); | |
favIntrv = setInterval(favIcoBlink.bind('iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAA3' + | |
'NCSVQICAjb4U/gAAAALVBMVEX////QRDfQRDfQRDfQRDfQRDfQRDfQRDfQRDfQRDfQRDfQRDfQRDfQRDfQRDdi' + | |
'Ad5MAAAAD3RSTlMAESIzRFVmd4iZu8zd7v9ufV8LAAAACXBIWXMAAAsSAAALEgHS3X78AAAAFXRFWHRDcmVhdG' + | |
'lvbiBUaW1lADEwLzIvMTOFMzGTAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAAH9J' + | |
'REFUCJljYEAAjbO3C0E067l37946ABlxLxWY6q4wMDDde+PAwPxGgYHj5bnLDAx1BQw8j3yBKvQ2MPA9YL53mI' + | |
'HvAJDB4PPOAMjgfsTA/O4wUIrjOQODzdt5CQyM9wwYmO+9EWBg8H2uwDTvMdBkFqAVbwxAlqmvOV2I5AYASFUr' + | |
'cXUe0gcAAAAASUVORK5CYII='), 800); | |
} | |
if (!Cfg.noErrInTitle) { | |
updateTitle(); | |
} | |
if (eCode !== 0 && eCode < 500) { | |
if (!checked4XX && (eCode === 404 || eCode === 400)) { | |
checked4XX = true; | |
} else { | |
updateTitle(); | |
disable(false); | |
return; | |
} | |
} | |
setState('warn'); | |
if (enabled) { | |
loadTO = setTimeout(loadPostsFun, delay); | |
} | |
return; | |
} | |
if (lastECode !== 200) { | |
lastECode = 200; | |
setState('on'); | |
checked4XX = false; | |
if ((focused || lPosts === 0) && !Cfg.noErrInTitle) { | |
updateTitle(); | |
} | |
} | |
if (!focused) { | |
if (lPosts !== 0) { | |
if (Cfg.favIcoBlink && favHref && newPosts === 0) { | |
favIntrv = setInterval(favIcoBlink.bind('iVBORw0KGgoAAAANSUhEUgAAABAAAAAQEAYAAABPYyMiAA' + | |
'AABmJLR0T///////8JWPfcAAAACXBIWXMAAABIAAAASABGyWs+AAAAF0lEQVRIx2NgGAWjYBSMglEwCkbB' + | |
'SAcACBAAAeaR9cIAAAAASUVORK5CYII='), 800); | |
} | |
newPosts += lPosts; | |
updateTitle(); | |
if (Cfg.desktNotif && notifGranted) { | |
var post = firstThr.last, | |
imgs = post.images, | |
notif = new Notification(aib.dm + '/' + brd + '/' + TNum + ': ' + newPosts + | |
Lng.newPost[lang][lang !== 0 ? +(newPosts !== 1) : (newPosts % 10) > 4 || | |
(newPosts % 10) === 0 || (((newPosts % 100) / 10) | 0) === 1 ? 2 : | |
(newPosts % 10) === 1 ? 0 : 1] + Lng.newPost[lang][3], | |
{ | |
'body': post.text.substring(0, 250).replace(/\s+/g, ' '), | |
'tag': aib.dm + brd + TNum, | |
'icon': imgs.length === 0 ? favHref : imgs[0].src | |
}); | |
notif.onshow = function () { | |
setTimeout(this.close.bind(this), 12e3); | |
}; | |
notif.onclick = function () { | |
window.focus(); | |
}; | |
notif.onerror = function () { | |
window.focus(); | |
requestNotifPermission(); | |
}; | |
} | |
if (hasAudio) { | |
if (audioRep) { | |
audioNotif(); | |
} else { | |
audioEl.play() | |
} | |
} | |
delay = initDelay; | |
} else if (delay !== 12e4) { | |
delay = Math.min(delay + initDelay, 12e4); | |
} | |
} | |
if (enabled) { | |
loadTO = setTimeout(loadPostsFun, delay); | |
} | |
} | |
function setState(state) { | |
var btn = stateButton || (stateButton = $q('a[id^="de-btn-upd"]', doc)); | |
btn.id = 'de-btn-upd-' + state; | |
btn.title = Lng.panelBtn['upd-' + (state === 'off' ? 'off' : 'on')][lang]; | |
} | |
function onVis() { | |
if (Cfg.favIcoBlink && favHref) { | |
clearInterval(favIntrv); | |
favNorm = true; | |
$del($q('link[rel="shortcut icon"]', doc.head)); | |
doc.head.insertAdjacentHTML('afterbegin', '<link rel="shortcut icon" href="' + favHref + '">'); | |
} | |
newPosts = 0; | |
focused = true; | |
sendError = false; | |
setTimeout(function () { | |
updateTitle(); | |
if (enabled) { | |
forceLoadPosts(); | |
} | |
}, 200); | |
} | |
function updateTitle() { | |
doc.title = (aPlayers === 0 ? '' : '♫ ') + | |
(sendError === true ? '{' + Lng.error[lang] + '} ' : '') + | |
(lastECode === 200 ? '' : '{' + lastECode + '} ') + | |
(newPosts === 0 ? '' : '[' + newPosts + '] ') + title; | |
} | |
function addPlayingTag() { | |
aPlayers++; | |
if (aPlayers === 1) { | |
updateTitle(); | |
} | |
} | |
function removePlayingTag() { | |
aPlayers = Math.max(aPlayers - 1, 0); | |
if (aPlayers === 0) { | |
updateTitle(); | |
} | |
} | |
function sendErrNotif() { | |
if (Cfg.sendErrNotif && !focused) { | |
sendError = true; | |
updateTitle(); | |
} | |
} | |
return { | |
get enabled() { | |
return enabled; | |
}, | |
get focused() { | |
return focused; | |
}, | |
forceLoad: forceLoadPosts, | |
enable: function () { | |
if (!inited) { | |
init(); | |
} else if (!enabled) { | |
enable(true); | |
} else { | |
return; | |
} | |
setState('on'); | |
}, | |
disable: function () { | |
disable(true); | |
}, | |
updateXHR: function (newXHR) { | |
currentXHR = newXHR; | |
}, | |
toggleAudio: toggleAudio, | |
addPlayingTag: addPlayingTag, | |
removePlayingTag: removePlayingTag, | |
sendErrNotif: sendErrNotif | |
}; | |
} | |
function initPage() { | |
if (Cfg.updScript) { | |
checkForUpdates(false, function (html) { | |
$alert(html, 'updavail', false); | |
}); | |
} | |
if (TNum) { | |
if (Cfg.rePageTitle) { | |
doc.title = '/' + brd + ' - ' + firstThr.op.title; | |
} | |
if (!localRun) { | |
firstThr.el.insertAdjacentHTML('afterend', | |
'<div id="de-updater-div">>> [<a class="de-abtn" id="de-updater-btn" href="#"></a>]' + | |
(aib.mak ? '[<a class="de-abtn" href="#" onclick="UnbanShow();">Реквест разбана</a>]' : '') + | |
'</div>'); | |
firstThr.el.nextSibling.addEventListener('click', Thread.loadNewPosts, false); | |
} | |
} else if (needScroll) { | |
setTimeout(window.scrollTo, 20, 0, 0); | |
} | |
updater = initThreadUpdater(doc.title, TNum && Cfg.ajaxUpdThr); | |
} | |
function checkForUpdates(isForce, Fn) { | |
var day, temp = Cfg.scrUpdIntrv; | |
if (!isForce) { | |
day = 2 * 1000 * 60 * 60 * 24; | |
switch (temp) { | |
case 0: temp = day; break; | |
case 1: temp = day * 2; break; | |
case 2: temp = day * 7; break; | |
case 3: temp = day * 14; break; | |
default: temp = day * 30; | |
} | |
if (Date.now() - +comCfg.lastUpd < temp) { | |
return; | |
} | |
} | |
GM_xmlhttpRequest({ | |
'method': 'GET', | |
'url': 'https://raw.github.com/SthephanShinkufag/Dollchan-Extension-Tools/master/Dollchan_Extension_Tools.meta.js', | |
'headers': {'Content-Type': 'text/plain'}, | |
'onreadystatechange': function (xhr) { | |
if (xhr.readyState !== 4) { | |
return; | |
} | |
if (xhr.status === 200) { | |
var dVer = xhr.responseText.match(/@version\s+([0-9.]+)/)[1].split('.'), | |
cVer = version.split('.'), | |
len = cVer.length > dVer.length ? cVer.length : dVer.length, | |
i = 0, | |
isUpd = false; | |
if (!dVer) { | |
if (isForce) { | |
Fn('<div style="color: red; font-weigth: bold;">' + Lng.noConnect[lang] + '</div>'); | |
} | |
return; | |
} | |
saveComCfg('lastUpd', Date.now()); | |
while (i < len) { | |
if ((+dVer[i] || 0) > (+cVer[i] || 0)) { | |
isUpd = true; | |
break; | |
} else if ((+dVer[i] || 0) < (+cVer[i] || 0)) { | |
break; | |
} | |
i++; | |
} | |
if (isUpd) { | |
Fn('<a style="color: blue; font-weight: bold;" href="https://raw.github.com/SthephanShinkufag/Dollchan-Extension-Tools/master/Dollchan_Extension_Tools.user.js">' + | |
Lng.updAvail[lang] + '</a>'); | |
} else if (isForce) { | |
Fn(Lng.haveLatest[lang]); | |
} | |
} else if (isForce) { | |
Fn('<div style="color: red; font-weigth: bold;">' + Lng.noConnect[lang] + '</div>'); | |
} | |
} | |
}); | |
} | |
// CSS | |
// =========================================================================================================== | |
function getThemeLang() { | |
return !Cfg.scriptStyle ? 'fr' : | |
Cfg.scriptStyle === 1 ? 'en' : | |
'de'; | |
} | |
function scriptCSS() { | |
var p, x = ''; | |
function cont(id, src) { | |
return id + ':before { content: ""; padding: 0 16px 0 0; margin: 0 4px; background: url(' + src + ') no-repeat center; }'; | |
} | |
function gif (id, src) { | |
return id + ' { background: url(data:image/gif;base64,' + src + ') no-repeat center !important; }'; | |
} | |
// Settings window | |
x += '#darude-sandstorm { -moz-box-sizing: content-box; box-sizing: content-box; }\ | |
.de-block { display: block; }\ | |
#de-content-cfg > div { float: left; border-radius: 10px 10px 0 0; width: auto; min-width: 0; padding: 0; margin: 5px 20px; }\ | |
.de-cfg-head { padding: 3px; border-radius: 10px 10px 0 0; color: #fff; text-align: center; font: bold 14px arial; cursor: default; }\ | |
.de-cfg-head:lang(en), #de-panel:lang(en) { background: linear-gradient(to bottom, #4b90df, #3d77be 5px, #376cb0 7px, #295591 13px, rgba(0,0,0,0) 13px), linear-gradient(to bottom, rgba(0,0,0,0) 12px, #183d77 13px, #1f4485 18px, #264c90 20px, #325f9e 25px); }\ | |
.de-cfg-head:lang(fr), #de-panel:lang(fr) { background: linear-gradient(to bottom, #7b849b, #616b86 2px, #3a414f 13px, rgba(0,0,0,0) 13px), linear-gradient(to bottom, rgba(0,0,0,0) 12px, #121212 13px, #1f2740 25px); }\ | |
.de-cfg-head:lang(de), #de-panel:lang(de) { background: #777; }\ | |
.de-cfg-body { min-height: 304px; min-width: 357px; padding: 11px 7px 7px; margin-top: -1px; font: 13px sans-serif !important;}\ | |
.de-cfg-body input, .de-cfg-body label, .de-cfg-body select { width: auto; padding: 0 !important; margin: 1px 2px !important; }\ | |
.de-cfg-body input[type="button"], .de-cfg-body input[type="text"] { padding: 1px 2px !important; }\ | |
.de-cfg-body, #de-cfg-btns { border: 1px solid #183d77; border-top: none; }\ | |
.de-cfg-body:lang(de), #de-cfg-btns:lang(de) { border-color: #444; }\ | |
#de-cfg-btns { padding: 3px; font-size: 13px !important; }\ | |
#de-cfg-btns input { padding: 0 3px; }\ | |
#de-cfg-bar { width: 100%; display: table; background-color: #1f2740; margin: 0; padding: 0; }\ | |
#de-cfg-bar:lang(en) { background-color: #325f9e; }\ | |
#de-cfg-bar:lang(de) { background-color: #777; }\ | |
.de-cfg-depend { padding-left: 25px; }\ | |
.de-cfg-tab { padding: 4px 4px; border-radius: 4px 4px 0 0; font: bold 12px arial; text-align: center; cursor: default; }\ | |
.de-cfg-tab-back { display: table-cell !important; float: none !important; width:auto; min-width: 0 !important; padding: 0 !important; box-shadow: none !important; border: 1px solid #183d77 !important; border-radius: 4px 4px 0 0 !important; opacity: 1; }\ | |
.de-cfg-tab-back:lang(de) { border-color: #444 !important; }\ | |
.de-cfg-tab-back:lang(fr) { border-color: #121421 !important; }\ | |
.de-cfg-tab-back[selected="true"] { border-bottom: none !important; }\ | |
.de-cfg-tab-back[selected="false"] > .de-cfg-tab { background-color: rgba(0,0,0,.2); }\ | |
.de-cfg-tab-back[selected="false"] > .de-cfg-tab:lang(en), .de-cfg-tab-back[selected="false"] > .de-cfg-tab:lang(fr) { background: linear-gradient(to bottom, rgba(132,132,132,.35) 0%, rgba(79,79,79,.35) 50%, rgba(40,40,40,.35) 50%, rgba(80,80,80,.35) 100%) !important; }\ | |
.de-cfg-tab-back[selected="false"] > .de-cfg-tab:hover { background-color: rgba(99,99,99,.2); }\ | |
.de-cfg-tab-back[selected="false"] > .de-cfg-tab:hover:lang(en), .de-cfg-tab-back[selected="false"] > .de-cfg-tab:hover:lang(fr) { background: linear-gradient(to top, rgba(132,132,132,.35) 0%, rgba(79,79,79,.35) 50%, rgba(40,40,40,.35) 50%, rgba(80,80,80,.35) 100%) !important; }\ | |
.de-cfg-tab::' + (nav.Firefox ? '-moz-' : '') + 'selection { background: transparent; }\ | |
.de-cfg-unvis { display: none; }\ | |
#de-spell-panel { float: right; }\ | |
#de-spell-panel > a { padding: 0 4px; }\ | |
#de-spell-div { display: table; }\ | |
#de-spell-div > div { display: table-cell; vertical-align: top; }\ | |
#de-spell-edit { padding: 2px !important; width: 325px; height: 180px; max-width: 100%; border: none !important; outline: none !important; }\ | |
#de-spell-rowmeter { padding: 2px 3px 0 0; margin: 2px 0; overflow: hidden; width: 2em; height: 182px; text-align: right; color: #fff; font: 12px courier new; }\ | |
#de-spell-rowmeter:lang(en), #de-spell-rowmeter:lang(fr) { background-color: #616b86; }\ | |
#de-spell-rowmeter:lang(de) { background-color: #777; }'; | |
// Main panel | |
x += '#de-btn-logo { margin-right: 3px; cursor: pointer; }\ | |
#de-panel { height: 25px; z-index: 9999; border-radius: 15px 0 0 0; cursor: default;}\ | |
#de-panel-btns { display: inline-block; padding: 0 0 0 2px; margin: 0; height: 25px; border-left: 1px solid #8fbbed; }\ | |
#de-panel-btns:lang(de), #de-panel-info:lang(de) { border-color: #ccc; }\ | |
#de-panel-btns:lang(fr), #de-panel-info:lang(fr) { border-color: #616b86; }\ | |
#de-panel-btns > li { margin: 0 1px; padding: 0; }\ | |
#de-panel-btns > li, #de-panel-btns > li > a, #de-btn-logo { display: inline-block; width: 25px; height: 25px; }\ | |
#de-panel-btns:lang(en) > li, #de-panel-btns:lang(fr) > li { transition: all 0.3s ease; }\ | |
#de-panel-btns:lang(en) > li:hover, #de-panel-btns:lang(fr) > li:hover { background-color: rgba(255,255,255,.15); box-shadow: 0 0 3px rgba(143,187,237,.5); }\ | |
#de-panel-btns:lang(de) > li > a { border-radius: 5px; }\ | |
#de-panel-btns:lang(de) > li > a:hover { width: 21px; height: 21px; border: 2px solid #444; }\ | |
#de-panel-info { vertical-align: 6px; padding: 2px 6px; margin-left: 2px; height: 25px; border-left: 1px solid #8fbbed; color: #fff; font: 18px serif; }'; | |
p = 'R0lGODlhGQAZAIAAAPDw8P///yH5BAEAAAEALAAAAAAZABkA'; | |
x += gif ('#de-btn-logo', p + 'QAI5jI+pywEPWoIIRomz3tN6K30ixZXM+HCgtjpk1rbmTNc0erHvLOt4vvj1KqnD8FQ0HIPCpbIJtB0KADs='); | |
x += gif ('#de-btn-settings', p + 'QAJAjI+pa+API0Mv1Ymz3hYuiQHHFYjcOZmlM3Jkw4aeAn7R/aL6zuu5VpH8aMJaKtZR2ZBEZnMJLM5kIqnP2csUAAA7'); | |
x += gif ('#de-btn-hidden', p + 'QAI5jI+pa+CeHmRHgmCp3rxvO3WhMnomUqIXl2UmuLJSNJ/2jed4Tad96JLBbsEXLPbhFRc8lU8HTRQAADs='); | |
x += gif ('#de-btn-favor', p + 'QAIzjI+py+AMjZs02ovzobzb1wDaeIkkwp3dpLEoeMbynJmzG6fYysNh3+IFWbqPb3OkKRUFADs='); | |
x += gif ('#de-btn-video', p + 'AAI9jI+py+0Po5wTWEvN3VjyH20a6HDHB5TiaTIkuyov3MltEuM3nS5z8EPsgsIY6rE6QlA5JDMDbEKn1KqhAAA7'); | |
x += gif ('#de-btn-refresh', p + 'AAJBjI+py+0Po5zUgItBxDZrmHUcGAbe15xiybCm5iYegsaHfY8Kvrb6/qPhZr7LgrcyJlHFE1LoVG6ilVewis1qDQUAOw=='); | |
x += gif ('#de-btn-goback', p + 'QAIrjI+pmwAMm4u02gud3lzjD4biJgbd6VVPybbua61lGqIoY98ZPcvwD4QUAAA7'); | |
x += gif ('#de-btn-gonext', p + 'QAIrjI+pywjQonuy2iuf3lzjD4Zis0Xd6YnQyLbua61tSqJnbXcqHVLwD0QUAAA7'); | |
x += gif ('#de-btn-goup', p + 'QAIsjI+pm+DvmDRw2ouzrbq9DmKcBpVfN4ZpyLYuCbgmaK7iydpw1OqZf+O9LgUAOw=='); | |
x += gif ('#de-btn-godown', p + 'QAItjI+pu+DA4ps02osznrq9DnZceIxkYILUd7bue6WhrLInLdokHq96tnI5YJoCADs='); | |
x += gif ('#de-btn-expimg', p + 'QAI9jI+pGwDn4GPL2Wep3rxXFEFel42mBE6kcYXqFqYnVc72jTPtS/KNr5OJOJMdq4diAXWvS065NNVwseehAAA7'); | |
x += gif ('#de-btn-preimg', p + 'QAJFjI+pGwCcHJPGWdoe3Lz7qh1WFJLXiX4qgrbXVEIYadLLnMX4yve+7ErBYorRjXiEeXagGguZAbWaSdHLOow4j8Hrj1EAADs='); | |
x += gif ('#de-btn-maskimg', p + 'QAJQjI+pGwD3TGxtJgezrKz7DzLYRlKj4qTqmoYuysbtgk02ZCG1Rkk53gvafq+i8QiSxTozIY7IcZJOl9PNBx1de1Sdldeslq7dJ9gsUq6QnwIAOw=='); | |
x += gif ('#de-btn-savethr', p + 'QAJFjI+pG+CQnHlwSYYu3rz7RoVipWib+aVUVD3YysAledKZHePpzvecPGnpDkBQEEV03Y7DkRMZ9ECNnemUlZMOQc+iT1EAADs=') | |
x += gif ('#de-btn-catalog', p + 'QAI2jI+pa+DhAHyRNYpltbz7j1Rixo0aCaaJOZ2SxbIwKTMxqub6zuu32wP9WsHPcFMs0XDJ5qEAADs='); | |
x += gif ('#de-btn-audio-off', p + 'QAI7jI+pq+DO1psvQHOj3rxTik1dCIzmSZqfmGXIWlkiB6L2jedhPqOfCitVYolgKcUwyoQuSe3WwzV1kQIAOw=='); | |
x += gif ('#de-btn-audio-on', p + 'QAJHjI+pq+AewJHs2WdoZLz7X11WRkEgNoHqimadOG7uAqOm+Y6atvb+D0TgfjHS6RIp8YQ1pbHRfA4n0eSTI7JqP8Wtahr0FAAAOw=='); | |
x += gif ('#de-btn-enable', p + 'AAJAjI+py+0Po5wUWKoswOF27z2aMX6bo51lioal2bzwISPyHSZ1lts9fwKKfjQiyXgkslq95TAFnUCdUirnis0eCgA7'); | |
p = 'Dw8P///wAAACH5BAEAAAIALAAAAAAZABkAQAJElI+pe2EBoxOTNYmr3bz7OwHiCDzQh6bq06QSCUhcZMCmNrfrzvf+XsF1MpjhCSainBg0AbKkFCJko6g0MSGyftwuowAAOw=='; | |
x += gif ('#de-btn-upd-on', 'R0lGODlhGQAZAJEAADL/Mv' + p); | |
x += gif ('#de-btn-upd-off', 'R0lGODlhGQAZAJEAAP8yMv' + p); | |
x += gif ('#de-btn-upd-warn', 'R0lGODlhGQAZAJEAAP/0Qf' + p); | |
if (Cfg.disabled) { | |
applyCSS(x); | |
return; | |
} | |
// Post panel | |
x += '.de-post-btns { margin-left: 4px; }\ | |
.de-post-note { color: inherit; margin: 0 4px; vertical-align: 1px; font: italic bold 12px serif; }\ | |
.de-thread-note { font-style: italic; }\ | |
.de-btn-expthr, .de-btn-fav, .de-btn-fav-sel, .de-btn-hide, .de-btn-hide-user, .de-btn-rep, .de-btn-sage, .de-btn-src, .de-btn-stick, .de-btn-stick-on { transform:rotate(0deg); display: inline-block; margin: 0 4px -2px 0 !important; cursor: pointer; '; | |
if (Cfg.postBtnsCSS === 0) { | |
x += 'color: #4F7942; font-size: 14px; }\ | |
.de-post-hide .de-btn-hide:after { content: "\u271A"; }\ | |
.de-post-hide .de-btn-hide-user:after { content: "\u271A"; }\ | |
.de-btn-expthr:after { content: "\u21D5"; }\ | |
.de-btn-fav:after { content: "\u2605"; }\ | |
.de-btn-fav-sel:after { content: "[\u2605]"; }\ | |
.de-btn-hide:after { content: "\u2716"; }\ | |
.de-btn-hide-user:after { content: "\u2716"; color: red !important; }\ | |
.de-btn-rep:after { content: "\u25B6"; }\ | |
.de-btn-sage:after { content: "\u274E"; }\ | |
.de-btn-src:after { content: "[S]"; }\ | |
.de-btn-stick:after { content: "\u25FB"; }\ | |
.de-btn-stick-on:after { content: "\u25FC"; }'; | |
} else if (Cfg.postBtnsCSS === 1) { | |
p = 'R0lGODlhDgAOAKIAAPDw8KCgoICAgEtLS////wAAAAAAAAAAACH5BAEAAAQALAAAAAAOAA4AAAM'; | |
x += 'padding: 0 14px 14px 0; }'; | |
x += gif ('.de-post-hide .de-btn-hide', p + '4SLLcqyHKGRe1E1cARPaSwIGVI3bOIAxc26oD7LqwusZcbMcNC9gLHsMHvFFixwFlGRgQdNAoIQEAOw=='); | |
x += gif ('.de-post-hide .de-btn-hide-user', 'R0lGODlhDgAOAKIAAP+/v6CgoICAgEtLS////wAAAAAAAAAAACH5BAEAAAQALAAAAAAOAA4AAAM4SLLcqyHKGRe1E1cARPaSwIGVI3bOIAxc26oD7LqwusZcbMcNC9gLHsMHvFFixwFlGRgQdNAoIQEAOw=='); | |
x += gif ('.de-btn-expthr', p + '5SLLcqyHGJaeoAoAr6dQaF3gZGFpO6AzNoLHMAC8uMAty+7ZwbfYzny02qNSKElkloDQSZNAolJAAADs='); | |
x += gif ('.de-btn-fav', p + '4SLLcqyHGJaeoAoAradec1Wigk5FoOQhDSq7DyrpyvLRpDb84AO++m+YXiVWMAWRlmSTEntAnIQEAOw=='); | |
x += gif ('.de-btn-fav-sel', 'R0lGODlhDgAOAKIAAP/hAKCgoICAgEtLS////wAAAAAAAAAAACH5BAEAAAQALAAAAAAOAA4AAAM4SLLcqyHGJaeoAoAradec1Wigk5FoOQhDSq7DyrpyvLRpDb84AO++m+YXiVWMAWRlmSTEntAnIQEAOw=='); | |
x += gif ('.de-btn-hide', p + '7SLLcqyHKGZcUE1ctAPdb0AHeCDpkWi4DM6gtGwtvOg9xDcu0rbc4FiA3lEkGE2QER2kGBgScdColJAAAOw=='); | |
x += gif ('.de-btn-hide-user', 'R0lGODlhDgAOAKIAAL//v6CgoICAgEtLS////wAAAAAAAAAAACH5BAEAAAQALAAAAAAOAA4AAAM7SLLcqyHKGZcUE1ctAPdb0AHeCDpkWi4DM6gtGwtvOg9xDcu0rbc4FiA3lEkGE2QER2kGBgScdColJAAAOw=='); | |
x += gif ('.de-btn-rep', p + '2SLLcqyHKGZe0NGABAL5C1XWfM47NsAznqA6qwLbAG8/nfeexvNe91UACywSKxsmAAGs6m4QEADs='); | |
x += gif ('.de-btn-sage', 'R0lGODlhDgAOAJEAAPDw8EtLS////wAAACH5BAEAAAIALAAAAAAOAA4AAAIZVI55pu0AgZs0SoqTzdnu5l1P1ImcwmBCAQA7'); | |
x += gif ('.de-btn-src', p + '/SLLcqyEuKWKYF4Cl6/VCF26UJHaUIzaDMGjA8Gqt7MJ47Naw3O832kxnay1sx11g6KMtBxEZ9DkdEKTYLCEBADs='); | |
x += gif ('.de-btn-stick', p + 'xSLLcqyHKGRe9wVYntQBgKGxMKDJDaQJouqzsMrgDTNO27Apzv88YCjAoGRB8yB4hAQA7'); | |
x += gif ('.de-btn-stick-on', 'R0lGODlhDgAOAKIAAL//v6CgoICAgEtLS////wAAAAAAAAAAACH5BAEAAAQALAAAAAAOAA4AAAMxSLLcqyHKGRe9wVYntQBgKGxMKDJDaQJouqzsMrgDTNO27Apzv88YCjAoGRB8yB4hAQA7'); | |
} else { | |
p = 'R0lGODlhDgAOAJEAAPDw8IyMjP///wAAACH5BAEAAAIALAAAAAAOAA4AAAI'; | |
x += 'padding: 0 14px 14px 0; }'; | |
x += gif ('.de-post-hide .de-btn-hide', p + 'ZVI55pu3vAIBI0mOf3LtxDmWUGE7XSTFpAQA7'); | |
x += gif ('.de-post-hide .de-btn-hide-user', 'R0lGODlhDgAOAJEAAP+/v4yMjP///wAAACH5BAEAAAIALAAAAAAOAA4AAAIZVI55pu3vAIBI0mOf3LtxDmWUGE7XSTFpAQA7 '); | |
x += gif ('.de-btn-expthr', p + 'bVI55pu0BwEMxzlonlHp331kXxjlYWH4KowkFADs='); | |
x += gif ('.de-btn-fav', p + 'dVI55pu0BwEtxnlgb3ljxrnHP54AgJSGZxT6MJRQAOw=='); | |
x += gif ('.de-btn-fav-sel', 'R0lGODlhDgAOAJEAAP/hAIyMjP///wAAACH5BAEAAAIALAAAAAAOAA4AAAIdVI55pu0BwEtxnlgb3ljxrnHP54AgJSGZxT6MJRQAOw=='); | |
x += gif ('.de-btn-hide', p + 'dVI55pu2vQJIN2GNpzPdxGHwep01d5pQlyDoMKBQAOw=='); | |
x += gif ('.de-btn-hide-user', 'R0lGODlhDgAOAJEAAL//v4yMjP///wAAACH5BAEAAAIALAAAAAAOAA4AAAIdVI55pu2vQJIN2GNpzPdxGHwep01d5pQlyDoMKBQAOw=='); | |
x += gif ('.de-btn-rep', p + 'aVI55pu2vAIBISmrty7rx63FbN1LmiTCUUAAAOw=='); | |
x += gif ('.de-btn-sage', 'R0lGODlhDgAOAJEAAPDw8FBQUP///wAAACH5BAEAAAIALAAAAAAOAA4AAAIZVI55pu0AgZs0SoqTzdnu5l1P1ImcwmBCAQA7'); | |
x += gif ('.de-btn-src', p + 'fVI55pt0ADnRh1uispfvpLkEieGGiZ5IUGmJrw7xCAQA7'); | |
x += gif ('.de-btn-stick', p + 'XVI55pu0PI5j00erutJpfj0XiKDKRUAAAOw=='); | |
x += gif ('.de-btn-stick-on', 'R0lGODlhDgAOAJEAAL//v4yMjP///wAAACH5BAEAAAIALAAAAAAOAA4AAAIXVI55pu0PI5j00erutJpfj0XiKDKRUAAAOw=='); | |
} | |
if (!pr.form && !pr.oeForm) { | |
x += '.de-btn-rep { display: none; }'; | |
} | |
// Search images buttons | |
x += cont('.de-src-google', 'https://google.com/favicon.ico'); | |
x += cont('.de-src-tineye', 'https://tineye.com/favicon.ico'); | |
x += cont('.de-src-iqdb', '//iqdb.org/favicon.ico'); | |
x += cont('.de-src-saucenao', 'https://saucenao.com/favicon.ico'); | |
// Posts counter | |
x += '.de-post-counter:after { counter-increment: de-cnt 1; content: counter(de-cnt); margin-right: 4px; vertical-align: 1px; color: #4f7942; font: bold 11px tahoma; cursor: default; }\ | |
.de-post-deleted:after { content: "' + Lng.deleted[lang] + '"; margin-right: 4px; vertical-align: 1px; color: #727579; font: bold 11px tahoma; cursor: default; }'; | |
// Text format buttons | |
x += '#de-txt-panel { display: block; height: 23px; font-weight: bold; cursor: pointer; }\ | |
#de-txt-panel > span:empty { display: inline-block; width: 27px; height: 23px; }'; | |
p = 'R0lGODlhFwAWAJEAAPDw8GRkZAAAAP///yH5BAEAAAMALAAAAAAXABYAQAJ'; | |
x += gif ('#de-btn-bold:empty', p + 'T3IKpq4YAoZgR0KqqnfzipIUikFWc6ZHBwbQtG4zyonW2Vkb2iYOo8Ps8ZLOV69gYEkU5yQ7YUzqhzmgsOLXWnlRIc9PleX06rnbJ/KITDqTLUAAAOw=='); | |
x += gif ('#de-btn-italic:empty', p + 'K3IKpq4YAYxRCSmUhzTfx3z3c9iEHg6JnAJYYSFpvRlXcLNUg3srBmgr+RL0MzxILsYpGzyepfEIjR43t5kResUQmtdpKOIQpQwEAOw=='); | |
x += gif ('#de-btn-under:empty', p + 'V3IKpq4YAoRARzAoV3hzoDnoJNlGSWSEHw7JrEHILiVp1NlZXtKe5XiptPrFh4NVKHh9FI5NX60WIJ6ATZoVeaVnf8xSU4r7NMRYcFk6pzYRD2TIUAAA7'); | |
x += gif ('#de-btn-strike:empty', p + 'S3IKpq4YAoRBR0qqqnVeD7IUaKHIecjCqmgbiu3jcfCbAjOfTZ0fmVnu8YIHW6lgUDkOkCo7Z8+2AmCiVqHTSgi6pZlrN3nJQ8TISO4cdyJWhAAA7'); | |
x += gif ('#de-btn-spoil:empty', 'R0lGODlhFwAWAJEAAPDw8GRkZP///wAAACH5BAEAAAIALAAAAAAXABYAQAJBlIKpq4YAmHwxwYtzVrprXk0LhBziGZiBx44hur4kTIGsZ99fSk+mjrMAd7XerEg7xnpLIVM5JMaiFxc14WBiBQUAOw=='); | |
x += gif ('#de-btn-code:empty', p + 'O3IKpq4YAoZgR0KpqnFxokH2iFm7eGCEHw7JrgI6L2F1YotloKek6iIvJAq+WkfgQinjKVLBS45CePSXzt6RaTjHmNjpNNm9aq6p4XBgKADs='); | |
x += gif ('#de-btn-sup:empty', p + 'Q3IKpq4YAgZiSQhGByrzn7YURGFGWhxzMuqqBGC7wRUNkeU7nnWNoMosFXKzi8BHs3EQnDRAHLY2e0BxnWfEJkRdT80NNTrliG3aWcBhZhgIAOw=='); | |
x += gif ('#de-btn-sub:empty', p + 'R3IKpq4YAgZiSxquujtOCvIUayAkVZEoRcjCu2wbivMw2WaYi7vVYYqMFYq/i8BEM4ZIrYOmpdD49m2VFd2oiUZTORWcNYT9SpnZrTjiML0MBADs='); | |
x += gif ('#de-btn-quote:empty', p + 'L3IKpq4YAYxRUSKguvRzkDkZfWFlicDCqmgYhuGjVO74zlnQlnL98uwqiHr5ODbDxHSE7Y490wxF90eUkepoysRxrMVaUJBzClaEAADs='); | |
// Show/close animation | |
if (nav.Anim) { | |
x += '@keyframes de-open {\ | |
0% { transform: translateY(-1500px); }\ | |
40% { transform: translateY(30px); }\ | |
70% { transform: translateY(-10px); }\ | |
100% { transform: translateY(0); }\ | |
}\ | |
@keyframes de-close {\ | |
0% { transform: translateY(0); }\ | |
20% { transform: translateY(20px); }\ | |
100% { transform: translateY(-4000px); }\ | |
}\ | |
@keyframes de-blink {\ | |
0%, 100% { transform: translateX(0); }\ | |
10%, 30%, 50%, 70%, 90% { transform: translateX(-10px); }\ | |
20%, 40%, 60%, 80% { transform: translateX(10px); }\ | |
}\ | |
@keyframes de-cfg-open { from { transform: translate(0,50%) scaleY(0); opacity: 0; } }\ | |
@keyframes de-cfg-close { to { transform: translate(0,50%) scaleY(0); opacity: 0; } }\ | |
@keyframes de-post-open-tl { from { transform: translate(-50%,-50%) scale(0); opacity: 0; } }\ | |
@keyframes de-post-open-bl { from { transform: translate(-50%,50%) scale(0); opacity: 0; } }\ | |
@keyframes de-post-open-tr { from { transform: translate(50%,-50%) scale(0); opacity: 0; } }\ | |
@keyframes de-post-open-br { from { transform: translate(50%,50%) scale(0); opacity: 0; } }\ | |
@keyframes de-post-close-tl { to { transform: translate(-50%,-50%) scale(0); opacity: 0; } }\ | |
@keyframes de-post-close-bl { to { transform: translate(-50%,50%) scale(0); opacity: 0; } }\ | |
@keyframes de-post-close-tr { to { transform: translate(50%,-50%) scale(0); opacity: 0; } }\ | |
@keyframes de-post-close-br { to { transform: translate(50%,50%) scale(0); opacity: 0; } }\ | |
@keyframes de-post-new { from { transform: translate(0,-50%) scaleY(0); opacity: 0; } }\ | |
.de-pview-anim { animation-duration: .2s; animation-timing-function: ease-in-out; animation-fill-mode: both; }\ | |
.de-open { animation: de-open .7s ease-out both; }\ | |
.de-close { animation: de-close .7s ease-in both; }\ | |
.de-blink { animation: de-blink .7s ease-in-out both; }\ | |
.de-cfg-open { animation: de-cfg-open .2s ease-out backwards; }\ | |
.de-cfg-close { animation: de-cfg-close .2s ease-in both; }\ | |
.de-post-new { animation: de-post-new .2s ease-out both; }'; | |
} | |
// Embedders | |
x += cont('.de-video-link.de-ytube', 'https://youtube.com/favicon.ico'); | |
x += cont('.de-video-link.de-vimeo', 'https://vimeo.com/favicon.ico'); | |
x += cont('.de-img-arch', 'data:image/gif;base64,R0lGODlhEAAQALMAAF82SsxdwQMEP6+zzRA872NmZQesBylPHYBBHP///wAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAkALAAAAAAQABAAQARTMMlJaxqjiL2L51sGjCOCkGiBGWyLtC0KmPIoqUOg78i+ZwOCUOgpDIW3g3KJWC4t0ElBRqtdMr6AKRsA1qYy3JGgMR4xGpAAoRYkVDDWKx6NRgAAOw=='); | |
x += cont('.de-img-audio', 'data:image/gif;base64,R0lGODlhEAAQAKIAAGya4wFLukKG4oq3802i7Bqy9P///wAAACH5BAEAAAYALAAAAAAQABAAQANBaLrcHsMN4QQYhE01OoCcQIyOYQGooKpV1GwNuAwAa9RkqTPpWqGj0YTSELg0RIYM+TjOkgba0sOaAEbGBW7HTQAAOw=='); | |
x += '.de-current:after { content: " \u25C6"; }\ | |
.de-img-arch, .de-img-audio { color: inherit; text-decoration: none; font-weight: bold; }\ | |
.de-img-pre, .de-img-full { display: block; border: none; outline: none; cursor: pointer; }\ | |
.de-img-pre { max-width: 200px; max-height: 200px; }\ | |
.de-img-full { float: left; }\ | |
.de-img-center { position: fixed; margin: 0 !important; z-index: 9999; background-color: #ccc; border: 1px solid black !important; -moz-box-sizing: content-box; box-sizing: content-box; }\ | |
#de-img-btn-next > div, #de-img-btn-prev > div { height: 36px; width: 36px; }' + | |
gif ('#de-img-btn-next > div', 'R0lGODlhIAAgAIAAAPDw8P///yH5BAEAAAEALAAAAAAgACAAQAJPjI8JkO1vlpzS0YvzhUdX/nigR2ZgSJ6IqY5Uy5UwJK/l/eI6A9etP1N8grQhUbg5RlLKAJD4DAJ3uCX1isU4s6xZ9PR1iY7j5nZibixgBQA7') + | |
gif ('#de-img-btn-prev > div', 'R0lGODlhIAAgAIAAAPDw8P///yH5BAEAAAEALAAAAAAgACAAQAJOjI8JkO24ooxPzYvzfJrWf3Rg2JUYVI4qea1g6zZmPLvmDeM6Y4mxU/v1eEKOpziUIA1BW+rXXEVVu6o1dQ1mNcnTckp7In3LAKyMchUAADs=') + | |
'#de-img-btn-next, #de-img-btn-prev { position: fixed; top: 50%; z-index: 10000; margin-top: -8px; background-color: black; cursor: pointer; }\ | |
#de-img-btn-next { right: 0; border-radius: 10px 0 0 10px; }\ | |
#de-img-btn-prev { left: 0; border-radius: 0 10px 10px 0; }\ | |
.de-mp3, .de-video-obj { margin: 5px 20px; }\ | |
.de-video-title[de-time]:after { content: " [" attr(de-time) "]"; color: red; }\ | |
td > a + .de-video-obj, td > img + .de-video-obj { display: inline-block; }\ | |
video { background: black; }'; | |
// Other | |
x += cont('.de-wait', 'data:image/gif;base64,R0lGODlhEAAQALMMAKqooJGOhp2bk7e1rZ2bkre1rJCPhqqon8PBudDOxXd1bISCef///wAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFAAAMACwAAAAAEAAQAAAET5DJyYyhmAZ7sxQEs1nMsmACGJKmSaVEOLXnK1PuBADepCiMg/DQ+/2GRI8RKOxJfpTCIJNIYArS6aRajWYZCASDa41Ow+Fx2YMWOyfpTAQAIfkEBQAADAAsAAAAABAAEAAABE6QyckEoZgKe7MEQMUxhoEd6FFdQWlOqTq15SlT9VQM3rQsjMKO5/n9hANixgjc9SQ/CgKRUSgw0ynFapVmGYkEg3v1gsPibg8tfk7CnggAIfkEBQAADAAsAAAAABAAEAAABE2QycnOoZjaA/IsRWV1goCBoMiUJTW8A0XMBPZmM4Ug3hQEjN2uZygahDyP0RBMEpmTRCKzWGCkUkq1SsFOFQrG1tr9gsPc3jnco4A9EQAh+QQFAAAMACwAAAAAEAAQAAAETpDJyUqhmFqbJ0LMIA7McWDfF5LmAVApOLUvLFMmlSTdJAiM3a73+wl5HYKSEET2lBSFIhMIYKRSimFriGIZiwWD2/WCw+Jt7xxeU9qZCAAh+QQFAAAMACwAAAAAEAAQAAAETZDJyRCimFqbZ0rVxgwF9n3hSJbeSQ2rCWIkpSjddBzMfee7nQ/XCfJ+OQYAQFksMgQBxumkEKLSCfVpMDCugqyW2w18xZmuwZycdDsRACH5BAUAAAwALAAAAAAQABAAAARNkMnJUqKYWpunUtXGIAj2feFIlt5JrWybkdSydNNQMLaND7pC79YBFnY+HENHMRgyhwPGaQhQotGm00oQMLBSLYPQ9QIASrLAq5x0OxEAIfkEBQAADAAsAAAAABAAEAAABE2QycmUopham+da1cYkCfZ94UiW3kmtbJuRlGF0E4Iwto3rut6tA9wFAjiJjkIgZAYDTLNJgUIpgqyAcTgwCuACJssAdL3gpLmbpLAzEQA7'); | |
x += '.de-abtn { text-decoration: none !important; outline: none; }\ | |
.de-after-fimg { clear: left; }\ | |
#de-alert { position: fixed; right: 0; top: 0; z-index: 9999; font: 14px arial; cursor: default; }\ | |
#de-alert > div { overflow: visible !important; float: right; clear: both; width: auto; min-width: 0pt; padding: 10px; margin: 1px; border: 1px solid grey; white-space: pre-wrap; }\ | |
.de-alert-btn { display: inline-block; vertical-align: top; color: green; cursor: pointer; }\ | |
.de-alert-btn:not(.de-wait) + div { margin-top: .15em; }\ | |
.de-alert-msg { display: inline-block; }\ | |
.de-content textarea { display: block; margin: 2px 0; font: 12px courier new; ' + (nav.Presto ? '' : 'resize: none !important; ') + '}\ | |
.de-content-block > a { color: inherit; font-weight: bold; font-size: 14px; }\ | |
.de-content-block > input { margin: 0 4px; }\ | |
#de-content-fav, #de-content-hid, #de-content-vid { font-size: 16px; padding: 10px; border: 1px solid gray; border-radius: 8px; }\ | |
.de-editor { display: block; font: 12px courier new; width: 619px; height: 337px; tab-size: 4; -moz-tab-size: 4; -o-tab-size: 4; }\ | |
.de-entry { display: block !important; float: none !important; width: auto; max-width: 100% !important; margin: 2px 0 !important; padding: 0 !important; border: none; font-size: 14px; ' + (nav.Presto ? 'white-space: nowrap; ' : '') + '}\ | |
.de-entry > a { text-decoration: none; border: none; }\ | |
.de-entry > input { margin: 2px 4px; }\ | |
.de-fav-inf-posts { float: right; margin-right: 4px; font: bold 14px serif; cursor: default; }\ | |
.de-fav-inf-new { color: #424f79; }\ | |
.de-fav-inf-new:before { content: "+ "; }\ | |
.de-fav-inf-old { color: #4f7942; }\ | |
.de-fav-title { margin-right: 15px; }\ | |
.de-file { display: inline-block; margin: 1px; height: 130px; width: 130px; text-align: center; border: 1px dashed grey; }\ | |
.de-file > .de-file-del { float: right; }\ | |
.de-file > .de-file-rar { float: left; }\ | |
.de-file > .de-file-rarmsg { float: left; padding: 0 4px 2px; color: #fff; background-color: rgba(55, 55, 55, 0.5); }\ | |
.de-file > .de-file-utils { display: none; }\ | |
.de-file > div { display: table; width: 100%; height: 100%; cursor: pointer; }\ | |
.de-file > div > div { display: table-cell; vertical-align: middle; }\ | |
.de-file + [type="file"] { opacity: 0; margin: 1px 0 0 -132px !important; vertical-align: top; width: 132px !important; height: 132px; border: none !important; cursor: pointer; }\ | |
.de-file-drag { background: rgba(88, 88, 88, 0.4); border: 1px solid grey; }\ | |
.de-file-hover > .de-file-utils { display: block; position: relative; margin: -18px 2px; }\ | |
.de-file-img > img, .de-file-img > video { max-width: 126px; max-height: 126px; }\ | |
.de-file-off > div > div:after { content: "' + Lng.noFile[lang] + '" }\ | |
.de-file-rarmsg { margin: 0 5px; font: bold 11px tahoma; cursor: default; }\ | |
.de-file-del, .de-file-rar { display: inline-block; margin: 0 4px -3px; width: 16px; height: 16px; cursor: pointer; }'; | |
x += gif ('.de-file-del', 'R0lGODlhEAAQALMOAP8zAMopAJMAAP/M//+DIP8pAP86Av9MDP9sFP9zHv9aC/9gFf9+HJsAAP///wAAACH5BAEAAA4ALAAAAAAQABAAAARU0MlJKw3B4hrGyFP3hQNBjE5nooLJMF/3msIkJAmCeDpeU4LFQkFUCH8VwWHJRHIM0CiIMwBYryhS4XotZDuFLUAg6LLC1l/5imykgW+gU0K22C0RADs='); | |
x += gif ('.de-file-rar', 'R0lGODlhEAAQALMAAF82SsxdwQMEP6+zzRA872NmZQesBylPHYBBHP///wAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAkALAAAAAAQABAAQARTMMlJaxqjiL2L51sGjCOCkGiBGWyLtC0KmPIoqUOg78i+ZwOCUOgpDIW3g3KJWC4t0ElBRqtdMr6AKRsA1qYy3JGgMR4xGpAAoRYkVDDWKx6NRgAAOw=='); | |
x += '.de-menu { padding: 0 !important; margin: 0 !important; width: auto; min-width: 0; z-index: 9999; border: 1px solid grey !important;}\ | |
.de-menu-item { display: block; padding: 3px 10px; color: inherit; text-decoration: none; font: 13px arial; white-space: nowrap; cursor: pointer; }\ | |
.de-menu-item:hover { background-color: #222; color: #fff; }\ | |
.de-new-post { ' + (nav.Presto ? 'border-left: 4px solid blue; border-right: 4px solid blue; }' : 'box-shadow: 6px 0 2px -2px blue, -6px 0 2px -2px blue; }') + '\ | |
.de-omitted { color: grey; font-style: italic; }\ | |
.de-omitted:before { content: "' + Lng.postsOmitted[lang] + '"; }\ | |
.de-opref::after { content: " [OP]"; }\ | |
.de-parea { text-align: center; }\ | |
.de-parea-btn-close:after { content: "' + Lng.hideForm[lang] + '" }\ | |
.de-parea-btn-thrd:after { content: "' + Lng.makeThrd[lang] + '" }\ | |
.de-parea-btn-reply:after { content: "' + Lng.makeReply[lang] + '" }\ | |
.de-pview { position: absolute; width: auto; min-width: 0; z-index: 9999; border: 1px solid grey !important; margin: 0 !important; display: block !important; }\ | |
.de-pview-info { padding: 3px 6px !important; }\ | |
.de-pview-link { font-weight: bold; }\ | |
#de-qarea > .de-cfg-head { text-align: left; cursor: pointer; }\ | |
.de-qarea-hanging { position: fixed; z-index: 9990; margin: 0; padding: 0; border: 1px solid gray; border-radius: 10px 10px 0 0; }\ | |
.de-qarea-hanging #de-qarea-utils > span:hover { color: #ff6; }\ | |
.de-qarea-inline { float: none; clear: left; width: 100%; padding: 3px 0 3px 3px; margin: 2px 0; }\ | |
#de-qarea-target { font-weight: bold; margin-left: 4px; }\ | |
#de-qarea-utils { float: right; margin-top: ' + (nav.Chrome ? -1 : -4) + 'px; font: normal 16px arial; cursor: pointer; }\ | |
#de-qarea-utils > span { margin-right: 4px; }\ | |
.de-ref-hid { text-decoration: line-through !important; }\ | |
.de-refmap { margin: 10px 4px 4px 4px; font-size: 75%; font-style: italic; }\ | |
.de-refmap:before { content: "' + Lng.replies[lang] + ' "; }\ | |
.de-reflink { text-decoration: none; }\ | |
.de-refcomma:last-child { display: none; }\ | |
#de-sagebtn { margin-right: 7px; cursor: pointer; }\ | |
.de-selected, .de-error-key { ' + (nav.Presto ? 'border-left: 4px solid red; border-right: 4px solid red; }' : 'box-shadow: 6px 0 2px -2px red, -6px 0 2px -2px red; }') + '\ | |
#de-txt-resizer { display: inline-block !important; float: none !important; padding: 6px; margin: -2px -12px; vertical-align: bottom; border-bottom: 2px solid #555; border-right: 2px solid #444; cursor: se-resize; }\ | |
#de-updater-btn:after { content: "' + Lng.getNewPosts[lang] + '" }\ | |
#de-updater-div { clear: left; margin-top: 10px; }\ | |
.de-viewed { color: #888 !important; }\ | |
.de-hidden, small[id^="rfmap"], body > hr, .theader, .postarea, .thumbnailmsg { display: none !important; }\ | |
form > hr { clear: both }\ | |
' + aib.css + aib.cssEn + '.de-post-hide > ' + aib.qHide + ' { display: none !important; }'; | |
if (!nav.Firefox) { | |
x = x.replace(/(transition|keyframes|transform|animation|linear-gradient)/g, nav.cssFix + '$1'); | |
if (!nav.Presto) { | |
x = x.replace(/\(to bottom/g, '(top').replace(/\(to top/g, '(bottom'); | |
} | |
} | |
applyCSS(x); | |
} | |
function applyCSS(x) { | |
$css(x).id = 'de-css'; | |
$css('').id = 'de-css-dynamic'; | |
$css('').id = 'de-css-user'; | |
updateCSS(); | |
} | |
function updateCSS() { | |
var x = '#de-video-list { padding: 0 0 4px; max-width: ' + (+Cfg.YTubeWidth + 40) + 'px; max-height: ' + (window.innerHeight - +Cfg.YTubeHeigh - 100) + 'px; overflow: auto; }'; | |
if (Cfg.attachPanel) { | |
x += '.de-content { position: fixed; right: 0; bottom: 25px; z-index: 9999; max-height: 92%; overflow-x: visible; overflow-y: auto; }\ | |
#de-content-fav, #de-content-hid { overflow-y: scroll; }\ | |
#de-panel { position: fixed; right: 0; bottom: 0; }' | |
} else { | |
x += '.de-content { clear: both; float: right; }\ | |
#de-panel { float: right; clear: both; }' | |
} | |
if (!Cfg.panelCounter) { | |
x += '#de-panel-info { display: none; }'; | |
} | |
if (!Cfg.imgNavBtns) { | |
x += '#de-img-btn-next, #de-img-btn-prev { display: none; }'; | |
} | |
if (Cfg.maskImgs) { | |
x += '.de-img-pre, .de-video-obj, .thumb, .ca_thumb, .fileThumb, img[src*="spoiler"], img[src*="thumb"], img[src^="blob"] { opacity: 0.07 !important; }\ | |
.de-img-pre:hover, .de-video-obj:hover, .thumb:hover, .ca_thumb:hover, .fileThumb:hover, img[src*="spoiler"]:hover, img[src*="thumb"]:hover, img[src^="blob"]:hover { opacity: 1 !important; }'; | |
} | |
if (!aib.dobr && !aib.krau && !aib.mak) { | |
x += '.de-img-full { margin: 2px 5px; }'; | |
} | |
if (Cfg.delHiddPost) { | |
x += '.de-thr-hid, .de-thr-hid + div + br, .de-thr-hid + div + br + hr { display: none; }'; | |
} | |
if (Cfg.noPostNames) { | |
x += aib.qName + ', .' + aib.cTrip + ' { display: none; }'; | |
} | |
if (Cfg.noSpoilers) { | |
if (aib.krau || aib.fch || aib._410) { | |
x += '.spoiler, s { color: #fff !important; }\ | |
.spoiler > a, s > a { color: #fff !important; }'; | |
} else { | |
x += '.spoiler { color: inherit !important; }\ | |
.spoiler > a { color: inherit !important; }'; | |
}; | |
} | |
if (Cfg.noPostScrl) { | |
x += 'blockquote, blockquote > p, .code_part { height: auto !important; max-height: 100% !important; overflow: visible !important; }'; | |
} | |
if (Cfg.noBoardRule) { | |
x += (aib.futa ? '.chui' : '.rules, #rules, #rules_row') + ' { display: none; }'; | |
} | |
if (aib.abu) { | |
if (Cfg.addYouTube) { | |
x += 'div[id^="post_video"] { display: none !important; }'; | |
} | |
} | |
$id('de-css-dynamic').textContent = x; | |
$id('de-css-user').textContent = Cfg.userCSS ? Cfg.userCSSTxt : ''; | |
} | |
// MAIN | |
// =========================================================================================================== | |
function addDelformStuff(isLog) { | |
preloadImages(null); | |
isLog && new Logger().log('Preload images'); | |
embedMP3Links(null); | |
isLog && new Logger().log('MP3 links'); | |
new YouTube().parseLinks(null); | |
isLog && new Logger().log('YouTube links'); | |
if (Cfg.addImgs) { | |
embedImagesLinks(dForm); | |
isLog && new Logger().log('Image links'); | |
} | |
if (Cfg.imgSrcBtns) { | |
addImagesSearch(dForm); | |
isLog && new Logger().log('Sauce buttons'); | |
} | |
if (firstThr && Cfg.linksNavig === 2) { | |
genRefMap(pByNum, ''); | |
for (var post = firstThr.op; post; post = post.next) { | |
if (post.hasRef) { | |
addRefMap(post, ''); | |
} | |
} | |
isLog && new Logger().log('Reflinks map'); | |
} | |
} | |
function initScript(checkDomains) { | |
new Logger().init(); | |
if (!Initialization(checkDomains)) { | |
return; | |
} | |
new Logger().log('Init'); | |
readCfg(doScript); | |
} | |
function doScript() { | |
new Logger().log('Config loading'); | |
if (Cfg.disabled) { | |
addPanel(); | |
scriptCSS(); | |
return; | |
} | |
spells = new Spells(!!Cfg.hideBySpell); | |
new Logger().log('Parsing spells'); | |
doc.body.style.display = 'none'; | |
replaceDelform(); | |
new Logger().log('Replace delform'); | |
pr = new PostForm($q(aib.qPostForm, doc), false, !liteMode, doc); | |
pByNum = Object.create(null); | |
try { | |
parseDelform(dForm, $Q(aib.qThread, dForm)); | |
} catch(e) { | |
console.log('DELFORM ERROR:\n' + getPrettyErrorMessage(e)); | |
doc.body.style.display = ''; | |
return; | |
} | |
initDelformAjax(); | |
readViewedPosts(); | |
new Logger().log('Parse delform'); | |
if (Cfg.hotKeys) { | |
hKeys = new HotKeys(); | |
new Logger().log('Init keybinds'); | |
} | |
if (!liteMode) { | |
initPage(); | |
new Logger().log('Init page'); | |
addPanel(); | |
new Logger().log('Add panel'); | |
} | |
initMessageFunctions(); | |
addDelformStuff(true); | |
scriptCSS(); | |
doc.body.style.display = ''; | |
new Logger().log('Apply CSS'); | |
readPosts(); | |
readUserPosts(); | |
readFavoritesPosts(); | |
new Logger().log('Apply spells'); | |
new Logger().finish(); | |
} | |
if (doc.readyState === 'interactive' || doc.readyState === 'complete') { | |
needScroll = false; | |
initScript(true); | |
} else { | |
aib = getImageBoard(true, false); | |
needScroll = true; | |
doc.addEventListener(doc.onmousewheel !== undefined ? "mousewheel" : "DOMMouseScroll", function wheelFunc(e) { | |
needScroll = false; | |
doc.removeEventListener(e.type, wheelFunc, false); | |
}, false); | |
doc.addEventListener('DOMContentLoaded', initScript.bind(null, false), false); | |
} | |
})(window.opera && window.opera.scriptStorage); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment