From 208aa9c6d89b12321bd14ad7ee8322af5e4f3ce9 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 15 Feb 2014 17:32:41 +0100 Subject: Creation of a basic template It is not supposed to be used... but it could. This is a minimalistic theme (about 725 lines). In the future, it could be great to based all official themes on this one. See #320 --- p/themes/template/loader.gif | Bin 0 -> 4167 bytes p/themes/template/metadata.json | 7 + p/themes/template/template.css | 725 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 732 insertions(+) create mode 100644 p/themes/template/loader.gif create mode 100644 p/themes/template/metadata.json create mode 100644 p/themes/template/template.css (limited to 'p') diff --git a/p/themes/template/loader.gif b/p/themes/template/loader.gif new file mode 100644 index 000000000..5ff26f0e3 Binary files /dev/null and b/p/themes/template/loader.gif differ diff --git a/p/themes/template/metadata.json b/p/themes/template/metadata.json new file mode 100644 index 000000000..d29c2b8e8 --- /dev/null +++ b/p/themes/template/metadata.json @@ -0,0 +1,7 @@ +{ + "name": "Template", + "author": "Marien Fressinaud", + "description": "A basic template for FreshRSS", + "version": 0.1, + "files": ["template.css"] +} diff --git a/p/themes/template/template.css b/p/themes/template/template.css new file mode 100644 index 000000000..22d59685b --- /dev/null +++ b/p/themes/template/template.css @@ -0,0 +1,725 @@ +@charset "UTF-8"; + +/*=== Links */ +a { + text-decoration: none; +} +a:hover { + text-decoration: underline; +} + +/*=== Lists */ +ul, ol, dd { + margin: 0; + padding: 0; +} + +/* TITRES */ +h1, h2, h3 { + min-height: 40px; + line-height: 40px; +} + +/* IMG */ +figcaption { + display: inline-block; +} +img { + height: auto; + max-width: 100%; +} + +/* VIDEOS */ +iframe, embed, object, video { + max-width: 100%; +} + +/* FORMULAIRES */ +legend { + display: block; + width: 100%; + clear: both; +} +label { + display: block; + min-height: 25px; + line-height: 25px; +} +input { + width: 180px; +} +textarea { + width: 360px; + height: 100px; +} +input, select, textarea { + display: inline-block; + max-width: 100%; + min-height: 25px; +} +input[type="radio"], +input[type="checkbox"] { + width: 15px !important; + min-height: 15px !important; +} +input:focus.extend { + width: 300px; +} + +.form-group { + margin: 0; +} +.form-group:after { + content: ""; + display: block; + clear: both; +} +.form-group.form-actions { + min-width: 250px; +} +.form-group .group-name { + display: block; + float: left; + width: 200px; +} +.form-group .group-controls { + min-width: 250px; + min-height: 25px; + margin: 0 0 0 220px; +} +.form-group .group-controls .control { + display: block; + min-height: 30px; + line-height: 25px; +} + +.stick { + display: inline-block; + white-space: nowrap; +} + +.btn { + display: inline-block; + min-height: 37px; + min-width: 15px; + line-height: 20px; + cursor: pointer; + overflow: hidden; +} +a.btn { + min-height: 25px; + line-height: 25px; +} +.btn-important { + background: #aaa; +} + +/* NAVIGATION */ +.nav-list .nav-header, +.nav-list .item { + display: block; + height: 35px; + line-height: 35px; +} +.nav-list .item > * { + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.nav-head { + display: block; +} +.nav-head .item { + display: inline-block; +} + +/* HORIZONTAL-LIST */ +.horizontal-list { + display: table; + table-layout: fixed; + width: 100%; +} +.horizontal-list .item { + display: table-cell; +} + +/* DROPDOWN */ +.dropdown { + position: relative; + display: inline-block; +} +.dropdown-target { + display: none; +} + +.dropdown-menu { + display: none; + min-width: 200px; + margin: 5px 0 0; + position: absolute; + right: 0px; + background: #fff; + border: 1px solid #aaa; +} +.dropdown-header { + display: block; +} +.dropdown-menu > .item { + display: block; + min-height: 30px; + line-height: 30px; +} +.dropdown-menu > .item > a { + display: block; + line-height: 30px; +} +.dropdown-menu > .item.share > a { + display: list-item; + list-style-position: inside; + list-style-type: decimal; +} +.dropdown-menu > .item[aria-checked="true"] > a:before { + content: '✓ '; +} +.dropdown-menu .input { + display: block; + height: 40px; + line-height: 30px; +} +.dropdown-menu .input select, +.dropdown-menu .input input { + display: block; + height: 20px; + width: 95%; +} +.dropdown-menu .input select { + width: 70%; + height: auto; +} +.dropdown-target:target ~ .dropdown-menu { + display: block; + z-index: 10; +} +.dropdown-close { + display: inline; +} +.dropdown-close a { + font-size: 0; + position: fixed; + top: 0; bottom: 0; + left: 0; right: 0; + display: block; + z-index: -10; +} + +.separator { + display: block; + height: 0; + border-bottom: 1px solid #aaa; +} + +/* ALERTS */ +.alert { + display: block; + width: 90%; +} +.alert-head { + margin: 0; +} + +/* ICÔNES */ +.icon { + display: inline-block; + width: 16px; + height: 16px; + vertical-align: middle; + line-height: 16px; +} + +/* Prompt (centré) */ +.prompt form { + width: 10em; +} +.prompt input { + width: 100%; +} + + + +/* STRUCTURE */ +.header { + display: table; + width: 100%; + table-layout: fixed; +} +.header > .item { + display: table-cell; +} +.header > .item.title { + width: 250px; + white-space: nowrap; +} +.logo { + display: inline-block; + height: 32px; + width: 32px; +} +.header > .item.title h1 { + display: inline-block; +} +.header > .item.configure { + width: 100px; +} + +#global { + display: table; + width: 100%; + height: 100%; + table-layout: fixed; +} +.aside { + display: table-cell; + height: 100%; + width: 250px; +} + +.nav-login { + display: none; +} + +.nav_menu { + width: 100%; +} +.nav_menu .search { + display: none; +} + +.favicon { + height: 16px; + width: 16px; +} + +.categories { + padding: 0; + list-style: none; +} +.category { + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.category .btn:first-child { + position: relative; +} +.category.stick .btn:first-child { + width: 160px; +} +.category .btn:first-child:not([data-unread="0"]):after { + content: attr(data-unread); + position: absolute; +} +.category + .feeds:not(.active) { + display: none; +} +.categories .feeds { + width: 100%; + padding: 0; + list-style: none; +} +.categories .feeds .item .feed { + display: inline-block; + margin: 0; + width: 165px; + line-height: 35px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + vertical-align: middle; +} +.feed:not([data-unread="0"]):before { + content: "(" attr(data-unread) ") "; +} +.categories .feeds .dropdown-menu { + left: 0; +} +.categories .feeds .item .dropdown-toggle > .icon { + visibility: hidden; + cursor: pointer; +} +.categories .feeds .item .dropdown-target:target ~ .dropdown-toggle > .icon, +.categories .feeds .item:hover .dropdown-toggle > .icon, +.categories .feeds .item.active .dropdown-toggle > .icon { + visibility: visible; +} + +.day { + min-height: 50px; + line-height: 50px; +} +.day .name { + position: absolute; + right: 0; + width: 50%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +#new-article { + display: none; + min-height: 40px; +} +#new-article > a { + display: block; + line-height: 40px; +} + +.horizontal-list > .item:not(.title):not(.website) > a { + display: block; +} + +.flux_header { + position: relative; + height: 25px; +} +.flux .item { + line-height: 40px; + white-space: nowrap; +} +.flux_header > .item { + overflow: hidden; + text-overflow: ellipsis; +} +.flux .item.manage { + width: 40px; +} +.flux .item.website { + width: 200px; +} +.flux .item.title a { + color: #000; +} +.flux.not_read .item.title, +.flux.current .item.title { + font-weight: bold; +} +.flux:not(.current):hover .item.title { + position: absolute; + top: 0; + max-width: calc(100% - 325px); + background: #fff; +} +.flux .item.date { + width: 145px; +} +.link { + width: 40px; +} + +#stream.global .box-category { + display: inline-block; + width: 280px; + border: 1px solid #aaa; + vertical-align: top; +} +#stream.global .category { + width: 100%; +} +#stream.global .btn { + display: block; + width: auto; + height: 35px; + line-height: 35px; +} +#stream.global .box-category .feeds { + display: block; + max-height: 250px; + overflow: auto; +} +#stream.global .box-category .feed { + width: 220px; +} + +.content { + min-height: 150px; + max-width: 550px; + line-height: 170%; + word-wrap: break-word; +} + +img.big { + display: block; +} +.content hr { + height: 1px; +} +.content pre { + overflow: auto; +} +.content q, .content blockquote { + display: block; +} + +#panel { + display: none; + position: fixed; + top: 10px; bottom: 10px; + left: 100px; right: 100px; + overflow: auto; + background: #fff; +} +#panel .close { + position: fixed; + top: 0; bottom: 0; + left: 0; right: 0; + display: block; +} +#panel .close img { + display: none; +} + +#overlay { + display: none; + position: fixed; + top: 0; bottom: 0; + left: 0; right: 0; + background: rgba(0, 0, 0, 0.9); +} + +.hide_posts > :not(.active) > .flux_content { + display: none; +} + +/*** PAGINATION ***/ +.pagination { + display: table; + width: 100%; + line-height: 200%; + table-layout: fixed; +} +.pagination .item { + display: table-cell; + line-height: 40px; +} +.pagination .pager-first, +.pagination .pager-previous, +.pagination .pager-next, +.pagination .pager-last { + width: 100px; +} +.pagination .item a { + display: block; +} + +#nav_entries { + display: table; + width: 250px; + height: 40px; + position: fixed; + bottom: 0; + left: 0; + line-height: 40px; + table-layout: fixed; +} +#nav_entries .item { + display: table-cell; + width: 30%; +} +#nav_entries a { + display: block; +} +#nav_entries .i_up { + vertical-align: top; +} + +.loading { + background: url("loader.gif") center center no-repeat; + font-size: 0; +} + +#bigMarkAsRead { + display: block; + text-align: center; +} +.bigTick { + font-size: 72pt; + line-height: 1.6em; +} + +/*** NOTIFICATION ***/ +#notification { + position: absolute; + top: 10px; + left: 25%; right: 25%; + min-height: 30px; + line-height: 30px; + z-index: 10; + border: 1px solid #aaa; +} +#notification.closed { + display: none; +} +#notification a.close { + display: inline-block; + width: 16px; + height: 16px; + float: right; + line-height: 16px; +} + +.toggle_aside, .btn.toggle_aside { + display: none; +} + +.actualizeProgress { + position: fixed; + top: 10px; + left: 25%; right: 25%; + border: 1px solid #aaa; +} +.actualizeProgress progress { + max-width: 100%; +} + +.log { + overflow: auto; +} +.log .date { + display: block; +} + +@media(max-width: 840px) { + .header, + .aside .btn-important, + .aside .feeds .dropdown, + .flux_header .item.website span, + .item.date { + display: none; + } + .flux_header .item.website { + width: 40px; + } + + .nav-login { + display: block; + } + + .pagination .pager-previous, .pagination .pager-next { + width: 100px; + } + + .toggle_aside, .btn.toggle_aside { + display: inline-block; + } + .aside { + position: fixed; + top: 0; left: 0; + width: 0; + overflow: hidden; + z-index: 10; + } + .aside:target { + width: 80%; + overflow: auto; + } + .aside .toggle_aside { + position: absolute; + right: 0; + display: inline-block; + width: 26px; + height: 26px; + line-height: 26px; + } + + #nav_entries { + width: 100%; + } + + .nav_menu .search { + display: inline-block; + max-width: 97%; + } + .nav_menu .search input { + max-width: 97%; + width: 90px; + } + .nav_menu .search input:focus { + width: 400px; + } + + #panel { + left: 5px; right: 5px; + } + #panel .close { + top: 10px; right: 0; + left: auto; bottom: auto; + display: inline-block; + width: 26px; + height: 26px; + } + #panel .close img { + display: block; + } + + .day .date { + display: none; + } + .day .name { + height: 2.6em; + } + + .flux:not(.current):hover .item.title { + position: relative; + width: auto; + } + + .notification, + .actualizeProgress { + left: 10px; + right: 10px; + } +} + +@media print { + .header, + .aside, + .nav_menu, + .day, + .flux_header, + .flux_content .bottom, + .pagination { + display: none; + } + + html, body { + background: #fff; + color: #000; + font-family: Serif; + font-size: 12pt; + } + + #global, + .flux_content { + display: block !important; + } + + .flux_content .content { + width: 100% !important; + text-align: justify; + } + + .flux_content .content a { + color: #000; + } + .flux_content .content a:after { + content: " (" attr(href) ") "; + text-decoration: underline; + } +} + +.stat > table { + width: 100%; +} \ No newline at end of file -- cgit v1.2.3 From d0f058307fd3e74cf2c83b104236798dcedfe68f Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 17 Feb 2014 01:02:16 +0100 Subject: Update template - Logical structure - Add Comments - Delete some rules See #320 --- p/themes/template/template.css | 480 ++++++++++++++++++----------------------- 1 file changed, 205 insertions(+), 275 deletions(-) (limited to 'p') diff --git a/p/themes/template/template.css b/p/themes/template/template.css index 22d59685b..e3567ea61 100644 --- a/p/themes/template/template.css +++ b/p/themes/template/template.css @@ -1,5 +1,7 @@ @charset "UTF-8"; +/*=== GENERAL */ +/*============*/ /*=== Links */ a { text-decoration: none; @@ -14,27 +16,28 @@ ul, ol, dd { padding: 0; } -/* TITRES */ +/*=== Titles */ h1, h2, h3 { min-height: 40px; line-height: 40px; } -/* IMG */ -figcaption { - display: inline-block; -} +/*=== Images */ img { height: auto; max-width: 100%; } +img.favicon { + height: 16px; + width: 16px; +} -/* VIDEOS */ +/*=== Videos */ iframe, embed, object, video { max-width: 100%; } -/* FORMULAIRES */ +/*=== Forms */ legend { display: block; width: 100%; @@ -62,13 +65,13 @@ input[type="checkbox"] { width: 15px !important; min-height: 15px !important; } -input:focus.extend { +input.extend:focus { width: 300px; } -.form-group { - margin: 0; -} +/*=== COMPONENTS */ +/*===============*/ +/*=== Forms */ .form-group:after { content: ""; display: block; @@ -90,14 +93,14 @@ input:focus.extend { .form-group .group-controls .control { display: block; min-height: 30px; - line-height: 25px; + line-height: 30px; } +/*=== Buttons */ .stick { display: inline-block; white-space: nowrap; } - .btn { display: inline-block; min-height: 37px; @@ -114,20 +117,20 @@ a.btn { background: #aaa; } -/* NAVIGATION */ +/*=== Navigation */ .nav-list .nav-header, .nav-list .item { display: block; height: 35px; line-height: 35px; } -.nav-list .item > * { +.nav-list .item, +.nav-list .item > a { display: block; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } - .nav-head { display: block; } @@ -135,7 +138,7 @@ a.btn { display: inline-block; } -/* HORIZONTAL-LIST */ +/*=== Horizontal-list */ .horizontal-list { display: table; table-layout: fixed; @@ -145,7 +148,7 @@ a.btn { display: table-cell; } -/* DROPDOWN */ +/*=== Dropdown */ .dropdown { position: relative; display: inline-block; @@ -153,7 +156,6 @@ a.btn { .dropdown-target { display: none; } - .dropdown-menu { display: none; min-width: 200px; @@ -175,11 +177,6 @@ a.btn { display: block; line-height: 30px; } -.dropdown-menu > .item.share > a { - display: list-item; - list-style-position: inside; - list-style-type: decimal; -} .dropdown-menu > .item[aria-checked="true"] > a:before { content: '✓ '; } @@ -213,23 +210,23 @@ a.btn { display: block; z-index: -10; } - .separator { display: block; height: 0; border-bottom: 1px solid #aaa; } -/* ALERTS */ +/*=== Alerts */ .alert { display: block; width: 90%; } .alert-head { margin: 0; + font-weight: bold; } -/* ICÔNES */ +/*=== Icons */ .icon { display: inline-block; width: 16px; @@ -238,17 +235,25 @@ a.btn { line-height: 16px; } -/* Prompt (centré) */ -.prompt form { - width: 10em; -} -.prompt input { +/*=== Pagination */ +.pagination { + display: table; width: 100%; + table-layout: fixed; +} +.pagination .item { + display: table-cell; +} +.pagination .pager-first, +.pagination .pager-previous, +.pagination .pager-next, +.pagination .pager-last { + width: 100px; } - - -/* STRUCTURE */ +/*=== STRUCTURE */ +/*===============*/ +/*=== Header */ .header { display: table; width: 100%; @@ -261,18 +266,20 @@ a.btn { width: 250px; white-space: nowrap; } -.logo { +.header > .item.title h1 { display: inline-block; - height: 32px; - width: 32px; } -.header > .item.title h1 { +.header > .item.title .logo { display: inline-block; + height: 32px; + width: 32px; + vertical-align: middle; } .header > .item.configure { width: 100px; } +/*=== Body */ #global { display: table; width: 100%; @@ -284,54 +291,31 @@ a.btn { height: 100%; width: 250px; } - -.nav-login { - display: none; -} - -.nav_menu { - width: 100%; -} -.nav_menu .search { - display: none; -} - -.favicon { - height: 16px; - width: 16px; +.aside.aside_flux { + background: #fff; } -.categories { - padding: 0; - list-style: none; -} +/*=== Aside main page (categories) */ .category { display: block; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } -.category .btn:first-child { - position: relative; -} -.category.stick .btn:first-child { - width: 160px; -} -.category .btn:first-child:not([data-unread="0"]):after { +.category .btn:not([data-unread="0"]):after { content: attr(data-unread); - position: absolute; -} -.category + .feeds:not(.active) { - display: none; } + +/*=== Aside main page (feeds) */ .categories .feeds { width: 100%; - padding: 0; list-style: none; } -.categories .feeds .item .feed { +.categories .feeds:not(.active) { + display: none; +} +.categories .feeds .feed { display: inline-block; - margin: 0; width: 165px; line-height: 35px; overflow: hidden; @@ -339,7 +323,7 @@ a.btn { text-overflow: ellipsis; vertical-align: middle; } -.feed:not([data-unread="0"]):before { +.categories .feeds .feed:not([data-unread="0"]):before { content: "(" attr(data-unread) ") "; } .categories .feeds .dropdown-menu { @@ -348,6 +332,7 @@ a.btn { .categories .feeds .item .dropdown-toggle > .icon { visibility: hidden; cursor: pointer; + vertical-align: top; } .categories .feeds .item .dropdown-target:target ~ .dropdown-toggle > .icon, .categories .feeds .item:hover .dropdown-toggle > .icon, @@ -355,19 +340,7 @@ a.btn { visibility: visible; } -.day { - min-height: 50px; - line-height: 50px; -} -.day .name { - position: absolute; - right: 0; - width: 50%; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - +/*=== New article notification */ #new-article { display: none; min-height: 40px; @@ -377,10 +350,17 @@ a.btn { line-height: 40px; } -.horizontal-list > .item:not(.title):not(.website) > a { - display: block; +/*=== Day indication */ +.day .name { + position: absolute; + right: 0; + width: 50%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; } +/*=== Feed article header and footer */ .flux_header { position: relative; height: 25px; @@ -388,20 +368,16 @@ a.btn { .flux .item { line-height: 40px; white-space: nowrap; -} -.flux_header > .item { - overflow: hidden; text-overflow: ellipsis; } -.flux .item.manage { +.flux .item.manage, +.flux .item.link { width: 40px; + text-align: center; } .flux .item.website { width: 200px; } -.flux .item.title a { - color: #000; -} .flux.not_read .item.title, .flux.current .item.title { font-weight: bold; @@ -412,116 +388,79 @@ a.btn { max-width: calc(100% - 325px); background: #fff; } +.flux .item.title a { + color: #000; + text-decoration: none; +} .flux .item.date { width: 145px; } -.link { - width: 40px; -} - -#stream.global .box-category { - display: inline-block; - width: 280px; - border: 1px solid #aaa; - vertical-align: top; -} -#stream.global .category { - width: 100%; -} -#stream.global .btn { +.flux .item:not(.title) > a { display: block; - width: auto; - height: 35px; - line-height: 35px; } -#stream.global .box-category .feeds { - display: block; - max-height: 250px; - overflow: auto; +.flux .flux_header .item, +.flux .bottom .item.date { + overflow: hidden; } -#stream.global .box-category .feed { - width: 220px; +.flux .item.share > a { + display: list-item; + list-style-position: inside; + list-style-type: decimal; } +/*=== Feed article content */ +.hide_posts > .flux:not(.active) > .flux_content { + display: none; +} .content { min-height: 150px; max-width: 550px; + margin: auto; line-height: 170%; word-wrap: break-word; } - -img.big { - display: block; -} -.content hr { - height: 1px; -} .content pre { overflow: auto; } -.content q, .content blockquote { - display: block; -} -#panel { - display: none; - position: fixed; - top: 10px; bottom: 10px; - left: 100px; right: 100px; - overflow: auto; +/*=== Notification and actualize notification */ +#notification { + position: absolute; + top: 10px; + left: 25%; right: 25%; + z-index: 10; background: #fff; + border: 1px solid #aaa; } -#panel .close { - position: fixed; - top: 0; bottom: 0; - left: 0; right: 0; - display: block; -} -#panel .close img { - display: none; -} - -#overlay { +#notification.closed { display: none; - position: fixed; - top: 0; bottom: 0; - left: 0; right: 0; - background: rgba(0, 0, 0, 0.9); } - -.hide_posts > :not(.active) > .flux_content { - display: none; +#notification a.close { + display: inline-block; + width: 16px; + height: 16px; + float: right; + line-height: 16px; } -/*** PAGINATION ***/ -.pagination { - display: table; - width: 100%; - line-height: 200%; - table-layout: fixed; -} -.pagination .item { - display: table-cell; - line-height: 40px; -} -.pagination .pager-first, -.pagination .pager-previous, -.pagination .pager-next, -.pagination .pager-last { - width: 100px; +.actualizeProgress { + position: fixed; + top: 10px; + left: 25%; right: 25%; + background: #fff; + border: 1px solid #aaa; } -.pagination .item a { - display: block; +.actualizeProgress progress { + max-width: 100%; } +/*=== Navigation menu (for articles) */ #nav_entries { + position: fixed; + bottom: 0; left: 0; display: table; width: 250px; - height: 40px; - position: fixed; - bottom: 0; - left: 0; - line-height: 40px; + background: #fff; table-layout: fixed; } #nav_entries .item { @@ -531,89 +470,114 @@ img.big { #nav_entries a { display: block; } -#nav_entries .i_up { - vertical-align: top; -} +/*=== "Load more" part */ .loading { background: url("loader.gif") center center no-repeat; font-size: 0; } - #bigMarkAsRead { display: block; + padding: 40px 0; text-align: center; } .bigTick { - font-size: 72pt; + font-size: 7em; line-height: 1.6em; } -/*** NOTIFICATION ***/ -#notification { - position: absolute; - top: 10px; - left: 25%; right: 25%; - min-height: 30px; - line-height: 30px; - z-index: 10; +/*=== Statistiques */ +.stat table { + width: 100%; +} + +/*=== GLOBAL VIEW */ +/*================*/ +/*=== Category boxes */ +#stream.global .box-category { + display: inline-block; + width: 280px; border: 1px solid #aaa; + vertical-align: top; } -#notification.closed { - display: none; +#stream.global .category { + width: 100%; } -#notification a.close { - display: inline-block; - width: 16px; - height: 16px; - float: right; - line-height: 16px; +#stream.global .btn { + display: block; +} +#stream.global .box-category .feeds { + display: block; + overflow: auto; +} +#stream.global .box-category .feed { + width: 220px; } -.toggle_aside, .btn.toggle_aside { +/*=== Panel */ +#overlay { display: none; + position: fixed; + top: 0; bottom: 0; + left: 0; right: 0; + background: rgba(0, 0, 0, 0.9); } - -.actualizeProgress { +#panel { + display: none; position: fixed; - top: 10px; - left: 25%; right: 25%; - border: 1px solid #aaa; + top: 10px; bottom: 10px; + left: 100px; right: 100px; + overflow: auto; + background: #fff; } -.actualizeProgress progress { - max-width: 100%; +#panel .close { + position: fixed; + top: 0; bottom: 0; + left: 0; right: 0; + display: block; +} +#panel .close img { + display: none; } -.log { - overflow: auto; +/*=== DIVERS */ +/*===========*/ +.nav-login, +.nav_menu .search, +.nav_menu .toggle_aside { + display: none; } -.log .date { - display: block; + +.aside .toggle_aside { + position: absolute; + right: 0; + display: none; + width: 26px; + height: 26px; + line-height: 26px; + text-align: center; } +/*=== MOBILE */ +/*===========*/ @media(max-width: 840px) { .header, .aside .btn-important, .aside .feeds .dropdown, .flux_header .item.website span, - .item.date { + .item.date, .day .date { display: none; } - .flux_header .item.website { - width: 40px; - } - - .nav-login { + .nav-login, + #panel .close img { display: block; } - - .pagination .pager-previous, .pagination .pager-next { - width: 100px; - } - - .toggle_aside, .btn.toggle_aside { + .nav_menu .toggle_aside, + .aside .toggle_aside, + .nav_menu .search { display: inline-block; } + .aside { position: fixed; top: 0; left: 0; @@ -625,29 +589,24 @@ img.big { width: 80%; overflow: auto; } - .aside .toggle_aside { - position: absolute; - right: 0; - display: inline-block; - width: 26px; - height: 26px; - line-height: 26px; - } - #nav_entries { - width: 100%; + .flux_header .item.website { + width: 40px; } - .nav_menu .search { - display: inline-block; - max-width: 97%; + .flux:not(.current):hover .item.title { + position: relative; + width: auto; } - .nav_menu .search input { - max-width: 97%; - width: 90px; + + #notification, + .actualizeProgress { + left: 10px; + right: 10px; } - .nav_menu .search input:focus { - width: 400px; + + #nav_entries { + width: 100%; } #panel { @@ -660,66 +619,37 @@ img.big { width: 26px; height: 26px; } - #panel .close img { - display: block; - } - - .day .date { - display: none; - } - .day .name { - height: 2.6em; - } - - .flux:not(.current):hover .item.title { - position: relative; - width: auto; - } - - .notification, - .actualizeProgress { - left: 10px; - right: 10px; - } } +/*=== PRINTER */ +/*============*/ @media print { - .header, - .aside, - .nav_menu, - .day, + .header, .aside, + .nav_menu, .day, .flux_header, .flux_content .bottom, - .pagination { + .pagination, + #nav_entries { display: none; } - html, body { background: #fff; color: #000; font-family: Serif; font-size: 12pt; } - #global, .flux_content { display: block !important; } - .flux_content .content { width: 100% !important; - text-align: justify; } - .flux_content .content a { color: #000; } .flux_content .content a:after { - content: " (" attr(href) ") "; - text-decoration: underline; + content: " [" attr(href) "] "; + font-style: italic; } } - -.stat > table { - width: 100%; -} \ No newline at end of file -- cgit v1.2.3 From 7afd9e398a505aebf540ab32c3c6a29bb94a9514 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Fri, 21 Feb 2014 20:48:43 +0100 Subject: Bug "mark all as read" when using DESC and pagination https://github.com/marienfressinaud/FreshRSS/issues/431#issuecomment-35710258 --- app/views/helpers/javascript_vars.phtml | 1 + p/scripts/main.js | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'p') diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 3d7c8a98f..afe0ab258 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -5,6 +5,7 @@ echo '"use strict";', "\n"; $mark = $this->conf->mark_when; echo 'var ', 'hide_posts=', ($this->conf->display_posts || Minz_Request::param('output') === 'reader') ? 'false' : 'true', + ',display_order="', Minz_Request::param('order', $this->conf->sort_order), '"', ',auto_mark_article=', $mark['article'] ? 'true' : 'false', ',auto_mark_site=', $mark['site'] ? 'true' : 'false', ',auto_mark_scroll=', $mark['scroll'] ? 'true' : 'false', diff --git a/p/scripts/main.js b/p/scripts/main.js index 34042c945..beb77a19c 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -774,7 +774,11 @@ function load_more_posts() { $.get(url_load_more, function (data) { box_load_more.children('.flux:last').after($('#stream', data).children('.flux, .day')); $('.pagination').replaceWith($('.pagination', data)); - $('#bigMarkAsRead').attr('href', $('#nav_menu_read_all>a').attr('href')); + if (display_order === 'ASC') { + $('#nav_menu_read_all>a').attr('href', $('#bigMarkAsRead').attr('href')); + } else { + $('#bigMarkAsRead').attr('href', $('#nav_menu_read_all>a').attr('href')); + } $('[id^=day_]').each(function (i) { var ids = $('[id="' + this.id + '"]'); -- cgit v1.2.3 From 27764b36353b3066a9e92da2a96ac17b546295be Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sat, 22 Feb 2014 16:53:51 -0500 Subject: Improve sharing Previously, the share page can handle only a limited number of shares and only one of each type. Now the configuration has been change to be more flexible and allows an unlimited number of shares. The share description is located in an array and the share configuration is stored along with the user configuration. Note: I tried to include the specific javascript code in a separate file but I did not succeded to import it. --- app/Controllers/configureController.php | 12 +---- app/Models/Configuration.php | 56 ++++++++++------------- app/Models/Share.php | 44 ++++++++++++++++++ app/i18n/en.php | 3 ++ app/i18n/fr.php | 3 ++ app/views/configure/sharing.phtml | 77 +++++++++++++------------------- app/views/helpers/view/normal_view.phtml | 73 +++++------------------------- data/shares.php | 75 +++++++++++++++++++++++++++++++ p/scripts/main.js | 28 +++++++++++- 9 files changed, 219 insertions(+), 152 deletions(-) create mode 100644 app/Models/Share.php create mode 100644 data/shares.php (limited to 'p') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index ad8bc546a..104fa8900 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -192,16 +192,8 @@ class FreshRSS_configure_Controller extends Minz_ActionController { public function sharingAction () { if (Minz_Request::isPost ()) { - $this->view->conf->_sharing (array( - 'shaarli' => Minz_Request::param ('shaarli', false), - 'wallabag' => Minz_Request::param ('wallabag', false), - 'diaspora' => Minz_Request::param ('diaspora', false), - 'twitter' => Minz_Request::param ('twitter', false), - 'g+' => Minz_Request::param ('g+', false), - 'facebook' => Minz_Request::param ('facebook', false), - 'email' => Minz_Request::param ('email', false), - 'print' => Minz_Request::param ('print', false), - )); + $params = Minz_Request::params(); + $this->view->conf->_sharing ($params['share']); $this->view->conf->save(); invalidateHttpCache(); diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index 2b719c370..052e28ba8 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -48,16 +48,7 @@ class FreshRSS_Configuration { 'bottomline_tags' => true, 'bottomline_date' => true, 'bottomline_link' => true, - 'sharing' => array( - 'shaarli' => '', - 'wallabag' => '', - 'diaspora' => '', - 'twitter' => true, - 'g+' => true, - 'facebook' => true, - 'email' => true, - 'print' => true, - ), + 'sharing' => array(), ); private $available_languages = array( @@ -65,8 +56,10 @@ class FreshRSS_Configuration { 'fr' => 'Français', ); - public function __construct ($user) { - $this->filename = DATA_PATH . '/' . $user . '_user.php'; + private $shares; + + public function __construct($user) { + $this->filename = DATA_PATH . DIRECTORY_SEPARATOR . $user . '_user.php'; $data = @include($this->filename); if (!is_array($data)) { @@ -80,10 +73,20 @@ class FreshRSS_Configuration { } } $this->data['user'] = $user; + + $this->shares = DATA_PATH . DIRECTORY_SEPARATOR . 'shares.php'; + + $shares = @include($this->shares); + if (!is_array($shares)) { + throw new Minz_PermissionDeniedException($this->shares); + } + + $this->data['shares'] = $shares; } public function save() { @rename($this->filename, $this->filename . '.bak.php'); + unset($this->data['shares']); // Remove shares because it is not intended to be stored in user configuration if (file_put_contents($this->filename, "data, true) . ';', LOCK_EX) === false) { throw new Minz_PermissionDeniedException($this->filename); } @@ -104,16 +107,6 @@ class FreshRSS_Configuration { } } - public function sharing($key = false) { - if ($key === false) { - return $this->data['sharing']; - } - if (isset($this->data['sharing'][$key])) { - return $this->data['sharing'][$key]; - } - return false; - } - public function availableLanguages() { return $this->available_languages; } @@ -187,24 +180,23 @@ class FreshRSS_Configuration { } } public function _sharing ($values) { - $are_url = array ('shaarli', 'wallabag', 'diaspora'); - foreach ($values as $key => $value) { - if (in_array($key, $are_url)) { + $this->data['sharing'] = array(); + foreach ($values as $value) { + if (array_key_exists('url', $value)) { $is_url = ( - filter_var ($value, FILTER_VALIDATE_URL) || + filter_var ($value['url'], FILTER_VALIDATE_URL) || (version_compare(PHP_VERSION, '5.3.3', '<') && (strpos($value, '-') > 0) && ($value === filter_var($value, FILTER_SANITIZE_URL))) ); //PHP bug #51192 - if (!$is_url) { - $value = ''; + continue; + } + if (!array_key_exists('name', $value) || strcmp($value['name'], '') === 0) { + $value['name'] = $value['type']; } - } elseif (!is_bool($value)) { - $value = true; } - - $this->data['sharing'][$key] = $value; + $this->data['sharing'][] = $value; } } public function _theme($value) { diff --git a/app/Models/Share.php b/app/Models/Share.php new file mode 100644 index 000000000..b146db722 --- /dev/null +++ b/app/Models/Share.php @@ -0,0 +1,44 @@ + 'HTTP username', 'http_password' => 'HTTP password', 'blank_to_disable' => 'Leave blank to disable', + 'share_name' => 'Share name to display', + 'share_url' => 'Share URL to use', 'not_yet_implemented' => 'Not yet implemented', 'access_protected_feeds' => 'Connection allows to access HTTP protected RSS feeds', 'no_selected_feed' => 'No feed selected.', @@ -230,6 +232,7 @@ return array ( 'more_information' => 'More information', 'activate_sharing' => 'Activate sharing', 'shaarli' => 'Shaarli', + 'blogotext' => 'Blogotext', 'wallabag' => 'wallabag', 'diaspora' => 'Diaspora*', 'twitter' => 'Twitter', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index ab7843d12..7420e2fdd 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -166,6 +166,8 @@ return array ( 'http_username' => 'Identifiant HTTP', 'http_password' => 'Mot de passe HTTP', 'blank_to_disable' => 'Laissez vide pour désactiver', + 'share_name' => 'Nom du partage à afficher', + 'share_url' => 'URL du partage à utiliser', 'not_yet_implemented' => 'Pas encore implémenté', 'access_protected_feeds' => 'La connexion permet d’accéder aux flux protégés par une authentification HTTP', 'no_selected_feed' => 'Aucun flux sélectionné.', @@ -230,6 +232,7 @@ return array ( 'more_information' => 'Plus d’informations', 'activate_sharing' => 'Activer le partage', 'shaarli' => 'Shaarli', + 'blogotext' => 'Blogotext', 'wallabag' => 'wallabag', 'diaspora' => 'Diaspora*', 'twitter' => 'Twitter', diff --git a/app/views/configure/sharing.phtml b/app/views/configure/sharing.phtml index e3ea11665..e46284955 100644 --- a/app/views/configure/sharing.phtml +++ b/app/views/configure/sharing.phtml @@ -3,54 +3,41 @@
-
+ +
' + data-advanced='
+ + + +
'> -
- -
- - - -
-
- -
- -
- - - -
-
- -
- -
- - - + conf->sharing as $key => $sharing): ?> + conf->shares[$sharing['type']]; ?> +
+ +
+ + ' /> + + + + + +
-
+ -
- +
- - - + +
@@ -61,4 +48,4 @@
- + \ No newline at end of file diff --git a/app/views/helpers/view/normal_view.phtml b/app/views/helpers/view/normal_view.phtml index ae93b627c..f27984025 100644 --- a/app/views/helpers/view/normal_view.phtml +++ b/app/views/helpers/view/normal_view.phtml @@ -8,19 +8,10 @@ if (!empty($this->entries)) { $display_yesterday = true; $display_others = true; if ($this->loginOk) { - $shaarli = $this->conf->sharing ('shaarli'); - $wallabag = $this->conf->sharing ('wallabag'); - $diaspora = $this->conf->sharing ('diaspora'); + $sharing = $this->conf->sharing; } else { - $shaarli = ''; - $wallabag = ''; - $diaspora = ''; + $sharing = array(); } - $twitter = $this->conf->sharing ('twitter'); - $google_plus = $this->conf->sharing ('g+'); - $facebook = $this->conf->sharing ('facebook'); - $email = $this->conf->sharing ('email'); - $print = $this->conf->sharing ('print'); $hidePosts = !$this->conf->display_posts; $lazyload = $this->conf->lazyload; $topline_read = $this->conf->topline_read; @@ -29,9 +20,7 @@ if (!empty($this->entries)) { $topline_link = $this->conf->topline_link; $bottomline_read = $this->conf->bottomline_read; $bottomline_favorite = $this->conf->bottomline_favorite; - $bottomline_sharing = $this->conf->bottomline_sharing && ( - $shaarli || $wallabag || $diaspora || $twitter || - $google_plus || $facebook || $email || $print); + $bottomline_sharing = $this->conf->bottomline_sharing && (count($sharing)); $bottomline_tags = $this->conf->bottomline_tags; $bottomline_date = $this->conf->bottomline_date; $bottomline_link = $this->conf->bottomline_link; @@ -146,55 +135,13 @@ if (!empty($this->entries)) { diff --git a/data/shares.php b/data/shares.php new file mode 100644 index 000000000..44176f1bf --- /dev/null +++ b/data/shares.php @@ -0,0 +1,75 @@ + array( + 'url' => '~URL~?post=~LINK~&title=~TITLE~&source=FreshRSS', + 'transform' => array('urlencode'), + 'help' => 'http://sebsauvage.net/wiki/doku.php?id=php:shaarli', + 'form' => 'advanced', + ), + 'blogotext' => array( + 'url' => '~URL~/admin/links.php?url=~LINK~', + 'transform' => array(), + 'help' => 'http://lehollandaisvolant.net/blogotext/fr/', + 'form' => 'advanced', + ), + 'wallabag' => array( + 'url' => '~URL~?action=add&url=~LINK~', + 'transform' => array( + 'link' => array('base64_encode'), + 'title' => array(), + ), + 'help' => 'http://www.wallabag.org/', + 'form' => 'advanced', + ), + 'diaspora' => array( + 'url' => '~URL~/bookmarklet?url=~LINK~&title=~TITLE~', + 'transform' => array('urlencode'), + 'help' => 'https://diasporafoundation.org/', + 'form' => 'advanced', + ), + 'twitter' => array( + 'url' => 'https://twitter.com/share?url=~LINK~&text=~TITLE~', + 'transform' => array('urlencode'), + 'form' => 'simple', + ), + 'g+' => array( + 'url' => 'https://plus.google.com/share?url=~LINK~', + 'transform' => array('urlencode'), + 'form' => 'simple', + ), + 'facebook' => array( + 'url' => 'https://www.facebook.com/sharer.php?u=~LINK~&t=~TITLE~', + 'transform' => array('urlencode'), + 'form' => 'simple', + ), + 'email' => array( + 'url' => 'mailto:?subject=~TITLE~&body=~LINK~', + 'transform' => array( + 'link' => array('urlencode'), + 'title' => array(), + ), + 'form' => 'simple', + ), + 'print' => array( + 'url' => '#', + 'transform' => array(), + 'form' => 'simple', + ), +); diff --git a/p/scripts/main.js b/p/scripts/main.js index beb77a19c..ec27bd50c 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1,6 +1,7 @@ "use strict"; var $stream = null, - isCollapsed = true; + isCollapsed = true, + shares = 0; function is_normal_mode() { return $stream.hasClass('normal'); @@ -945,7 +946,7 @@ function init_confirm_action() { } function init_print_action() { - $('.print-article').click(function () { + $('.item.share > a[href="#"]').click(function () { var content = " diff --git a/p/themes/p.css b/p/themes/p.css new file mode 100644 index 000000000..171b2078b --- /dev/null +++ b/p/themes/p.css @@ -0,0 +1,17 @@ +@charset "UTF-8"; + +body { + font-family: sans-serif; + text-align: center; +} +h1 { + font-size: xx-large; + text-shadow: 1px -1px 0 #CCCCCC; +} +h1 a { + color: #0062BE; + text-decoration: none; +} +img { + border: 0; +} -- cgit v1.2.3 From 06189cb6661edf75079037f90cf82276ab5f5648 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 10 Apr 2016 11:52:16 +0200 Subject: API support for REDIRECT HTTP headers https://github.com/FreshRSS/FreshRSS/issues/1127 --- p/api/greader.php | 3 +++ 1 file changed, 3 insertions(+) (limited to 'p') diff --git a/p/api/greader.php b/p/api/greader.php index 62782ce1a..894c2e960 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -46,6 +46,8 @@ function headerVariable($headerName, $varName) { $upName = 'HTTP_' . strtoupper($headerName); if (isset($_SERVER[$upName])) { $header = $_SERVER[$upName]; + } elseif (isset($_SERVER['REDIRECT_' . $upName])) { + $header = $_SERVER['REDIRECT_' . $upName]; } elseif (function_exists('getallheaders')) { $ALL_HEADERS = getallheaders(); if (isset($ALL_HEADERS[$headerName])) { @@ -134,6 +136,7 @@ function checkCompatibility() { die('FAIL 64-bit or GMP extension!'); } if ((!array_key_exists('HTTP_AUTHORIZATION', $_SERVER)) && //Apache mod_rewrite trick should be fine + (!array_key_exists('REDIRECT_HTTP_AUTHORIZATION', $_SERVER)) && //Apache mod_rewrite with FCGI (empty($_SERVER['SERVER_SOFTWARE']) || (stripos($_SERVER['SERVER_SOFTWARE'], 'nginx') === false)) && //nginx should be fine (empty($_SERVER['SERVER_SOFTWARE']) || (stripos($_SERVER['SERVER_SOFTWARE'], 'lighttpd') === false)) && //lighttpd should be fine ((!function_exists('getallheaders')) || (stripos(php_sapi_name(), 'cgi') !== false))) { //Main problem is Apache/CGI mode -- cgit v1.2.3 From 624824673592dbc21300f9a26c27781f54429de5 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 23 Apr 2016 21:48:37 +0200 Subject: Adjust caching for favicon with errors --- p/f.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'p') diff --git a/p/f.php b/p/f.php index c904e1fcb..0f23921e3 100644 --- a/p/f.php +++ b/p/f.php @@ -44,14 +44,13 @@ function download_favicon($website, $dest) { } -function show_default_favicon() { +function show_default_favicon($cacheSeconds = 3600) { global $default_favicon; - header('Content-Type: image/x-icon'); header('Content-Disposition: inline; filename="default_favicon.ico"'); $default_mtime = @filemtime($default_favicon); - if (!httpConditional($default_mtime, 2592000, 2)) { + if (!httpConditional($default_mtime, $cacheSeconds, 2)) { readfile($default_favicon); } } @@ -68,10 +67,11 @@ $ico = $favicons_dir . $id . '.ico'; $ico_mtime = @filemtime($ico); $txt_mtime = @filemtime($txt); +header('Content-Type: image/x-icon'); if ($ico_mtime == false || $txt_mtime > $ico_mtime) { if ($txt_mtime == false) { - show_default_favicon(); + show_default_favicon(1800); return; } @@ -79,12 +79,11 @@ if ($ico_mtime == false || $txt_mtime > $ico_mtime) { $url = file_get_contents($txt); if (!download_favicon($url, $ico)) { // Download failed, show the default favicon - show_default_favicon(); + show_default_favicon(86400); return; } } -header('Content-Type: image/x-icon'); header('Content-Disposition: inline; filename="' . $id . '.ico"'); if (!httpConditional($ico_mtime, 2592000, 2)) { -- cgit v1.2.3 From d9e14621b5a0de1c189486bbc8c18a7b007d6965 Mon Sep 17 00:00:00 2001 From: romibi Date: Fri, 8 Jul 2016 19:12:43 +0200 Subject: Make Sidebar Sticky --- README.fr.md | 1 + README.md | 1 + app/FreshRSS.php | 3 ++- p/scripts/jquery.sticky-kit.min.js | 9 +++++++++ p/scripts/main.js | 5 ++++- 5 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 p/scripts/jquery.sticky-kit.min.js (limited to 'p') diff --git a/README.fr.md b/README.fr.md index c28cd3069..8892ddc3f 100644 --- a/README.fr.md +++ b/README.fr.md @@ -126,6 +126,7 @@ mysqldump -u utilisateur -p --databases freshrss > freshrss.sql * [MINZ](https://github.com/marienfressinaud/MINZ) * [php-http-304](http://alexandre.alapetite.fr/doc-alex/php-http-304/) * [jQuery](http://jquery.com/) +* [jQuery Plugin Sticky-Kit](http://leafo.net/sticky-kit/) * [keyboard_shortcuts](http://www.openjs.com/scripts/events/keyboard_shortcuts/) * [flotr2](http://www.humblesoftware.com/flotr2) diff --git a/README.md b/README.md index db06b4315..0beed2946 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,7 @@ mysqldump -u user -p --databases freshrss > freshrss.sql * [MINZ](https://github.com/marienfressinaud/MINZ) * [php-http-304](http://alexandre.alapetite.fr/doc-alex/php-http-304/) * [jQuery](http://jquery.com/) +* [jQuery Plugin Sticky-Kit](http://leafo.net/sticky-kit/) * [keyboard_shortcuts](http://www.openjs.com/scripts/events/keyboard_shortcuts/) * [flotr2](http://www.humblesoftware.com/flotr2) diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 4933892bc..b1c01478f 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -95,7 +95,8 @@ class FreshRSS extends Minz_FrontController { } } - Minz_View::appendScript(Minz_Url::display('/scripts/jquery.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/jquery.min.js'))); + Minz_View::appendScript(Minz_Url::display('/scripts/jquery.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/jquery.min.js')),false,false,false); + Minz_View::appendScript(Minz_Url::display('/scripts/jquery.sticky-kit.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/jquery.sticky-kit.min.js'))); Minz_View::appendScript(Minz_Url::display('/scripts/shortcut.js?' . @filemtime(PUBLIC_PATH . '/scripts/shortcut.js'))); Minz_View::appendScript(Minz_Url::display('/scripts/main.js?' . @filemtime(PUBLIC_PATH . '/scripts/main.js'))); diff --git a/p/scripts/jquery.sticky-kit.min.js b/p/scripts/jquery.sticky-kit.min.js new file mode 100644 index 000000000..e2a3c6de9 --- /dev/null +++ b/p/scripts/jquery.sticky-kit.min.js @@ -0,0 +1,9 @@ +/* + Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net +*/ +(function(){var b,f;b=this.jQuery||window.jQuery;f=b(window);b.fn.stick_in_parent=function(d){var A,w,J,n,B,K,p,q,k,E,t;null==d&&(d={});t=d.sticky_class;B=d.inner_scrolling;E=d.recalc_every;k=d.parent;q=d.offset_top;p=d.spacer;w=d.bottoming;null==q&&(q=0);null==k&&(k=void 0);null==B&&(B=!0);null==t&&(t="is_stuck");A=b(document);null==w&&(w=!0);J=function(a,d,n,C,F,u,r,G){var v,H,m,D,I,c,g,x,y,z,h,l;if(!a.data("sticky_kit")){a.data("sticky_kit",!0);I=A.height();g=a.parent();null!=k&&(g=g.closest(k)); +if(!g.length)throw"failed to find stick parent";v=m=!1;(h=null!=p?p&&a.closest(p):b("
"))&&h.css("position",a.css("position"));x=function(){var c,f,e;if(!G&&(I=A.height(),c=parseInt(g.css("border-top-width"),10),f=parseInt(g.css("padding-top"),10),d=parseInt(g.css("padding-bottom"),10),n=g.offset().top+c+f,C=g.height(),m&&(v=m=!1,null==p&&(a.insertAfter(h),h.detach()),a.css({position:"",top:"",width:"",bottom:""}).removeClass(t),e=!0),F=a.offset().top-(parseInt(a.css("margin-top"),10)||0)-q, +u=a.outerHeight(!0),r=a.css("float"),h&&h.css({width:a.outerWidth(!0),height:u,display:a.css("display"),"vertical-align":a.css("vertical-align"),"float":r}),e))return l()};x();if(u!==C)return D=void 0,c=q,z=E,l=function(){var b,l,e,k;if(!G&&(e=!1,null!=z&&(--z,0>=z&&(z=E,x(),e=!0)),e||A.height()===I||x(),e=f.scrollTop(),null!=D&&(l=e-D),D=e,m?(w&&(k=e+u+c>C+n,v&&!k&&(v=!1,a.css({position:"fixed",bottom:"",top:c}).trigger("sticky_kit:unbottom"))),eb&&!v&&(c-=l,c=Math.max(b-u,c),c=Math.min(q,c),m&&a.css({top:c+"px"})))):e>F&&(m=!0,b={position:"fixed",top:c},b.width="border-box"===a.css("box-sizing")?a.outerWidth()+"px":a.width()+"px",a.css(b).addClass(t),null==p&&(a.after(h),"left"!==r&&"right"!==r||h.append(a)),a.trigger("sticky_kit:stick")),m&&w&&(null==k&&(k=e+u+c>C+n),!v&&k)))return v=!0,"static"===g.css("position")&&g.css({position:"relative"}), +a.css({position:"absolute",bottom:d,top:"auto"}).trigger("sticky_kit:bottom")},y=function(){x();return l()},H=function(){G=!0;f.off("touchmove",l);f.off("scroll",l);f.off("resize",y);b(document.body).off("sticky_kit:recalc",y);a.off("sticky_kit:detach",H);a.removeData("sticky_kit");a.css({position:"",bottom:"",top:"",width:""});g.position("position","");if(m)return null==p&&("left"!==r&&"right"!==r||a.insertAfter(h),h.remove()),a.removeClass(t)},f.on("touchmove",l),f.on("scroll",l),f.on("resize", +y),b(document.body).on("sticky_kit:recalc",y),a.on("sticky_kit:detach",H),setTimeout(l,0)}};n=0;for(K=this.length;n Date: Sat, 30 Jul 2016 12:19:02 +0200 Subject: Fix logs style scroll bug https://github.com/FreshRSS/FreshRSS/issues/1178 There was a conflict on the ".logs" class name --- app/views/index/logs.phtml | 2 +- p/themes/BlueLagoon/BlueLagoon.css | 2 +- p/themes/Dark/dark.css | 2 +- p/themes/Flat/flat.css | 2 +- p/themes/Origine/origine.css | 2 +- p/themes/Pafat/pafat.css | 2 +- p/themes/Screwdriver/screwdriver.css | 2 +- p/themes/base-theme/base.css | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) (limited to 'p') diff --git a/app/views/index/logs.phtml b/app/views/index/logs.phtml index 02256bd98..0938491c3 100644 --- a/app/views/index/logs.phtml +++ b/app/views/index/logs.phtml @@ -10,7 +10,7 @@ logsPaginator->items(); ?> -
+
logsPaginator->render('logs_pagination.phtml', 'page'); ?> diff --git a/p/themes/BlueLagoon/BlueLagoon.css b/p/themes/BlueLagoon/BlueLagoon.css index e1b93dac9..d64ffd9a0 100644 --- a/p/themes/BlueLagoon/BlueLagoon.css +++ b/p/themes/BlueLagoon/BlueLagoon.css @@ -1054,7 +1054,7 @@ opacity: 1; /*=== LOGS */ /*=========*/ -.logs { +.loglist { border: 1px solid #aaa; border-radius: 5px; overflow: hidden; diff --git a/p/themes/Dark/dark.css b/p/themes/Dark/dark.css index 65ee0a049..f72ed8b5b 100644 --- a/p/themes/Dark/dark.css +++ b/p/themes/Dark/dark.css @@ -928,7 +928,7 @@ a.btn { /*=== LOGS */ /*=========*/ -.logs { +.loglist { overflow: hidden; border: 1px solid #333; } diff --git a/p/themes/Flat/flat.css b/p/themes/Flat/flat.css index 1e5cdf8ff..0672c6a38 100644 --- a/p/themes/Flat/flat.css +++ b/p/themes/Flat/flat.css @@ -921,7 +921,7 @@ a.btn { /*=== LOGS */ /*=========*/ -.logs { +.loglist { overflow: hidden; border: 1px solid #aaa; } diff --git a/p/themes/Origine/origine.css b/p/themes/Origine/origine.css index ee08b33bb..da461087b 100644 --- a/p/themes/Origine/origine.css +++ b/p/themes/Origine/origine.css @@ -966,7 +966,7 @@ a.btn { /*=== LOGS */ /*=========*/ -.logs { +.loglist { border: 1px solid #aaa; border-radius: 5px; overflow: hidden; diff --git a/p/themes/Pafat/pafat.css b/p/themes/Pafat/pafat.css index 374471ebc..5e46a63ca 100644 --- a/p/themes/Pafat/pafat.css +++ b/p/themes/Pafat/pafat.css @@ -977,7 +977,7 @@ a.btn { /*=== LOGS */ /*=========*/ -.logs { +.loglist { border: 1px solid #aaa; border-radius: 5px; overflow: hidden; diff --git a/p/themes/Screwdriver/screwdriver.css b/p/themes/Screwdriver/screwdriver.css index 8754b0b2f..b7bbd923e 100644 --- a/p/themes/Screwdriver/screwdriver.css +++ b/p/themes/Screwdriver/screwdriver.css @@ -1052,7 +1052,7 @@ opacity: 1; /*=== LOGS */ /*=========*/ -.logs { +.loglist { border: 1px solid #aaa; border-radius: 5px; overflow: hidden; diff --git a/p/themes/base-theme/base.css b/p/themes/base-theme/base.css index 6c788371d..192a957c9 100644 --- a/p/themes/base-theme/base.css +++ b/p/themes/base-theme/base.css @@ -731,7 +731,7 @@ a.btn { /*=== LOGS */ /*=========*/ -.logs { +.loglist { overflow: hidden; } .log { -- cgit v1.2.3 From 462c1e208f02e4977c7e96c0f5936987931d5bc1 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 30 Jul 2016 23:37:13 +0200 Subject: PSHB: work-around for SuperFeeder Feeds using SuperFeeder for PubSubHubbub push had timeout problems during substription. SuperFeeder bot was returning 422 "We could not verify your callback Error: ETIMEDOUT" It seems to be due to the the fact that SuperFeeder bot uses keep-alive but expects the server to close the connection. https://github.com/FreshRSS/FreshRSS/issues/312#issuecomment-73716936 --- p/api/pshb.php | 2 ++ 1 file changed, 2 insertions(+) (limited to 'p') diff --git a/p/api/pshb.php b/p/api/pshb.php index 7de4cc1a2..136b98fc9 100644 --- a/p/api/pshb.php +++ b/p/api/pshb.php @@ -65,11 +65,13 @@ if (!empty($_REQUEST['hub_mode']) && $_REQUEST['hub_mode'] === 'subscribe') { $hubJson['error'] = true; //Do not assume that PubSubHubbub works until the first successul push } file_put_contents('./!hub.json', json_encode($hubJson)); + header('Connection: close'); exit(isset($_REQUEST['hub_challenge']) ? $_REQUEST['hub_challenge'] : ''); } if (!empty($_REQUEST['hub_mode']) && $_REQUEST['hub_mode'] === 'unsubscribe') { if (empty($hubJson['lease_end']) || $hubJson['lease_end'] < time()) { + header('Connection: close'); exit(isset($_REQUEST['hub_challenge']) ? $_REQUEST['hub_challenge'] : ''); } else { header('HTTP/1.1 422 Unprocessable Entity'); -- cgit v1.2.3 From 21a6521ba9ab8df18ad8386465cba9e9af99ce7f Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 31 Jul 2016 01:38:46 +0200 Subject: More links for API help https://github.com/FreshRSS/FreshRSS/issues/328#issuecomment-236100791 https://github.com/FreshRSS/FreshRSS/issues/957#issuecomment-133581712 --- app/views/user/profile.phtml | 1 + p/api/index.html | 20 -------------------- p/api/index.php | 29 +++++++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 20 deletions(-) delete mode 100644 p/api/index.html create mode 100644 p/api/index.php (limited to 'p') diff --git a/app/views/user/profile.phtml b/app/views/user/profile.phtml index 7ae2c7ede..a97970927 100644 --- a/app/views/user/profile.phtml +++ b/app/views/user/profile.phtml @@ -37,6 +37,7 @@ />
+
diff --git a/p/api/index.html b/p/api/index.html deleted file mode 100644 index 8da0bcb58..000000000 --- a/p/api/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - -FreshRSS API - - - - - -

FreshRSS API

- -

Google Reader compatible API

- - - - diff --git a/p/api/index.php b/p/api/index.php new file mode 100644 index 000000000..3ab4e02b3 --- /dev/null +++ b/p/api/index.php @@ -0,0 +1,29 @@ + + + + +FreshRSS API + + + + + +

FreshRSS API

+ +

Google Reader compatible API

+
+
Your API address:
+
+
+ + + + -- cgit v1.2.3 From c1548e732d7472c40473b3d99858059333a05eae Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 31 Jul 2016 14:58:19 +0200 Subject: Remove Mozilla Persona login https://github.com/FreshRSS/FreshRSS/issues/1052 --- README.fr.md | 3 +- README.md | 3 +- app/Controllers/authController.php | 152 +------------------------------- app/Controllers/userController.php | 25 ------ app/FreshRSS.php | 8 -- app/Models/Auth.php | 18 +--- app/Models/ConfigurationSetter.php | 7 +- app/i18n/cz/admin.php | 6 -- app/i18n/cz/conf.php | 1 - app/i18n/cz/feedback.php | 1 - app/i18n/cz/gen.php | 3 - app/i18n/cz/install.php | 6 -- app/i18n/de/admin.php | 6 -- app/i18n/de/conf.php | 1 - app/i18n/de/feedback.php | 1 - app/i18n/de/gen.php | 3 - app/i18n/de/install.php | 6 -- app/i18n/en/admin.php | 6 -- app/i18n/en/conf.php | 1 - app/i18n/en/feedback.php | 1 - app/i18n/en/gen.php | 3 - app/i18n/en/install.php | 6 -- app/i18n/fr/admin.php | 6 -- app/i18n/fr/conf.php | 1 - app/i18n/fr/feedback.php | 1 - app/i18n/fr/gen.php | 3 - app/i18n/fr/install.php | 6 -- app/i18n/it/admin.php | 6 -- app/i18n/it/conf.php | 1 - app/i18n/it/feedback.php | 1 - app/i18n/it/gen.php | 3 - app/i18n/it/install.php | 6 -- app/i18n/nl/admin.php | 6 -- app/i18n/nl/conf.php | 1 - app/i18n/nl/feedback.php | 1 - app/i18n/nl/gen.php | 3 - app/i18n/nl/install.php | 6 -- app/i18n/ru/admin.php | 6 -- app/i18n/ru/conf.php | 1 - app/i18n/ru/feedback.php | 1 - app/i18n/ru/gen.php | 3 - app/i18n/ru/install.php | 6 -- app/i18n/tr/admin.php | 6 -- app/i18n/tr/conf.php | 1 - app/i18n/tr/feedback.php | 1 - app/i18n/tr/gen.php | 3 - app/i18n/tr/install.php | 6 -- app/install.php | 45 +--------- app/views/auth/index.phtml | 3 +- app/views/auth/personaLogin.phtml | 28 ------ app/views/auth/register.phtml | 5 -- app/views/auth/reset.phtml | 33 ------- app/views/helpers/javascript_vars.phtml | 2 - app/views/user/manage.phtml | 8 -- app/views/user/profile.phtml | 9 -- data/config.default.php | 1 - data/users/_/config.default.php | 1 - lib/lib_rss.php | 1 - p/scripts/install.js | 8 +- p/scripts/persona.js | 76 ---------------- 60 files changed, 11 insertions(+), 561 deletions(-) delete mode 100644 app/views/auth/personaLogin.phtml delete mode 100644 app/views/auth/reset.phtml delete mode 100644 p/scripts/persona.js (limited to 'p') diff --git a/README.fr.md b/README.fr.md index fd01a507b..067d6d1a1 100644 --- a/README.fr.md +++ b/README.fr.md @@ -89,7 +89,6 @@ sudo chmod -R g+w ./data/ # Contrôle d’accès Il est requis pour le mode multi-utilisateur, et recommandé dans tous les cas, de limiter l’accès à votre FreshRSS. Au choix : * En utilisant l’identification par formulaire (requiert JavaScript, et PHP 5.3.7+ recommandé – fonctionne avec certaines versions de PHP 5.3.3+) -* En utilisant l’identification par [Mozilla Persona](https://login.persona.org/about) incluse dans FreshRSS * En utilisant un contrôle d’accès HTTP défini par votre serveur Web * Voir par exemple la [documentation d’Apache sur l’authentification](http://httpd.apache.org/docs/trunk/howto/auth.html) * Créer dans ce cas un fichier `./p/i/.htaccess` avec un fichier `.htpasswd` correspondant. @@ -111,7 +110,7 @@ Par exemple, pour exécuter le script toutes les heures : * En cas de problème, les logs peuvent être utile à lire, soit depuis l’interface de FreshRSS, soit manuellement depuis `./data/log/*.log`. # Sauvegarde -* Il faut conserver vos fichiers `./data/config.php` ainsi que `./data/*_user.php` et éventuellement `./data/persona/` +* Il faut conserver vos fichiers `./data/config.php` ainsi que `./data/*_user.php` * Vous pouvez exporter votre liste de flux depuis FreshRSS au format OPML * Pour sauvegarder les articles eux-mêmes, vous pouvez utiliser [phpMyAdmin](http://www.phpmyadmin.net) ou les outils de MySQL : diff --git a/README.md b/README.md index a0d22a75c..76975adbd 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,6 @@ sudo chmod -R g+w ./data/ # Access control It is needed for the multi-user mode to limit access to FreshRSS. You can: * use form authentication (need JavaScript and PHP 5.3.7+, works with some PHP 5.3.3+) -* use [Mozilla Persona](https://login.persona.org/about) authentication included in FreshRSS * use HTTP authentication supported by your web server * See [Apache documentation](http://httpd.apache.org/docs/trunk/howto/auth.html) * In that case, create a `./p/i/.htaccess` file with a matching `.htpasswd` file. @@ -111,7 +110,7 @@ For example, if you want to run the script every hour: * If you encounter any problem, logs are accessible from the interface or manually in `./data/log/*.log` files. # Backup -* You need to keep `./data/config.php`, `./data/*_user.php` and `./data/persona/` files +* You need to keep `./data/config.php`, and `./data/*_user.php` files * You can export your feed list in OPML format from FreshRSS * To save articles, you can use [phpMyAdmin](http://www.phpmyadmin.net) or MySQL tools: diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index f58b008de..9decba431 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -70,7 +70,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { /** * This action handles the login page. * - * It forwards to the correct login page (form or Persona) or main page if + * It forwards to the correct login page (form) or main page if * the user is already connected. */ public function loginAction() { @@ -83,9 +83,6 @@ class FreshRSS_auth_Controller extends Minz_ActionController { case 'form': Minz_Request::forward(array('c' => 'auth', 'a' => 'formLogin')); break; - case 'persona': - Minz_Request::forward(array('c' => 'auth', 'a' => 'personaLogin')); - break; case 'http_auth': case 'none': // It should not happened! @@ -188,81 +185,6 @@ class FreshRSS_auth_Controller extends Minz_ActionController { } } - /** - * This action handles Persona login page. - * - * If this action is reached through a POST request, assertion from Persona - * is verificated and user connected if all is ok. - * - * Parameter is: - * - assertion (default: false) - * - * @todo: Persona system should be moved to a plugin - */ - public function personaLoginAction() { - $this->view->res = false; - - if (Minz_Request::isPost()) { - $this->view->_useLayout(false); - - $assert = Minz_Request::param('assertion'); - $url = 'https://verifier.login.persona.org/verify'; - $params = 'assertion=' . $assert . '&audience=' . - urlencode(Minz_Url::display(null, 'php', true)); - $ch = curl_init(); - $options = array( - CURLOPT_URL => $url, - CURLOPT_RETURNTRANSFER => TRUE, - CURLOPT_POST => 2, - CURLOPT_POSTFIELDS => $params - ); - curl_setopt_array($ch, $options); - $result = curl_exec($ch); - curl_close($ch); - - $res = json_decode($result, true); - - $login_ok = false; - $reason = ''; - if ($res['status'] === 'okay') { - $email = filter_var($res['email'], FILTER_VALIDATE_EMAIL); - if ($email != '') { - $persona_file = DATA_PATH . '/persona/' . $email . '.txt'; - if (($current_user = @file_get_contents($persona_file)) !== false) { - $current_user = trim($current_user); - $conf = get_user_configuration($current_user); - if (!is_null($conf)) { - $login_ok = strcasecmp($email, $conf->mail_login) === 0; - } else { - $reason = 'Invalid configuration for user ' . - '[' . $current_user . ']'; - } - } - } else { - $reason = 'Invalid email format [' . $res['email'] . ']'; - } - } else { - $reason = $res['reason']; - } - - if ($login_ok) { - Minz_Session::_param('currentUser', $current_user); - Minz_Session::_param('mail', $email); - FreshRSS_Auth::giveAccess(); - invalidateHttpCache(); - } else { - Minz_Log::warning($reason); - - $res = array(); - $res['status'] = 'failure'; - $res['reason'] = _t('feedback.auth.login.invalid'); - } - - header('Content-Type: application/json; charset=UTF-8'); - $this->view->res = $res; - } - } - /** * This action removes all accesses of the current user. */ @@ -273,78 +195,6 @@ class FreshRSS_auth_Controller extends Minz_ActionController { array('c' => 'index', 'a' => 'index')); } - /** - * This action resets the authentication system. - * - * After reseting, form auth is set by default. - */ - public function resetAction() { - Minz_View::prependTitle(_t('admin.auth.title_reset') . ' · '); - - Minz_View::appendScript(Minz_Url::display( - '/scripts/bcrypt.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js') - )); - - $this->view->no_form = false; - // Enable changement of auth only if Persona! - if (FreshRSS_Context::$system_conf->auth_type != 'persona') { - $this->view->message = array( - 'status' => 'bad', - 'title' => _t('gen.short.damn'), - 'body' => _t('feedback.auth.not_persona') - ); - $this->view->no_form = true; - return; - } - - $conf = get_user_configuration(FreshRSS_Context::$system_conf->default_user); - if (is_null($conf)) { - return; - } - - // Admin user must have set its master password. - if (!$conf->passwordHash) { - $this->view->message = array( - 'status' => 'bad', - 'title' => _t('gen.short.damn'), - 'body' => _t('feedback.auth.no_password_set') - ); - $this->view->no_form = true; - return; - } - - invalidateHttpCache(); - - if (Minz_Request::isPost()) { - $nonce = Minz_Session::param('nonce'); - $username = Minz_Request::param('username', ''); - $challenge = Minz_Request::param('challenge', ''); - - $ok = FreshRSS_FormAuth::checkCredentials( - $username, $conf->passwordHash, $nonce, $challenge - ); - - if ($ok) { - FreshRSS_Context::$system_conf->auth_type = 'form'; - $ok = FreshRSS_Context::$system_conf->save(); - - if ($ok) { - Minz_Request::good(_t('feedback.auth.form.set')); - } else { - Minz_Request::bad(_t('feedback.auth.form.not_set'), - array('c' => 'auth', 'a' => 'reset')); - } - } else { - Minz_Log::warning('Password mismatch for' . - ' user=' . $username . - ', nonce=' . $nonce . - ', c=' . $challenge); - Minz_Request::bad(_t('feedback.auth.login.invalid'), - array('c' => 'auth', 'a' => 'reset')); - } - } - } - /** * This action gives possibility to a user to create an account. */ diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index 1c7d621f1..0521bc008 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -64,21 +64,8 @@ class FreshRSS_user_Controller extends Minz_ActionController { FreshRSS_Context::$user_conf->apiPasswordHash = $passwordHash; } - // TODO: why do we need of hasAccess here? - if (FreshRSS_Auth::hasAccess('admin')) { - FreshRSS_Context::$user_conf->mail_login = Minz_Request::param('mail_login', '', true); - } - $email = FreshRSS_Context::$user_conf->mail_login; - Minz_Session::_param('mail', $email); - $ok &= FreshRSS_Context::$user_conf->save(); - if ($email != '') { - $personaFile = DATA_PATH . '/persona/' . $email . '.txt'; - @unlink($personaFile); - $ok &= (file_put_contents($personaFile, Minz_Session::param('currentUser', '_')) !== false); - } - if ($ok) { Minz_Request::good(_t('feedback.profile.updated'), array('c' => 'user', 'a' => 'profile')); @@ -119,7 +106,6 @@ class FreshRSS_user_Controller extends Minz_ActionController { * - new_user_language * - new_user_name * - new_user_passwordPlain - * - new_user_email * - r (i.e. a redirection url, optional) * * @todo clean up this method. Idea: write a method to init a user with basic information. @@ -168,22 +154,12 @@ class FreshRSS_user_Controller extends Minz_ActionController { if (empty($passwordHash)) { $passwordHash = ''; } - - $new_user_email = filter_var($_POST['new_user_email'], FILTER_VALIDATE_EMAIL); - if (empty($new_user_email)) { - $new_user_email = ''; - } else { - $personaFile = join_path(DATA_PATH, 'persona', $new_user_email . '.txt'); - @unlink($personaFile); - $ok &= (file_put_contents($personaFile, $new_user_name) !== false); - } } if ($ok) { mkdir(join_path(DATA_PATH, 'users', $new_user_name)); $config_array = array( 'language' => $new_user_language, 'passwordHash' => $passwordHash, - 'mail_login' => $new_user_email, ); $ok &= (file_put_contents($configPath, "deleteUser($username); $ok &= recursive_unlink($user_data); - //TODO: delete Persona file } if ($ok && $self_deletion) { FreshRSS_Auth::removeAccess(); diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 4933892bc..20640266e 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -98,14 +98,6 @@ class FreshRSS extends Minz_FrontController { Minz_View::appendScript(Minz_Url::display('/scripts/jquery.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/jquery.min.js'))); Minz_View::appendScript(Minz_Url::display('/scripts/shortcut.js?' . @filemtime(PUBLIC_PATH . '/scripts/shortcut.js'))); Minz_View::appendScript(Minz_Url::display('/scripts/main.js?' . @filemtime(PUBLIC_PATH . '/scripts/main.js'))); - - if (FreshRSS_Context::$system_conf->auth_type === 'persona') { - // TODO move it in a plugin - // Needed for login AND logout with Persona. - Minz_View::appendScript('https://login.persona.org/include.js'); - $file_mtime = @filemtime(PUBLIC_PATH . '/scripts/persona.js'); - Minz_View::appendScript(Minz_Url::display('/scripts/persona.js?' . $file_mtime)); - } } private static function loadNotifications() { diff --git a/app/Models/Auth.php b/app/Models/Auth.php index 4e7a71947..d689f7cdb 100644 --- a/app/Models/Auth.php +++ b/app/Models/Auth.php @@ -60,16 +60,6 @@ class FreshRSS_Auth { Minz_Session::_param('currentUser', $current_user); } return $login_ok; - case 'persona': - $email = filter_var(Minz_Session::param('mail'), FILTER_VALIDATE_EMAIL); - $persona_file = DATA_PATH . '/persona/' . $email . '.txt'; - if (($current_user = @file_get_contents($persona_file)) !== false) { - $current_user = trim($current_user); - Minz_Session::_param('currentUser', $current_user); - Minz_Session::_param('mail', $email); - return true; - } - return false; case 'none': return true; default: @@ -93,9 +83,6 @@ class FreshRSS_Auth { case 'http_auth': self::$login_ok = strcasecmp($current_user, httpAuthUser()) === 0; break; - case 'persona': - self::$login_ok = strcasecmp(Minz_Session::param('mail'), $user_conf->mail_login) === 0; - break; case 'none': self::$login_ok = true; break; @@ -143,9 +130,6 @@ class FreshRSS_Auth { Minz_Session::_param('passwordHash'); FreshRSS_FormAuth::deleteCookie(); break; - case 'persona': - Minz_Session::_param('mail'); - break; case 'http_auth': case 'none': // Nothing to do... @@ -170,7 +154,7 @@ class FreshRSS_Auth { public static function accessNeedsAction() { $conf = Minz_Configuration::get('system'); $auth_type = $conf->auth_type; - return $auth_type === 'form' || $auth_type === 'persona'; + return $auth_type === 'form'; } } diff --git a/app/Models/ConfigurationSetter.php b/app/Models/ConfigurationSetter.php index 250c14c39..e472b1e7f 100644 --- a/app/Models/ConfigurationSetter.php +++ b/app/Models/ConfigurationSetter.php @@ -95,11 +95,6 @@ class FreshRSS_ConfigurationSetter { $data['language'] = $value; } - private function _mail_login(&$data, $value) { - $value = filter_var($value, FILTER_VALIDATE_EMAIL); - $data['mail_login'] = $value ? $value : ''; - } - private function _old_entries(&$data, $value) { $value = intval($value); $data['old_entries'] = $value > 0 ? $value : 3; @@ -278,7 +273,7 @@ class FreshRSS_ConfigurationSetter { private function _auth_type(&$data, $value) { $value = strtolower($value); - if (!in_array($value, array('form', 'http_auth', 'persona', 'none'))) { + if (!in_array($value, array('form', 'http_auth', 'none'))) { $value = 'none'; } $data['auth_type'] = $value; diff --git a/app/i18n/cz/admin.php b/app/i18n/cz/admin.php index 342ac7ccd..881c02fc6 100644 --- a/app/i18n/cz/admin.php +++ b/app/i18n/cz/admin.php @@ -8,7 +8,6 @@ return array( 'form' => 'Webový formulář (tradiční, vyžaduje JavaScript)', 'http' => 'HTTP (pro pokročilé uživatele s HTTPS)', 'none' => 'Žádný (nebezpečné)', - 'persona' => 'Mozilla Persona (moderní, vyžaduje JavaScript)', 'title' => 'Přihlášení', 'title_reset' => 'Reset přihlášení', 'token' => 'Authentizační token', @@ -75,10 +74,6 @@ return array( 'nok' => 'Nemáte PDO nebo některý z podporovaných ovladačů (pdo_mysql, pdo_sqlite).', 'ok' => 'Máte PDO a alespoň jeden z podporovaných ovladačů (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Zkontrolujte oprávnění adresáře ./data/persona. HTTP server musí mít do tohoto adresáře práva zápisu', - 'ok' => 'Oprávnění adresáře Mozilla Persona jsou v pořádku.', - ), 'php' => array( '_' => 'PHP instalace', 'nok' => 'Vaše verze PHP je %s, ale FreshRSS vyžaduje alespoň verzi %s.', @@ -169,7 +164,6 @@ return array( 'user' => array( 'articles_and_size' => '%s článků (%s)', 'create' => 'Vytvořit nového uživatele', - 'email_persona' => 'Email pro přihlášení
(pro Mozilla Persona)', 'language' => 'Jazyk', 'number' => 'Zatím je vytvořen %d účet', 'numbers' => 'Zatím je vytvořeno %d účtů', diff --git a/app/i18n/cz/conf.php b/app/i18n/cz/conf.php index 823ab1ea3..ec25f988c 100644 --- a/app/i18n/cz/conf.php +++ b/app/i18n/cz/conf.php @@ -76,7 +76,6 @@ return array( '_' => 'Smazání účtu', 'warn' => 'Váš účet bude smazán spolu se všemi souvisejícími daty', ), - 'email_persona' => 'Email pro přihlášení
(pro Mozilla Persona)', 'password_api' => 'Password API
(tzn. pro mobilní aplikace)', 'password_form' => 'Heslo
(pro přihlášení webovým formulářem)', 'password_format' => 'Alespoň 7 znaků', diff --git a/app/i18n/cz/feedback.php b/app/i18n/cz/feedback.php index b75a4a15a..81302afca 100644 --- a/app/i18n/cz/feedback.php +++ b/app/i18n/cz/feedback.php @@ -21,7 +21,6 @@ return array( 'success' => 'Jste odhlášen', ), 'no_password_set' => 'Heslo administrátora nebylo nastaveno. Tato funkce není k dispozici.', - 'not_persona' => 'Resetovat lze pouze systém Persona.', ), 'conf' => array( 'error' => 'Během ukládání nastavení došlo k chybě', diff --git a/app/i18n/cz/gen.php b/app/i18n/cz/gen.php index 5e15ae6f9..e73325c55 100644 --- a/app/i18n/cz/gen.php +++ b/app/i18n/cz/gen.php @@ -24,8 +24,6 @@ return array( 'email' => 'Email', 'keep_logged_in' => 'Zapamatovat přihlášení (1 měsíc)', 'login' => 'Login', - 'login_persona' => 'Přihlášení pomocí Persona', - 'login_persona_problem' => 'Problém s připojením k Persona?', 'logout' => 'Odhlášení', 'password' => array( '_' => 'Heslo', @@ -42,7 +40,6 @@ return array( 'admin' => 'Název administrátorského účtu', 'format' => 'maximálně 16 alfanumerických znaků', ), - 'will_reset' => 'Přihlašovací systém bude vyresetován: místo sytému Persona bude použito přihlášení formulářem.', ), 'date' => array( 'Apr' => '\\D\\u\\b\\e\\n', diff --git a/app/i18n/cz/install.php b/app/i18n/cz/install.php index bc3e01992..6b94c0d4b 100644 --- a/app/i18n/cz/install.php +++ b/app/i18n/cz/install.php @@ -9,13 +9,11 @@ return array( 'reinstall' => 'Reinstalovat FreshRSS', ), 'auth' => array( - 'email_persona' => 'Email pro přihlášení
(pro Mozilla Persona)', 'form' => 'Webový formulář (tradiční, vyžaduje JavaScript)', 'http' => 'HTTP (pro pokročilé uživatele s HTTPS)', 'none' => 'Žádný (nebezpečné)', 'password_form' => 'Heslo
(pro přihlášení webovým formulářem)', 'password_format' => 'Alespoň 7 znaků', - 'persona' => 'Mozilla Persona (moderní, vyžaduje JavaScript)', 'type' => 'Způsob přihlášení', ), 'bdd' => array( @@ -78,10 +76,6 @@ return array( 'nok' => 'Nemáte PDO nebo některý z podporovaných ovladačů (pdo_mysql, pdo_sqlite).', 'ok' => 'Máte PDO a alespoň jeden z podporovaných ovladačů (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Zkontrolujte oprávnění adresáře ./data/persona. HTTP server musí mít do tohoto adresáře práva zápisu', - 'ok' => 'Oprávnění adresáře Mozilla Persona jsou v pořádku.', - ), 'php' => array( 'nok' => 'Vaše verze PHP je %s, ale FreshRSS vyžaduje alespoň verzi %s.', 'ok' => 'Vaše verze PHP je %s a je kompatibilní s FreshRSS.', diff --git a/app/i18n/de/admin.php b/app/i18n/de/admin.php index 6e6cc0956..7b75fe5f4 100644 --- a/app/i18n/de/admin.php +++ b/app/i18n/de/admin.php @@ -8,7 +8,6 @@ return array( 'form' => 'Webformular (traditionell, benötigt JavaScript)', 'http' => 'HTTP (HTTPS für erfahrene Benutzer)', 'none' => 'Keine (gefährlich)', - 'persona' => 'Mozilla Persona (modern, benötigt JavaScript)', 'title' => 'Authentifizierung', 'title_reset' => 'Zurücksetzen der Authentifizierung', 'token' => 'Authentifizierungs-Token', @@ -75,10 +74,6 @@ return array( 'nok' => 'Ihnen fehlt PDO oder einer der unterstützten Treiber (pdo_mysql, pdo_sqlite).', 'ok' => 'Sie haben PDO und mindestens einen der unterstützten Treiber (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses ./data/persona. Der HTTP-Server muss Schreibrechte besitzen.', - 'ok' => 'Die Berechtigungen des Verzeichnisses ./data/persona sind in Ordnung.', - ), 'php' => array( '_' => 'PHP-Installation', 'nok' => 'Ihre PHP-Version ist %s aber FreshRSS benötigt mindestens Version %s.', @@ -169,7 +164,6 @@ return array( 'user' => array( 'articles_and_size' => '%s Artikel (%s)', 'create' => 'Neuen Benutzer erstellen', - 'email_persona' => 'Anmelde-E-Mail-Adresse
(für Mozilla Persona)', 'language' => 'Sprache', 'number' => 'Es wurde bis jetzt %d Account erstellt', 'numbers' => 'Es wurden bis jetzt %d Accounts erstellt', diff --git a/app/i18n/de/conf.php b/app/i18n/de/conf.php index c1a762f12..7c57d5655 100644 --- a/app/i18n/de/conf.php +++ b/app/i18n/de/conf.php @@ -76,7 +76,6 @@ return array( '_' => 'Accountlöschung', 'warn' => 'Dein Account und alle damit bezogenen Daten werden gelöscht.', ), - 'email_persona' => 'Anmelde-E-Mail-Adresse
(für Mozilla Persona)', 'password_api' => 'Passwort-API
(z. B. für mobile Anwendungen)', 'password_form' => 'Passwort
(für die Anmeldemethode per Webformular)', 'password_format' => 'mindestens 7 Zeichen', diff --git a/app/i18n/de/feedback.php b/app/i18n/de/feedback.php index 4c15aadc3..f93992982 100644 --- a/app/i18n/de/feedback.php +++ b/app/i18n/de/feedback.php @@ -21,7 +21,6 @@ return array( 'success' => 'Sie sind abgemeldet', ), 'no_password_set' => 'Administrator-Passwort ist nicht gesetzt worden. Dieses Feature ist nicht verfügbar.', - 'not_persona' => 'Nur das Persona-System kann zurückgesetzt werden.', ), 'conf' => array( 'error' => 'Während der Speicherung der Konfiguration trat ein Fehler auf', diff --git a/app/i18n/de/gen.php b/app/i18n/de/gen.php index 4b85c722a..c6e7f1ef3 100644 --- a/app/i18n/de/gen.php +++ b/app/i18n/de/gen.php @@ -24,8 +24,6 @@ return array( 'email' => 'E-Mail-Adresse', 'keep_logged_in' => 'Eingeloggt bleiben (1 Monat)', 'login' => 'Anmelden', - 'login_persona' => 'Anmelden mit Persona', - 'login_persona_problem' => 'Verbindungsproblem mit Persona?', 'logout' => 'Abmelden', 'password' => array( '_' => 'Passwort', @@ -42,7 +40,6 @@ return array( 'admin' => 'Administrator-Nutzername', 'format' => 'maximal 16 alphanumerische Zeichen', ), - 'will_reset' => 'Authentifikationssystem wird zurückgesetzt: ein Formular wird anstelle von Persona benutzt.', ), 'date' => array( 'Apr' => '\\A\\p\\r\\i\\l', diff --git a/app/i18n/de/install.php b/app/i18n/de/install.php index d16496818..a77822e7b 100644 --- a/app/i18n/de/install.php +++ b/app/i18n/de/install.php @@ -9,13 +9,11 @@ return array( 'reinstall' => 'Neuinstallation von FreshRSS', ), 'auth' => array( - 'email_persona' => 'Anmelde-E-Mail-Adresse
(für Mozilla Persona)', 'form' => 'Webformular (traditionell, benötigt JavaScript)', 'http' => 'HTTP (HTTPS für erfahrene Benutzer)', 'none' => 'Keine (gefährlich)', 'password_form' => 'Passwort
(für die Anmeldemethode per Webformular)', 'password_format' => 'mindestens 7 Zeichen', - 'persona' => 'Mozilla Persona (modern, benötigt JavaScript)', 'type' => 'Authentifizierungsmethode', ), 'bdd' => array( @@ -78,10 +76,6 @@ return array( 'nok' => 'Ihnen fehlt PDO oder einer der unterstützten Treiber (pdo_mysql, pdo_sqlite).', 'ok' => 'Sie haben PDO und mindestens einen der unterstützten Treiber (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Überprüfen Sie die Berechtigungen des Verzeichnisses ./data/persona. Der HTTP-Server muss Schreibrechte besitzen.', - 'ok' => 'Die Berechtigungen des Verzeichnisses ./data/persona sind in Ordnung.', - ), 'php' => array( 'nok' => 'Ihre PHP-Version ist %s aber FreshRSS benötigt mindestens Version %s.', 'ok' => 'Ihre PHP-Version ist %s, welche kompatibel mit FreshRSS ist.', diff --git a/app/i18n/en/admin.php b/app/i18n/en/admin.php index a58771edf..a88552087 100644 --- a/app/i18n/en/admin.php +++ b/app/i18n/en/admin.php @@ -8,7 +8,6 @@ return array( 'form' => 'Web form (traditional, requires JavaScript)', 'http' => 'HTTP (for advanced users with HTTPS)', 'none' => 'None (dangerous)', - 'persona' => 'Mozilla Persona (modern, requires JavaScript)', 'title' => 'Authentication', 'title_reset' => 'Authentication reset', 'token' => 'Authentication token', @@ -75,10 +74,6 @@ return array( 'nok' => 'You lack PDO or one of the supported drivers (pdo_mysql, pdo_sqlite).', 'ok' => 'You have PDO and at least one of the supported drivers (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Check permissions on ./data/persona directory. HTTP server must have rights to write into', - 'ok' => 'Permissions on Mozilla Persona directory are good.', - ), 'php' => array( '_' => 'PHP installation', 'nok' => 'Your PHP version is %s but FreshRSS requires at least version %s.', @@ -169,7 +164,6 @@ return array( 'user' => array( 'articles_and_size' => '%s articles (%s)', 'create' => 'Create new user', - 'email_persona' => 'Login mail address
(for Mozilla Persona)', 'language' => 'Language', 'number' => 'There is %d account created yet', 'numbers' => 'There are %d accounts created yet', diff --git a/app/i18n/en/conf.php b/app/i18n/en/conf.php index 38e9197e9..b5ab73510 100644 --- a/app/i18n/en/conf.php +++ b/app/i18n/en/conf.php @@ -76,7 +76,6 @@ return array( '_' => 'Account deletion', 'warn' => 'Your account and all the related data will be deleted.', ), - 'email_persona' => 'Login email address
(for Mozilla Persona)', 'password_api' => 'API password
(e.g., for mobile apps)', 'password_form' => 'Password
(for the Web-form login method)', 'password_format' => 'At least 7 characters', diff --git a/app/i18n/en/feedback.php b/app/i18n/en/feedback.php index c9189c0d0..7ce2ae9cf 100644 --- a/app/i18n/en/feedback.php +++ b/app/i18n/en/feedback.php @@ -21,7 +21,6 @@ return array( 'success' => 'You are disconnected', ), 'no_password_set' => 'Administrator password hasn’t been set. This feature isn’t available.', - 'not_persona' => 'Only Persona system can be reset.', ), 'conf' => array( 'error' => 'An error occurred during configuration saving', diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index ba4e2f86c..17b47ba2f 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -24,8 +24,6 @@ return array( 'email' => 'Email address', 'keep_logged_in' => 'Keep me logged in (1 month)', 'login' => 'Login', - 'login_persona' => 'Login with Persona', - 'login_persona_problem' => 'Connection problem with Persona?', 'logout' => 'Logout', 'password' => array( '_' => 'Password', @@ -42,7 +40,6 @@ return array( 'admin' => 'Administrator username', 'format' => 'maximum 16 alphanumeric characters', ), - 'will_reset' => 'Authentication system will be reset: a form will be used instead of Persona.', ), 'date' => array( 'Apr' => '\\A\\p\\r\\i\\l', diff --git a/app/i18n/en/install.php b/app/i18n/en/install.php index 4b5bbc62e..d1c5f37c8 100644 --- a/app/i18n/en/install.php +++ b/app/i18n/en/install.php @@ -9,13 +9,11 @@ return array( 'reinstall' => 'Reinstall FreshRSS', ), 'auth' => array( - 'email_persona' => 'Login email address
(for Mozilla Persona)', 'form' => 'Web form (traditional, requires JavaScript)', 'http' => 'HTTP (for advanced users with HTTPS)', 'none' => 'None (dangerous)', 'password_form' => 'Password
(for the Web-form login method)', 'password_format' => 'At least 7 characters', - 'persona' => 'Mozilla Persona (modern, requires JavaScript)', 'type' => 'Authentication method', ), 'bdd' => array( @@ -78,10 +76,6 @@ return array( 'nok' => 'You lack PDO or one of the supported drivers (pdo_mysql, pdo_sqlite).', 'ok' => 'You have PDO and at least one of the supported drivers (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Check permissions on ./data/persona directory. HTTP server must have rights to write into', - 'ok' => 'Permissions on Mozilla Persona directory are good.', - ), 'php' => array( 'nok' => 'Your PHP version is %s but FreshRSS requires at least version %s.', 'ok' => 'Your PHP version is %s, which is compatible with FreshRSS.', diff --git a/app/i18n/fr/admin.php b/app/i18n/fr/admin.php index f4f267306..c359e9d24 100644 --- a/app/i18n/fr/admin.php +++ b/app/i18n/fr/admin.php @@ -8,7 +8,6 @@ return array( 'form' => 'Formulaire (traditionnel, requiert JavaScript)', 'http' => 'HTTP (pour utilisateurs avancés avec HTTPS)', 'none' => 'Aucune (dangereux)', - 'persona' => 'Mozilla Persona (moderne, requiert JavaScript)', 'title' => 'Authentification', 'title_reset' => 'Réinitialisation de l’authentification', 'token' => 'Jeton d’identification', @@ -75,10 +74,6 @@ return array( 'nok' => 'Vous ne disposez pas de PDO ou d’un des drivers supportés (pdo_mysql, pdo_sqlite).', 'ok' => 'Vous disposez de PDO et d’au moins un des drivers supportés (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Veuillez vérifier les droits sur le répertoire ./data/persona. Le serveur HTTP doit être capable d’écrire dedans', - 'ok' => 'Les droits sur le répertoire de Mozilla Persona sont bons.', - ), 'php' => array( '_' => 'Installation de PHP', 'nok' => 'Votre version de PHP est la %s mais FreshRSS requiert au moins la version %s.', @@ -169,7 +164,6 @@ return array( 'user' => array( 'articles_and_size' => '%s articles (%s)', 'create' => 'Créer un nouvel utilisateur', - 'email_persona' => 'Adresse courriel de connexion
(pour Mozilla Persona)', 'language' => 'Langue', 'number' => '%d compte a déjà été créé', 'numbers' => '%d comptes ont déjà été créés', diff --git a/app/i18n/fr/conf.php b/app/i18n/fr/conf.php index 6193b7a01..7a6d12e17 100644 --- a/app/i18n/fr/conf.php +++ b/app/i18n/fr/conf.php @@ -76,7 +76,6 @@ return array( '_' => 'Suppression du compte', 'warn' => 'Le compte et toutes les données associées vont être supprimées.', ), - 'email_persona' => 'Adresse courriel de connexion
(pour Mozilla Persona)', 'password_api' => 'Mot de passe API
(ex. : pour applis mobiles)', 'password_form' => 'Mot de passe
(pour connexion par formulaire)', 'password_format' => '7 caractères minimum', diff --git a/app/i18n/fr/feedback.php b/app/i18n/fr/feedback.php index e2364a251..15f3ab859 100644 --- a/app/i18n/fr/feedback.php +++ b/app/i18n/fr/feedback.php @@ -21,7 +21,6 @@ return array( 'success' => 'Vous avez été déconnecté', ), 'no_password_set' => 'Aucun mot de passe administrateur n’a été précisé. Cette fonctionnalité n’est pas disponible.', - 'not_persona' => 'Seul le système d’authentification Persona peut être réinitialisé.', ), 'conf' => array( 'error' => 'Une erreur est survenue durant la sauvegarde de la configuration', diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php index 031098aa2..d61a716a7 100644 --- a/app/i18n/fr/gen.php +++ b/app/i18n/fr/gen.php @@ -24,8 +24,6 @@ return array( 'email' => 'Adresse courriel', 'keep_logged_in' => 'Rester connecté (1 mois)', 'login' => 'Connexion', - 'login_persona' => 'Connexion avec Persona', - 'login_persona_problem' => 'Problème de connexion à Persona ?', 'logout' => 'Déconnexion', 'password' => array( '_' => 'Mot de passe', @@ -42,7 +40,6 @@ return array( 'admin' => 'Nom d’utilisateur administrateur', 'format' => '16 caractères alphanumériques maximum', ), - 'will_reset' => 'Le système d’authentification va être réinitialisé : un formulaire sera utilisé à la place de Persona.', ), 'date' => array( 'Apr' => '\\a\\v\\r\\i\\l', diff --git a/app/i18n/fr/install.php b/app/i18n/fr/install.php index 91dfbbb09..946a210ee 100644 --- a/app/i18n/fr/install.php +++ b/app/i18n/fr/install.php @@ -9,13 +9,11 @@ return array( 'reinstall' => 'Réinstaller FreshRSS', ), 'auth' => array( - 'email_persona' => 'Adresse courriel de connexion
(pour Mozilla Persona)', 'form' => 'Formulaire (traditionnel, requiert JavaScript)', 'http' => 'HTTP (pour utilisateurs avancés avec HTTPS)', 'none' => 'Aucune (dangereux)', 'password_form' => 'Mot de passe
(pour connexion par formulaire)', 'password_format' => '7 caractères minimum', - 'persona' => 'Mozilla Persona (moderne, requiert JavaScript)', 'type' => 'Méthode d’authentification', ), 'bdd' => array( @@ -78,10 +76,6 @@ return array( 'nok' => 'Vous ne disposez pas de PDO ou d’un des drivers supportés (pdo_mysql, pdo_sqlite).', 'ok' => 'Vous disposez de PDO et d’au moins un des drivers supportés (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Veuillez vérifier les droits sur le répertoire ./data/persona. Le serveur HTTP doit être capable d’écrire dedans', - 'ok' => 'Les droits sur le répertoire de Mozilla Persona sont bons.', - ), 'php' => array( 'nok' => 'Votre version de PHP est la %s mais FreshRSS requiert au moins la version %s.', 'ok' => 'Votre version de PHP est la %s, qui est compatible avec FreshRSS.', diff --git a/app/i18n/it/admin.php b/app/i18n/it/admin.php index 94b2d6762..4eea158f6 100644 --- a/app/i18n/it/admin.php +++ b/app/i18n/it/admin.php @@ -8,7 +8,6 @@ return array( 'form' => 'Web form (tradizionale, richiede JavaScript)', 'http' => 'HTTP (per gli utenti avanzati con HTTPS)', 'none' => 'Nessuno (pericoloso)', - 'persona' => 'Mozilla Persona (moderno, richiede JavaScript)', 'title' => 'Autenticazione', 'title_reset' => 'Reset autenticazione', 'token' => 'Token di autenticazione', @@ -75,10 +74,6 @@ return array( 'nok' => 'Manca PDO o uno degli altri driver supportati (pdo_mysql, pdo_sqlite).', 'ok' => 'PDO e altri driver supportati (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Verifica i permessi sulla cartella ./data/persona. Il server HTTP deve avere i permessi per scriverci dentro', - 'ok' => 'I permessi sulla cartella Mozilla Persona sono corretti.', - ), 'php' => array( '_' => 'Installazione PHP', 'nok' => 'Versione PHP %s FreshRSS richiede almeno la versione %s.', @@ -169,7 +164,6 @@ return array( 'user' => array( 'articles_and_size' => '%s articoli (%s)', 'create' => 'Crea nuovo utente', - 'email_persona' => 'Indirizzo mail
(Login Mozilla Persona)', 'language' => 'Lingua', 'number' => ' %d profilo utente creato', 'numbers' => 'Sono presenti %d profili utente', diff --git a/app/i18n/it/conf.php b/app/i18n/it/conf.php index b757b3210..19b62c9a7 100644 --- a/app/i18n/it/conf.php +++ b/app/i18n/it/conf.php @@ -76,7 +76,6 @@ return array( '_' => 'Cancellazione account', 'warn' => 'Il tuo account e tutti i dati associati saranno cancellati.', ), - 'email_persona' => 'Indirizzo email
(Login Mozilla Persona)', 'password_api' => 'Password API
(e.g., per applicazioni mobili)', 'password_form' => 'Password
(per il login classico)', 'password_format' => 'Almeno 7 caratteri', diff --git a/app/i18n/it/feedback.php b/app/i18n/it/feedback.php index caf1cd2b4..f217586b0 100644 --- a/app/i18n/it/feedback.php +++ b/app/i18n/it/feedback.php @@ -21,7 +21,6 @@ return array( 'success' => 'Disconnessione effettuata', ), 'no_password_set' => 'Password di amministrazione non impostata. Opzione non disponibile.', - 'not_persona' => 'Solo il sistema Mozilla Persona può essere resettato.', ), 'conf' => array( 'error' => 'Si è verificato un errore durante il salvataggio della configurazione', diff --git a/app/i18n/it/gen.php b/app/i18n/it/gen.php index d24377593..c02ddd13a 100644 --- a/app/i18n/it/gen.php +++ b/app/i18n/it/gen.php @@ -24,8 +24,6 @@ return array( 'email' => 'Indirizzo email', 'keep_logged_in' => 'Ricorda i dati (1 mese)', 'login' => 'Accedi', - 'login_persona' => 'Accedi con Mozilla Persona', - 'login_persona_problem' => 'Problemi di connessione con Mozilla Persona?', 'logout' => 'Esci', 'password' => array( '_' => 'Password', @@ -42,7 +40,6 @@ return array( 'admin' => 'Username amministratore', 'format' => 'massimo 16 caratteri alfanumerici', ), - 'will_reset' => 'Il sistema di autenticazione verrà resettato: un form verrà usato per Mozilla Persona.', ), 'date' => array( 'Apr' => '\\A\\p\\r\\i\\l\\e', diff --git a/app/i18n/it/install.php b/app/i18n/it/install.php index 8f5300bd5..a60dd4523 100644 --- a/app/i18n/it/install.php +++ b/app/i18n/it/install.php @@ -9,13 +9,11 @@ return array( 'reinstall' => 'Reinstalla FreshRSS', ), 'auth' => array( - 'email_persona' => 'Indirizzo mail
(per Mozilla Persona)', 'form' => 'Web form (tradizionale, richiede JavaScript)', 'http' => 'HTTP (per gli utenti avanzati con HTTPS)', 'none' => 'Nessuno (pericoloso)', 'password_form' => 'Password
(per il login tramite Web-form tradizionale)', 'password_format' => 'Almeno 7 caratteri', - 'persona' => 'Mozilla Persona (moderno, richiede JavaScript)', 'type' => 'Metodo di autenticazione', ), 'bdd' => array( @@ -78,10 +76,6 @@ return array( 'nok' => 'Manca PDO o uno degli altri driver supportati (pdo_mysql, pdo_sqlite).', 'ok' => 'PDO e altri driver supportati (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Verifica i permessi sulla cartella ./data/persona. Il server HTTP deve avere i permessi per scriverci dentro', - 'ok' => 'I permessi sulla cartella Mozilla Persona sono corretti.', - ), 'php' => array( '_' => 'Installazione PHP', 'nok' => 'Versione di PHP %s FreshRSS richiede almeno la versione %s.', diff --git a/app/i18n/nl/admin.php b/app/i18n/nl/admin.php index bd7d63b6a..9f05d69b1 100644 --- a/app/i18n/nl/admin.php +++ b/app/i18n/nl/admin.php @@ -8,7 +8,6 @@ return array( 'form' => 'Web formulier (traditioneel, benodigd JavaScript)', 'http' => 'HTTP (voor geavanceerde gebruikers met HTTPS)', 'none' => 'Geen (gevaarlijk)', - 'persona' => 'Mozilla Persona (modern, benodigd JavaScript)', 'title' => 'Authenticatie', 'title_reset' => 'Authenticatie terugzetten', 'token' => 'Authenticatie teken', @@ -75,10 +74,6 @@ return array( 'nok' => 'U mist PDO of een van de ondersteunde drivers (pdo_mysql, pdo_sqlite).', 'ok' => 'U hebt PDO en ten minste één van de ondersteunde drivers (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Controleer de permissies op de ./data/persona map. HTTP server moet rechten hebben om hierin te schrijven', - 'ok' => 'Permissies op de Mozilla Persona map zijn goed.', - ), 'php' => array( '_' => 'PHP installatie', 'nok' => 'Uw PHP versie is %s maar FreshRSS benodigd tenminste versie %s.', @@ -169,7 +164,6 @@ return array( 'user' => array( 'articles_and_size' => '%s artikelen (%s)', 'create' => 'Creëer nieuwe gebruiker', - 'email_persona' => 'Log in mail adres
(voor Mozilla Persona)', 'language' => 'Taal', 'number' => 'Er is %d accounts gemaakt', 'numbers' => 'Er zijn %d accounts gemaakt', diff --git a/app/i18n/nl/conf.php b/app/i18n/nl/conf.php index 9b0aff793..573dabf45 100644 --- a/app/i18n/nl/conf.php +++ b/app/i18n/nl/conf.php @@ -76,7 +76,6 @@ return array( '_' => 'Account verwijderen', 'warn' => 'Uw account en alle gerelateerde gegvens worden verwijderd.', ), - 'email_persona' => 'Log in mail adres
(voor Mozilla Persona)', 'password_api' => 'Wachtwoord API
(e.g., voor mobiele apps)', 'password_form' => 'Wachtwoord
(voor de Web-formulier log in methode)', 'password_format' => 'Ten minste 7 tekens', diff --git a/app/i18n/nl/feedback.php b/app/i18n/nl/feedback.php index 54d84f7d6..b703c43cf 100644 --- a/app/i18n/nl/feedback.php +++ b/app/i18n/nl/feedback.php @@ -21,7 +21,6 @@ return array( 'success' => 'U bent uitgelogd', ), 'no_password_set' => 'Administrateur wachtwoord is niet ingesteld. Deze mogelijkheid is niet beschikbaar.', - 'not_persona' => 'Alleen Persona systeem kan worden gereset.', ), 'conf' => array( 'error' => 'Er is een fout opgetreden tijdens het opslaan van de configuratie', diff --git a/app/i18n/nl/gen.php b/app/i18n/nl/gen.php index 24cba574e..7e03229c9 100644 --- a/app/i18n/nl/gen.php +++ b/app/i18n/nl/gen.php @@ -24,8 +24,6 @@ return array( 'email' => 'Email adres', 'keep_logged_in' => 'Ingelogd blijven voor (1 maand)', 'login' => 'Log in', - 'login_persona' => 'Login met Persona', - 'login_persona_problem' => 'Connectiviteits problemen met Persona', 'logout' => 'Log uit', 'password' => array( '_' => 'Wachtwoord', @@ -42,7 +40,6 @@ return array( 'admin' => 'Administrator gebruikersnaam', 'format' => 'maximaal 16 alphanumerieke tekens', ), - 'will_reset' => 'Het authenticatie system zal worden gereset: een formulier zal worden gebruikt in plaats van Persona.', ), 'date' => array( 'Apr' => '\\A\\p\\r\\i\\l', diff --git a/app/i18n/nl/install.php b/app/i18n/nl/install.php index d16dda4ca..77783cd48 100644 --- a/app/i18n/nl/install.php +++ b/app/i18n/nl/install.php @@ -9,13 +9,11 @@ return array( 'reinstall' => 'Installeer FreshRSS opnieuw', ), 'auth' => array( - 'email_persona' => 'Log in mail adres
(voor Mozilla Persona)', 'form' => 'Web formulier (traditioneel, benodigd JavaScript)', 'http' => 'HTTP (voor geavanceerde gebruikers met HTTPS)', 'none' => 'Geen (gevaarlijk)', 'password_form' => 'Wachtwoord
(voor de Web-formulier log in methode)', 'password_format' => 'Tenminste 7 tekens', - 'persona' => 'Mozilla Persona (modern, benodigd JavaScript)', 'type' => 'Authenticatie methode', ), 'bdd' => array( @@ -78,10 +76,6 @@ return array( 'nok' => 'U mist PDO of één van de ondersteunde (pdo_mysql, pdo_sqlite).', 'ok' => 'U hebt PDO en ten minste één van de ondersteunde drivers (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Controleer permissies van de ./data/persona map. HTTP server moet rechten hebben om er in te kunnen schrijven', - 'ok' => 'Permissies van de Mozilla Persona map zijn goed.', - ), 'php' => array( 'nok' => 'Uw PHP versie is %s maar FreshRSS benodigd tenminste versie %s.', 'ok' => 'Uw PHP versie is %s, welke compatibel is met FreshRSS.', diff --git a/app/i18n/ru/admin.php b/app/i18n/ru/admin.php index dfea5b3cb..caea627f3 100644 --- a/app/i18n/ru/admin.php +++ b/app/i18n/ru/admin.php @@ -8,7 +8,6 @@ return array( 'form' => 'На основе веб-формы (традиционный, необходим JavaScript)', 'http' => 'HTTP (для продвинутых пользователей - по HTTPS)', 'none' => 'Без аутентификации (небезопасный)', - 'persona' => 'Mozilla Persona (новый, необходим JavaScript)', 'title' => 'Аутентификации', 'title_reset' => 'Сброс аутентицикации', 'token' => 'Токен аутентификации', @@ -75,10 +74,6 @@ return array( 'nok' => 'У вас не установлен PDO или один из необходимых драйверов (pdo_mysql, pdo_sqlite).', 'ok' => 'У вас установлен PDO и как минимум один из поддерживаемых драйверов (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Проверьте права доступа к папке ./data/persona . Сервер HTTP должен иметь права на запись в эту папку.', - 'ok' => 'Права на папку Mozilla Persona в порядке.', - ), 'php' => array( '_' => 'PHP installation', 'nok' => 'У вас установлен PHP версии %s, но FreshRSS необходима версия не ниже %s.', @@ -169,7 +164,6 @@ return array( 'user' => array( 'articles_and_size' => '%s статей (%s)', 'create' => 'Создать нового пользователя', - 'email_persona' => 'Адрес электронной почты для входа
(for Mozilla Persona)', 'language' => 'Язык', 'number' => 'На данный момент создан %d аккаунт', 'numbers' => 'На данный момент аккаунтов создано: %d', diff --git a/app/i18n/ru/conf.php b/app/i18n/ru/conf.php index e502e9a43..557fbe369 100644 --- a/app/i18n/ru/conf.php +++ b/app/i18n/ru/conf.php @@ -76,7 +76,6 @@ return array( '_' => 'Account deletion', 'warn' => 'Your account and all the related data will be deleted.', ), - 'email_persona' => 'Login email address
(for Mozilla Persona)', 'password_api' => 'Password API
(e.g., for mobile apps)', 'password_form' => 'Password
(for the Web-form login method)', 'password_format' => 'At least 7 characters', diff --git a/app/i18n/ru/feedback.php b/app/i18n/ru/feedback.php index c9189c0d0..7ce2ae9cf 100644 --- a/app/i18n/ru/feedback.php +++ b/app/i18n/ru/feedback.php @@ -21,7 +21,6 @@ return array( 'success' => 'You are disconnected', ), 'no_password_set' => 'Administrator password hasn’t been set. This feature isn’t available.', - 'not_persona' => 'Only Persona system can be reset.', ), 'conf' => array( 'error' => 'An error occurred during configuration saving', diff --git a/app/i18n/ru/gen.php b/app/i18n/ru/gen.php index b8e8511d9..eecd72749 100644 --- a/app/i18n/ru/gen.php +++ b/app/i18n/ru/gen.php @@ -24,8 +24,6 @@ return array( 'email' => 'Email address', 'keep_logged_in' => 'Keep me logged in (1 month)', 'login' => 'Login', - 'login_persona' => 'Login with Persona', - 'login_persona_problem' => 'Connection problem with Persona?', 'logout' => 'Logout', 'password' => array( '_' => 'Password', @@ -42,7 +40,6 @@ return array( 'admin' => 'Administrator username', 'format' => 'maximum 16 alphanumeric characters', ), - 'will_reset' => 'Authentication system will be reset: a form will be used instead of Persona.', ), 'date' => array( 'Apr' => '\\A\\p\\r\\i\\l', diff --git a/app/i18n/ru/install.php b/app/i18n/ru/install.php index c838b2eba..a52e2959b 100644 --- a/app/i18n/ru/install.php +++ b/app/i18n/ru/install.php @@ -9,13 +9,11 @@ return array( 'reinstall' => 'Переустановить FreshRSS', ), 'auth' => array( - 'email_persona' => 'Почта (логин) для
(for Mozilla Persona)', 'form' => 'Вэб-форма (традиционный, необходим JavaScript)', 'http' => 'HTTP (для продвинутых пользователей с HTTPS)', 'none' => 'Никакого (опасно)', 'password_form' => 'Пароль
(для метода аутентификации на Вэб-формах)', 'password_format' => 'Как минимум 7 букв', - 'persona' => 'Mozilla Persona (современный, необходим JavaScript)', 'type' => 'Метод аутентификации', ), 'bdd' => array( @@ -74,10 +72,6 @@ return array( 'nok' => 'У вас не установлен PDO или один из необходимых драйверов (pdo_mysql, pdo_sqlite).', 'ok' => 'У вас установлен PDO и как минимум один из поддерживаемых драйверов (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => 'Проверьте права доступа к папке ./data/persona . Сервер HTTP должен иметь права на запись в эту папку.', - 'ok' => 'Права на папку Mozilla Persona в порядке.', - ), 'php' => array( 'nok' => 'У вас установлен PHP версии %s, но FreshRSS необходима версия не ниже %s.', 'ok' => 'У вас установлен PHP версии %s, который совместим с FreshRSS.', diff --git a/app/i18n/tr/admin.php b/app/i18n/tr/admin.php index 3a6f8118e..43f8e23c5 100644 --- a/app/i18n/tr/admin.php +++ b/app/i18n/tr/admin.php @@ -8,7 +8,6 @@ return array( 'form' => 'Web formu (geleneksel, JavaScript gerektirir)', 'http' => 'HTTP (ileri kullanıcılar için, HTTPS)', 'none' => 'Hiçbiri (tehlikeli)', - 'persona' => 'Mozilla Persona (modern, JavaScript gerektirir)', 'title' => 'Kimlik doğrulama', 'title_reset' => 'Kimlik doğrulama sıfırla', 'token' => 'Kimlik doğrulama işareti', @@ -75,10 +74,6 @@ return array( 'nok' => 'PDO veya PDO destekli bir sürücü eksik (pdo_mysql, pdo_sqlite).', 'ok' => 'PDO sorunsuz (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => './data/persona klasör yetkisini kontrol edin. HTTP yazma yetkisi olmalı', - 'ok' => 'Mozilla Persona klasörü yetkileri sorunsuz.', - ), 'php' => array( '_' => 'PHP kurulumu', 'nok' => 'PHP versiyonunuz %s fakat FreshRSS için gerekli olan en düşük sürüm %s.', @@ -169,7 +164,6 @@ return array( 'user' => array( 'articles_and_size' => '%s makale (%s)', 'create' => 'Yeni kullanıcı oluştur', - 'email_persona' => 'Giriş email adresi
(Mozilla Persona için)', 'language' => 'Dil', 'number' => 'Oluşturulmuş %d hesap var', 'numbers' => 'Oluşturulmuş %d hesap var', diff --git a/app/i18n/tr/conf.php b/app/i18n/tr/conf.php index d9e275b21..2fdc248e4 100644 --- a/app/i18n/tr/conf.php +++ b/app/i18n/tr/conf.php @@ -76,7 +76,6 @@ return array( '_' => 'Hesap silme', 'warn' => 'Hesabınız ve tüm verileriniz silinecek.', ), - 'email_persona' => 'Giriş email adresi
(Mozilla Persona için)', 'password_api' => 'API Şifresi
(ör. mobil uygulamalar için)', 'password_form' => 'Şifre
(Tarayıcı girişi için)', 'password_format' => 'En az 7 karakter', diff --git a/app/i18n/tr/feedback.php b/app/i18n/tr/feedback.php index 0572c6da1..a53316206 100644 --- a/app/i18n/tr/feedback.php +++ b/app/i18n/tr/feedback.php @@ -21,7 +21,6 @@ return array( 'success' => 'Bağlantı koptu', ), 'no_password_set' => 'Yönetici şifresi ayarlanmadı. Bu özellik kullanıma uygun değil.', - 'not_persona' => 'Sadece Persona sistem sıfırlanabilir.', ), 'conf' => array( 'error' => 'Yapılandırma ayarları kaydedilirken hata oluştu', diff --git a/app/i18n/tr/gen.php b/app/i18n/tr/gen.php index 492e2cb9b..865dbd4e2 100644 --- a/app/i18n/tr/gen.php +++ b/app/i18n/tr/gen.php @@ -24,8 +24,6 @@ return array( 'email' => 'Email adresleri', 'keep_logged_in' => '(1 ay) oturumu açık tut', 'login' => 'Giriş', - 'login_persona' => 'Persona ile giriş yap', - 'login_persona_problem' => 'Persona ile bağlantı sorununuz mu var ?', 'logout' => 'Çıkış', 'password' => array( '_' => 'Şifre', @@ -42,7 +40,6 @@ return array( 'admin' => 'Yönetici kullanıcı adı', 'format' => 'en fazla 16 alfanümerik karakter', ), - 'will_reset' => 'Kimlik doğrulama sistemi sıfırlanacak: Persone yerine bir form kullanılacak.', ), 'date' => array( 'Apr' => '\\N\\i\\s\\a\\n', diff --git a/app/i18n/tr/install.php b/app/i18n/tr/install.php index 85134845b..951a7c5fd 100644 --- a/app/i18n/tr/install.php +++ b/app/i18n/tr/install.php @@ -9,13 +9,11 @@ return array( 'reinstall' => 'FreshRSS i yeniden yükle', ), 'auth' => array( - 'email_persona' => 'Giriş email adresi
(Mozilla Persona için)', 'form' => 'Web formu (geleneksel, JavaScript gerektirir)', 'http' => 'HTTP (ileri kullanıcılar için, HTTPS)', 'none' => 'Hiçbiri (tehlikeli)', 'password_form' => 'Şifre
(Tarayıcı girişi için)', 'password_format' => 'En az 7 karakter', - 'persona' => 'Mozilla Persona (modern, JavaScript gerektirir)', 'type' => 'Kimlik doğrulama yöntemi', ), 'bdd' => array( @@ -78,10 +76,6 @@ return array( 'nok' => 'PDO veya PDO destekli bir sürücü eksik (pdo_mysql, pdo_sqlite).', 'ok' => 'PDO sorunsuz (pdo_mysql, pdo_sqlite).', ), - 'persona' => array( - 'nok' => './data/persona klasör yetkisini kontrol edin. HTTP yazma yetkisi olmalı', - 'ok' => 'Mozilla Persona klasörü yetkileri sorunsuz.', - ), 'php' => array( 'nok' => 'PHP versiyonunuz %s fakat FreshRSS için gerekli olan en düşük sürüm %s.', 'ok' => 'PHP versiyonunuz %s, FreshRSS ile tam uyumlu.', diff --git a/app/install.php b/app/install.php index 062f66814..e73bc9972 100644 --- a/app/install.php +++ b/app/install.php @@ -103,7 +103,6 @@ function saveStep1() { $_SESSION['title'] = $system_conf->title; $_SESSION['auth_type'] = $system_conf->auth_type; $_SESSION['old_entries'] = $user_conf->old_entries; - $_SESSION['mail_login'] = $user_conf->mail_login; $_SESSION['default_user'] = $current_user; $_SESSION['passwordHash'] = $user_conf->passwordHash; @@ -128,7 +127,6 @@ function saveStep2() { $_SESSION['old_entries'] = param('old_entries', $user_default_config->old_entries); $_SESSION['auth_type'] = param('auth_type', 'form'); $_SESSION['default_user'] = substr(preg_replace('/[^a-zA-Z0-9]/', '', param('default_user', '')), 0, 16); - $_SESSION['mail_login'] = filter_var(param('mail_login', ''), FILTER_VALIDATE_EMAIL); $password_plain = param('passwordPlain', false); if ($password_plain !== false && cryptAvailable()) { @@ -146,8 +144,7 @@ function saveStep2() { return false; } - if (($_SESSION['auth_type'] === 'form' && empty($_SESSION['passwordHash'])) || - ($_SESSION['auth_type'] === 'persona' && empty($_SESSION['mail_login']))) { + if ($_SESSION['auth_type'] === 'form' && empty($_SESSION['passwordHash'])) { return false; } @@ -157,15 +154,11 @@ function saveStep2() { } $token = ''; - if ($_SESSION['mail_login']) { - $token = sha1($_SESSION['salt'] . $_SESSION['mail_login']); - } $config_array = array( 'language' => $_SESSION['language'], 'theme' => $user_default_config->theme, 'old_entries' => $_SESSION['old_entries'], - 'mail_login' => $_SESSION['mail_login'], 'passwordHash' => $_SESSION['passwordHash'], 'token' => $token, ); @@ -179,12 +172,6 @@ function saveStep2() { mkdir($user_dir); file_put_contents($user_config_path, " $cache ? 'ok' : 'ko', 'users' => $users ? 'ok' : 'ko', 'favicons' => $favicons ? 'ok' : 'ko', - 'persona' => $persona ? 'ok' : 'ko', 'http_referer' => $http_referer ? 'ok' : 'ko', 'all' => $php && $minz && $curl && $pdo && $pcre && $ctype && $dom && $xml && - $data && $cache && $users && $favicons && $persona && $http_referer ? + $data && $cache && $users && $favicons && $http_referer ? 'ok' : 'ko' ); } @@ -380,7 +365,6 @@ function freshrss_already_installed() { function checkStep2() { $conf = !empty($_SESSION['old_entries']) && - isset($_SESSION['mail_login']) && !empty($_SESSION['default_user']); $form = ( @@ -388,11 +372,6 @@ function checkStep2() { ($_SESSION['auth_type'] != 'form' || !empty($_SESSION['passwordHash'])) ); - $persona = ( - isset($_SESSION['auth_type']) && - ($_SESSION['auth_type'] != 'persona' || !empty($_SESSION['mail_login'])) - ); - $defaultUser = empty($_POST['default_user']) ? null : $_POST['default_user']; if ($defaultUser === null) { $defaultUser = empty($_SESSION['default_user']) ? '' : $_SESSION['default_user']; @@ -402,9 +381,8 @@ function checkStep2() { return array( 'conf' => $conf ? 'ok' : 'ko', 'form' => $form ? 'ok' : 'ko', - 'persona' => $persona ? 'ok' : 'ko', 'data' => $data ? 'ok' : 'ko', - 'all' => $conf && $form && $persona && $data ? 'ok' : 'ko' + 'all' => $conf && $form && $data ? 'ok' : 'ko' ); } @@ -612,12 +590,6 @@ function printStep1() {

- -

- -

- -

@@ -673,12 +645,11 @@ function printStep2() { @@ -697,14 +668,6 @@ function printStep2() { -
- -
- tabindex="6"/> - -
-
-
diff --git a/app/views/auth/index.phtml b/app/views/auth/index.phtml index 8e4df8c2c..8f81ac856 100644 --- a/app/views/auth/index.phtml +++ b/app/views/auth/index.phtml @@ -10,11 +10,10 @@
diff --git a/app/views/auth/personaLogin.phtml b/app/views/auth/personaLogin.phtml deleted file mode 100644 index c6d738bf6..000000000 --- a/app/views/auth/personaLogin.phtml +++ /dev/null @@ -1,28 +0,0 @@ -res === false) { ?> -
-

- - - - - -

- - -

- - - - - -

- -

-
-res); -} -?> diff --git a/app/views/auth/register.phtml b/app/views/auth/register.phtml index 306679601..0c261319a 100644 --- a/app/views/auth/register.phtml +++ b/app/views/auth/register.phtml @@ -16,11 +16,6 @@
-
- - -
-
-

- - message)) { ?> -

- message['title']; ?>
- message['body']; ?> -

- - - no_form) { ?> -
-

-
- -

- -
- - -
-
- - -
- -
-
- -
-
- -
diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 6178cacf2..1aa43a207 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -1,6 +1,5 @@ mark_when; -$mail = Minz_Session::param('mail', false); $s = FreshRSS_Context::$user_conf->shortcuts; echo htmlspecialchars(json_encode(array( 'context' => array( @@ -16,7 +15,6 @@ echo htmlspecialchars(json_encode(array( 'sticky_post' => !!FreshRSS_Context::isStickyPostEnabled(), 'html5_notif_timeout' => FreshRSS_Context::$user_conf->html5_notif_timeout, 'auth_type' => FreshRSS_Context::$system_conf->auth_type, - 'current_user_mail' => $mail ? ('"' . $mail . '"') : null, 'current_view' => Minz_Request::actionName(), ), 'shortcuts' => array( diff --git a/app/views/user/manage.phtml b/app/views/user/manage.phtml index fe1b6618b..e48841d9b 100644 --- a/app/views/user/manage.phtml +++ b/app/views/user/manage.phtml @@ -37,14 +37,6 @@
-
- - mail_login; ?> -
- -
-
-
diff --git a/app/views/user/profile.phtml b/app/views/user/profile.phtml index 7ae2c7ede..e96b5aa32 100644 --- a/app/views/user/profile.phtml +++ b/app/views/user/profile.phtml @@ -41,15 +41,6 @@
-
- - mail_login; ?> -
- placeholder="alice@example.net" /> - -
-
-
diff --git a/data/config.default.php b/data/config.default.php index cae15330f..be3fa8ae2 100644 --- a/data/config.default.php +++ b/data/config.default.php @@ -40,7 +40,6 @@ return array( # Login method: # `none` is without password and shows only the default user; # `form` is a conventional Web login form; - # `persona` is the email-based login by Mozilla; # `http_auth` is an access controled by the HTTP Web server (e.g. `/FreshRSS/p/i/.htaccess` for Apache) # if you use `http_auth`, remember to protect only `/FreshRSS/p/i/`, # and in particular not protect `/FreshRSS/p/api/` if you would like to use the API (different login system). diff --git a/data/users/_/config.default.php b/data/users/_/config.default.php index 8f8ff528c..4a3403453 100644 --- a/data/users/_/config.default.php +++ b/data/users/_/config.default.php @@ -5,7 +5,6 @@ return array ( 'old_entries' => 3, 'keep_history_default' => 0, 'ttl_default' => 3600, - 'mail_login' => '', 'token' => '', 'passwordHash' => '', 'apiPasswordHash' => '', diff --git a/lib/lib_rss.php b/lib/lib_rss.php index f89baf9b1..8196f7847 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -440,7 +440,6 @@ function check_install_files() { 'cache' => CACHE_PATH && is_writable(CACHE_PATH), 'users' => USERS_PATH && is_writable(USERS_PATH), 'favicons' => is_writable(DATA_PATH . '/favicons'), - 'persona' => is_writable(DATA_PATH . '/persona'), 'tokens' => is_writable(DATA_PATH . '/tokens'), ); } diff --git a/p/scripts/install.js b/p/scripts/install.js index 9a49e6031..57fc2450a 100644 --- a/p/scripts/install.js +++ b/p/scripts/install.js @@ -24,18 +24,12 @@ function auth_type_change() { var auth_type = document.getElementById('auth_type'); if (auth_type) { var auth_value = auth_type.value, - password_input = document.getElementById('passwordPlain'), - mail_input = document.getElementById('mail_login'); + password_input = document.getElementById('passwordPlain'); if (auth_value === 'form') { password_input.required = true; - mail_input.required = false; - } else if (auth_value === 'persona') { - password_input.required = false; - mail_input.required = true; } else { password_input.required = false; - mail_input.required = false; } } } diff --git a/p/scripts/persona.js b/p/scripts/persona.js deleted file mode 100644 index 63ab43795..000000000 --- a/p/scripts/persona.js +++ /dev/null @@ -1,76 +0,0 @@ -"use strict"; - -function init_persona() { - if (!(navigator.id && window.$ && window.url)) { - if (window.console) { - console.log('FreshRSS (Persona) waiting for JS…'); - } - window.setTimeout(init_persona, 100); - return; - } - - $('a.signin').click(function() { - navigator.id.request(); - return false; - }); - - $('a.signout').click(function() { - navigator.id.logout(); - return false; - }); - - navigator.id.watch({ - loggedInUser: context['current_user_mail'], - - onlogin: function(assertion) { - // A user has logged in! Here you need to: - // 1. Send the assertion to your backend for verification and to create a session. - // 2. Update your UI. - $.ajax ({ - type: 'POST', - url: url['login'], - data: {assertion: assertion}, - success: function(res, status, xhr) { - if (res.status === 'failure') { - openNotification(res.reason, 'bad'); - } else if (res.status === 'okay') { - location.href = url['index']; - } - }, - error: function(res, status, xhr) { - // alert(res); - } - }); - }, - onlogout: function() { - // A user has logged out! Here you need to: - // Tear down the user's session by redirecting the user or making a call to your backend. - // Also, make sure loggedInUser will get set to null on the next page load. - // (That's a literal JavaScript null. Not false, 0, or undefined. null.) - $.ajax ({ - type: 'POST', - url: url['logout'], - success: function(res, status, xhr) { - location.href = url['index']; - }, - error: function(res, status, xhr) { - // alert(res); - } - }); - } - }); -} - -if (document.readyState && document.readyState !== 'loading') { - if (window.console) { - console.log('FreshRSS (Persona) immediate init…'); - } - init_persona(); -} else if (document.addEventListener) { - document.addEventListener('DOMContentLoaded', function () { - if (window.console) { - console.log('FreshRSS (Persona) waiting for DOMContentLoaded…'); - } - init_persona(); - }, false); -} -- cgit v1.2.3 From b382f266de0369352344324f88bc5d3dc136119d Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 2 Aug 2016 00:29:31 +0200 Subject: Fix bug articles not marked as read https://github.com/FreshRSS/FreshRSS/issues/1123 https://github.com/FreshRSS/FreshRSS/issues/423 --- p/scripts/main.js | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) (limited to 'p') diff --git a/p/scripts/main.js b/p/scripts/main.js index f1b82900e..c6e108ca1 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -113,7 +113,7 @@ function incUnreadsFeed(article, feed_id, nb) { return isCurrentView; } -var pending_feeds = []; +var pending_entries = {}; function mark_read(active, only_not_read) { if (active.length === 0 || (only_not_read === true && !active.hasClass("not_read"))) { @@ -126,14 +126,12 @@ function mark_read(active, only_not_read) { } var feed_url = active.find(".website>a").attr("href"), - feed_id = feed_url.substr(feed_url.lastIndexOf('f_')), - index_pending = pending_feeds.indexOf(feed_id); + feed_id = feed_url.substr(feed_url.lastIndexOf('f_')); - if (index_pending !== -1) { + if (pending_entries[active.attr('id')]) { return false; } - - pending_feeds.push(feed_id); + pending_entries[active.attr('id')] = true; $.ajax({ type: 'POST', @@ -154,10 +152,10 @@ function mark_read(active, only_not_read) { incUnreadsFeed(active, feed_id, inc); faviconNbUnread(); - pending_feeds.splice(index_pending, 1); + delete pending_entries[active.attr('id')]; }).fail(function (data) { openNotification(i18n.notif_request_failed, 'bad'); - pending_feeds.splice(index_pending, 1); + delete pending_entries[active.attr('id')]; }); } @@ -172,14 +170,12 @@ function mark_favorite(active) { } var feed_url = active.find(".website>a").attr("href"), - feed_id = feed_url.substr(feed_url.lastIndexOf('f_')), - index_pending = pending_feeds.indexOf(feed_id); + feed_id = feed_url.substr(feed_url.lastIndexOf('f_')); - if (index_pending !== -1) { + if (pending_entries[active.attr('id')]) { return false; } - - pending_feeds.push(feed_id); + pending_entries[active.attr('id')] = true; $.ajax({ type: 'POST', @@ -212,10 +208,10 @@ function mark_favorite(active) { } } - pending_feeds.splice(index_pending, 1); + delete pending_entries[active.attr('id')]; }).fail(function (data) { openNotification(i18n.notif_request_failed, 'bad'); - pending_feeds.splice(index_pending, 1); + delete pending_entries[active.attr('id')]; }); } -- cgit v1.2.3 From 75d2fa3fd325f98a98304e7b1e1bdb56bf0f2af7 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 2 Aug 2016 00:30:11 +0200 Subject: JS load optimization Start loading what we can already before DOM is ready --- p/scripts/main.js | 49 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 15 deletions(-) (limited to 'p') diff --git a/p/scripts/main.js b/p/scripts/main.js index c6e108ca1..69d0e33da 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1294,27 +1294,46 @@ function parseJsonVars() { window.icons = json.icons; } -function init_all() { +function init_beforeDOM() { if (!window.$) { if (window.console) { - console.log('FreshRSS waiting for JS…'); + console.log('FreshRSS waiting for jQuery…'); } - window.setTimeout(init_all, 50); + window.setTimeout(init_beforeDOM, 50); return; } - parseJsonVars(); - init_notifications(); init_confirm_action(); + if (['normal', 'reader', 'global'].indexOf(context['current_view']) >= 0) { + $stream = $('#stream'); + if ($stream.length < 1) { + if (window.console) { + console.log('FreshRSS waiting for content…'); + } + window.setTimeout(init_beforeDOM, 50); + return; + } + init_column_categories(); + init_stream($stream); + init_shortcuts(); + init_actualize(); + faviconNbUnread(); + } +} + +function init_afterDOM() { + if (!window.$) { + if (window.console) { + console.log('FreshRSS waiting again for jQuery…'); + } + window.setTimeout(init_afterDOM, 50); + return; + } + init_notifications(); $stream = $('#stream'); if ($stream.length > 0) { - init_actualize(); - init_column_categories(); init_load_more($stream); init_posts(); - init_stream($stream); init_nav_entries(); - init_shortcuts(); - faviconNbUnread(); init_print_action(); init_notifs_html5(); window.setInterval(refreshUnreads, 120000); @@ -1335,16 +1354,16 @@ function init_all() { } } +parseJsonVars(); +init_beforeDOM(); //Can be called before DOM is fully loaded + if (document.readyState && document.readyState !== 'loading') { - if (window.console) { - console.log('FreshRSS immediate init…'); - } - init_all(); + init_afterDOM(); } else if (document.addEventListener) { document.addEventListener('DOMContentLoaded', function () { if (window.console) { console.log('FreshRSS waiting for DOMContentLoaded…'); } - init_all(); + init_afterDOM(); }, false); } -- cgit v1.2.3 From 32b6ecc3afdc0cac3345ff89ee42f88c95c1775a Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 2 Aug 2016 00:42:07 +0200 Subject: JS unused variables, syntax --- p/scripts/main.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'p') diff --git a/p/scripts/main.js b/p/scripts/main.js index 69d0e33da..01c8c9cf5 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -125,9 +125,6 @@ function mark_read(active, only_not_read) { return false; } - var feed_url = active.find(".website>a").attr("href"), - feed_id = feed_url.substr(feed_url.lastIndexOf('f_')); - if (pending_entries[active.attr('id')]) { return false; } @@ -149,6 +146,9 @@ function mark_read(active, only_not_read) { } $r.find('.icon').replaceWith(data.icon); + var feed_url = active.find(".website>a").attr("href"), + feed_id = feed_url.substr(feed_url.lastIndexOf('f_')); + incUnreadsFeed(active, feed_id, inc); faviconNbUnread(); @@ -169,9 +169,6 @@ function mark_favorite(active) { return false; } - var feed_url = active.find(".website>a").attr("href"), - feed_id = feed_url.substr(feed_url.lastIndexOf('f_')); - if (pending_entries[active.attr('id')]) { return false; } @@ -901,7 +898,7 @@ function notifs_html5_show(nb) { notification.onclick = function() { window.location.reload(); - } + }; if (context['html5_notif_timeout'] !== 0) { setTimeout(function() { -- cgit v1.2.3 From 7c1b5e322cca0134f57b3a436129985ba9170b9f Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 2 Aug 2016 22:49:35 +0200 Subject: PostgreSQL draft https://github.com/FreshRSS/FreshRSS/issues/416 Based on @Damstre work https://github.com/FreshRSS/FreshRSS/pull/1071 Not tested --- app/Models/CategoryDAO.php | 7 +- app/Models/ConfigurationSetter.php | 1 + app/Models/EntryDAO.php | 2 +- app/Models/EntryDAOPGSQL.php | 92 ++++++++++++++++++ app/Models/Factory.php | 42 ++++---- app/Models/FeedDAO.php | 2 +- app/Models/StatsDAO.php | 8 +- app/Models/StatsDAOPGSQL.php | 192 +++++++++++++++++++++++++++++++++++++ app/SQL/install.sql.mysql.php | 2 + app/SQL/install.sql.pgsql.php | 91 ++++++++++++++++++ app/install.php | 31 +++++- lib/Minz/ModelPdo.php | 77 +++++++++------ p/scripts/install.js | 6 +- 13 files changed, 495 insertions(+), 58 deletions(-) create mode 100644 app/Models/EntryDAOPGSQL.php create mode 100644 app/Models/StatsDAOPGSQL.php create mode 100644 app/SQL/install.sql.pgsql.php (limited to 'p') diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index fc431553e..a44edb0f6 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -10,7 +10,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable ); if ($stm && $stm->execute($values)) { - return $this->bd->lastInsertId(); + return $this->bd->lastInsertId('"' . parent::prefix . 'category_id_seq"'); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); Minz_Log::error('SQL error addCategory: ' . $info[2]); @@ -207,12 +207,13 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable $previousLine = null; $feedsDao = array(); + $feedDao = FreshRSS_Factory::createFeedDAO(); foreach ($listDAO as $line) { if ($previousLine['c_id'] != null && $line['c_id'] !== $previousLine['c_id']) { // End of the current category, we add it to the $list $cat = new FreshRSS_Category( $previousLine['c_name'], - FreshRSS_FeedDAO::daoToFeed($feedsDao, $previousLine['c_id']) + $feedDao->daoToFeed($feedsDao, $previousLine['c_id']) ); $cat->_id($previousLine['c_id']); $list[$previousLine['c_id']] = $cat; @@ -228,7 +229,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable if ($previousLine != null) { $cat = new FreshRSS_Category( $previousLine['c_name'], - FreshRSS_FeedDAO::daoToFeed($feedsDao, $previousLine['c_id']) + $feedDao->daoToFeed($feedsDao, $previousLine['c_id']) ); $cat->_id($previousLine['c_id']); $list[$previousLine['c_id']] = $cat; diff --git a/app/Models/ConfigurationSetter.php b/app/Models/ConfigurationSetter.php index e472b1e7f..988e83356 100644 --- a/app/Models/ConfigurationSetter.php +++ b/app/Models/ConfigurationSetter.php @@ -287,6 +287,7 @@ class FreshRSS_ConfigurationSetter { switch ($value['type']) { case 'mysql': + case 'pgsql': if (empty($value['host']) || empty($value['user']) || empty($value['base']) || diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index c9e6f9742..ba52d3f15 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -3,7 +3,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { public function isCompressed() { - return parent::$sharedDbType !== 'sqlite'; + return parent::$sharedDbType === 'mysql'; } public function hasNativeHex() { diff --git a/app/Models/EntryDAOPGSQL.php b/app/Models/EntryDAOPGSQL.php new file mode 100644 index 000000000..95c12ff5d --- /dev/null +++ b/app/Models/EntryDAOPGSQL.php @@ -0,0 +1,92 @@ +bd->beginTransaction(); + + $sql = 'UPDATE "' . $this->prefix . 'entry" ' + . 'SET is_read=:is_read ' + . 'WHERE id_feed=:id_feed AND NOT is_read AND id <= :idmax'; + $values = array($id_feed, $idMax); + $stm = $this->bd->prepare($sql); + $stm->bindValue(':is_read', true, PDO::PARAM_BOOL); + $stm->bindValue(':id_feed', $id_feed); + $stm->bindValue(':idmax', $idMax); + + if (!($stm && $stm->execute())) { + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::error('SQL error markReadFeed: ' . $info[2]); + $this->bd->rollBack(); + return false; + } + $affected = $stm->rowCount(); + + $this->bd->commit(); + return $affected; + } + + public function listHashForFeedGuids($id_feed, $guids) { + if (count($guids) < 1) { + return array(); + } + $sql = 'SELECT guid, hash AS hexHash FROM "' . $this->prefix . 'entry" WHERE id_feed=? AND guid IN (' . str_repeat('?,', count($guids) - 1). '?)'; + $stm = $this->bd->prepare($sql); + $values = array($id_feed); + $values = array_merge($values, $guids); + if ($stm && $stm->execute($values)) { + $result = array(); + $rows = $stm->fetchAll(PDO::FETCH_ASSOC); + foreach ($rows as $row) { + $result[$row['guid']] = $row['hexHash']; + } + return $result; + } else { + $info = $stm == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $stm->errorInfo(); + if ($this->autoAddColumn($info)) { + return $this->listHashForFeedGuids($id_feed, $guids); + } + Minz_Log::error('SQL error listHashForFeedGuids: ' . $info[0] . ': ' . $info[1] . ' ' . $info[2] + . ' while querying feed ' . $id_feed); + return false; + } + } + + public function optimizeTable() { + return null; + } + + public function size($all = true) { + $db = FreshRSS_Context::$system_conf->db; + $sql = 'SELECT pg_size_pretty(pg_database_size(?))'; + $values = array($db['base']); + $stm = $this->bd->prepare($sql); + $stm->execute($values); + $res = $stm->fetchAll(PDO::FETCH_COLUMN, 0); + return $res[0]; + } + +} diff --git a/app/Models/Factory.php b/app/Models/Factory.php index db09d155d..764987c46 100644 --- a/app/Models/Factory.php +++ b/app/Models/Factory.php @@ -4,37 +4,47 @@ class FreshRSS_Factory { public static function createFeedDao($username = null) { $conf = Minz_Configuration::get('system'); - if ($conf->db['type'] === 'sqlite') { - return new FreshRSS_FeedDAOSQLite($username); - } else { - return new FreshRSS_FeedDAO($username); + switch ($conf->db['type']) { + case 'sqlite': + return new FreshRSS_FeedDAOSQLite($username); + default: + return new FreshRSS_FeedDAO($username); } } public static function createEntryDao($username = null) { $conf = Minz_Configuration::get('system'); - if ($conf->db['type'] === 'sqlite') { - return new FreshRSS_EntryDAOSQLite($username); - } else { - return new FreshRSS_EntryDAO($username); + switch ($conf->db['type']) { + case 'sqlite': + return new FreshRSS_EntryDAOSQLite($username); + case 'pgsql': + return new FreshRSS_EntryDAOPGSQL($username); + default: + return new FreshRSS_EntryDAO($username); } } public static function createStatsDAO($username = null) { $conf = Minz_Configuration::get('system'); - if ($conf->db['type'] === 'sqlite') { - return new FreshRSS_StatsDAOSQLite($username); - } else { - return new FreshRSS_StatsDAO($username); + switch ($conf->db['type']) { + case 'sqlite': + return new FreshRSS_StatsDAOSQLite($username); + case 'pgsql': + return new FreshRSS_StatsDAOPGSQL($username); + default: + return new FreshRSS_StatsDAO($username); } } public static function createDatabaseDAO($username = null) { $conf = Minz_Configuration::get('system'); - if ($conf->db['type'] === 'sqlite') { - return new FreshRSS_DatabaseDAOSQLite($username); - } else { - return new FreshRSS_DatabaseDAO($username); + switch ($conf->db['type']) { + case 'sqlite': + return new FreshRSS_DatabaseDAOSQLite($username); + case 'pgsql': + return new FreshRSS_DatabaseDAOPGSQL($username); + default: + return new FreshRSS_DatabaseDAO($username); } } diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index 475d39286..f29dac9c0 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -16,7 +16,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { ); if ($stm && $stm->execute($values)) { - return $this->bd->lastInsertId(); + return $this->bd->lastInsertId('"' . parent::prefix . 'feed_id_seq"'); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); Minz_Log::error('SQL error addFeed: ' . $info[2]); diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 5ca333396..e18ba4748 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -37,10 +37,10 @@ class FreshRSS_StatsDAO extends Minz_ModelPdo { $filter .= "AND e.id_feed = {$feed}"; } $sql = <<prefix}entry AS e , {$this->prefix}feed AS f WHERE e.id_feed = f.id diff --git a/app/Models/StatsDAOPGSQL.php b/app/Models/StatsDAOPGSQL.php new file mode 100644 index 000000000..0bde72e58 --- /dev/null +++ b/app/Models/StatsDAOPGSQL.php @@ -0,0 +1,192 @@ +prefix}entry" AS e +, "{$this->prefix}feed" AS f +WHERE e.id_feed = f.id +{$filter} +SQL; + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetchAll(PDO::FETCH_ASSOC); + + return $res[0]; + } + + /** + * Calculates entry count per day on a 30 days period. + * Returns the result as a JSON string. + * + * @return string + */ + public function calculateEntryCount() { + $count = $this->initEntryCountArray(); + $period = self::ENTRY_COUNT_PERIOD; + + // Get stats per day for the last 30 days + $sql = <<prefix}entry" AS e +WHERE to_timestamp(e.date) BETWEEN NOW() - INTERVAL '{$period} DAYS' AND NOW() - INTERVAL '1 DAY' +GROUP BY day +ORDER BY day ASC +SQL; + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetchAll(PDO::FETCH_ASSOC); + + foreach ($res as $value) { + $count[$value['day']] = (int) $value['count']; + } + + return $this->convertToSerie($count); + } + + /** + * Calculates entry average per day on a 30 days period. + * + * @return integer + */ + public function calculateEntryAverage() { + $period = self::ENTRY_COUNT_PERIOD; + + // Get stats per day for the last 30 days + $sql = <<prefix}entry" AS e +WHERE to_timestamp(e.date) BETWEEN NOW() - INTERVAL '{$period} DAYS' AND NOW() - INTERVAL '1 DAY' +SQL; + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetch(PDO::FETCH_NAMED); + + return round($res['average'], 2); + } + + /** + * Calculates the number of article per hour of the day per feed + * + * @param integer $feed id + * @return string + */ + public function calculateEntryRepartitionPerFeedPerHour($feed = null) { + return $this->calculateEntryRepartitionPerFeedPerPeriod('hour', $feed); + } + + /** + * Calculates the number of article per day of week per feed + * + * @param integer $feed id + * @return string + */ + public function calculateEntryRepartitionPerFeedPerDayOfWeek($feed = null) { + return $this->calculateEntryRepartitionPerFeedPerPeriod('day', $feed); + } + + /** + * Calculates the number of article per month per feed + * + * @param integer $feed + * @return string + */ + public function calculateEntryRepartitionPerFeedPerMonth($feed = null) { + return $this->calculateEntryRepartitionPerFeedPerPeriod('month', $feed); + } + + /** + * Calculates the number of article per period per feed + * + * @param string $period format string to use for grouping + * @param integer $feed id + * @return string + */ + protected function calculateEntryRepartitionPerFeedPerPeriod($period, $feed = null) { + $restrict = ''; + if ($feed) { + $restrict = "WHERE e.id_feed = {$feed}"; + } + $sql = <<prefix}entry" AS e +{$restrict} +GROUP BY period +ORDER BY period ASC +SQL; + + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetchAll(PDO::FETCH_NAMED); + + foreach ($res as $value) { + $repartition[(int) $value['period']] = (int) $value['count']; + } + + return $this->convertToSerie($repartition); + } + + /** + * Calculates the average number of article per feed + * + * @param float $period number used to divide the number of day in the period + * @param integer $feed id + * @return integer + */ + protected function calculateEntryAveragePerFeedPerPeriod($period, $feed = null) { + $restrict = ''; + if ($feed) { + $restrict = "WHERE e.id_feed = {$feed}"; + } + $sql = <<prefix}entry" AS e +{$restrict} +SQL; + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetch(PDO::FETCH_NAMED); + $date_min = new \DateTime(); + $date_min->setTimestamp($res['date_min']); + $date_max = new \DateTime(); + $date_max->setTimestamp($res['date_max']); + $interval = $date_max->diff($date_min, true); + $interval_in_days = $interval->format('%a'); + if ($interval_in_days <= 0) { + // Surely only one article. + // We will return count / (period/period) == count. + $interval_in_days = $period; + } + + return $res['count'] / ($interval_in_days / $period); + } + +} diff --git a/app/SQL/install.sql.mysql.php b/app/SQL/install.sql.mysql.php index c78839ef7..92a00aecc 100644 --- a/app/SQL/install.sql.mysql.php +++ b/app/SQL/install.sql.mysql.php @@ -1,4 +1,6 @@ $curl ? 'ok' : 'ko', 'pdo-mysql' => $pdo_mysql ? 'ok' : 'ko', 'pdo-sqlite' => $pdo_sqlite ? 'ok' : 'ko', + 'pdo-pgsql' => $pdo_pgsql ? 'ok' : 'ko', 'pdo' => $pdo ? 'ok' : 'ko', 'pcre' => $pcre ? 'ok' : 'ko', 'ctype' => $ctype ? 'ok' : 'ko', @@ -435,6 +438,22 @@ function checkBD() { PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, ); break; + case 'pgsql': + $driver_options = array( + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + ); + + try { // on ouvre une connexion juste pour créer la base si elle n'existe pas + $str = 'pgsql:host=' . $_SESSION['bd_host'] . ';'; + $c = new PDO($str, $_SESSION['bd_user'], $_SESSION['bd_password'], $driver_options); + $sql = sprintf(SQL_CREATE_DB, $_SESSION['bd_base']); + $res = $c->query($sql); + } catch (PDOException $e) { + } + + // on écrase la précédente connexion en sélectionnant la nouvelle BDD + $str = 'pgsql:host=' . $_SESSION['bd_host'] . ';dbname=' . $_SESSION['bd_base']; + break; default: return false; } @@ -708,6 +727,12 @@ function printStep3() { SQLite + + +
diff --git a/lib/Minz/ModelPdo.php b/lib/Minz/ModelPdo.php index 845aecaae..b98a26d06 100644 --- a/lib/Minz/ModelPdo.php +++ b/lib/Minz/ModelPdo.php @@ -55,36 +55,36 @@ class Minz_ModelPdo { $driver_options = isset($conf->db['pdo_options']) && is_array($conf->db['pdo_options']) ? $conf->db['pdo_options'] : array(); try { - $type = $db['type']; - if ($type === 'mysql') { - $string = 'mysql:host=' . $db['host'] - . ';dbname=' . $db['base'] - . ';charset=utf8mb4'; - $driver_options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES utf8mb4'; - $this->prefix = $db['prefix'] . $currentUser . '_'; - } elseif ($type === 'sqlite') { - $string = 'sqlite:' . join_path(DATA_PATH, 'users', $currentUser, 'db.sqlite'); - //$driver_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION; - $this->prefix = ''; - } else { - throw new Minz_PDOConnectionException( - 'Invalid database type!', - $db['user'], Minz_Exception::ERROR - ); - } - self::$sharedDbType = $type; - self::$sharedPrefix = $this->prefix; - - $this->bd = new MinzPDO( - $string, - $db['user'], - $db['password'], - $driver_options - ); - if ($type === 'sqlite') { - $this->bd->exec('PRAGMA foreign_keys = ON;'); + switch ($db['type']) { + case 'mysql': + $string = 'mysql:host=' . $db['host'] . ';dbname=' . $db['base'] . ';charset=utf8mb4'; + $driver_options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES utf8mb4'; + $this->prefix = $db['prefix'] . $currentUser . '_'; + $this->bd = new MinzPDO($string, $db['user'], $db['password'], $driver_options); + //TODO Consider: $this->bd->exec("SET SESSION sql_mode = 'ANSI_QUOTES';"); + break; + case 'sqlite': + $string = 'sqlite:' . join_path(DATA_PATH, 'users', $currentUser, 'db.sqlite'); + $this->prefix = ''; + $this->bd = new MinzPDO($string, $db['user'], $db['password'], $driver_options); + $this->bd->exec('PRAGMA foreign_keys = ON;'); + break; + case 'pgsql': + $string = 'pgsql:host=' . $db['host'] . ';dbname=' . $db['base'] . ';charset=utf8'; + $this->prefix = $db['prefix'] . $currentUser . '_'; + $this->bd = new MinzPDOPGSQL($string, $db['user'], $db['password'], $driver_options); + $this->bd->exec("SET NAMES 'UTF8';"); + break; + default: + throw new Minz_PDOConnectionException( + 'Invalid database type!', + $db['user'], Minz_Exception::ERROR + ); + break; } self::$sharedBd = $this->bd; + self::$sharedDbType = $db['type']; + self::$sharedPrefix = $this->prefix; } catch (Exception $e) { throw new Minz_PDOConnectionException( $string, @@ -119,18 +119,39 @@ class MinzPDO extends PDO { } } + protected function compatibility($statement) { + return $statement; + } + public function prepare($statement, $driver_options = array()) { MinzPDO::check($statement); + $statement = MinzPDO::compatibility($statement); return parent::prepare($statement, $driver_options); } public function exec($statement) { MinzPDO::check($statement); + $statement = MinzPDO::compatibility($statement); return parent::exec($statement); } public function query($statement) { MinzPDO::check($statement); + $statement = MinzPDO::compatibility($statement); return parent::query($statement); } + + public function lastInsertId($name = null) { + return parent::lastInsertId(); //We discard the name, only used by PostgreSQL + } +} + +class MinzPDOPGSQL extends MinzPDO { + protected function compatibility($statement) { + return str_replace(array('`', " X'"), array('"', " E'\\x"), $statement); + } + + public function lastInsertId($name = null) { + return parent::lastInsertId($name); + } } diff --git a/p/scripts/install.js b/p/scripts/install.js index 57fc2450a..3e1db57b5 100644 --- a/p/scripts/install.js +++ b/p/scripts/install.js @@ -42,13 +42,15 @@ if (auth_type) { function mySqlShowHide() { var mysql = document.getElementById('mysql'); if (mysql) { - mysql.style.display = document.getElementById('type').value === 'mysql' ? 'block' : 'none'; - if (document.getElementById('type').value !== 'mysql') { + if (document.getElementById('type').value === 'sqlite') { document.getElementById('host').value = ''; document.getElementById('user').value = ''; document.getElementById('pass').value = ''; document.getElementById('base').value = ''; document.getElementById('prefix').value = ''; + mysql.style.display = 'none'; + } else { + mysql.style.display = 'block'; } } } -- cgit v1.2.3 From 3652dea854200f31492a71243727f6a1be317c4a Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 6 Aug 2016 13:18:46 +0200 Subject: JSHint and safer async init_normal --- p/scripts/category.js | 4 +- p/scripts/global_view.js | 3 + p/scripts/install.js | 1 + p/scripts/main.js | 140 +++++++++++++++++++++++++---------------------- p/scripts/repartition.js | 18 +++--- p/scripts/stats.js | 3 + 6 files changed, 93 insertions(+), 76 deletions(-) (limited to 'p') diff --git a/p/scripts/category.js b/p/scripts/category.js index c33e68528..be9605bec 100644 --- a/p/scripts/category.js +++ b/p/scripts/category.js @@ -1,4 +1,6 @@ "use strict"; +/* globals i18n */ +/* jshint globalstrict: true */ var loading = false, dnd_successful = false; @@ -20,7 +22,7 @@ function dragend_process(t) { $(t).remove(); if (parent.children().length <= 0) { - parent.append('
  • ' + i18n['category_empty'] + '
  • '); + parent.append('
  • ' + i18n.category_empty + '
  • '); } } } diff --git a/p/scripts/global_view.js b/p/scripts/global_view.js index 7d7ba22b5..f1b9c8ad4 100644 --- a/p/scripts/global_view.js +++ b/p/scripts/global_view.js @@ -1,4 +1,7 @@ "use strict"; +/* globals init_load_more, init_posts, init_stream */ +/* jshint globalstrict: true */ + var panel_loading = false; function load_panel(link) { diff --git a/p/scripts/install.js b/p/scripts/install.js index 57fc2450a..d7f4e7b02 100644 --- a/p/scripts/install.js +++ b/p/scripts/install.js @@ -1,4 +1,5 @@ "use strict"; +/* jshint globalstrict: true */ function show_password() { var button = this; diff --git a/p/scripts/main.js b/p/scripts/main.js index 01c8c9cf5..21e26d6df 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1,4 +1,7 @@ "use strict"; +/* globals context, i18n, shortcut, shortcuts, url */ +/* jshint globalstrict: true */ + var $stream = null, isCollapsed = true, shares = 0, @@ -49,9 +52,7 @@ function numberFormat(nStr) { function incLabel(p, inc, spaceAfter) { var i = str2int(p) + inc; - return i > 0 - ? ((spaceAfter ? '' : ' ') + '(' + numberFormat(i) + ')' + (spaceAfter ? ' ' : '')) - : ''; + return i > 0 ? ((spaceAfter ? '' : ' ') + '(' + numberFormat(i) + ')' + (spaceAfter ? ' ' : '')) : ''; } function incUnreadsFeed(article, feed_id, nb) { @@ -217,7 +218,7 @@ function toggleContent(new_active, old_active) { return; } - if (context['does_lazyload']) { + if (context.does_lazyload) { new_active.find('img[data-original], iframe[data-original]').each(function () { this.setAttribute('src', this.getAttribute('data-original')); this.removeAttribute('data-original'); @@ -230,17 +231,17 @@ function toggleContent(new_active, old_active) { } old_active.removeClass("active current"); new_active.addClass("current"); - if (context['auto_remove_article'] && !old_active.hasClass('not_read')) { + if (context.auto_remove_article && !old_active.hasClass('not_read')) { auto_remove(old_active); } } else { new_active.toggleClass('active'); } - var relative_move = context['current_view'] === 'global', + var relative_move = context.current_view === 'global', box_to_move = $(relative_move ? "#panel" : "html,body"); - if (context['sticky_post']) { + if (context.sticky_post) { var prev_article = new_active.prevAll('.flux'), new_pos = new_active.offset().top, old_scroll = box_to_move.scrollTop(); @@ -252,7 +253,7 @@ function toggleContent(new_active, old_active) { } } - if (context['hide_posts']) { + if (context.hide_posts) { if (relative_move) { new_pos += old_scroll; } @@ -271,7 +272,7 @@ function toggleContent(new_active, old_active) { } } - if (context['auto_mark_article'] && new_active.hasClass('active')) { + if (context.auto_mark_article && new_active.hasClass('active')) { mark_read(new_active, true); } } @@ -381,7 +382,7 @@ function collapse_entry() { var flux_current = $(".flux.current"); flux_current.toggleClass("active"); - if (isCollapsed && context['auto_mark_article']) { + if (isCollapsed && context.auto_mark_article) { mark_read(flux_current, true); } } @@ -456,11 +457,11 @@ function inMarkViewport(flux, box_to_follow) { function init_posts() { var box_to_follow = $(window); - if (context['current_view'] === 'global') { + if (context.current_view === 'global') { box_to_follow = $("#panel"); } - if (context['auto_mark_scroll']) { + if (context.auto_mark_scroll) { box_to_follow.scroll(function () { $('.not_read:visible').each(function () { if ($(this).children(".flux_content").is(':visible') && inMarkViewport($(this), box_to_follow)) { @@ -470,7 +471,7 @@ function init_posts() { }); } - if (context['auto_load_more']) { + if (context.auto_load_more) { box_to_follow.scroll(function () { var load_more = $("#load_more"); if (!load_more.is(':visible')) { @@ -487,7 +488,7 @@ function init_posts() { } function init_column_categories() { - if (context['current_view'] !== 'normal') { + if (context.current_view !== 'normal') { return; } @@ -559,14 +560,16 @@ function init_shortcuts() { }, { 'disable_in_input': true }); - for(var i = 1; i < 10; i++){ - shortcut.add(i.toString(), function (e) { - if ($('#dropdown-query').siblings('.dropdown-menu').is(':visible')) { - user_filter(String.fromCharCode(e.keyCode)); - } else { - auto_share(String.fromCharCode(e.keyCode)); - } - }, { + + function addShortcut(evt) { + if ($('#dropdown-query').siblings('.dropdown-menu').is(':visible')) { + user_filter(String.fromCharCode(evt.keyCode)); + } else { + auto_share(String.fromCharCode(evt.keyCode)); + } + } + for(var i = 1; i < 10; i++) { + shortcut.add(i.toString(), addShortcut, { 'disable_in_input': true }); } @@ -628,7 +631,7 @@ function init_shortcuts() { shortcut.add(shortcuts.go_website, function () { var url_website = $('.flux.current > .flux_header > .title > a').attr("href"); - if (context['auto_mark_site']) { + if (context.auto_mark_site) { $(".flux.current").each(function () { mark_read($(this), true); }); @@ -652,7 +655,7 @@ function init_shortcuts() { }); shortcut.add(shortcuts.help, function () { - redirect(url['help'], true); + redirect(url.help, true); }, { 'disable_in_input': true }); @@ -674,7 +677,7 @@ function init_stream(divStream) { new_active = $(this).parent(); isCollapsed = true; if (e.target.tagName.toUpperCase() === 'A') { //Leave real links alone - if (context['auto_mark_article']) { + if (context.auto_mark_article) { mark_read(new_active, true); } return true; @@ -684,7 +687,7 @@ function init_stream(divStream) { divStream.on('click', '.flux a.read', function () { var active = $(this).parents(".flux"); - if (context['auto_remove_article'] && active.hasClass('not_read')) { + if (context.auto_remove_article && active.hasClass('not_read')) { auto_remove(active); } mark_read(active, false); @@ -710,9 +713,9 @@ function init_stream(divStream) { if (e.which == 2) { // If middle click, we want same behaviour as CTRL+click. - var e = jQuery.Event("click"); - e.ctrlKey = true; - $(this).trigger(e); + var ev = jQuery.Event("click"); + ev.ctrlKey = true; + $(this).trigger(ev); } else if(e.which == 1) { // Normal click, just toggle article. $(this).parent().click(); @@ -723,7 +726,7 @@ function init_stream(divStream) { $(this).attr('target', '_blank'); }); - if (context['auto_mark_site']) { + if (context.auto_mark_site) { // catch mouseup instead of click so we can have the correct behaviour // with middle button click (scroll button). divStream.on('mouseup', '.flux .link > a', function (e) { @@ -765,17 +768,17 @@ var feed_processed = 0; function updateFeed(feeds, feeds_count) { var feed = feeds.pop(); - if (feed == undefined) { + if (!feed) { return; } $.ajax({ type: 'POST', - url: feed['url'], + url: feed.url, }).complete(function (data) { feed_processed++; $("#actualizeProgress .progress").html(feed_processed + " / " + feeds_count); - $("#actualizeProgress .title").html(feed['title']); + $("#actualizeProgress .title").html(feed.title); if (feed_processed === feeds_count) { window.location.reload(); @@ -819,7 +822,7 @@ function init_actualize() { return false; }); - if (context['auto_actualize_feeds']) { + if (context.auto_actualize_feeds) { auto = true; $("#actualize").click(); } @@ -887,12 +890,12 @@ function notifs_html5_ask_permission() { function notifs_html5_show(nb) { if (notifs_html5_permission !== "granted") { - return + return; } - var notification = new window.Notification(i18n['notif_title_articles'], { + var notification = new window.Notification(i18n.notif_title_articles, { icon: "../themes/icons/favicon-256.png", - body: i18n['notif_body_articles'].replace('%d', nb), + body: i18n.notif_body_articles.replace('%d', nb), tag: "freshRssNewArticles" }); @@ -900,10 +903,10 @@ function notifs_html5_show(nb) { window.location.reload(); }; - if (context['html5_notif_timeout'] !== 0) { + if (context.html5_notif_timeout !== 0) { setTimeout(function() { notification.close(); - }, context['html5_notif_timeout'] * 1000); + }, context.html5_notif_timeout * 1000); } } @@ -930,7 +933,7 @@ function refreshUnreads() { (nbUnreads - feed_unreads > 0)) { $('#new-article').attr('aria-hidden', 'false').show(); new_articles = true; - }; + } }); var nb_unreads = str2int($('.category.all .title').attr('data-unread')); @@ -957,7 +960,7 @@ function load_more_posts() { $.get(url_load_more, function (data) { box_load_more.children('.flux:last').after($('#stream', data).children('.flux, .day')); $('.pagination').replaceWith($('.pagination', data)); - if (context['display_order'] === 'ASC') { + if (context.display_order === 'ASC') { $('#nav_menu_read_all > .read_all').attr( 'formaction', $('#bigMarkAsRead').attr('formaction') ); @@ -988,7 +991,7 @@ function focus_search() { function init_load_more(box) { box_load_more = box; - if (!context['does_lazyload']) { + if (!context.does_lazyload) { $('img[postpone], audio[postpone], iframe[postpone], video[postpone]').each(function () { this.removeAttribute('postpone'); }); @@ -1027,6 +1030,7 @@ function poormanSalt() { //If crypto.getRandomValues is not available } function init_crypto_form() { + /* globals dcodeIO */ var $crypto_form = $('#crypto-form'); if ($crypto_form.length === 0) { return; @@ -1050,7 +1054,7 @@ function init_crypto_form() { dataType: 'json', async: false }).done(function (data) { - if (data.salt1 == '' || data.nonce == '') { + if (!data.salt1 || !data.nonce) { openNotification('Invalid user!', 'bad'); } else { try { @@ -1058,7 +1062,7 @@ function init_crypto_form() { s = dcodeIO.bcrypt.hashSync($('#passwordPlain').val(), data.salt1), c = dcodeIO.bcrypt.hashSync(data.nonce + s, strong ? dcodeIO.bcrypt.genSaltSync(4) : poormanSalt()); $('#challenge').val(c); - if (s == '' || c == '') { + if (!s || !c) { openNotification('Crypto error!', 'bad'); } else { success = true; @@ -1083,7 +1087,7 @@ function init_confirm_action() { $('body').on('click', '.confirm', function () { var str_confirmation = $(this).attr('data-str-confirm'); if (!str_confirmation) { - str_confirmation = i18n['confirmation_default']; + str_confirmation = i18n.confirmation_default; } return confirm(str_confirmation); @@ -1092,13 +1096,13 @@ function init_confirm_action() { function init_print_action() { $('.item.share > a[href="#"]').click(function () { - var content = "" - + $(".flux.current .content").html() - + ""; + var content = "" + + $(".flux.current .content").html() + + ""; var tmp_window = window.open(); tmp_window.document.writeln(content); @@ -1291,6 +1295,22 @@ function parseJsonVars() { window.icons = json.icons; } +function init_normal() { + $stream = $('#stream'); + if ($stream.length < 1) { + if (window.console) { + console.log('FreshRSS waiting for content…'); + } + window.setTimeout(init_normal, 50); + return; + } + init_column_categories(); + init_stream($stream); + init_shortcuts(); + init_actualize(); + faviconNbUnread(); +} + function init_beforeDOM() { if (!window.$) { if (window.console) { @@ -1300,20 +1320,8 @@ function init_beforeDOM() { return; } init_confirm_action(); - if (['normal', 'reader', 'global'].indexOf(context['current_view']) >= 0) { - $stream = $('#stream'); - if ($stream.length < 1) { - if (window.console) { - console.log('FreshRSS waiting for content…'); - } - window.setTimeout(init_beforeDOM, 50); - return; - } - init_column_categories(); - init_stream($stream); - init_shortcuts(); - init_actualize(); - faviconNbUnread(); + if (['normal', 'reader', 'global'].indexOf(context.current_view) >= 0) { + init_normal(); } } diff --git a/p/scripts/repartition.js b/p/scripts/repartition.js index a391de2f2..be70456fa 100644 --- a/p/scripts/repartition.js +++ b/p/scripts/repartition.js @@ -1,4 +1,7 @@ "use strict"; +/* globals Flotr, numberFormat */ +/* jshint globalstrict: true */ + function initStats() { if (!window.Flotr) { if (window.console) { @@ -19,9 +22,8 @@ function initStats() { { grid: {verticalLines: false}, xaxis: {noTicks: 23, - tickFormatter: function(x) { - var x = parseInt(x); - return x + 1; + tickFormatter: function(x1) { + return 1 + parseInt(x1); }, min: -0.9, max: 23.9, @@ -38,9 +40,8 @@ function initStats() { { grid: {verticalLines: false}, xaxis: {noTicks: 6, - tickFormatter: function(x) { - var x = parseInt(x); - return stats.days[x]; + tickFormatter: function(x2) { + return stats.days[parseInt(x2)]; }, min: -0.9, max: 6.9, @@ -57,9 +58,8 @@ function initStats() { { grid: {verticalLines: false}, xaxis: {noTicks: 12, - tickFormatter: function(x) { - var x = parseInt(x); - return stats.months[(x - 1)]; + tickFormatter: function(x3) { + return stats.months[parseInt(x3) - 1]; }, min: 0.1, max: 12.9, diff --git a/p/scripts/stats.js b/p/scripts/stats.js index 2e8ab6e27..9cd14721c 100644 --- a/p/scripts/stats.js +++ b/p/scripts/stats.js @@ -1,4 +1,7 @@ "use strict"; +/* globals Flotr, numberFormat */ +/* jshint globalstrict: true */ + function initStats() { if (!window.Flotr) { if (window.console) { -- cgit v1.2.3 From 5fa4f40133c78388ce3474f3d211707ea3c04ce6 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 6 Aug 2016 13:24:04 +0200 Subject: jQuery 3.1.0 http://blog.jquery.com/2016/07/07/jquery-3-1-0-released-no-more-silent-errors/ --- p/scripts/jquery.min.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'p') diff --git a/p/scripts/jquery.min.js b/p/scripts/jquery.min.js index 349030de9..f6a6a99e6 100644 --- a/p/scripts/jquery.min.js +++ b/p/scripts/jquery.min.js @@ -1,4 +1,4 @@ -/*! jQuery v2.2.1 | (c) jQuery Foundation | jquery.org/license */ -!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="2.2.1",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!k.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?i[j.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=d.createElement("script"),b.text=a,d.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:h.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(d=e.call(arguments,2),f=function(){return a.apply(b||this,d.concat(e.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:l}),"function"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){i["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=!!a&&"length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+M+"))|)"+L+"*\\]",O=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+N+")*)|.*)\\)|)",P=new RegExp(L+"+","g"),Q=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),R=new RegExp("^"+L+"*,"+L+"*"),S=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),T=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),U=new RegExp(O),V=new RegExp("^"+M+"$"),W={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M+"|[*])"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},X=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Z=/^[^{]+\{\s*\[native \w/,$=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,_=/[+~]/,aa=/'|\\/g,ba=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),ca=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},da=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(ea){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fa(a,b,d,e){var f,h,j,k,l,o,r,s,w=b&&b.ownerDocument,x=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==x&&9!==x&&11!==x)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==x&&(o=$.exec(a)))if(f=o[1]){if(9===x){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(w&&(j=w.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(o[2])return H.apply(d,b.getElementsByTagName(a)),d;if((f=o[3])&&c.getElementsByClassName&&b.getElementsByClassName)return H.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==x)w=b,s=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(aa,"\\$&"):b.setAttribute("id",k=u),r=g(a),h=r.length,l=V.test(k)?"#"+k:"[id='"+k+"']";while(h--)r[h]=l+" "+qa(r[h]);s=r.join(","),w=_.test(a)&&oa(b.parentNode)||b}if(s)try{return H.apply(d,w.querySelectorAll(s)),d}catch(y){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(Q,"$1"),b,d,e)}function ga(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ha(a){return a[u]=!0,a}function ia(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ja(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function ka(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function la(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function na(a){return ha(function(b){return b=+b,ha(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function oa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=fa.support={},f=fa.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fa.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ia(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ia(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Z.test(n.getElementsByClassName),c.getById=ia(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return"undefined"!=typeof b.getElementsByClassName&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=Z.test(n.querySelectorAll))&&(ia(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ia(function(a){var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Z.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ia(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",O)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Z.test(o.compareDocumentPosition),t=b||Z.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return ka(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?ka(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},fa.matches=function(a,b){return fa(a,null,null,b)},fa.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(T,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fa(b,n,null,[a]).length>0},fa.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fa.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fa.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fa.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fa.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fa.selectors={cacheLength:50,createPseudo:ha,match:W,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ba,ca),a[3]=(a[3]||a[4]||a[5]||"").replace(ba,ca),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fa.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fa.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return W.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&U.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ba,ca).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fa.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(P," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fa.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ha(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ha(function(a){var b=[],c=[],d=h(a.replace(Q,"$1"));return d[u]?ha(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ha(function(a){return function(b){return fa(a,b).length>0}}),contains:ha(function(a){return a=a.replace(ba,ca),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ha(function(a){return V.test(a||"")||fa.error("unsupported lang: "+a),a=a.replace(ba,ca).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Y.test(a.nodeName)},input:function(a){return X.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:na(function(){return[0]}),last:na(function(a,b){return[b-1]}),eq:na(function(a,b,c){return[0>c?c+b:c]}),even:na(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:na(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:na(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:na(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function ra(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j,k=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(j=b[u]||(b[u]={}),i=j[b.uniqueID]||(j[b.uniqueID]={}),(h=i[d])&&h[0]===w&&h[1]===f)return k[2]=h[2];if(i[d]=k,k[2]=a(b,c,g))return!0}}}function sa(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ta(a,b,c){for(var d=0,e=b.length;e>d;d++)fa(a,b[d],c);return c}function ua(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function va(a,b,c,d,e,f){return d&&!d[u]&&(d=va(d)),e&&!e[u]&&(e=va(e,f)),ha(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ta(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ua(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ua(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ua(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function wa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ra(function(a){return a===b},h,!0),l=ra(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[ra(sa(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return va(i>1&&sa(m),i>1&&qa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(Q,"$1"),c,e>i&&wa(a.slice(i,e)),f>e&&wa(a=a.slice(e)),f>e&&qa(a))}m.push(c)}return sa(m)}function xa(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=F.call(i));u=ua(u)}H.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&fa.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ha(f):f}return h=fa.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xa(e,d)),f.selector=a}return f},i=fa.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ba,ca),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=W.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ba,ca),_.test(j[0].type)&&oa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qa(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||_.test(a)&&oa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ia(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ia(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ja("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ia(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ja("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ia(function(a){return null==a.getAttribute("disabled")})||ja(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fa}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.uniqueSort=n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},v=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},w=n.expr.match.needsContext,x=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,y=/^.[^:#\[\.,]*$/;function z(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(y.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return h.call(b,a)>-1!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(z(this,a||[],!1))},not:function(a){return this.pushStack(z(this,a||[],!0))},is:function(a){return!!z(this,"string"==typeof a&&w.test(a)?n(a):a||[],!1).length}});var A,B=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=n.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||A,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:B.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),x.test(e[1])&&n.isPlainObject(b))for(e in b)n.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&f.parentNode&&(this.length=1,this[0]=f),this.context=d,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?void 0!==c.ready?c.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};C.prototype=n.fn,A=n(d);var D=/^(?:parents|prev(?:Until|All))/,E={children:!0,contents:!0,next:!0,prev:!0};n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=w.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?h.call(n(a),this[0]):h.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.uniqueSort(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function F(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return u(a,"parentNode")},parentsUntil:function(a,b,c){return u(a,"parentNode",c)},next:function(a){return F(a,"nextSibling")},prev:function(a){return F(a,"previousSibling")},nextAll:function(a){return u(a,"nextSibling")},prevAll:function(a){return u(a,"previousSibling")},nextUntil:function(a,b,c){return u(a,"nextSibling",c)},prevUntil:function(a,b,c){return u(a,"previousSibling",c)},siblings:function(a){return v((a.parentNode||{}).firstChild,a)},children:function(a){return v(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(E[a]||n.uniqueSort(e),D.test(a)&&e.reverse()),this.pushStack(e)}});var G=/\S+/g;function H(a){var b={};return n.each(a.match(G)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?H(a):n.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),h>=c&&h--}),this},has:function(a){return a?n.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().progress(c.notify).done(c.resolve).fail(c.reject):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=e.call(arguments),d=c.length,f=1!==d||a&&n.isFunction(a.promise)?d:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?e.call(arguments):d,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(d>1)for(i=new Array(d),j=new Array(d),k=new Array(d);d>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().progress(h(b,j,i)).done(h(b,k,c)).fail(g.reject):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(d,[n]),n.fn.triggerHandler&&(n(d).triggerHandler("ready"),n(d).off("ready"))))}});function J(){d.removeEventListener("DOMContentLoaded",J),a.removeEventListener("load",J),n.ready()}n.ready.promise=function(b){return I||(I=n.Deferred(),"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(n.ready):(d.addEventListener("DOMContentLoaded",J),a.addEventListener("load",J))),I.promise(b)},n.ready.promise();var K=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)K(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},L=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function M(){this.expando=n.expando+M.uid++}M.uid=1,M.prototype={register:function(a,b){var c=b||{};return a.nodeType?a[this.expando]=c:Object.defineProperty(a,this.expando,{value:c,writable:!0,configurable:!0}),a[this.expando]},cache:function(a){if(!L(a))return{};var b=a[this.expando];return b||(b={},L(a)&&(a.nodeType?a[this.expando]=b:Object.defineProperty(a,this.expando,{value:b,configurable:!0}))),b},set:function(a,b,c){var d,e=this.cache(a);if("string"==typeof b)e[b]=c;else for(d in b)e[d]=b[d];return e},get:function(a,b){return void 0===b?this.cache(a):a[this.expando]&&a[this.expando][b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=a[this.expando];if(void 0!==f){if(void 0===b)this.register(a);else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in f?d=[b,e]:(d=e,d=d in f?[d]:d.match(G)||[])),c=d.length;while(c--)delete f[d[c]]}(void 0===b||n.isEmptyObject(f))&&(a.nodeType?a[this.expando]=void 0:delete a[this.expando])}},hasData:function(a){var b=a[this.expando];return void 0!==b&&!n.isEmptyObject(b)}};var N=new M,O=new M,P=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Q=/[A-Z]/g;function R(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(Q,"-$&").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:P.test(c)?n.parseJSON(c):c}catch(e){}O.set(a,b,c); -}else c=void 0;return c}n.extend({hasData:function(a){return O.hasData(a)||N.hasData(a)},data:function(a,b,c){return O.access(a,b,c)},removeData:function(a,b){O.remove(a,b)},_data:function(a,b,c){return N.access(a,b,c)},_removeData:function(a,b){N.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=O.get(f),1===f.nodeType&&!N.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),R(f,d,e[d])));N.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){O.set(this,a)}):K(this,function(b){var c,d;if(f&&void 0===b){if(c=O.get(f,a)||O.get(f,a.replace(Q,"-$&").toLowerCase()),void 0!==c)return c;if(d=n.camelCase(a),c=O.get(f,d),void 0!==c)return c;if(c=R(f,d,void 0),void 0!==c)return c}else d=n.camelCase(a),this.each(function(){var c=O.get(this,d);O.set(this,d,b),a.indexOf("-")>-1&&void 0!==c&&O.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){O.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=N.get(a,b),c&&(!d||n.isArray(c)?d=N.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return N.get(a,c)||N.access(a,c,{empty:n.Callbacks("once memory").add(function(){N.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length",""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};$.optgroup=$.option,$.tbody=$.tfoot=$.colgroup=$.caption=$.thead,$.th=$.td;function _(a,b){var c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function aa(a,b){for(var c=0,d=a.length;d>c;c++)N.set(a[c],"globalEval",!b||N.get(b[c],"globalEval"))}var ba=/<|&#?\w+;/;function ca(a,b,c,d,e){for(var f,g,h,i,j,k,l=b.createDocumentFragment(),m=[],o=0,p=a.length;p>o;o++)if(f=a[o],f||0===f)if("object"===n.type(f))n.merge(m,f.nodeType?[f]:f);else if(ba.test(f)){g=g||l.appendChild(b.createElement("div")),h=(Y.exec(f)||["",""])[1].toLowerCase(),i=$[h]||$._default,g.innerHTML=i[1]+n.htmlPrefilter(f)+i[2],k=i[0];while(k--)g=g.lastChild;n.merge(m,g.childNodes),g=l.firstChild,g.textContent=""}else m.push(b.createTextNode(f));l.textContent="",o=0;while(f=m[o++])if(d&&n.inArray(f,d)>-1)e&&e.push(f);else if(j=n.contains(f.ownerDocument,f),g=_(l.appendChild(f),"script"),j&&aa(g),c){k=0;while(f=g[k++])Z.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var da=/^key/,ea=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,fa=/^([^.]*)(?:\.(.+)|)/;function ga(){return!0}function ha(){return!1}function ia(){try{return d.activeElement}catch(a){}}function ja(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ja(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=ha;else if(!e)return a;return 1===f&&(g=e,e=function(a){return n().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=n.guid++)),a.each(function(){n.event.add(this,b,e,d,c)})}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=N.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return"undefined"!=typeof n&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(G)||[""],j=b.length;while(j--)h=fa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=N.hasData(a)&&N.get(a);if(r&&(i=r.events)){b=(b||"").match(G)||[""],j=b.length;while(j--)if(h=fa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&N.remove(a,"handle events")}},dispatch:function(a){a=n.event.fix(a);var b,c,d,f,g,h=[],i=e.call(arguments),j=(N.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.rnamespace||a.rnamespace.test(g.namespace))&&(a.handleObj=g,a.data=g.data,d=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==d&&(a.result=d)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&("click"!==a.type||isNaN(a.button)||a.button<1))for(;i!==this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>-1:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,la=/\s*$/g;function pa(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function qa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function ra(a){var b=na.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function sa(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(N.hasData(a)&&(f=N.access(a),g=N.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}O.hasData(a)&&(h=O.access(a),i=n.extend({},h),O.set(b,i))}}function ta(a,b){var c=b.nodeName.toLowerCase();"input"===c&&X.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}function ua(a,b,c,d){b=f.apply([],b);var e,g,h,i,j,k,m=0,o=a.length,p=o-1,q=b[0],r=n.isFunction(q);if(r||o>1&&"string"==typeof q&&!l.checkClone&&ma.test(q))return a.each(function(e){var f=a.eq(e);r&&(b[0]=q.call(this,e,f.html())),ua(f,b,c,d)});if(o&&(e=ca(b,a[0].ownerDocument,!1,a,d),g=e.firstChild,1===e.childNodes.length&&(e=g),g||d)){for(h=n.map(_(e,"script"),qa),i=h.length;o>m;m++)j=e,m!==p&&(j=n.clone(j,!0,!0),i&&n.merge(h,_(j,"script"))),c.call(a[m],j,m);if(i)for(k=h[h.length-1].ownerDocument,n.map(h,ra),m=0;i>m;m++)j=h[m],Z.test(j.type||"")&&!N.access(j,"globalEval")&&n.contains(k,j)&&(j.src?n._evalUrl&&n._evalUrl(j.src):n.globalEval(j.textContent.replace(oa,"")))}return a}function va(a,b,c){for(var d,e=b?n.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||n.cleanData(_(d)),d.parentNode&&(c&&n.contains(d.ownerDocument,d)&&aa(_(d,"script")),d.parentNode.removeChild(d));return a}n.extend({htmlPrefilter:function(a){return a.replace(ka,"<$1>")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=_(h),f=_(a),d=0,e=f.length;e>d;d++)ta(f[d],g[d]);if(b)if(c)for(f=f||_(a),g=g||_(h),d=0,e=f.length;e>d;d++)sa(f[d],g[d]);else sa(a,h);return g=_(h,"script"),g.length>0&&aa(g,!i&&_(a,"script")),h},cleanData:function(a){for(var b,c,d,e=n.event.special,f=0;void 0!==(c=a[f]);f++)if(L(c)){if(b=c[N.expando]){if(b.events)for(d in b.events)e[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);c[N.expando]=void 0}c[O.expando]&&(c[O.expando]=void 0)}}}),n.fn.extend({domManip:ua,detach:function(a){return va(this,a,!0)},remove:function(a){return va(this,a)},text:function(a){return K(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return ua(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=pa(this,a);b.appendChild(a)}})},prepend:function(){return ua(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=pa(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return ua(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return ua(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(_(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return K(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!la.test(a)&&!$[(Y.exec(a)||["",""])[1].toLowerCase()]){a=n.htmlPrefilter(a);try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(_(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return ua(this,arguments,function(b){var c=this.parentNode;n.inArray(this,a)<0&&(n.cleanData(_(this)),c&&c.replaceChild(b,this))},a)}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),f=e.length-1,h=0;f>=h;h++)c=h===f?this:this.clone(!0),n(e[h])[b](c),g.apply(d,c.get());return this.pushStack(d)}});var wa,xa={HTML:"block",BODY:"block"};function ya(a,b){var c=n(b.createElement(a)).appendTo(b.body),d=n.css(c[0],"display");return c.detach(),d}function za(a){var b=d,c=xa[a];return c||(c=ya(a,b),"none"!==c&&c||(wa=(wa||n("