Compare commits

...

108 Commits

Author SHA1 Message Date
Alexey Skobkin 787d5b1c37 Release 1.42.1 2016-08-19 18:05:31 +03:00
Alexey Skobkin 58a38460f9 Booru images API base URL changed. 2016-08-19 18:03:17 +03:00
Alexey Skobkin 02c0594509 Release 1.42.0 2016-05-15 23:42:39 +03:00
Alexey Skobkin 552e65520d jQuery updated to version 3. 2016-05-15 23:40:56 +03:00
Alexey Skobkin af6cf59fdd Some scripts for building extension package. 2016-05-15 23:05:22 +03:00
Alexey Skobkin 7fcbc7c039 Release 1.41.1 2016-05-15 22:19:56 +03:00
Alexey Skobkin fe15a1633f update_right_panel_unread_count() bug fix. Now it counts comments on any tree level. 2016-05-15 22:19:46 +03:00
Alexey Skobkin 07b6a8d8bf Release 1.41.0 2016-05-15 16:31:23 +03:00
Alexey Skobkin afee3205dc Option "option_fancybox_smart_hints" removed. 2016-05-15 16:31:04 +03:00
Alexey Skobkin 0674268548 Some refactoring and optimizations. 2016-05-15 16:07:59 +03:00
Alexey Skobkin be749ff31f Release 1.40.4 2016-05-13 03:56:48 +03:00
Alexey Skobkin 207dff9e67 "Move /all button" fix and minor refactoring. 2016-05-13 03:56:34 +03:00
Alexey Skobkin b2fc048450 Release 1.40.3 2016-05-10 22:11:47 +03:00
Alexey Skobkin a771b26952 Updating comments count on WebSocket comment message. 2016-05-10 22:11:41 +03:00
Alexey Skobkin 2fc1134124 Release 1.40.2 2016-05-10 01:22:47 +03:00
Alexey Skobkin 6ee91fbb25 #78 fixed. Null recomendations comments fixed. WS close messages in console. 2016-05-10 01:22:43 +03:00
Alexey Skobkin 072ece28cd Do not "Go to new comment" button outside of the post page. 2016-05-10 00:49:46 +03:00
Alexey Skobkin e7a48b467f Release 1.40.1 2016-05-10 00:42:19 +03:00
Alexey Skobkin 0ba765e181 #95 fixed. 2016-05-10 00:42:16 +03:00
Alexey Skobkin 8f75c8d315 Release 1.40.0 2016-05-10 00:31:54 +03:00
Alexey Skobkin e67eb36443 Sidebar "go to unread comment" button bugfix. "Remove the fucking button" option added. 2016-05-10 00:31:50 +03:00
Alexey Skobkin ffef920411 Release 1.39.0 2016-05-09 04:56:56 +03:00
Alexey Skobkin 99760d2eb7 #97 done. Side panel with "Go to new comment" button. 2016-05-09 04:56:51 +03:00
Alexey Skobkin dc58ac8532 Release 1.38.0 2016-05-09 03:33:35 +03:00
Alexey Skobkin f91dfc4ba7 #96 and some other fixed. Now inserting new comments as HTML (new WebSocket message format). 2016-05-09 03:33:31 +03:00
Alexey Skobkin 75bc6636b2 Release 1.37.1 2016-05-09 03:18:30 +03:00
Alexey Skobkin eecd3133b8 #98 fixed. Adding new comments with 'unread' class. 2016-05-09 03:18:24 +03:00
Alexey Skobkin 06682d3222 Release 1.37.0 2016-05-09 02:52:49 +03:00
Alexey Skobkin 6c286150fa nbproject removed. 2016-05-09 02:47:08 +03:00
Alexey Skobkin 1df716d694 #102 done. Move /all page link to left menu. 2016-05-09 02:42:51 +03:00
Alexey Skobkin 7715c43ba1 Release 1.36.3 2015-07-19 22:55:26 +03:00
Alexey Skobkin 465c10137e Duplicate comments quick fix. 2015-07-19 22:47:09 +03:00
Alexey Skobkin a3a82d6087 nbproject removed. IDEA project added to .gitignore. 2015-07-19 22:22:29 +03:00
isqua b2d1bfdf4a Update grunt-bump version 2015-02-22 14:53:47 +03:00
Alexey Skobkin cc647700f0 Merged in remove_innerhtml (pull request #48) Remove unnecessary html inserting 2015-02-12 20:02:00 +03:00
isqua e865c41504 Remove unnecessary html inserting 2015-02-11 14:16:28 +03:00
Alexey Skobkin a64719424d Release 1.36.2 2015-02-10 22:22:06 +03:00
Alexey Skobkin 643919c62f Popup moved to the bottom. 2015-02-10 22:19:06 +03:00
Alexey Skobkin 11b1338841 Merged in iss87 (pull request #47) Улучшить аяксовые рекоммендации 2015-02-10 19:47:01 +03:00
isqua af70f93ec0 Показывать уведомление при успешной рекомендации без комментария; Fixes #86 2015-02-08 22:04:36 +03:00
isqua d45df7d629 Вставлять собственный комментарий-рекомендацию как комментарий-рекомендацию; Fixes #85 2015-02-08 22:04:12 +03:00
isqua 4e6d09a774 Поменять url для рекомендации комментария; Fixes #87 2015-02-08 22:03:52 +03:00
Alexey Skobkin 0bea1baa24 Release 1.36.1 2015-02-08 19:37:34 +03:00
Alexey Skobkin 2a0546fd65 Merged in iss84 (pull request #46) Не проверять файлы, если поля аттача нет; Fixes #84 2015-02-08 19:03:11 +03:00
isqua 0089798f86 Не проверять файлы, если поля аттача нет 2015-02-08 17:01:56 +03:00
Alexey Skobkin 2d98767bdd Merge branch 'master' of bitbucket.org:skobkin/chrome_point_plus 2015-02-08 13:44:15 +03:00
Alexey Skobkin 25fc9af6fa Release 1.36.0 2015-02-08 13:42:23 +03:00
Alexey Skobkin 4f7fc33cbd Fix fancybox missing images. Garbage deleted. 2015-02-08 13:39:39 +03:00
isqua 9d012c676f Replace Никита with NokitaKaze 2015-02-08 13:13:49 +03:00
isqua 7b4e3f250a Merged in iss83 (pull request #44)
Показывать добавленный комментарий; Fixes #83
2015-02-07 20:49:25 +03:00
isqua 35b1a2c309 Открывать пост и комментарий, если комментарий отправлен не со страницы поста 2015-02-07 20:27:19 +03:00
isqua 00846a56cc Скроллить к добавленному комментарию на странице поста 2015-02-07 20:27:19 +03:00
isqua 62e20aca51 Merged in options_top_elem_fix (pull request #45)
Поправить нецеликом нажимающийся верхний пункт
2015-02-07 20:26:30 +03:00
isqua a9a879b273 Поправить нецеликом нажимающийся верхний пункт 2015-02-07 20:25:51 +03:00
isqua 4615113a44 Merged in iss81 (pull request #43)
Отправлять форму не аяксом, если выбран файл; Fixes #81
2015-02-07 20:16:07 +03:00
isqua 5faabf04bd Отправлять форму не аяксом, если выбран файл 2015-02-07 19:38:11 +03:00
isqua ec6eb34e22 Не добавлять комментарий, если с сервера пришло {"error":"SomeError"} 2015-02-07 19:38:11 +03:00
isqua ad5ace57cb Merged in isqua/chrome_point_plus/iss82 (pull request #42)
Починить рекомендацию постов и комментариев при ajax-комментах; Fixes #82
2015-02-07 19:37:40 +03:00
isqua 94846f28f3 Починить рекомендацию постов и комментариев при ajax-комментах 2015-02-07 18:17:49 +03:00
isqua 13ee04dcc2 Merged in isqua/chrome_point_plus/ajax_comments (pull request #41)
Вынести ajax-комментарии, добавить биндинг на отправку формы
2015-02-07 00:21:04 +03:00
isqua a5accb5be3 Вынести ajax-комментарии, добавить биндинг на отправку формы 2015-02-05 22:48:13 +03:00
isqua 6b7df230b6 Merged in isqua/chrome_point_plus/iss80 (pull request #40)
AJAX comment sending indictaion; Fixes #80
2015-02-05 20:51:47 +03:00
isqua 639b72620b AJAX comment sending indictaion 2015-02-04 13:58:03 +03:00
isqua 74c0e0319f Merged in isqua/chrome_point_plus/code-style (pull request #14)
Code style checking
2015-02-04 13:56:19 +03:00
isqua 0a2b4c7538 Add info about build to README 2015-02-04 13:54:33 +03:00
isqua bd2aa28afc Fix codestyle in options.js 2015-02-03 19:07:22 +03:00
isqua 98982c6145 Fix codestyle in background.js 2015-02-03 19:07:22 +03:00
isqua 82b88b2146 Add jscs config 2015-02-03 19:07:22 +03:00
isqua 2af04fb767 Add jshint configs 2015-02-03 19:07:22 +03:00
isqua eb32411fa7 Add jshint and jscs 2015-02-03 19:07:22 +03:00
isqua 81ad370af1 Merged in isqua/chrome_point_plus/refactor_booru (pull request #39)
Refactor embedding from booru, tumblr etc.
2015-02-03 19:04:40 +03:00
isqua 358d44b3bd Add info about Nokita server to options 2015-02-02 14:47:58 +03:00
isqua 795298c94f Refactor embedding from booru, tumblr etc. 2015-02-02 14:47:57 +03:00
Alexey Skobkin f8e573a8b5 Merged in isqua/chrome_point_plus/combine_embedding_remove_link (pull request #38) Replace all “don’t remove original link” with single “remove original link” option 2015-01-31 15:30:13 +03:00
isqua fe6381ccfd Add chevron to video embedding option 2015-01-31 15:12:50 +03:00
isqua 18e75842f8 Remove video original link option 2015-01-31 15:12:50 +03:00
isqua a2f6aab453 Remove audio, soundclound and pleer.com original link option 2015-01-31 15:11:56 +03:00
isqua 82c2ef8442 Remove coub original link option 2015-01-31 15:11:56 +03:00
isqua fad1e5e689 Remove instagram original link option 2015-01-31 15:11:56 +03:00
isqua cb7cb397c1 Add single option `Remove original link` 2015-01-31 15:11:17 +03:00
Alexey Skobkin d35dc6036e Merged in isqua/chrome_point_plus/refactor_prostopleer (pull request #37) Refactor pleer.com and instagram embedding, remove bquery_ajax; Fixes #79 2015-01-31 14:49:09 +03:00
isqua 1f97b6d19c Remove bquery_ajax 2015-01-31 14:41:33 +03:00
isqua 0f9cb4e167 Refactor instagram embedding 2015-01-31 14:41:32 +03:00
isqua 08fa6c7bfa Remove pleercom_nokita_server option 2015-01-31 14:41:32 +03:00
isqua 21cab163d5 Refactor pleer.com embedding 2015-01-31 14:41:32 +03:00
Alexey Skobkin 068c461070 Merged in isqua/chrome_point_plus/iss74 (pull request #35) String option type; Fixes #74 2015-01-31 14:41:04 +03:00
isqua 54966185d1 Добавить текстовый тип опций 2015-01-31 11:54:54 +03:00
isqua fa02bd8f7b Переименовать объкет Options в OptionsPage во избежание путаницы 2015-01-31 11:54:54 +03:00
Alexey Skobkin 5f88797a93 Merged in isqua/chrome_point_plus/refactor_unique_comments (pull request #36) Remove bquery_ajax from unique comments counter 2015-01-31 08:34:33 +03:00
Alexey Skobkin 62673d3790 Merged in merge_pr25 (pull request #34) Instagram, drafts, some fixes. 2015-01-31 08:20:24 +03:00
Alexey Skobkin eb6b67f612 Some fixes. 2015-01-31 08:10:54 +03:00
isqua 13aa8595e7 Remove bquery_ajax from unique comments counter 2015-01-29 14:23:42 +03:00
Alexey Skobkin d818c7dc66 Fix bug #11. WebSocket recommendation comments. 2015-01-27 05:43:20 +03:00
Alexey Skobkin 6a951ea8d3 Fix bug #17. "@" on the subscribers and subscriptions page. 2015-01-27 04:36:02 +03:00
Alexey Skobkin f7d399c41a i18n for options page title. 2015-01-27 04:10:13 +03:00
Alexey Skobkin 3e6e3d5855 Space key fix from pull request #25. 2015-01-27 04:02:48 +03:00
Alexey Skobkin aa7b9649d1 Twitter fix. 2015-01-27 03:59:05 +03:00
Alexey Skobkin 684f6c15fe Post draft saving with option and some optimization. 2015-01-27 03:55:15 +03:00
Alexey Skobkin 429c432dc5 Встраивание Instagram из pull request #25. 2015-01-27 02:55:15 +03:00
Alexey Skobkin afa1ef0fb0 Merged in isqua/chrome_point_plus/oop_messages (pull request #28) Create objects for CSS and JS injections and for Message Handler 2015-01-27 00:30:57 +03:00
isqua 633410061a Add MessageSender module 2015-01-21 17:24:41 +03:00
isqua 49328a4b4a Refactor background.js 2015-01-21 17:24:41 +03:00
isqua 4a8d6f49f4 Move OptionsManager to separate file 2015-01-21 17:24:41 +03:00
Alexey Skobkin d90ebd48f3 Merge branch 'master' of bitbucket.org:skobkin/chrome_point_plus 2015-01-21 17:22:01 +03:00
isqua 552b997ba3 Merged in isqua/chrome_point_plus/nested_level_img_fix (pull request #33)
Исправить покусанные кружки
2015-01-21 17:10:32 +03:00
isqua b7768ca8a9 Заменить PNG-точечки на SVG 2015-01-20 15:14:32 +03:00
isqua 26893fbb4f Исправить обрезанные кружки при резиновой вёрстке 2015-01-20 15:12:26 +03:00
Alexey Skobkin 0eca347c7d Release 1.35.1 2015-01-20 12:19:41 +04:00
38 changed files with 2168 additions and 1455 deletions

4
.gitignore vendored
View File

@ -1,5 +1,7 @@
chrome_point_plus/vendor/
/nbproject/private/
/nbproject/
node_modules/
npm-debug.log
publish
vendor/
/.idea/

119
.jscs.json Normal file
View File

@ -0,0 +1,119 @@
{
"disallowImplicitTypeConversion": [ "numeric", "boolean", "binary" ],
"disallowKeywordsOnNewLine": [ "else" ],
"disallowMixedSpacesAndTabs": true,
"disallowMultipleLineBreaks": true,
"disallowMultipleLineStrings": true,
"disallowNewlineBeforeBlockStatements": true,
"disallowOperatorBeforeLineBreak": [ "+", "-", "*", "/", "." ],
"disallowPaddingNewlinesInBlocks": true,
"disallowQuotedKeysInObjects": "allButReserved",
"disallowSpaceAfterObjectKeys": true,
"disallowSpaceAfterPrefixUnaryOperators": [ "++", "--", "+", "-" ],
"disallowSpaceBeforePostfixUnaryOperators": true,
"disallowSpacesInCallExpression": true,
"disallowSpacesInFunctionExpression": {
"beforeOpeningRoundBrace": true
},
"disallowSpacesInNamedFunctionExpression": {
"beforeOpeningRoundBrace": true
},
"disallowSpacesInsideParentheses": true,
"disallowTrailingComma": true,
"disallowTrailingWhitespace": true,
"disallowYodaConditions": true,
"requireBlocksOnNewline": true,
"requireCapitalizedConstructors": true,
"requireCommaBeforeLineBreak": true,
"requireCurlyBraces": [
"if",
"else",
"for",
"while",
"do",
"try",
"catch"
],
"requireDotNotation": true,
"requireLineBreakAfterVariableAssignment": true,
"requireLineFeedAtFileEnd": true,
"requirePaddingNewlinesBeforeKeywords": [
"do",
"for",
"if",
"switch",
"try",
"void",
"while",
"with",
"return"
],
"requireSpaceAfterBinaryOperators": true,
"requireSpaceAfterKeywords": [
"do",
"for",
"if",
"else",
"switch",
"case",
"try",
"catch",
"void",
"while",
"with",
"return",
"typeof"
],
"requireSpaceAfterLineComment": {
"allExcept": [ "#", "=" ]
},
"requireSpaceAfterPrefixUnaryOperators": [ "~", "!" ],
"requireSpaceBeforeBinaryOperators": [
"=",
"+",
"-",
"/",
"*",
"==",
"===",
"!=",
"!=="
],
"requireSpaceBeforeBlockStatements": true,
"requireSpaceBeforeKeywords": [
"else",
"while",
"catch"
],
"requireSpaceBeforeObjectValues": true,
"requireSpaceBetweenArguments": true,
"requireSpacesInAnonymousFunctionExpression": {
"beforeOpeningCurlyBrace": true
},
"requireSpacesInForStatement": true,
"requireSpacesInFunctionDeclaration": {
"beforeOpeningCurlyBrace": true
},
"requireSpacesInFunctionExpression": {
"beforeOpeningCurlyBrace": true
},
"requireSpacesInNamedFunctionExpression": {
"beforeOpeningCurlyBrace": true
},
"requireSpacesInsideObjectBrackets": "allButNested",
"validateIndentation": 4,
"validateLineBreaks": "LF",
"validateParameterSeparator": ", ",
"excludeFiles": [
"chrome_point_plus/js/bquery_ajax.js",
"chrome_point_plus/js/markitup/sets/markdown/set.js",
"chrome_point_plus/js/point-plus.js",
"chrome_point_plus/vendor/**",
"nbproject/**",
"node_modules/**",
"publish/**",
"vendor/**"
]
}

9
.jshintignore Normal file
View File

@ -0,0 +1,9 @@
.git/**
chrome_point_plus/js/bquery_ajax.js
chrome_point_plus/js/markitup/sets/markdown/set.js
chrome_point_plus/js/point-plus.js
chrome_point_plus/vendor/**
nbproject/**
node_modules/**
publish/**
vendor/**

26
.jshintrc Normal file
View File

@ -0,0 +1,26 @@
{
"bitwise": true,
"camelcase": false,
"curly": true,
"eqeqeq": true,
"es3": false,
"forin": true,
"freeze": true,
"latedef": true,
"maxlen": 120,
"maxparams": 4,
"newcap": true,
"noarg": true,
"noempty": true,
"nonbsp": true,
"quotmark": "single",
"shadow": "inner",
"undef": true,
"unused": true,
"browser": true,
"jquery": true,
"globals": {
"chrome": true,
"console": true
}
}

View File

@ -1,5 +1,5 @@
var vendorCopy = [
'jquery/jquery.min.js',
'jquery/dist/jquery.min.js',
'fancybox/source/jquery.fancybox.pack.js',
'fancybox/source/helpers/jquery.fancybox-media.js',
@ -18,12 +18,15 @@ var vendorCopy = [
vendorCopy.push({
expand: true,
src: [ 'vendor/fancybox/source/*.png' ],
src: [
'vendor/fancybox/source/*.png',
'vendor/fancybox/source/*.gif'
],
dest: 'chrome_point_plus/'
});
/* global module */
module.exports = function(grunt) {
// Настройки
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
@ -46,7 +49,7 @@ module.exports = function(grunt) {
gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d',
globalReplace: true
}
},
}
});
// Загрузить плагины

View File

@ -1,30 +1,63 @@
# README #
Коротенькое пояснение what the fuck is going on.
### Что это за репозиторий? ###
В данном репозитории располагаются исходные коды расширения Point+, которое предназначено для расширения функциональности сайта [Point.im](https://point.im/).
### Как заставить его работать? ###
Есть несколько вариантов. Выбирайте на свой вкус:
* Установить расширение из [репозитория Opera addons](https://addons.opera.com/en/extensions/details/point/?display=en)
* Установить расширение из [репозитория Google Chrome Extensions](https://chrome.google.com/webstore/detail/point%2B/ghaddonhnchkdjaciggjijhophciboam?hl=ru)
* Установить расширение из [раздела Downloads на Bitbucket](https://bitbucket.org/skobkin/chrome_point_plus/downloads) (*.nex - Opera, *.crx - Chrome)
* Собрать самостоятельно из исходников ([Chrome](https://developer.chrome.com/extensions/packaging), [Opera](https://dev.opera.com/extensions/tut_basics.html))
### Как настраивать? ###
В адресной строке (омнибокс) появится иконка Point.im. Если на нёё нажать - появится окошко настроек.
![Настройки расширения](https://storage4.static.itmages.ru/i/15/0107/h_1420652338_6632200_307d80b672.png "Окно настроек расширения")
### Хочу помочь, ШТОДЕЛОЦ? ###
* Писать мне [в поинте](https://skobkin-ru.point.im/) или [куда-нибудь ещё](https://skobk.in/contacts/)
* Сразу присылать пулл-реквесты с шашкой наголо
* Поставить в магазинах Opera и Chrome оценку расширению
* Задонатить (см. таб Feedback в настройках)
# README #
Коротенькое пояснение what the fuck is going on.
### Что это за репозиторий? ###
В данном репозитории располагаются исходные коды расширения Point+, которое предназначено для расширения функциональности сайта [Point.im](https://point.im/).
### Как заставить его работать? ###
Есть несколько вариантов. Выбирайте на свой вкус:
* Установить расширение из [репозитория Opera addons](https://addons.opera.com/en/extensions/details/point/?display=en)
* Установить расширение из [репозитория Google Chrome Extensions](https://chrome.google.com/webstore/detail/point%2B/ghaddonhnchkdjaciggjijhophciboam?hl=ru)
* Установить расширение из [раздела Downloads на Bitbucket](https://bitbucket.org/skobkin/chrome_point_plus/downloads) (*.nex - Opera, *.crx - Chrome)
* Собрать самостоятельно из исходников ([Chrome](https://developer.chrome.com/extensions/packaging), [Opera](https://dev.opera.com/extensions/tut_basics.html))
### Как настраивать? ###
В адресной строке (омнибокс) появится иконка Point.im. Если на нёё нажать - появится окошко настроек.
![Настройки расширения](https://storage4.static.itmages.ru/i/15/0107/h_1420652338_6632200_307d80b672.png "Окно настроек расширения")
### Хочу помочь, ШТОДЕЛОЦ? ###
* Писать мне [в поинте](https://skobkin-ru.point.im/) или [куда-нибудь ещё](https://skobk.in/contacts/)
* Сразу присылать пулл-реквесты с шашкой наголо
* Поставить в магазинах Opera и Chrome оценку расширению
* Задонатить (см. таб Feedback в настройках)
### Как собрать из исходников
Для сборки используется Node.js. Ещё нужно глобально установить npm-пакет grunt-cli (`npm i -g grunt-cli`).
Все команды ниже нужно выполнять в корне проекта.
Установить npm и bower зависимости и разложить библиотеки по местам:
```
npm install
```
Если у вас нет Node.js, то вы можете посмотреть используемые библиотеки в файле `bower.json` и положить их
в `chrome_point_plus/vendor`.
Проверить кодстайл:
```
npm run lint
```
Поднять версию ([примеры](https://github.com/vojtajina/grunt-bump/blob/master/README.md#usage-examples)):
```
grunt bump
```
Запустить сборку расширения браузером:
```
/bin/bash pack_chromium.sh /usr/bin/chromium /path/to/repository/chrome_point_plus /path/to/private/key.pem
```

View File

@ -1,6 +1,6 @@
{
"name": "chrome-point-plus",
"version": "1.35.0",
"version": "1.42.1",
"authors": [
"Alexey Skobkin"
],
@ -14,7 +14,7 @@
"chrome_point_plus/vendors/**"
],
"dependencies": {
"jquery": "~1.10.1",
"jquery": "~3",
"fancybox": "~2.1.5",
"markitup": "~1.1.14",
"soundcloud": "git@github.com:soundcloud/Widget-JS-API.git"

View File

@ -6,9 +6,12 @@
"message": "Alexey Skobkin"
},
"ext_page_action_title": {
"message": "Point+ settings"
"message": "Settings"
},
"options_page_title": {
"message": "Point+ settings"
},
"options_text_saved": {
"message": "Reload page to apply changes."
@ -47,9 +50,6 @@
"option_fancybox_bind_images_to_one_flow": {
"message": "Bind all images to one Fancybox gallery"
},
"option_fancybox_smart_hints": {
"message": "Generate image caption from tags"
},
"option_images_load_original": {
"message": "Load original images instead of thumbnails"
},
@ -57,13 +57,13 @@
"message": "Enable embedding ▼"
},
"option_images_load_booru": {
"message": "Load pictures from Booru, Tumblr, etc"
"message": "Load pictures from Booru, Tumblr, etc via @NokitaKaze server"
},
"option_audios_parse_links": {
"message": "Audio from direct links"
},
"option_videos_parse_links": {
"message": "Video from direct links"
"message": "Video from direct links ▼"
},
"option_videos_parse_webm": {
"message": "Only webm"
@ -71,30 +71,24 @@
"option_videos_parse_all_links": {
"message": "Parse all links"
},
"option_videos_parse_leave_links": {
"message": "Leave original link"
},
"option_embedding_soundcloud": {
"message": "Soundcloud ▼"
},
"option_embedding_soundcloud_orig_link": {
"message": "Leave original link"
"message": "Soundcloud"
},
"option_embedding_pleercom": {
"message": "Pleer.com ▼"
},
"option_embedding_pleercom_nokita_server": {
"message": "Use Nokita's server (deprecated)"
"message": "Pleer.com"
},
"option_embedding_coubcom": {
"message": "Coub.com ▼"
},
"option_embedding_coubcom_orig_link": {
"message": "Leave original link"
"message": "Coub.com"
},
"option_embedding_twitter_tweets": {
"message": "Twitter"
},
"option_embedding_instagram_posts": {
"message": "Instagram"
},
"option_embedding_remove_original_link": {
"message": "Remove original link"
},
"option_nsfw": {
"message": "NSFW content filtering"
},
@ -119,6 +113,12 @@
"option_ajax_comments": {
"message": "Send comments via AJAX (CTRL+Enter)"
},
"option_right_panel": {
"message": "Right side panel"
},
"option_right_panel_to_unread": {
"message": "\"Go to unread comment\" button"
},
"option_fluid_layout": {
"message": "Fluid layout"
},
@ -172,10 +172,19 @@
"message": "Your hints about users"
},
"option_other_comments_count_refresh":{
"message": "Refresh unread posts and comments count in left menu"
"message": "Refresh unread posts and comments count in the sidebar"
},
"option_other_comments_count_refresh_title":{
"message": "Show counts in the title of tabs"
"message": "Page title"
},
"option_other_move_all_to_menu":{
"message": "Move \"All posts\" to left menu"
},
"option_other_remove_fucking_button":{
"message": "Remove the fucking button"
},
"option_other_post_draft_save":{
"message": "Save post drafts"
},
"options_feedback_text": {
@ -185,5 +194,11 @@
"msg_comment_send_failed":{
"message": "Comment send error:"
},
"msg_saving_post_draft":{
"message": "Saving the post..."
},
"msg_success_recommendation": {
"message": "is recommended"
}
}

View File

@ -6,9 +6,12 @@
"message": "Алексей Скобкин"
},
"ext_page_action_title": {
"message": "Настройки Point+"
"message": "Настройки"
},
"options_page_title": {
"message": "Настройки Point+"
},
"options_text_saved": {
"message": "Для применения изменений перезагрузите страницу."
@ -47,9 +50,6 @@
"option_fancybox_bind_images_to_one_flow": {
"message": "Связать все картинки в одну галерею Fancybox"
},
"option_fancybox_smart_hints": {
"message": "Генерировать подписи к картинкам из тегов"
},
"option_images_load_original": {
"message": "Загружать оригиналы вместо миниатюр"
},
@ -57,13 +57,13 @@
"message": "Включить встраивание ▼"
},
"option_images_load_booru": {
"message": "Загружать картинки с Booru, Tumblr и т.п."
"message": "Загружать картинки с Booru, Tumblr и т.п. через сервер @NokitaKaze"
},
"option_audios_parse_links": {
"message": "Аудио по прямой ссылке"
},
"option_videos_parse_links": {
"message": "Видео по прямой ссылке"
"message": "Видео по прямой ссылке ▼"
},
"option_videos_parse_webm": {
"message": "Только webm"
@ -71,30 +71,24 @@
"option_videos_parse_all_links": {
"message": "Все ссылки на видео"
},
"option_videos_parse_leave_links": {
"message": "Оставлять ссылку на видео"
},
"option_embedding_soundcloud": {
"message": "Soundcloud ▼"
},
"option_embedding_soundcloud_orig_link": {
"message": "Не убирать ссылку"
"message": "Soundcloud"
},
"option_embedding_pleercom": {
"message": "Pleer.com ▼"
},
"option_embedding_pleercom_nokita_server": {
"message": "Использовать сервер @NokitaKaze (deprecated)"
"message": "Pleer.com"
},
"option_embedding_coubcom": {
"message": "Coub.com ▼"
},
"option_embedding_coubcom_orig_link": {
"message": "Не убирать ссылку"
"message": "Coub.com"
},
"option_embedding_twitter_tweets": {
"message": "Twitter"
},
"option_embedding_instagram_posts": {
"message": "Instagram"
},
"option_embedding_remove_original_link": {
"message": "Удалять оригинальную ссылку"
},
"option_nsfw": {
"message": "Фильтрация NSFW-контента"
},
@ -119,6 +113,12 @@
"option_ajax_comments": {
"message": "Отправка комментариев через AJAX (CTRL+Enter)"
},
"option_right_panel": {
"message": "Боковая панель справа"
},
"option_right_panel_to_unread": {
"message": "Кнопка \"Перейти к непрочитанному\""
},
"option_fluid_layout": {
"message": ""Резиновая" вёрстка (растянуть сайт по горизонтали)"
},
@ -172,10 +172,19 @@
"message": "Заметки о пользователях на полях"
},
"option_other_comments_count_refresh":{
"message": "Обновляем количество непрочитанных комментариев и постов в ленте"
"message": "Обновление количества непрочитанных постов и комментариев в сайдбаре"
},
"option_other_comments_count_refresh_title":{
"message": "Указываем кол-во комментариев и сообщений в заголовке страницы"
"message": "В заголовке страницы"
},
"option_other_move_all_to_menu":{
"message": "Переместить \"Всё подряд\" в левое меню"
},
"option_other_remove_fucking_button":{
"message": "Убрать ёбаную кнопку"
},
"option_other_post_draft_save":{
"message": "Сохранение черновика поста"
},
@ -186,5 +195,11 @@
"msg_comment_send_failed":{
"message": "Ошибка отправки комментария:"
},
"msg_saving_post_draft":{
"message": "Сохранение поста..."
},
"msg_success_recommendation": {
"message": "рекомендовано"
}
}

View File

@ -16,6 +16,11 @@
background-image: url('chrome-extension://__MSG_@@extension_id__/vendor/fancybox/source/fancybox_overlay.png');
}
.fancybox-nav {
/* To supress errors */
background-image: url('chrome-extension://__MSG_@@extension_id__/vendor/fancybox/source/blank.gif'); /* helps IE */
}
@media only screen and (min-device-pixel-ratio: 1.5) {
#fancybox-loading, .fancybox-close, .fancybox-prev span, .fancybox-next span {
background-image: url('chrome-extension://__MSG_@@extension_id__/vendor/fancybox/source/fancybox_sprite@2x.png');

View File

@ -1,8 +1,12 @@
/* @ before username */
#main #content a.user:before {
/* Posts */
#content .post-content a.user:before,
/* Subscribers */
#content .users span.user:before,
/* Subscriptions */
#content .users .info a.user:before {
content: "@";
}
/* Fix for recommendations in the feed */
#main #content .rec .user:before {
margin-right: -4px;
}
/* Fix for recommendations */
#content .post-content .rec .user:before {
margin-right: -3px;
}

View File

@ -0,0 +1,28 @@
#pp-right-panel {
width: 32px;
position: fixed;
top: 50%;
right: 3px;
opacity: .3;
transition: opacity 500ms;
}
#pp-right-panel:hover {
opacity: 1;
transition: opacity 500ms;
}
#pp-right-panel #pp-go-to-unread {
background-image: url("/img/menu-my.png");
height: 32px;
width: 32px;
cursor: pointer;
}
#pp-right-panel span#pp-unread-count {
position: relative;
top: 7px;
left: 11px;
-webkit-user-select: none;
user-select: none;
}

View File

@ -94,7 +94,7 @@ p
box-sizing: border-box;
max-height: 100%;
margin: 0;
padding: 10px 15px 5px;
padding: 20px 15px 5px;
border: none;
background: transparent;

View File

@ -28,31 +28,40 @@ div#markItUpText-input {
}
/* Auto-loaded Booru pictures */
.booru_pic {
.booru_pic, .instagram-post-embedded {
display: block !important;
float: none !important;
}
.booru_pic img {
.booru_pic img, .instagram-post-embedded img {
border: none;
max-width: 60%;
max-height: 300px;
}
/* Labels in post */
.post .post-id a .cn.changed_background {
/* Unique ID and Recomendation */
.pp-post-counters
{
float: left;
color: #999;
font-size: 12px;
margin-left: 1em;
}
.post .post-id a .authors_unique_count, .post .post-id a .recommendation_count {
padding: 0 .5em;
font-weight: normal;
color: #35587c;
background-color: #f2f2eb;
.pp-unique-comments
{
margin-right: .5em;
}
.post .post-id a .recommendation_count {
margin-left: 0.2em;
background-color: #f2eceb;
/* @todo i18n */
.pp-unique-comments::before
{
content: 'Комментаторов: ';
}
.pp-recommendation-count::before
{
content: 'Рекомендаций: ';
}
/* NSFW-content */
@ -115,7 +124,7 @@ div#markItUpText-input {
right: 5px;
top: 5px;
display: none;
background-image: url("//point.im/img/btn-edit.png");
background-image: url('//point.im/img/btn-edit.png');
background-size: 100% 100%;
width: 16px;
height: 16px;
@ -173,8 +182,9 @@ div#markItUpText-input {
content: '';
opacity: 0;
background-image: url('chrome-extension://__MSG_@@extension_id__/images/nesting-point.png');
background-image: url('chrome-extension://__MSG_@@extension_id__/images/nesting-point.svg');
background-repeat: repeat-x;
background-position: right center;
}
#comments.nesting_level .post:hover .info::before {
@ -182,3 +192,68 @@ div#markItUpText-input {
opacity: 1;
}
.pp-progress.reply-form {
margin-top: 8px;
padding-top: 4px;
}
.pp-progress.reply-form::before {
content: '';
display: block;
height: 4px;
background: linear-gradient(to right, #fff, #9aacbe, #fff);
-webkit-animation: loading 1s;
-webkit-animation-iteration-count: infinite;
}
@-webkit-keyframes loading {
from {
background-position: -640px 0;
}
to {
background-position: 0 0;
}
}
/* "All" link in left menu */
#pp-left-menu-all {
/* Opened Lock icon from default point.im icon set */
background-image: url('/img/icon-private-inactive.png') !important;
}
/* Highlight post with new comments */
.pp-post-unread {
background-color: #EEFFEE;
}
/* Video from direct links */
.pp-video-player {
display: block;
max-width: 95%;
}
/* Audio from direct links */
.pp-audio-player {
display: block;
}
/* Coub embedded video */
.pp-video-player-coub {
max-width: 640px;
border: none;
}
/* New posts and comments auto refresh in left menu by @NokitaKaze */
.pp-left-menu-refreshed {
background-color: #f2ebee;
color: #7c3558;
}
#pp-iframe-unread-refresh {
width: 600px;
height: 300px;
display: none;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1003 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 651 B

View File

@ -0,0 +1 @@
<svg version="1" xmlns="http://www.w3.org/2000/svg" height="10" width="10"><circle cx="5" cy="5" r="3" fill="#9aacbe"/></svg>

After

Width:  |  Height:  |  Size: 125 B

View File

@ -1,15 +1,193 @@
var VERSION = (function() {
/**
* @deprecated XMLHttpRequest in the background worker is deprecated
* according to the Chrome warning. But we definitely need synchronous
* AJAX here
*/
var xhr = new XMLHttpRequest(),
manifest;
xhr.open('GET', chrome.extension.getURL('manifest.json'), false);
xhr.send(null);
manifest = JSON.parse(xhr.responseText);
return manifest.version;
})();
/**
* Вставка нескольких файлов друг за другом
* @param {Array} files Список файлов
* @param {Function} injectOne Функция вставки одного файла. Должна принимать file и callback
* @param {Function} [onAllInjected] Функция обработки ответа
* @param {Array} [results] Результаты вставки (их не нужно передавать при запуске извне)
*/
function injectFiles(files, injectOne, onAllInjected, results) {
results = results || [];
if (files.length) {
injectOne(files.shift(), function(res) {
if (res) {
results.unshift(res[0]);
}
injectFiles(files, injectOne, onAllInjected, results);
});
} else {
onAllInjected(results);
}
}
/**
* @constructor Менеджер сообщений
*/
function MessageListener() {
/* jshint unused:false */
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
if (this.isMethodAvailable(message)) {
console.info('Call #%s() method for tab #%s', message.type, this.getTabId(sender));
this[message.type].apply(this, arguments);
return true;
} else {
console.warn('Method #%s() called from tab #%s does not exists', message.type, this.getTabId(sender));
return false;
}
}.bind(this));
/* jshint unused:true */
}
/**
* @param {Object} message Сообщение
* @returns {Boolean} Есть ли необходимый метод в MessageListener
*/
MessageListener.prototype.isMethodAvailable = function(message) {
return message && message.type && typeof this[message.type] === 'function';
};
/**
* @param {Object} sender
* @returns {Number|Null} Идентификатор вкладки, с которой пришло сообщение
*/
MessageListener.prototype.getTabId = function(sender) {
return sender.tab && sender.tab.id || null;
};
/**
* @param {Object} message Сообщение
* @param {Object} sender Отправитель
* @param {Function} sendResponse Коллбек для обработки результата
*/
MessageListener.prototype.showPageAction = function(message, sender, sendResponse) {
chrome.pageAction.show(this.getTabId(sender));
sendResponse(true);
};
/**
* Показывает нотификацию
* @param {Object} message Сообщение
* @param {Object} sender Отправитель
* @param {Function} sendResponse Коллбек для обработки результата
*/
MessageListener.prototype.showNotification = function(message, sender, sendResponse) {
chrome.notifications.create(
message.notificationId, {
type: 'basic',
iconUrl: message.avatarUrl,
title: message.title,
message: message.text,
priority: 0,
isClickable: true
}, function(notificationId) {
console.info('Notification "%s" created', notificationId);
sendResponse(true);
}
);
};
/**
* Получает версию плагина из манифеста
* @param {Object} message Сообщение
* @param {Object} sender Отправитель
* @param {Function} sendResponse Коллбек для обработки результата
*/
MessageListener.prototype.getManifestVersion = function(message, sender, sendResponse) {
sendResponse({ version: VERSION });
};
/**
* @param {Object} message Сообщение
*/
MessageListener.prototype.getFiles = function(message, defaultRunAt) {
var files;
if (! message.files) {
return false;
} else {
files = Array.isArray(message.files) ? message.files : [ message.files ];
return files.map(function(file) {
return {
file: typeof file === 'string' ? file : file.file,
runAt: file.runAt || defaultRunAt
};
});
}
};
/**
* Вставляет JS-файлы во вкладку
* @param {Object} message Сообщение
* @param {Object} sender Отправитель
* @param {Function} sendResponse Коллбек для обработки результата
*/
MessageListener.prototype.executeJSFiles = function(message, sender, sendResponse) {
var tabId = this.getTabId(sender);
injectFiles(
this.getFiles(message, 'document_end'),
function(file, callback) {
chrome.tabs.executeScript(tabId, file, callback);
},
sendResponse
);
};
/**
* Вставляет CSS-файлы во вкладку
* @param {Object} message Сообщение
* @param {Object} sender Отправитель
* @param {Function} sendResponse Коллбек для обработки результата
*/
MessageListener.prototype.injectCSSFiles = function(message, sender, sendResponse) {
var tabId = this.getTabId(sender);
injectFiles(
this.getFiles(message),
function(file, callback) {
chrome.tabs.insertCSS(tabId, file, callback);
},
sendResponse
);
};
new MessageListener();
// Maintaining options version
chrome.storage.sync.get('options_version', function(data) {
var pp_version = getVersion();
console.info('Point+ %s. Options are for %s.', pp_version, data.options_version);
if (data.options_version != pp_version) {
chrome.tabs.create({url: 'options.html'});
console.info('Point+ %s. Options are for %s.', VERSION, data.options_version);
if (data.options_version !== VERSION) {
chrome.tabs.create({ url: 'options.html' });
}
});
// Adding notification click event listener
chrome.notifications.onClicked.addListener(function(notificationId) {
var tab_url;
// Detecting notification type
if (notificationId.indexOf('comment_') === 0) {
tab_url = 'https://point.im/' + notificationId.replace(/comment_/g, '');
@ -24,175 +202,3 @@ chrome.notifications.onClicked.addListener(function(notificationId) {
});
}
});
// Crutches and bikes
/**
* Inject several JS files
* @param {number} tabId Unique ID of tab which requested injection
* @param {Object[]} files Array of objects of files to inject
* @param {function} onAllInjected allback function running when injection ends
*/
function injectJS(tabId, files, onAllInjected) {
var item = files.shift();
if (item) {
console.log('Injecting JS "%s" to the tab #%s', item.file, tabId);
if ('file' in item) {
chrome.tabs.executeScript(tabId ? tabId : null, {
file: item.file,
runAt: item.runAt || 'document_start'
}, function(result) {
console.info('"%s" injected to the tab #%s', item.file, tabId);
injectJS(tabId, files, onAllInjected);
});
}
} else {
onAllInjected();
}
}
// @todo Implement injectCSS (because JS execution working always after CSS injection)
// Message listener
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
// @todo Check if sender.tab may be undefined in some cases
console.log('Received message from tab #%s: %O', sender.tab ? sender.tab.id : 'undefined', message);
if (message) {
switch (message.type) {
case 'showPageAction':
chrome.pageAction.show(sender.tab.id);
sendResponse(true);
console.log('Showed pageAction for tab #%s', sender.tab.id);
// Fuck You, Chrome API documentation!!11
return true;
break;
case 'showNotification':
chrome.notifications.create(
message.notificationId, {
type: 'basic',
iconUrl: message.avatarUrl,
title: message.title,
message: message.text,
priority: 0,
isClickable: true
}, function(notificationId) {
console.info('Notification "%s" created', notificationId);
sendResponse(true);
}
);
// Fuck You, Chrome API documentation!!11
return true;
break;
case 'getManifestVersion':
sendResponse({version: getVersion()});
return true;
break;
/**
* @deprecated since 1.19.1
*/
case 'injectJSFile':
console.log('Executing JS: %s', message.file);
chrome.tabs.executeScript(sender.tab.id ? sender.tab.id : null, {
file: message.file,
runAt: message.runAt || 'document_start'
}, function() {
sendResponse(true);
console.info('JS file executed: "%s"', message.file);
return true;
});
// Fuck You, Chrome API documentation!
return true;
break;
// Inject several files
case 'executeJSFiles':
//console.debug('Received JS file list: %O', message.files);
if (message.files.length) {
injectJS(sender.tab.id ? sender.tab.id : null, message.files, function() {
// @fixme does not sending response now!
console.info('All scripts executed');
sendResponse(true);
return true;
});
} else {
/*
* May be not?
* But I don't want to block some shit-code execution
*/
sendResponse(false);
console.warn('No scripts executed (empty script array)');
}
// Fuck You, Chrome API documentation!
return true;
break;
/**
* @deprecated since 1.19.1
*/
case 'injectCSSFile':
console.log('Injecting CSS: "%s"', message.file);
chrome.tabs.insertCSS(sender.tab.id ? sender.tab.id : null, {
file: message.file
}, function() {
// @todo message response callback processing
//sendResponse(true);
console.info('CSS file "%s" injected', message.file);
});
// Fuck You, Chrome API documentation!
return true;
break;
case 'injectCSSCode':
if (message.code !== undefined) {
chrome.tabs.insertCSS(sender.tab.id ? sender.tab.id : null, {
code: message.code
}, function() {
// @todo message response callback processing
//sendResponse(true);
console.info('CSS code injected: \n%s', message.file);
});
}
// Fuck You, Chrome API documentation!
return true;
break;
default:
sendResponse(false);
return true;
break;
}
}
});
// Getting version from manifest.json
function getVersion() {
/**
* @deprecated XMLHttpRequest in the background worker is deprecated
* according to the Chrome warning. But we definitely need synchronous
* AJAX here
*/
var xhr = new XMLHttpRequest();
xhr.open('GET', chrome.extension.getURL('manifest.json'), false);
xhr.send(null);
var manifest = JSON.parse(xhr.responseText);
return manifest.version;
}

View File

@ -1,95 +0,0 @@
function $ajax_prot(settings){
if (settings==undefined){return;}
if (settings['url'] ==undefined){return;}this.url=settings['url'];
if (settings['async'] !==undefined){this.async =settings['async'];}
if (settings['type'] !==undefined){this.type =settings['type'];}
if (settings['postdata']!==undefined){this.postdata=settings['postdata'];}
if (settings['dont_set_content_type']!==undefined){
this.dont_set_content_type=settings['dont_set_content_type'];
}
this.xhr=new XMLHttpRequest();
this.xhr.parent =this;
this.xhr.settings=settings;
this.xhr.success =settings['success'];
this.xhr.error =settings['error'];
this.xhr.onreadystatechange=this.change;
this.xhr.open(this.type, this.url, this.async);
if ((this.type=='POST')&& !this.dont_set_content_type){
this.xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
}
if (settings.headers!==undefined){
for (var i=0;i<settings.headers.length;i++){
this.xhr.setRequestHeader(settings.headers[i][0], settings.headers[i][1]);
}
}
this.xhr.send(this.postdata);
}
$ajax_prot.prototype={
version: '0.0.5a',
url: '',
type: 'GET',
async: true,
postdata:null,
xhr: null,
dont_set_content_type: false,
change:function(){
if (this.readyState!==4){return;}
if (this.status==200){
if (this.success!==undefined){this.success(this.responseText,this.textStatus,this);}
}else{
if (this.error !==undefined){this.error(this.responseText,this.textStatus,this);}
}
}
}
$ajax=function (settings){return new $ajax_prot(settings);}
function urlencode(text){return encodeURIComponent(text);}
function sad_safe_reg(text){
var ar='.-\\/[]{}?+';
var s=''; for (var i=0;i<text.length;i++){
if ((' '+ar).indexOf(text[i])>0){
s+='\\'+text[i];
}else{
s+=text[i];
}
}
return s;
}
function sad_xml_getnode(node,path){//node as domNode
if ('' ==path){return node;}
if ('#'==path){return node.textContent || node.text;}
var ri=new RegExp('^([a-z0-9.:_-]*)(\\|[0-9]+)?(/?(.*))?','i');
var t=path.match(ri);
if (t[1].length<1){return undefined;}
if (t[2]==undefined){t[2]='';}
if (t[4]==undefined){t[4]='';}
var k=parseInt(t[2].substr(1));
if (!(k>0)){k=1;}
var r=new RegExp('^'+sad_safe_reg(t[1])+'$');
for (var i=0;i<node.childNodes.length;i++){
if (r.test(node.childNodes[i].nodeName)){
k--;if (k==0){return sad_xml_getnode(node.childNodes[i],t[4]);}
}
}
return undefined;
}
function sad_xml_attribute(node,name){
if (node==undefined){return undefined;}
var r=new RegExp('^'+sad_safe_reg(name)+'$','i');
for (var i=0;i<node.attributes.length;i++){
if (r.test(node.attributes[i].nodeName)){return node.attributes[i].nodeValue;}
}
return '';
}
function sad_x2n(xml){
return xml.responseXML.childNodes[xml.responseXML.childNodes.length-1];
}

View File

@ -0,0 +1,20 @@
function MessageSender() {}
function stub() {}
MessageSender.prototype.css = function(files, callback) {
this.sendMessage({
type: 'injectCSSFiles',
files: files
}, callback || stub);
};
MessageSender.prototype.js = function(files, callback) {
this.sendMessage({
type: 'executeJSFiles',
files: files
}, callback || stub);
};
MessageSender.prototype.sendMessage = function() {
chrome.runtime.sendMessage.apply(chrome.runtime, arguments);
};

View File

@ -0,0 +1,37 @@
/**
* Объект для получения опций
* @constructor {OptionsManager}
* @param {Object} options Хеш настроек
*/
function OptionsManager(options) {
this._options = options || {};
}
/**
* @param {String} optionName Имя опции
* @returns {Boolean|String|Null} Значение опции
*/
OptionsManager.prototype.get = function(optionName) {
return this._options.hasOwnProperty(optionName) ? this._options[optionName].value : null;
};
/**
* Проверяет, равна ли опция значению value. Если value не переданно, проверяет задана ли она и не равна ли false/''
* @param {String} optionName Имя опции
* @param {Boolean|String} [value=true] Значение опции
* @returns {Boolean}
*/
OptionsManager.prototype.is = function(optionName, value) {
if (typeof value !== 'undefined') {
return this.get(optionName) === value;
} else {
return Boolean(this.get(optionName));
}
};
/**
* @returns {Object} Хеш опций
*/
OptionsManager.prototype.getOptions = function() {
return this._options;
};

View File

@ -4,19 +4,19 @@
* При создании сохраняет версию, восстанавливает настройки, слушает изменения на инпутах.
* @constructor
*/
function Options() {
function OptionsPage() {
this.form = document.querySelector('form');
this.listenTabs();
chrome.runtime.sendMessage(null, {
type: 'getManifestVersion'
}, null, function(response) {
this.version = response.version || 'undefined';
this.showVersion();
this.restore();
this.form.addEventListener('change', this._onChange.bind(this));
}.bind(this));
}
@ -25,7 +25,7 @@ function Options() {
* Получает версию настроек. Если она не равна версии приложения, записывает в сторедж плагина настройки из инпутов
* и версию приложения.
*/
Options.prototype.updateOptionsFromFrom = function() {
OptionsPage.prototype.updateOptionsFromFrom = function() {
chrome.storage.sync.get('options_version', function(data) {
this.logVersion(data.options_version);
@ -40,7 +40,8 @@ Options.prototype.updateOptionsFromFrom = function() {
}, function() {
console.log('Default options initialized. Version upgraded to %s.', this.version);
if ( ! confirm(chrome.i18n.getMessage('options_text_new_version'))) {
/* global confirm */
if (! confirm(chrome.i18n.getMessage('options_text_new_version'))) {
window.close();
}
});
@ -51,7 +52,7 @@ Options.prototype.updateOptionsFromFrom = function() {
/**
* Сохраняет настройки
*/
Options.prototype.save = function() {
OptionsPage.prototype.save = function() {
var ppOptions = this.getValues();
console.log('Saving options: %O', ppOptions);
@ -62,7 +63,7 @@ Options.prototype.save = function() {
/**
* Получает настройки из стореджа плагина, устанавливает соответствующим инпутам соответствующие значения.
*/
Options.prototype.restore = function() {
OptionsPage.prototype.restore = function() {
this.checkOldStyle();
chrome.storage.sync.get('options', function(data) {
@ -80,6 +81,7 @@ Options.prototype.restore = function() {
break;
case 'enum':
case 'plain':
input.value = data.value;
break;
@ -97,19 +99,19 @@ Options.prototype.restore = function() {
/**
* @returns {Object} Хеш настроек вида { имяастроки: значениеастройки }
*/
Options.prototype.getValues = function() {
OptionsPage.prototype.getValues = function() {
return this._options;
};
/**
* @param {Event} event Событие изменения
*/
Options.prototype._onChange = function(event) {
OptionsPage.prototype._onChange = function(event) {
this.updateOptionFromInput(event.target);
this.save();
};
Options.prototype.updateOptionFromInput = function(input) {
OptionsPage.prototype.updateOptionFromInput = function(input) {
var key = this.getOptionKey(input.name);
if (this.isBoolean(input)) {
@ -122,6 +124,11 @@ Options.prototype.updateOptionFromInput = function(input) {
type: 'enum',
value: input.value
};
} else {
this._options[key] = {
type: 'plain',
value: input.value
};
}
};
@ -129,7 +136,7 @@ Options.prototype.updateOptionFromInput = function(input) {
* @param {HTMLElement} option Элемент опции
* @returns {Boolean} Является ли настройка булевой
*/
Options.prototype.isBoolean = function(option) {
OptionsPage.prototype.isBoolean = function(option) {
return option.getAttribute('type') === 'checkbox';
};
@ -138,7 +145,7 @@ Options.prototype.isBoolean = function(option) {
* @param {HTMLElement} option Элемент опции
* @returns {Boolean} Является ли настройка енумом
*/
Options.prototype.isEnum = function(option) {
OptionsPage.prototype.isEnum = function(option) {
return option.getAttribute('type') === 'radio';
};
@ -146,7 +153,7 @@ Options.prototype.isEnum = function(option) {
* @param {String} name Имя инпута
* @returns {String} Ключ для хеша настроек
*/
Options.prototype.getOptionKey = function(name) {
OptionsPage.prototype.getOptionKey = function(name) {
return name.replace(/-/g, '_');
};
@ -154,7 +161,7 @@ Options.prototype.getOptionKey = function(name) {
* @param {String} Ключ хеша настроек
* @returns {String} Имя инпута
*/
Options.prototype.getOptionName = function(key) {
OptionsPage.prototype.getOptionName = function(key) {
return key.replace(/_/g, '-');
};
@ -162,31 +169,34 @@ Options.prototype.getOptionName = function(key) {
* Выводит в консоль версию настроек и версию плагина
* @param {String} optionsVersion
*/
Options.prototype.logVersion = function(optionsVersion) {
OptionsPage.prototype.logVersion = function(optionsVersion) {
console.info('Point+ %s, local options are for %s', this.version, optionsVersion);
};
/**
* Добавляет номер версии в подвал
*/
Options.prototype.showVersion = function() {
OptionsPage.prototype.showVersion = function() {
document.querySelector('#version').innerHTML = this.version;
};
/**
* Проверяет, не старого ли формата настройки. И если старого, то удаляет их.
*/
Options.prototype.checkOldStyle = function() {
OptionsPage.prototype.checkOldStyle = function() {
chrome.storage.sync.get('option_fancybox', function(data) {
if ((data.option_fancybox === true) || (data.option_fancybox === false)) {
console.log('Found old-style options. Cleaning...');
chrome.storage.sync.get(null, function(data) {
var option;
console.log('Old data: %O', data);
for (option in data) {
chrome.storage.sync.remove(option);
if (data.hasOwnProperty(option)) {
chrome.storage.sync.remove(option);
}
}
console.log('All old data removed');
@ -198,7 +208,7 @@ Options.prototype.checkOldStyle = function() {
/**
* Показывает плашку про то, что настройки сохранились и надо обновить страницу
*/
Options.prototype.updateStatus = function() {
OptionsPage.prototype.updateStatus = function() {
this.status = this.status || document.querySelector('.saved');
this.status.classList.remove('hidden');
@ -207,7 +217,7 @@ Options.prototype.updateStatus = function() {
/**
* Слушает события на табах
*/
Options.prototype.listenTabs = function() {
OptionsPage.prototype.listenTabs = function() {
var options = this;
options._selectedItem = document.querySelector('.tabs-item.selected');
@ -229,4 +239,4 @@ Options.prototype.listenTabs = function() {
});
};
new Options();
new OptionsPage();

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
{
"manifest_version": 2,
"name": "Point+",
"version": "1.35.0",
"version": "1.42.1",
"default_locale": "ru",
"author": "__MSG_ext_author__",
"homepage_url": "https://bitbucket.org/skobkin/chrome_point_plus",
@ -27,15 +27,16 @@
{
"matches": ["http://*.point.im/*", "https://*.point.im/*"],
"js": [
"vendor/jquery/jquery.min.js",
"vendor/jquery/dist/jquery.min.js",
"js/bquery_ajax.js",
"js/point-plus.js"
],
"js/options-manager.js",
"js/message-sender.js",
"js/point-plus.js"
],
"css": [
"css/point-plus.css"
],
"css/point-plus.css"
],
"run_at": "document_end"
}
],
@ -49,6 +50,8 @@
"scripts": ["js/background.js"]
},
"permissions": [
"http://point.im/*",
"https://point.im/*",
"http://*.point.im/*",
"https://*.point.im/*",
"https://pleer.com/*",
@ -56,6 +59,8 @@
"https://player.soundcloud.com/*",
"https://api.kanaria.ru/point/*",
"https://*.twitter.com/*",
"https://api.instagram.com/*",
"https://coub.com/embed/*",
"storage",
"notifications",
"tabs"

View File

@ -0,0 +1,27 @@
.pp-notification {
display: block;
position: fixed;
bottom: 40px;
right: 40px;
padding: 20px;
border-radius: 2px;
font-size: 15px;
line-height: 20px;
transition: all 10s ease-in;
color: #fff;
}
.pp-notification a,
.pp-notification a:visited {
color: #fff;
text-decoration: none;
font-weight: bold;
}
.pp-notification-success {
background: #4CAF50;
}
.pp-notification.pp-fade {
opacity: 0;
}

View File

@ -0,0 +1,311 @@
/**
* Находит элемент #comments, и если он есть, начинает слушать на нём события
* @constructor
*/
function AjaxComments() {
var comments = document.querySelector('#comments');
if (comments) {
this._comments = comments;
this.listen(comments);
this.listenFirstComments();
}
}
/**
* Вешает обработчики. Магия в последнем параметре addEventListener
*/
AjaxComments.prototype.listen = function(elem) {
elem.addEventListener('submit', this.onSubmit.bind(this), true);
elem.addEventListener('keypress', this.onKeypress.bind(this), true);
};
/**
* Слушает отправки первых комментариев
*/
AjaxComments.prototype.listenFirstComments = function() {
var posts = document.querySelectorAll('.post-content');
// Чтобы не ловить события на чём попало и мочь использовать useCapture, приходится
// получать все post-content и на каждый вешать обработчики.
Array.prototype.forEach.call(posts, this.listen.bind(this));
};
/**
* Обрабатывает событие отправки формы
* @param {Event} event Событие отправки
*/
AjaxComments.prototype.onSubmit = function(event) {
var $form = $(event.target);
event.preventDefault();
event.stopPropagation();
if ($form.hasClass('reply-form')) {
this.submit($form);
}
};
/**
* Проверяет, выбран ли файл. Если да отправляет форму с перезагрузкой, иначе аяксом
* @param {jQuery} $form Элемент формы
*/
AjaxComments.prototype.submit = function($form) {
var proc;
if (this.isFileSelected($form)) {
$form.submit();
} else {
proc = new AjaxCommentProcessor($form);
}
};
/**
* Обрабатывает нажатия кнопок. Если это сочетание Ctrl|+Enter, отправляет коммент
* @param {Event} event Событие нажатия кнопки
*/
AjaxComments.prototype.onKeypress = function(event) {
var $form;
if (this.isProperKeys(event)) {
event.preventDefault();
event.stopPropagation();
$form = $(event.target).closest('.reply-form');
if ($form.length) {
this.submit($form);
}
}
};
/**
* Проверяет, что нажато нужное сочетание клавишь
* @param {Event} event Событие нажатия
* @return {Boolean}
*/
AjaxComments.prototype.isProperKeys = function(event) {
return (event.keyCode === 10 || event.keyCode === 13) && (event.ctrlKey || event.metaKey);
};
/**
* @param {jQuery} $form
* @return {Boolean} Выбран ли файл
*/
AjaxComments.prototype.isFileSelected = function($form) {
var attach = $form.get(0).elements.attach;
if (attach) {
return Boolean(attach.files && attach.files.length);
} else {
return false;
}
};
/**
* Создаётся при каждой отправке комментария
* @param {jQuery} $form Элемент формы, на которой это произошло
*/
function AjaxCommentProcessor($form) {
this._$form = $form;
this._$post = $form.closest('.post');
this._$textarea = $form.find('textarea');
this._text = this._$textarea.val();
this._CSRF = $form.get(0).elements.csrf_token.value;
this._actionUrl = this._$form.attr('action');
this._postId = this._$post.data('id');
this._commentId = this._$post.data('comment-id');
this.sendComment();
}
/**
* Регулярка для урла, проверяюшая, не рекомендация ли это
* @type {RegExp}
*/
AjaxCommentProcessor.recommendationReg = /^\/[^/]*\/r$/;
/**
* Отправляет комментарий
*/
AjaxCommentProcessor.prototype.sendComment = function() {
this.setProgress(true);
$.ajax({
type: 'POST',
url: this.getUrl(),
data: {
text: this._text,
comment_id: this._commentId
},
beforeSend: this.beforeSend.bind(this),
error: this.onError.bind(this),
success: this.onSuccess.bind(this)
});
};
/**
* @return {Boolean} true это коммент-рекомендация, fasle обычный коммент
*/
AjaxCommentProcessor.prototype.isRecommendation = function() {
return this._isRec || (this._isRec = this.constructor.recommendationReg.test(this._actionUrl));
};
/**
* @return {String} Адрес, на который слать запрос
*/
AjaxCommentProcessor.prototype.getUrl = function() {
// Если это рекомендация комментария
if (this.isRecommendation() && this._commentId) {
return '/api/post/' + this._postId + '/' + this._commentId + '/r';
} else {
return '/api/post' + this._actionUrl;
}
};
/**
* Подкладывает CSRF-токен в заголовки запроса
* @param {XMLHttpRequest} xhr Объект запроса
*/
AjaxCommentProcessor.prototype.beforeSend = function(xhr) {
xhr.setRequestHeader('X-CSRF', this._CSRF);
};
/**
* Скрывает форму отправки комментария
* @return {[type]} [description]
*/
AjaxCommentProcessor.prototype.hideForm = function() {
this._$form.prev().prop('checked', false);
};
/**
* Создаёт новый комментарий, скрывает форму, снимает прогресс.
* @param {Object} data Ответ сервера
* @param {String} textStatus Статус ответа
*/
AjaxCommentProcessor.prototype.onSuccess = function(data, textStatus) {
var $textarea = this._$textarea;
if (textStatus === 'success') {
if (data.error) {
this.onError(null, null, data.error);
} else {
if (this.isRecommendation() && this._text.trim().length === 0) {
this.showSuccessRecommendation();
}/* else {
this.createComment(data);
}*/
this.hideForm();
// Cleaning textarea
$textarea.val('');
this.setProgress(false);
}
}
};
AjaxCommentProcessor.prototype.createComment = function(data) {
/* global create_comment_elements */
create_comment_elements({
id: data.comment_id,
toId: this._commentId || null,
postId: this._postId,
author: $('#name h1').text(),
text: this._text,
fadeOut: true,
isRec: this.isRecommendation()
}, this.insertComment.bind(this));
};
/**
* Вставляет комментарий в DOM
* @param {jQuery} $comment
*/
AjaxCommentProcessor.prototype.insertComment = function($comment) {
var $parentCommentChildren;
if ($('#comments #tree-switch a').eq(0).hasClass('active') || (this._commentId === undefined)) {
// Adding to the end of the list
$('.content-wrap #comments #post-reply').before($comment);
} else {
// Check for children
$parentCommentChildren = this._$post.next('.comments');
// @fixme Find a bug with lost indentation of new comment
// If child comment already exist
if ($parentCommentChildren.length) {
console.log('Child comments found. Appending...');
$parentCommentChildren.append($comment);
} else {
console.log('No child comments found. Creating...');
this._$post.after(
$('<div>')
.addClass('comments')
.append($comment)
);
}
}
this.showComment($comment);
};
AjaxCommentProcessor.prototype.showComment = function($comment) {
$('body').animate({
scrollTop: $comment.offset().top
}, 500);
};
/**
* Показывает алерт с ошибкой и снимает прогресс, если коммент не отправился
* @param {*} req
* @param {*} status
* @param {String} error
*/
AjaxCommentProcessor.prototype.onError = function(req, status, error) {
/* global alert */
alert(chrome.i18n.getMessage('msg_comment_send_failed') + '\n' + error);
this.setProgress(false);
};
/**
* Устанавливает прогресс
* @param {Boolean} isProgress true включить прогресс, false отключить
*/
AjaxCommentProcessor.prototype.setProgress = function(isProgress) {
this._$textarea.prop('disabled', isProgress);
this._$form.toggleClass('pp-progress', isProgress);
};
AjaxCommentProcessor.prototype.getRecommendationLink = function() {
var url = '//point.im/' + this._postId;
var text = '#' + this._postId;
if (this._commentId) {
url += '#' + this._commentId;
text += '/' + this._commentId;
}
return '<a href="' + url + '">' + text + '</a>';
};
AjaxCommentProcessor.prototype.showSuccessRecommendation = function() {
var $notification = $('<div>')
.addClass('pp-notification pp-notification-success');
$notification.html(this.getRecommendationLink() + ' ' + chrome.i18n.getMessage('msg_success_recommendation'));
$notification.on('transitionend', function() {
$notification.remove();
});
$('body').append($notification);
window.requestAnimationFrame(function() {
$notification.addClass('pp-fade');
});
};

View File

@ -0,0 +1,172 @@
/**
* Подгружает картинки через сервер Никиты
* @constructor
* @param {jQuery} $links Коллекция ссылок
* @param {OptionsManager} options Опции
*/
function Booru($links, options) {
this.count = 0;
this.loadAllImages($links, options.is('option_embedding_remove_original_link'));
}
/**
* Base URL of gelbooru picture API (@NokitaKaze)
* @type {String}
*/
Booru.baseUrl = 'https://evidell.xyz/get_booru_picture.php';
/* jshint maxlen:false */
Booru.services = {
danbooru: {
mask: new RegExp('^https?://danbooru\\.donmai\\.us/posts/([0-9]+)', 'i'),
matchNumber: 1
},
gelbooru: {
mask: new RegExp('^https?\\://(www\\.)?gelbooru\\.com\\/index\\.php\\?page\\=post&s\\=view&id=([0-9]+)', 'i'),
matchNumber: 2
},
safebooru: {
mask: new RegExp('^https?\\://(www\\.)?safebooru\\.org\\/index\\.php\\?page\\=post&s\\=view&id=([0-9]+)', 'i'),
matchNumber: 2
},
deviantart: {
mask: new RegExp('^https?\\://(www\\.)?([a-z0-9-]+\\.)?deviantart\\.com\\/art/[0-9a-z-]+?\\-([0-9]+)(\\?.+)?$', 'i'),
matchNumber: 3
},
e621: {
mask: new RegExp('^https?\\://(www\\.)?e621\\.net\\/post\\/show\\/([0-9]+)\\/', 'i'),
matchNumber: 2
},
derpibooru: {
mask: new RegExp('^https?\\://derpiboo\\.ru\\/([0-9]+)', 'i'),
matchNumber: 1
},
tumblr: {
mask: new RegExp('^https?\\://([0-9a-z-]+)\\.tumblr\\.com\\/post\\/([0-9]+)', 'i'),
matchNumber: 2,
params: {
add_username: 1
}
},
pixiv: {
mask: new RegExp('^https?://(www\\.)?pixiv\\.net\\/member_illust\\.php\\?mode\\=medium\\&illust_id\\=([0-9]+)', 'i'),
matchNumber: 2
},
animepicturesnet: {
mask: new RegExp('^http\\:\\/\\/anime\\-pictures\\.net\\/pictures\\/view_post\\/([0-9]+)', 'i'),
matchNumber: 1
}
};
/* jshint maxlen:120 */
/**
* Обрабатывает все картинки
* @param {jQuery} $links Коллекция ссылок
* @param {Boolean} removeOriginal Удалять ли оригинальную ссылку
*/
Booru.prototype.loadAllImages = function($links, removeOriginal) {
var booru = this;
$links.each(function(index, link) {
var $link = $(link);
var href = link.href;
var $image;
if ($link.hasClass('booru_pic')) {
return;
}
Object.keys(booru.constructor.services).some(function(service) {
$image = booru.createImageFromService(service, href);
return $image;
});
if ($image) {
$link.before($image);
this.count++;
if (removeOriginal) {
$link.remove();
}
}
});
};
/**
* Создаёт картинку исходя из сервиса, если адрес картинки матчится
* @param {String} service Идентификатор сервиса
* @param {String} href URL картинки (который вставлен в пост)
*/
Booru.prototype.createImageFromService = function(service, href) {
var serviceInfo = this.constructor.services[service];
var matches = href.match(serviceInfo.mask);
var imageArgs;
var params = {};
var key;
if (matches) {
imageArgs = [ service, matches[serviceInfo.matchNumber] ];
if (serviceInfo.params) {
for (key in serviceInfo.params) {
if (serviceInfo.params.hasOwnProperty(key)) {
params[key] = matches[serviceInfo.params[key]];
}
}
imageArgs.push(params);
}
return this.createImage.apply(this, imageArgs);
}
};
/**
* Создаёт ссылку с картикной
* @param {String} service Ключевое имя сервиса для Никиты
* @param {String} id Идентификатор картинки
* @param {Object} [params] Дополнительные параметры, которые надо добавить в url
* @returns {jQuery} Элемент ссылки
*/
Booru.prototype.createImage = function(service, id, params) {
var $link = $('<a>');
var $img = $('<img>');
var title = service + ' image #' + id;
var imageSource = this.getImageLink(service, id, params);
$link
.addClass('booru_pic')
.addClass('booru-' + service + '-' + id)
.addClass('postimg')
.attr({
href: imageSource,
id: 'booru_pic_' + this.count,
title: title,
target: '_blank'
});
$img.attr({
alt: title,
src: imageSource
});
$link.append($img);
return $link;
};
/**
* Генерирует ссылку на картинку
* @param {String} service Ключевое имя сервиса для Никиты
* @param {String} id Идентификатор картинки
* @param {Object} [params] Дополнительные параметры, которые надо добавить в url
* @returns {String} Ссылка на картинку
*/
Booru.prototype.getImageLink = function(service, id, params) {
return this.constructor.baseUrl + '?' + $.param($.extend({
domain: service,
id: id
}, params));
};

View File

@ -1,307 +1,307 @@
<!DOCTYPE html>
<html>
<head>
<title>Point Plus options</title>
<meta charset="utf-8">
<link rel="stylesheet" href="css/options.css" type="text/css">
</head>
<body>
<main>
<nav class="tabs-list">
<a class="tabs-item selected" href="#media" data-i18n="options_tabs_media"></a>
<a class="tabs-item" href="#other" data-i18n="options_tabs_other"></a>
<a class="tabs-item" href="#websocket" data-i18n="options_tabs_websocket"></a>
<a class="tabs-item" href="#feedback" data-i18n="options_tabs_feedback"></a>
</nav>
<form class="tabs-content">
<section class="tabs-content-item selected" id="media">
<div class="option-node">
<input type="checkbox" name="option-fancybox" id="option-fancybox">
<label for="option-fancybox" data-i18n="option_fancybox"></label>
<label class="option-node">
<input type="checkbox" name="option-fancybox-images">
<span data-i18n="option_fancybox_images"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-fancybox-videos">
<span data-i18n="option_fancybox_videos"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-fancybox-posts">
<span data-i18n="option_fancybox_posts"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-fancybox-bind-images-to-one-flow">
<span data-i18n="option_fancybox_bind_images_to_one_flow"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-fancybox-smart-hints">
<span data-i18n="option_fancybox_smart_hints"></span>
</label>
</div>
<label class="option-node">
<input type="checkbox" name="option-images-load-original">
<span data-i18n="option_images_load_original"></span>
</label>
<div class="option-node">
<input type="checkbox" name="option-embedding" id="option-embedding">
<label for="option-embedding" data-i18n="option_embedding"></label>
<label class="option-node">
<input type="checkbox" name="option-images-load-booru">
<span data-i18n="option_images_load_booru"></span>
</label>
<div class="option-node">
<input type="checkbox" name="option-videos-parse-links" id="option-videos-parse-links">
<label for="option-videos-parse-links" data-i18n="option_videos_parse_links"></label>
<div class="option-node">
<label>
<input type="radio" name="option-videos-parse-links-type" value="webm">
<span data-i18n="option_videos_parse_webm"></span>
</label>
<label>
<input type="radio" name="option-videos-parse-links-type" value="all" checked="checked">
<span data-i18n="option_videos_parse_all_links"></span>
</label>
</div>
<label class="option-node">
<input type="checkbox" name="option-videos-parse-leave-links">
<span data-i18n="option_videos_parse_leave_links"></span>
</label>
</div>
<div class="option-node">
<input type="checkbox" name="option-audios-parse-links" id="option-audios-parse-links">
<label for="option-audios-parse-links" data-i18n="option_audios_parse_links"></label>
<label class="option-node">
<input type="checkbox" name="option-audios-parse-leave-links">
<span data-i18n="option_embedding_soundcloud_orig_link"></span>
</label>
</div>
<div class="option-node">
<input type="checkbox" name="option-embedding-soundcloud" id="option-embedding-soundcloud">
<label for="option-embedding-soundcloud" data-i18n="option_embedding_soundcloud"></label>
<label class="option-node">
<input type="checkbox" name="option-embedding-soundcloud-orig-link">
<span data-i18n="option_embedding_soundcloud_orig_link"></span>
</label>
</div>
<div class="option-node">
<input type="checkbox" name="option-embedding-pleercom" id="option-embedding-pleercom">
<label for="option-embedding-pleercom" data-i18n="option_embedding_pleercom"></label>
<label class="option-node">
<input type="checkbox" name="option-embedding-pleercom-nokita-server">
<span data-i18n="option_embedding_pleercom_nokita_server"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-embedding-pleercom-orig-link">
<span data-i18n="option_embedding_soundcloud_orig_link"></span>
</label>
</div>
<div class="option-node">
<input type="checkbox" name="option-embedding-coubcom" id="option-embedding-coubcom">
<label for="option-embedding-coubcom" data-i18n="option_embedding_coubcom"></label>
<label class="option-node">
<input type="checkbox" name="option-embedding-coubcom-orig-link">
<span data-i18n="option_embedding_coubcom_orig_link"></span>
</label>
</div>
<label class="option-node">
<input type="checkbox" name="option-embedding-twitter-tweets">
<span data-i18n="option_embedding_twitter_tweets"></span>
</label>
</div>
<div class="option-node">
<input type="checkbox" name="option-nsfw" id="option-nsfw">
<label for="option-nsfw" data-i18n="option_nsfw"></label>
<label class="option-node">
<input type="checkbox" name="option-nsfw-hide-posts">
<span data-i18n="option_nsfw_hide_posts"></span>
</label>
<div class="option-node">
<input type="checkbox" name="option-nsfw-blur-posts-images" id="option-nsfw-blur-posts-images">
<label for="option-nsfw-blur-posts-images" data-i18n="option_nsfw_blur_posts_images"></label>
<label class="option-node">
<input type="checkbox" name="option-nsfw-blur-posts-entire">
<span data-i18n="option_nsfw_blur_posts_entire"></span>
</label>
</div>
<div class="option-node">
<input type="checkbox" name="option-nsfw-blur-comments-images" id="option-nsfw-blur-comments-images">
<label for="option-nsfw-blur-comments-images" data-i18n="option_nsfw_blur_comments_images"></label>
<label class="option-node">
<input type="checkbox" name="option-nsfw-blur-comments-entire">
<span data-i18n="option_nsfw_blur_comments_entire"></span>
</label>
</div>
</div>
</section>
<section class="tabs-content-item" id="other">
<div class="option-node">
<input type="checkbox" name="option-ajax" id="option-ajax">
<label for="option-ajax" data-i18n="option_ajax"></label>
<label class="option-node">
<input type="checkbox" name="option-ajax-comments">
<span data-i18n="option_ajax_comments"></span>
</label>
</div>
<label class="option-node">
<input type="checkbox" name="option-fluid-layout">
<span data-i18n="option_fluid_layout"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-visual-editor-post">
<span data-i18n="option_visual_editor_post"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-search-with-google">
<span data-i18n="option_search_with_google"></span>
</label>
<div class="option-node">
<input type="checkbox" name="option-enlarge-font" id="option-enlarge-font">
<label for="option-enlarge-font" data-i18n="option_enlarge_font"></label>
<div class="option-node">
<label>
<input type="radio" name="option-enlarge-font-size" value="85" checked="checked"> 0.85 em
</label>
<label>
<input type="radio" name="option-enlarge-font-size" value="100"> 1 em
</label>
<label>
<input type="radio" name="option-enlarge-font-size" value="110"> 1.1 em
</label>
</div>
</div>
<label class="option-node">
<input type="checkbox" name="option-at-before-username">
<span data-i18n="option_at_before_username"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-other-hightlight-post-comments">
<span data-i18n="option_other_hightlight_post_comments"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-other-show-recommendation-count">
<span data-i18n="option_other_show_recommendation_count"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-other-scroll-space-key">
<span data-i18n="option_other_scroll_space_key"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-other-comments-nesting-level">
<span data-i18n="option_other_comments_nesting_level"></span>
</label>
<div class="option-node">
<input type="checkbox" name="option-other-comments-count-refresh" id="option-other-comments-count-refresh">
<label for="option-other-comments-count-refresh" data-i18n="option_other_comments_count_refresh"></label>
<label class="option-node">
<input type="checkbox" name="option-other-comments-count-refresh-title">
<span data-i18n="option_other_comments_count_refresh_title"></span>
</label>
</div>
<label class="option-node">
<input type="checkbox" name="option-other-comments-user-system">
<span data-i18n="option_other_comments_user_system"></span>
</label>
</section>
<section class="tabs-content-item" id="websocket">
<div class="option-node">
<input type="checkbox" name="option-ws" id="option-ws">
<label for="option-ws" data-i18n="option_ws"></label>
<div class="option-node">
<input type="checkbox" name="option-ws-comments" id="option-ws-comments">
<label for="option-ws-comments" data-i18n="option_ws_comments"></label>
<label class="option-node">
<input type="checkbox" name="option-ws-comments-color-fadeout">
<span data-i18n="option_ws_comments_color_fadeout"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-ws-comments-notifications">
<span data-i18n="option_ws_comments_notifications"></span>
</label>
</div>
<div class="option-node">
<input type="checkbox" name="option-ws-posts" id="option-ws-posts">
<label for="option-ws-posts" data-i18n="option_ws_posts"></label>
<label class="option-node">
<input type="checkbox" name="option-ws-posts-add" disabled>
<span data-i18n="option_ws_posts_add"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-ws-posts-notifications">
<span data-i18n="option_ws_posts_notifications"></span>
</label>
</div>
</div>
</section>
<section class="tabs-content-item" id="feedback">
<div data-i18n="options_feedback_text"></div>
</section>
</form>
</main>
<p class="saved hidden" data-i18n="options_text_saved"></p>
<footer class="footer">
<p>Point+ <span id="version"></span> by
<a href="https://skobkin-ru.point.im/" target="_blank">@skobkin-ru</a>,
<a href="https://isqua.point.im/" target="_blank">@isqua</a>,
<a href="https://nokitakaze.point.im/" target="_blank">@NokitaKaze</a>
</p>
</footer>
<script src="js/options.js"></script>
<script src="js/i18n.js"></script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title data-i18n="options_page_title"></title>
<link rel="stylesheet" href="css/options.css" type="text/css">
</head>
<body>
<main>
<nav class="tabs-list">
<a class="tabs-item selected" href="#media" data-i18n="options_tabs_media"></a>
<a class="tabs-item" href="#other" data-i18n="options_tabs_other"></a>
<a class="tabs-item" href="#websocket" data-i18n="options_tabs_websocket"></a>
<a class="tabs-item" href="#feedback" data-i18n="options_tabs_feedback"></a>
</nav>
<form class="tabs-content">
<section class="tabs-content-item selected" id="media">
<div class="option-node">
<input type="checkbox" name="option-fancybox" id="option-fancybox">
<label for="option-fancybox" data-i18n="option_fancybox"></label>
<label class="option-node">
<input type="checkbox" name="option-fancybox-images">
<span data-i18n="option_fancybox_images"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-fancybox-videos">
<span data-i18n="option_fancybox_videos"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-fancybox-posts">
<span data-i18n="option_fancybox_posts"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-fancybox-bind-images-to-one-flow">
<span data-i18n="option_fancybox_bind_images_to_one_flow"></span>
</label>
</div>
<label class="option-node">
<input type="checkbox" name="option-images-load-original">
<span data-i18n="option_images_load_original"></span>
</label>
<div class="option-node">
<input type="checkbox" name="option-embedding" id="option-embedding">
<label for="option-embedding" data-i18n="option_embedding"></label>
<label class="option-node">
<input type="checkbox" name="option-images-load-booru">
<span data-i18n="option_images_load_booru"></span>
</label>
<div class="option-node">
<input type="checkbox" name="option-videos-parse-links" id="option-videos-parse-links">
<label for="option-videos-parse-links" data-i18n="option_videos_parse_links"></label>
<div class="option-node">
<label>
<input type="radio" name="option-videos-parse-links-type" value="webm">
<span data-i18n="option_videos_parse_webm"></span>
</label>
<label>
<input type="radio" name="option-videos-parse-links-type" value="all" checked="checked">
<span data-i18n="option_videos_parse_all_links"></span>
</label>
</div>
</div>
<label class="option-node">
<input type="checkbox" name="option-audios-parse-links">
<span data-i18n="option_audios_parse_links"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-embedding-soundcloud">
<span data-i18n="option_embedding_soundcloud"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-embedding-pleercom">
<span data-i18n="option_embedding_pleercom"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-embedding-coubcom">
<span data-i18n="option_embedding_coubcom"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-embedding-twitter-tweets">
<span data-i18n="option_embedding_twitter_tweets"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-embedding-instagram-posts">
<span data-i18n="option_embedding_instagram_posts"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-embedding-remove-original-link">
<span data-i18n="option_embedding_remove_original_link">
</label>
</div>
<div class="option-node">
<input type="checkbox" name="option-nsfw" id="option-nsfw">
<label for="option-nsfw" data-i18n="option_nsfw"></label>
<label class="option-node">
<input type="checkbox" name="option-nsfw-hide-posts">
<span data-i18n="option_nsfw_hide_posts"></span>
</label>
<div class="option-node">
<input type="checkbox" name="option-nsfw-blur-posts-images" id="option-nsfw-blur-posts-images">
<label for="option-nsfw-blur-posts-images" data-i18n="option_nsfw_blur_posts_images"></label>
<label class="option-node">
<input type="checkbox" name="option-nsfw-blur-posts-entire">
<span data-i18n="option_nsfw_blur_posts_entire"></span>
</label>
</div>
<div class="option-node">
<input type="checkbox" name="option-nsfw-blur-comments-images" id="option-nsfw-blur-comments-images">
<label for="option-nsfw-blur-comments-images" data-i18n="option_nsfw_blur_comments_images"></label>
<label class="option-node">
<input type="checkbox" name="option-nsfw-blur-comments-entire">
<span data-i18n="option_nsfw_blur_comments_entire"></span>
</label>
</div>
</div>
</section>
<section class="tabs-content-item" id="other">
<div class="option-node">
<input type="checkbox" name="option-ajax" id="option-ajax">
<label for="option-ajax" data-i18n="option_ajax"></label>
<label class="option-node">
<input type="checkbox" name="option-ajax-comments">
<span data-i18n="option_ajax_comments"></span>
</label>
</div>
<div class="option-node">
<input type="checkbox" name="option-right-panel" id="option-right-panel">
<label for="option-right-panel" data-i18n="option_right_panel"></label>
<label class="option-node">
<input type="checkbox" name="option-right-panel-to-unread">
<span data-i18n="option_right_panel_to_unread"></span>
</label>
</div>
<label class="option-node">
<input type="checkbox" name="option-fluid-layout">
<span data-i18n="option_fluid_layout"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-visual-editor-post">
<span data-i18n="option_visual_editor_post"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-search-with-google">
<span data-i18n="option_search_with_google"></span>
</label>
<div class="option-node">
<input type="checkbox" name="option-enlarge-font" id="option-enlarge-font">
<label for="option-enlarge-font" data-i18n="option_enlarge_font"></label>
<div class="option-node">
<label>
<input type="radio" name="option-enlarge-font-size" value="85" checked="checked"> 0.85 em
</label>
<label>
<input type="radio" name="option-enlarge-font-size" value="100"> 1 em
</label>
<label>
<input type="radio" name="option-enlarge-font-size" value="110"> 1.1 em
</label>
</div>
</div>
<label class="option-node">
<input type="checkbox" name="option-at-before-username">
<span data-i18n="option_at_before_username"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-other-hightlight-post-comments">
<span data-i18n="option_other_hightlight_post_comments"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-other-show-recommendation-count">
<span data-i18n="option_other_show_recommendation_count"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-other-scroll-space-key">
<span data-i18n="option_other_scroll_space_key"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-other-comments-nesting-level">
<span data-i18n="option_other_comments_nesting_level"></span>
</label>
<div class="option-node">
<input type="checkbox" name="option-other-comments-count-refresh" id="option-other-comments-count-refresh">
<label for="option-other-comments-count-refresh" data-i18n="option_other_comments_count_refresh"></label>
<label class="option-node">
<input type="checkbox" name="option-other-comments-count-refresh-title">
<span data-i18n="option_other_comments_count_refresh_title"></span>
</label>
</div>
<label class="option-node">
<input type="checkbox" name="option-other-comments-user-system">
<span data-i18n="option_other_comments_user_system"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-other-move-all-to-menu">
<span data-i18n="option_other_move_all_to_menu"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-other-remove-fucking-button">
<span data-i18n="option_other_remove_fucking_button"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-other-post-draft-save">
<span data-i18n="option_other_post_draft_save"></span>
</label>
</section>
<section class="tabs-content-item" id="websocket">
<div class="option-node">
<input type="checkbox" name="option-ws" id="option-ws">
<label for="option-ws" data-i18n="option_ws"></label>
<div class="option-node">
<input type="checkbox" name="option-ws-comments" id="option-ws-comments">
<label for="option-ws-comments" data-i18n="option_ws_comments"></label>
<label class="option-node">
<input type="checkbox" name="option-ws-comments-color-fadeout">
<span data-i18n="option_ws_comments_color_fadeout"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-ws-comments-notifications">
<span data-i18n="option_ws_comments_notifications"></span>
</label>
</div>
<div class="option-node">
<input type="checkbox" name="option-ws-posts" id="option-ws-posts">
<label for="option-ws-posts" data-i18n="option_ws_posts"></label>
<label class="option-node">
<input type="checkbox" name="option-ws-posts-add" disabled>
<span data-i18n="option_ws_posts_add"></span>
</label>
<label class="option-node">
<input type="checkbox" name="option-ws-posts-notifications">
<span data-i18n="option_ws_posts_notifications"></span>
</label>
</div>
</div>
</section>
<section class="tabs-content-item" id="feedback">
<div data-i18n="options_feedback_text"></div>
</section>
</form>
</main>
<p class="saved hidden" data-i18n="options_text_saved"></p>
<footer class="footer">
<p>Point+ <span id="version"></span> by
<a href="https://skobkin-ru.point.im/" target="_blank">@skobkin-ru</a>,
<a href="https://isqua.point.im/" target="_blank">@isqua</a>,
<a href="https://nokitakaze.point.im/" target="_blank">@NokitaKaze</a>
</p>
</footer>
<script src="js/options.js"></script>
<script src="js/i18n.js"></script>
</body>
</html>

View File

@ -1,18 +0,0 @@
auxiliary.org-netbeans-modules-css-prep.less_2e_compiler_2e_options=
auxiliary.org-netbeans-modules-css-prep.less_2e_enabled=false
auxiliary.org-netbeans-modules-css-prep.less_2e_mappings=/less:/css
auxiliary.org-netbeans-modules-css-prep.sass_2e_compiler_2e_options=
auxiliary.org-netbeans-modules-css-prep.sass_2e_enabled=false
auxiliary.org-netbeans-modules-css-prep.sass_2e_mappings=/scss:/css
auxiliary.org-netbeans-modules-javascript2-requirejs.enabled=false
auxiliary.org-netbeans-modules-web-clientproject-api.js_2e_libs_2e_folder=node_modules/bower/node_modules/inquirer/node_modules/rx/src/core/linq/observable
browser.autorefresh.Chrome.INTEGRATED=true
browser.highlightselection.Chrome.INTEGRATED=true
config.folder=
file.reference.src-chrome_point_plus=.
files.encoding=UTF-8
grunt.action.build=
site.root.folder=${file.reference.src-chrome_point_plus}
start.file=chrome_point_plus/options.html
test.folder=
web.context.root=/file:///chrome_point_plus

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.web.clientproject</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/clientside-project/1">
<name>chrome_point_plus</name>
</data>
</configuration>
</project>

8
pack_chromium.sh Normal file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env bash
BROWSER_BINARY=$1
PATH_EXTENSION=$2
PATH_KEY=$3
echo "Packing extension using $BROWSER_BINARY and key from $PATH_KEY"
#echo "$BROWSER_BINARY --pack-extension=$PATH_EXTENSION --pack-extension-key=$PATH_KEY"
eval "$BROWSER_BINARY --pack-extension=$PATH_EXTENSION --pack-extension-key=$PATH_KEY"

2
pack_zip.sh Normal file
View File

@ -0,0 +1,2 @@
#!/usr/bin/env bash
zip -9 -r chrome_point_plus.zip chrome_point_plus

View File

@ -1,10 +1,12 @@
{
"name": "chrome-point-plus",
"version": "1.35.0",
"version": "1.42.1",
"description": "Chrome extension for point.im",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"postinstall": "./node_modules/.bin/bower install && grunt",
"lint": "./node_modules/.bin/jshint . && ./node_modules/.bin/jscs .",
"test": "npm run lint"
},
"repository": {
"type": "git",
@ -15,7 +17,9 @@
"devDependencies": {
"bower": "^1.3.12",
"grunt": "^0.4.5",
"grunt-bump": "git://github.com/nkirkes/grunt-bump.git#nkirkes/restrict-version-key-name",
"grunt-contrib-copy": "^0.7.0"
"grunt-bump": "^0.3.0",
"grunt-contrib-copy": "^0.7.0",
"jscs": "^1.10.0",
"jshint": "^2.6.0"
}
}