From ec56aa9e815b58f66e1c4b5bbf05592ee34b8063 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 28 Oct 2018 17:39:35 +0100 Subject: Prepare next version 1.12.1-dev --- CHANGELOG.md | 4 ++++ constants.php | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f9923d03..12284e35c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # FreshRSS changelog +## 2018-1X-XX FreshRSS 1.12.1-dev + + + ## 2018-10-28 FreshRSS 1.12.0 * Features diff --git a/constants.php b/constants.php index 2740dc63d..65c2027ee 100644 --- a/constants.php +++ b/constants.php @@ -2,7 +2,7 @@ //NB: Do not edit; use ./constants.local.php instead. // -define('FRESHRSS_VERSION', '1.12.0'); +define('FRESHRSS_VERSION', '1.12.1-dev'); define('FRESHRSS_WEBSITE', 'https://freshrss.org'); define('FRESHRSS_WIKI', 'https://freshrss.github.io/FreshRSS/'); -- cgit v1.2.3 From 31e70e4342fbdf0a02e4dae83a5e6d2e998187c0 Mon Sep 17 00:00:00 2001 From: Patrick Crandol Date: Sun, 28 Oct 2018 20:26:19 -0400 Subject: Update Swage CSS Fix highlighting issue in Config pages, prepare for variable-width config buttons --- p/themes/Swage/swage.css | 1233 ++++++++++++++++++++------------------------- p/themes/Swage/swage.scss | 30 +- 2 files changed, 573 insertions(+), 690 deletions(-) diff --git a/p/themes/Swage/swage.css b/p/themes/Swage/swage.css index 5cab13bd7..f8ff0189f 100644 --- a/p/themes/Swage/swage.css +++ b/p/themes/Swage/swage.css @@ -1,1211 +1,1076 @@ -textarea,input,select { -min-height:25px; -margin-top:4px; -line-height:25px; -vertical-align:middle; -background:#FCFCFC; -border:none; -padding-left:5px +textarea, input, select { +min-height: 25px; +margin-top: 4px; +line-height: 25px; +vertical-align: middle; +background: #FCFCFC; +border: none; +padding-left: 5px; } -input:invalid,select:invalid { -color:#B0425B; -border-color:#B0425B; -box-shadow:none +input:invalid, select:invalid { +color: #B0425B; +border-color: #B0425B; +box-shadow: none; } -.nav-list .nav-header,.nav-list .item { -height:2.5em; -line-height:2.5em; -font-size:.9rem +.nav-list .nav-header, .nav-list .item { +height: 2.5em; +line-height: 2.5em; +font-size: 0.9rem; } -.dropdown-menu > .item,.dropdown-menu > .item > a,.dropdown-menu > .item > span,.dropdown-menu > .item > as-link,.dropdown-menu > .item button { -padding:0 22px; -line-height:2.5em; -font-size:.8rem; -color:#FCFCFC +.dropdown-menu > .item, .dropdown-menu > .item > a, .dropdown-menu > .item > span, .dropdown-menu > .item > as-link, .dropdown-menu > .item button { +padding: 0 22px; +line-height: 2.5em; +font-size: 0.8rem; +color: #FCFCFC; } -.form-group::after,.flux::after { -content:""; -display:block; -clear:both +.form-group::after, .flux::after { +content: ""; +display: block; +clear: both; } -html,body { -height:100%; -font-family:Helvetica,Arial,sans-serif +.stick.configure-feeds, .header > .item.title, .aside, #new-article, .notification, #nav_entries { +width: 231px; } -a { -color:#00488b; -outline:none +html, body { +height: 100%; +font-family: Helvetica, Arial, sans-serif; } +a { +color: #00488b; +outline: none; +} a.btn { -min-height:25px; -line-height:25px; -text-decoration:none +min-height: 25px; +line-height: 25px; +text-decoration: none; } - a.btn:hover { -background:#00488b +background: #00488b; +} +a#btn-subscription { +width: 76%; +} +a#btn-importExport { +width: 5%; } img.icon:hover { -background:none +background: none; } div#stream { -margin-top:35px +margin-top: 35px; } sup { -top:-.3em +top: -0.3em; } legend { -display:inline-block; -width:auto; -margin:20px 0 5px; -padding:5px 20px; -font-size:1.4em; -clear:both; -background:#e3e3e3 +display: inline-block; +width: auto; +margin: 20px 0 5px; +padding: 5px 20px; +font-size: 1.4em; +clear: both; +background: #e3e3e3; } label { -min-height:25px +min-height: 25px; } textarea { -width:360px; -height:100px; -background:#e3e3e3 +width: 360px; +height: 100px; +background: #e3e3e3; } - textarea:focus { -border-color:#00488b +border-color: #00488b; } -input:focus,select:focus { -border-color:#00488b +input:focus, select:focus { +border-color: #00488b; } - -input:disabled,select:disabled { -background:#FCFCFC +input:disabled, select:disabled { +background: #FCFCFC; } select { -background:#e3e3e3 +background: #e3e3e3; } input.extend { -transition:width 200ms linear +transition: width 200ms linear; } option { -padding:0 .5em +padding: 0 .5em; } table { -border-collapse:collapse +border-collapse: collapse; } -tr,td,th { -padding:.5em; -border:1px solid #e3e3e3 +tr, td, th { +padding: 0.5em; +border: 1px solid #e3e3e3; } th { -background:#FCFCFC +background: #FCFCFC; } -form td,form th { -font-weight:400; -text-align:center +form td, form th { +font-weight: normal; +text-align: center; } .category .title.error::before { -display:inline-block; -padding-right:7px; -width:16px; -content:url(../Swage/icons/error.svg) +display: inline-block; +padding-right: 7px; +width: 16px; +content: url(../Swage/icons/error.svg); } .form-group { -padding:5px; -border:1px solid transparent +padding: 5px; +border: 1px solid transparent; } - .form-group:hover { -background:#FCFCFC; -border:1px solid #FCFCFC +background: #FCFCFC; +border: 1px solid #FCFCFC; } - .form-group.form-actions { -margin:15px 0 25px; -padding:5px 0; -background:#e3e3e3; -border-top:3px solid #e3e3e3 +margin: 15px 0 25px; +padding: 5px 0; +background: #e3e3e3; +border-top: 3px solid #e3e3e3; } - .form-group.form-actions .btn { -margin:0 10px +margin: 0 10px; } - .form-group .group-name { -padding:10px 0; -text-align:right +padding: 10px 0; +text-align: right; } - .form-group .group-controls { -min-height:25px; -padding:5px 0 +min-height: 25px; +padding: 5px 0; } - .form-group .group-controls .control { -line-height:2em +line-height: 2.0em; } - .form-group table { -margin:10px 0 0 220px +margin: 10px 0 0 220px; } .stick { -vertical-align:middle; -font-size:0 +vertical-align: middle; +font-size: 0; } .btn { -display:inline-block; -min-height:35px; -min-width:15px; -margin:0; -padding:5px 10px; -font-size:.9rem; -vertical-align:middle; -cursor:pointer; -overflow:hidden; -background:#0062be; -border:none; -color:#FCFCFC +display: inline-block; +min-height: 35px; +min-width: 15px; +margin: 0; +padding: 5px 10px; +font-size: 0.9rem; +vertical-align: middle; +cursor: pointer; +overflow: hidden; +background: #0062be; +border: none; +color: #FCFCFC; } - -.btn.active,.btn :active,.btn :hover { -background:#00488b; -text-decoration:none +.btn.active, .btn :active, .btn :hover { +background: #00488b; +text-decoration: none; } -.btn-important,.btn-attention { -font-weight:400; -background:#FA8052; -color:#FCFCFC +.btn-important, .btn-attention { +font-weight: normal; +background: #FA8052; +color: #FCFCFC; } - -.btn-important:hover,.btn-important :active,.btn-attention:hover,.btn-attention :active { -background:#f95c20!important +.btn-important:hover, .btn-important :active, .btn-attention:hover, .btn-attention :active { +background: #f95c20 !important; } .nav-list .nav-header { -padding:0 10px; -font-weight:700; -background:#22303d; -color:#FCFCFC; -cursor:default +padding: 0 10px; +font-weight: bold; +background: #22303d; +color: #FCFCFC; +cursor: default; } - -.nav-list .item:hover,.nav-list .item .active { -background:#00488b; -color:#FCFCFC +.nav-list .item:hover, .nav-list .item.active { +background: #00488b; +color: #FCFCFC; } - -.nav-list .item:hover a,.nav-list .item .active a { -color:#FCFCFC +.nav-list .item:hover a, .nav-list .item.active a { +color: #FCFCFC; } - -.nav-list .item:hover.empty a,.nav-list .item:hover .error a,.nav-list .item .active.empty a,.nav-list .item .active .error a { -color:#FCFCFC +.nav-list .item:hover.empty a, .nav-list .item:hover .error a, .nav-list .item.active.empty a, .nav-list .item.active .error a { +color: #FCFCFC; } - -.nav-list .item:hover.empty a,.nav-list .item .active.empty a { -background:#FA8052 +.nav-list .item:hover.empty a, .nav-list .item.active.empty a { +background: #FA8052; } - -.nav-list .item:hover.error a,.nav-list .item .active.error a { -background:#c46178 +.nav-list .item:hover.error a, .nav-list .item.active.error a { +background: #c46178; } - .nav-list .item > a { -padding:0 10px +padding: 0 10px; } - .nav-list .item.empty a { -color:#FA8052 +color: #FA8052; } - .nav-list .item.error a { -color:#c46178 +color: #c46178; } - .nav-list .disable { -text-align:center; -background:#FCFCFC; -color:#969696 +text-align: center; +background: #FCFCFC; +color: #969696; } - .nav-list .nav-form { -padding:3px; -text-align:center +padding: 3px; +text-align: center; } - .nav-list a:hover { -text-decoration:none +text-decoration: none; } .nav-head { -margin:0; -text-align:right; -background:#22303d; -color:#FCFCFC +margin: 0; +text-align: right; +background: #22303d; +color: #FCFCFC; } - .nav-head a { -color:#FCFCFC +color: #FCFCFC; } - .nav-head .item { -padding:5px 10px; -font-size:.9rem; -line-height:1.5rem +padding: 5px 10px; +font-size: 0.9rem; +line-height: 1.5rem; } .horizontal-list { -margin:0; -padding:0 +margin: 0; +padding: 0; } - .horizontal-list .item { -vertical-align:middle +vertical-align: middle; } .dropdown-menu { -padding:5px 0; -font-size:.8rem; -text-align:left; -border:none; -background-color:#00488b +padding: 5px 0; +font-size: 0.8rem; +text-align: left; +border: none; +background-color: #00488b; } - .dropdown-menu .dropdown-header { -cursor:default +cursor: default; } - .dropdown-menu > .item { -padding:0; -margin-left:10px +padding: 0; +margin-left: 10px; } - .dropdown-menu > .item > a { -min-width:initial; -white-space:nowrap +min-width: initial; +white-space: nowrap; } - .dropdown-menu > .item:hover { -background:#0062be; -color:#FCFCFC +background: #0062be; +color: #FCFCFC; } - .dropdown-menu > .item:hover > a { -text-decoration:none; -color:#FCFCFC +text-decoration: none; +color: #FCFCFC; } - .dropdown-menu > .item[aria-checked="true"] > a::before { -font-weight:700; -margin:0 0 0 -14px +font-weight: bold; +margin: 0 0 0 -14px; } - -.dropdown-menu .input select,.dropdown-menu .input input { -margin:0 auto 5px; -padding:2px 5px +.dropdown-menu .input select, .dropdown-menu .input input { +margin: 0 auto 5px; +padding: 2px 5px; } .dropdown-header { -padding:0 5px 5px; -font-weight:700; -text-align:left; -color:#FCFCFC +padding: 0 5px 5px; +font-weight: bold; +text-align: left; +color: #FCFCFC; } .separator { -margin:5px 0; -border-bottom:1px solid #e3e3e3; -cursor:default +margin: 5px 0; +border-bottom: 1px solid #e3e3e3; +cursor: default; } .alert { -margin:5px auto; -padding:10px 15px; -font-size:.9em; -background:#FCFCFC; -border:none; -color:#969696; -text-shadow:0 0 1px #FCFCFC +margin: 5px auto; +padding: 10px 15px; +font-size: 0.9em; +background: #FCFCFC; +border: none; +color: #969696; +text-shadow: 0 0 1px #FCFCFC; } - .alert > a { -text-decoration:underline; -color:inherit +text-decoration: underline; +color: inherit; } .alert-head { -font-size:1.15em +font-size: 1.15em; } -.alert-warn,.alert-success,.alert-error { -border:none +.alert-warn, .alert-success, .alert-error { +border: none; } .alert-warn { -background:#FCFCFC; -color:#FA8052 +background: #FCFCFC; +color: #FA8052; } .alert-success { -background:#FCFCFC; -color:#5EAABF +background: #FCFCFC; +color: #5EAABF; } .alert-error { -background:#FCFCFC; -color:#B0425B +background: #FCFCFC; +color: #B0425B; } .pagination { -text-align:center; -font-size:.8em; -background:#e3e3e3; -color:#181621 +text-align: center; +font-size: 0.8em; +background: #e3e3e3; +color: #181621; } - .pagination .item.pager-current { -font-weight:700; -font-size:1.5em; -background:#22303d; -color:#e3e3e3 +font-weight: bold; +font-size: 1.5em; +background: #22303d; +color: #e3e3e3; } - .pagination .item a { -display:block; -font-style:italic; -line-height:3em; -text-decoration:none; -color:#181621 +display: block; +font-style: italic; +line-height: 3em; +text-decoration: none; +color: #181621; } - .pagination .item a:hover { -background:#22303d; -color:#e3e3e3 +background: #22303d; +color: #e3e3e3; } - -.pagination .loading,.pagination a:hover.loading { -font-size:0; -background:url(loader.gif) center center no-repeat #22303d +.pagination .loading, .pagination a:hover.loading { +font-size: 0; +background: url(loader.gif) center center no-repeat #22303d; } .content { -padding:20px 10px +padding: 20px 10px; } - .content .pagination { -margin:0; -padding:0 +margin: 0; +padding: 0; } - .content hr { -margin:30px 10px; -height:1px; -background:#e3e3e3; -border:0; -box-shadow:0 2px 5px #e3e3e3 +margin: 30px 10px; +height: 1px; +background: #e3e3e3; +border: 0; +box-shadow: 0 2px 5px #e3e3e3; } - .content pre { -margin:10px auto; -padding:10px 20px; -overflow:auto; -background:#181621; -color:#FCFCFC; -font-size:.9rem +margin: 10px auto; +padding: 10px 20px; +overflow: auto; +background: #181621; +color: #FCFCFC; +font-size: 0.9rem; } - .content pre code { -background:transparent; -color:#FCFCFC; -border:none +background: transparent; +color: #FCFCFC; +border: none; } - .content code { -padding:2px 5px; -color:#B0425B; -background:#FCFCFC; -border:1px solid #FCFCFC +padding: 2px 5px; +color: #B0425B; +background: #FCFCFC; +border: 1px solid #FCFCFC; } - .content blockquote { -display:block; -margin:0; -padding:5px 20px; -border-top:1px solid #e3e3e3; -border-bottom:1px solid #e3e3e3; -background:#FCFCFC; -color:#969696 +display: block; +margin: 0; +padding: 5px 20px; +border-top: 1px solid #e3e3e3; +border-bottom: 1px solid #e3e3e3; +background: #FCFCFC; +color: #969696; } - .content blockquote p { -margin:0 +margin: 0; } - .content > h1.title > a { -color:#181621 +color: #181621; } .box { -border:1px solid #e3e3e3 +border: 1px solid #e3e3e3; } - .box .box-title { -margin:0; -padding:5px 10px; -background:#e3e3e3; -color:#969696; -border-bottom:1px solid #e3e3e3 +margin: 0; +padding: 5px 10px; +background: #e3e3e3; +color: #969696; +border-bottom: 1px solid #e3e3e3; } - .box .box-content { -max-height:260px +max-height: 260px; } - .box .box-content .item { -padding:0 10px; -font-size:.9rem; -line-height:2.5em +padding: 0 10px; +font-size: 0.9rem; +line-height: 2.5em; } - .box .box-content .item .configure { -visibility:hidden +visibility: hidden; } - .box .box-content .item .configure .icon { -vertical-align:middle; -background-color:#e3e3e3 +vertical-align: middle; +background-color: #e3e3e3; } - .box .box-content .item:hover .configure { -visibility:visible +visibility: visible; } - .box.category .box-title .title { -font-weight:400; -text-decoration:none; -text-align:left +font-weight: normal; +text-decoration: none; +text-align: left; } - .box.category:not([data-unread="0"]) .box-title { -background:#0062be +background: #0062be; } - .box.category:not([data-unread="0"]) .box-title:active { -background:#00488b +background: #00488b; } - .box.category:not([data-unread="0"]) .box-title .title { -font-weight:700; -color:#FCFCFC +font-weight: bold; +color: #FCFCFC; } - .box.category .title:not([data-unread="0"])::after { -position:absolute; -top:5px; -right:10px; -border:0; -background:none; -font-weight:700; -box-shadow:none; -text-shadow:none +position: absolute; +top: 5px; +right: 10px; +border: 0; +background: none; +font-weight: bold; +box-shadow: none; +text-shadow: none; } - .box.category .item.feed { -padding:2px 10px; -font-size:.8rem +padding: 2px 10px; +font-size: 0.8rem; } .tree { -margin:10px 0 +margin: 10px 0; } .tree-folder-title { -position:relative; -padding:0 10px; -background:#22303d; -line-height:2.3rem; -font-size:1rem; -height:35px +position: relative; +padding: 0 10px; +background: #22303d; +line-height: 2.3rem; +font-size: 1rem; +height: 35px; } - .tree-folder-title .title { -background:inherit; -color:#FCFCFC +background: inherit; +color: #FCFCFC; } - .tree-folder-title .title:hover { -text-decoration:none +text-decoration: none; } .tree-folder-items { -background:#22303d +background: #22303d; } - .tree-folder-items > .item { -padding:0 10px; -line-height:2.5rem; -font-size:.8rem +padding: 0 10px; +line-height: 2.5rem; +font-size: 0.8rem; } - .tree-folder-items > .item.active { -background:#00488b +background: #00488b; } - .tree-folder-items > .item > a { -text-decoration:none; -color:#FCFCFC +text-decoration: none; +color: #FCFCFC; } .header > .item { -vertical-align:middle +vertical-align: middle; } - .header > .item.title { -width:231px; -position:absolute +position: absolute; } - .header > .item.title h1 { -margin:0; -display:block +margin: 0; +display: block; } - .header > .item.title h1 a { -text-decoration:none; -color:#FCFCFC +text-decoration: none; +color: #FCFCFC; } - .header > .item.title .logo { -display:inline-block; -height:26px; -vertical-align:top; -position:relative; -top:5px +display: inline-block; +height: 26px; +vertical-align: top; +position: relative; +top: 5px; } - .header > .item.search input { -width:230px +width: 230px; } - .header .item.search input:focus { -width:350px +width: 350px; } - .header .item.search { -display:none +display: none; } - .header .item.configure { -position:fixed; -right:0; -z-index:1000; -width:35px +position: fixed; +right: 0px; +z-index: 1000; +width: 35px; } - .header h1 { -text-align:center; -font-size:1.5em +text-align: center; +font-size: 1.5em; } .aside { -background:#22303d; -padding:35px 0; -width:231px +background: #22303d; +padding: 35px 0; } - .aside.aside_feed .tree { -margin:0 0 50px +margin: 0 0 50px; } - -.aside.aside_feed .nav-form input,.aside.aside_feed .nav-form select { -width:140px +.aside.aside_feed .nav-form input, .aside.aside_feed .nav-form select { +width: 140px; } - .aside.aside_feed .nav-form .dropdown .dropdown-menu { -right:-20px +right: -20px; } - .aside.aside_feed .nav-form .dropdown .dropdown-menu::after { -right:33px +right: 33px; } .aside_feed .tree-folder-title > .title:not([data-unread="0"])::after { -position:absolute; -right:0; -margin:6px 0; -padding:0 10px; -font-size:.9rem; -line-height:1.5rem; -background:inherit +position: absolute; +right: 0; +margin: 6px 0; +padding: 0 10px; +font-size: 0.9rem; +line-height: 1.5rem; +background: inherit; } - .aside_feed .tree-folder-items .dropdown-menu::after { -left:2px +left: 2px; } .post { -padding:10px 50px; -font-size:.9em +padding: 10px 50px; +font-size: 0.9em; } - .post input { -background:#e3e3e3 +background: #e3e3e3; +} +.post input.long { +height: 33px; +margin-top: 0px; } - .post form { -margin:10px 0 +margin: 10px 0; } - .post.content { -max-width:550px +max-width: 550px; } .prompt { -text-align:center +text-align: center; } - .prompt label { -text-align:left +text-align: left; } - .prompt form { -margin:10px auto 20px; -width:200px +margin: 10px auto 20px auto; +width: 200px; } - .prompt input { -margin:5px auto; -width:100% +margin: 5px auto; +width: 100%; } - .prompt p { -margin:20px 0 +margin: 20px 0; } #new-article { -text-align:center; -font-size:1em; -background:#0062be; -position:fixed; -bottom:48px; -z-index:900; -left:0; -width:231px; -line-height:1.5em +text-align: center; +font-size: 1em; +background: #0062be; +position: fixed; +bottom: 48px; +z-index: 900; +left: 0; +line-height: 1.5em; } - #new-article:hover { -background:#00488b +background: #00488b; } - #new-article > a { -line-height:1.5em; -font-weight:700; -color:#FCFCFC +line-height: 1.5em; +font-weight: bold; +color: #FCFCFC; } - #new-article > a:hover { -text-decoration:none +text-decoration: none; } .day { -padding:0 10px; -font-weight:700; -line-height:3em; -text-align:center +padding: 0 10px; +font-weight: bold; +line-height: 3em; +text-align: center; } - .day .name { -display:none +display: none; } .nav a { -color:#FCFCFC +color: #FCFCFC; } .nav_menu { -font-size:0; -background-color:#0062be; -position:fixed; -width:100%; -z-index:900 +font-size: 0; +background-color: #0062be; +position: fixed; +width: 100%; +z-index: 900; } - .nav_menu .item.search { -display:inline-block; -position:fixed; -right:40px +display: inline-block; +position: fixed; +right: 40px; } .flux { -padding-right:10px; -background:#FCFCFC +padding-right: 10px; +background: #FCFCFC; } - .flux::after { -margin:0 auto; -width:90%; -border-top:1px solid #e3e3e3 +margin: 0 auto; +width: 90%; +border-top: 1px solid #e3e3e3; } - -.flux:hover,.flux .current { -background:#FFF +.flux:hover, .flux .current { +background: #FFFFFF; } - -.flux:hover:not(.current):hover .item.title,.flux .current:not(.current):hover .item.title { -background:#FFF +.flux:hover:not(.current):hover .item.title, .flux .current:not(.current):hover .item.title { +background: #FFFFFF; } - .flux.not_read { -background:#FFF3ED +background: #FFF3ED; } - .flux.not_read:not(.current):hover .item.title { -background:#FFF3ED +background: #FFF3ED; } - .flux.favorite { -background:#FFF6DA +background: #FFF6DA; } - .flux.favorite:not(.current):hover .item.title { -background:#FFF6DA +background: #FFF6DA; } - .flux .date { -font-size:.7rem; -color:#969696 +font-size: 0.7rem; +color: #969696; } - .flux .bottom { -font-size:.8rem; -text-align:center +font-size: 0.8rem; +text-align: center; } - .flux .website .favicon { -padding:5px +padding: 5px; } - .flux label { -color:#FCFCFC; -cursor:pointer +color: #FCFCFC; +cursor: pointer; } .flux_header { -font-size:.8rem; -cursor:pointer +font-size: 0.8rem; +cursor: pointer; } - .flux_header .title { -font-size:.9rem +font-size: 0.9rem; } .notification { -text-align:center; -font-weight:700; -font-size:1em; -padding:10px 0; -z-index:10; -vertical-align:middle; -background:#e3e3e3; -color:#969696; -border:none; -position:fixed; -bottom:48px; -left:0; -top:auto; -width:231px; -height:auto -} - -.notification.good,.notification .bad { -color:#FCFCFC +text-align: center; +font-weight: bold; +font-size: 1em; +padding: 10px 0; +z-index: 10; +vertical-align: middle; +background: #e3e3e3; +color: #969696; +border: none; +position: fixed; +bottom: 48px; +left: 0; +top: auto; +height: auto; +} +.notification.good, .notification .bad { +color: #FCFCFC; } - .notification.good { -background:#5EAABF +background: #5EAABF; } - .notification.good a.close:hover { -background:#5EAABF +background: #5EAABF; } - .notification.bad { -background:#c46178 +background: #c46178; } - .notification.bad a.close:hover { -background:#c46178 +background: #c46178; } - .notification#actualizeProgress { -line-height:2em +line-height: 2em; } - .notification a.close { -display:none +display: none; } #bigMarkAsRead { -text-align:center; -text-decoration:none; -background:#e3e3e3; -padding:20px!important +text-align: center; +text-decoration: none; +background: #e3e3e3; +padding: 20px !IMPORTANT; } - #bigMarkAsRead:hover { -background:#22303d; -color:#FCFCFC +background: #22303d; +color: #FCFCFC; } #nav_entries { -margin:0; -text-align:center; -line-height:3em; -table-layout:fixed; -width:231px; -background:#22303d +margin: 0; +text-align: center; +line-height: 3em; +table-layout: fixed; +background: #22303d; } .stat { -margin:10px 0 20px +margin: 10px 0 20px; } - -.stat th,.stat td,.stat tr { -border:none +.stat th, .stat td, .stat tr { +border: none; } - -.stat > table td,.stat > table th { -border-bottom:1px solid #e3e3e3 +.stat > table td, .stat > table th { +border-bottom: 1px solid #e3e3e3; } - .stat > .horizontal-list { -margin:0 0 5px +margin: 0 0 5px; } - .stat > .horizontal-list .item { -overflow:hidden; -white-space:nowrap; -text-overflow:ellipsis +overflow: hidden; +white-space: nowrap; +text-overflow: ellipsis; } - .stat > .horizontal-list .item:first-child { -width:270px +width: 270px; } .loglist { -overflow:hidden; -border:1px solid #969696 +overflow: hidden; +border: 1px solid #969696; } .log { -padding:5px 2%; -overflow:auto; -font-size:.8rem; -background:#FCFCFC +padding: 5px 2%; +overflow: auto; +font-size: 0.8rem; +background: #FCFCFC; } - .log > .date { -margin:0 10px 0 0; -padding:5px 10px +margin: 0 10px 0 0; +padding: 5px 10px; } - .log.error > .date { -background:#c46178; -color:#FCFCFC +background: #c46178; +color: #FCFCFC; } - .log.warning > .date { -background:#FA8052; -color:#FCFCFC +background: #FA8052; +color: #FCFCFC; } - .log.notice > .date { -background:#e3e3e3; -color:#FCFCFC +background: #e3e3e3; +color: #FCFCFC; } - .log.debug > .date { -background:#181621; -color:#FCFCFC +background: #181621; +color: #FCFCFC; } @media (max-width: 840px) { -.dropdown-header,.dropdown-menu > .item { -padding:12px +.dropdown-header, .dropdown-menu > .item { +padding: 12px; } #new-article { -width:100%; -bottom:initial +width: 100%; +bottom: initial; } .header { -display:table +display: table; } - .header .item.title .logo { -display:none +display: none; } .header > .item.title h1 a { -display:block; -position:absolute; -top:-35px; -left:10px; -font-size:.6em +display: block; +position: absolute; +top: -35px; +left: 10px; +font-size: 0.6em; } -.header .item.configure,button.read_all.btn { -display:none +.header .item.configure, button.read_all.btn { +display: none; } -.flux .item.manage,.flux_header .item.website { -width:35px; -text-align:center +.flux .item.manage, .flux_header .item.website { +width: 35px; +text-align: center; } .aside { -width:0; -transition:width 200ms linear +width: 0; +transition: width 200ms linear; } - .aside .toggle_aside { -display:block; -height:50px; -line-height:50px; -text-align:right; -padding-right:10px; -background:#22303d +display: block; +height: 50px; +line-height: 50px; +text-align: right; +padding-right: 10px; +background: #22303d; } - .aside.aside_feed { -padding:0 +padding: 0; } - .aside:target { -width:78% +width: 78%; } .nav_menu { -position:initial; -height:71px +position: initial; +height: 71px; } - .nav_menu .btn { -margin:5px 10px +margin: 5px 10px; } - .nav_menu .stick { -margin:0 10px +margin: 0 10px; } - .nav_menu .stick .btn { -margin:5px 0 +margin: 5px 0; } - .nav_menu .search { -position:absolute!important; -top:35px; -left:55px +position: absolute !important; +top: 35px; +left: 55px; } - .nav_menu .search input { -width:85% +width: 85%; } .pagination { -margin:0 0 3.5em +margin: 0 0 3.5em; } #panel .close { -display:block; -height:50px; -line-height:50px; -text-align:right; -padding-right:10px; -background:#22303d +display: block; +height: 50px; +line-height: 50px; +text-align: right; +padding-right: 10px; +background: #22303d; } .day .name { -font-size:1.1rem +font-size: 1.1rem; } .notification { -width:100% +width: 100%; } - .notification a.close { -display:block; -left:0; -background:transparent +display: block; +left: 0; +background: transparent; } - .notification a.close:hover { -opacity:.5 +opacity: 0.5; } - .notification a.close .icon { -display:none +display: none; } #nav_entries { -width:100%!important +width: 100% !important; } div#stream { -margin-top:0 +margin-top: 0px; } a.btn.toggle_aside { -position:absolute; -top:29px +position: absolute; +top: 29px; } -form#mark-read-menu,a#actualize,a#toggle-order,div#nav_menu_actions,div#nav_menu_views { -position:absolute +form#mark-read-menu, a#actualize, a#toggle-order, div#nav_menu_actions, div#nav_menu_views { +position: absolute; } form#mark-read-menu { -right:46px; -top:30px; -z-index:1100 +right: 46px; +top: 30px; +z-index: 1100; } -a#actualize,a#toggle-order { -right:0 +a#actualize, a#toggle-order { +right: 0px; } a#actualize { -top:29px +top: 29px; } -a#toggle-order,div#nav_menu_actions,div#nav_menu_views { -top:65px +a#toggle-order, div#nav_menu_actions, div#nav_menu_views { +top: 65px; } div#nav_menu_actions { -left:0 +left: 0px; } div#nav_menu_views { -right:50px +right: 50px; } } - @media (max-width: 410px) { .nav_menu .stick { -margin:0 +margin: 0; } } - @media (max-width: 374px) { #nav_menu_views { -display:none +display: none; } } - button.as-link { -color:#FCFCFC; -outline:none +color: #FCFCFC; +outline: none; } .dropdown-target:target ~ .btn.dropdown-toggle { -background:#00488b +background: #00488b; } .tree-folder.active .tree-folder-title { -background:#00488b; -font-weight:700 +background: #00488b; +font-weight: bold; } .feed.item.empty { -color:#FA8052 +color: #FA8052; } - .feed.item.empty.active { -background:#FA8052; -color:#FCFCFC +background: #FA8052; +color: #FCFCFC; } - .feed.item.empty.active > a { -color:#FCFCFC +color: #FCFCFC; } - .feed.item.empty > a { -color:#FA8052 +color: #FA8052; } - .feed.item.error { -color:#c46178 +color: #c46178; } - .feed.item.error.active { -background:#c46178; -color:#FCFCFC +background: #c46178; +color: #FCFCFC; } - .feed.item.error.active > a { -color:#FCFCFC +color: #FCFCFC; } - .feed.item.error > a { -color:#c46178 +color: #c46178; } #dropdown-query ~ .dropdown-menu .dropdown-header .icon { -vertical-align:middle; -float:right +vertical-align: middle; +float: right; } #stream.reader .flux { -padding:0 0 50px; -background:#FCFCFC; -color:#22303d; -border:none +padding: 0 0 50px; +background: #FCFCFC; +color: #22303d; +border: none; } - #stream.reader .flux .author { -margin:0 0 10px; -font-size:90%; -color:#969696 +margin: 0 0 10px; +font-size: 90%; +color: #969696; } -#nav_menu_actions ul.dropdown-menu,#nav_menu_read_all ul.dropdown-menu { -left:0 +#nav_menu_actions ul.dropdown-menu, #nav_menu_read_all ul.dropdown-menu { +left: 0px; } #slider label { -min-height:initial +min-height: initial; } - #slider .form-group:hover { -background:inital -} \ No newline at end of file +background: inital; +} diff --git a/p/themes/Swage/swage.scss b/p/themes/Swage/swage.scss index 9bd0326d9..b5d6c049e 100644 --- a/p/themes/Swage/swage.scss +++ b/p/themes/Swage/swage.scss @@ -12,6 +12,7 @@ $color_stared: #FFF6DA; $color_unread: #FFF3ED; $color_hover: #FFFFFF; + // @extend-elements %input { min-height: 25px; @@ -48,6 +49,10 @@ $color_hover: #FFFFFF; clear: both; } +%aside-width { + width: 231px; +} + // /@extend-elements html, body { @@ -66,6 +71,12 @@ a { background: darken( $color_nav, 10%); } } + &#btn-subscription { + width: 76%; + } + &#btn-importExport { + width: 5%; + } } img { @@ -205,6 +216,9 @@ form { .stick { vertical-align: middle; font-size: 0; + &.configure-feeds { + @extend %aside-width; + } } .btn { @@ -250,7 +264,7 @@ form { .item { @extend %nav-list; &:hover, - .active { + &.active { background: darken( $color_nav, 10%); color: $color_light; a { @@ -593,7 +607,7 @@ form { > .item { vertical-align: middle; &.title { - width: 231px; + @extend %aside-width; position: absolute; h1 { margin: 0; @@ -636,7 +650,7 @@ form { .aside { background: $color_aside; padding: 35px 0; - width: 231px; + @extend %aside-width; &.aside_feed { .tree { margin: 0 0 50px; @@ -678,6 +692,10 @@ form { font-size: 0.9em; input { background: darken( $color_light, 10% ); + &.long{ + height: 33px; + margin-top: 0px; + } } form { margin: 10px 0; @@ -713,7 +731,7 @@ form { bottom: 48px; z-index: 900; left: 0; - width: 231px; + @extend %aside-width; line-height: 1.5em; &:hover { background: darken( $color_nav, 10%); @@ -825,7 +843,7 @@ form { bottom: 48px; left: 0; top: auto; - width: 231px; + @extend %aside-width; height: auto; &.good, .bad { @@ -867,7 +885,7 @@ form { text-align: center; line-height: 3em; table-layout: fixed; - width: 231px; + @extend %aside-width; background: $color_aside; } -- cgit v1.2.3 From b790b160c4782405d3cec506a9775b3c4f1d8df1 Mon Sep 17 00:00:00 2001 From: Patrick Crandol Date: Sun, 28 Oct 2018 20:28:30 -0400 Subject: Add ID's to buttons in configure-feed Add ID's to be able to individually target buttons inside the configure feeds (Subscriptions Management & Import/Export) buttons. --- app/layout/aside_feed.phtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/layout/aside_feed.phtml b/app/layout/aside_feed.phtml index ce029cfa0..7b1645ebd 100644 --- a/app/layout/aside_feed.phtml +++ b/app/layout/aside_feed.phtml @@ -12,8 +12,8 @@
- - + +
-- cgit v1.2.3 From a02b1fb2a0e8da3d99bc54c73e3aa2a1a0100efa Mon Sep 17 00:00:00 2001 From: Patrick Crandol Date: Sun, 28 Oct 2018 23:24:15 -0400 Subject: Fix Dropdown being obscured by other elements increased z-index of dropdown-menu to prevent it from being obscured by other page elements --- p/themes/base-theme/template.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index b211d0516..273b3d07f 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -256,7 +256,7 @@ a.btn { } .dropdown-target:target ~ .dropdown-menu { display: block; - z-index: 10; + z-index: 1000; } .dropdown-close { display: inline; -- cgit v1.2.3 From 38e3f792a4e7702b6a479470c9f61f460309c981 Mon Sep 17 00:00:00 2001 From: Patrick Crandol Date: Tue, 30 Oct 2018 14:15:50 -0400 Subject: reallow items kept unread to be interactive (#2085) Remove .keep_unread from classes that do nothing. --- p/scripts/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p/scripts/main.js b/p/scripts/main.js index f96828048..92fa8db4c 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -752,7 +752,7 @@ function init_shortcuts() { function init_stream(divStream) { divStream.on('click', '.flux_header,.flux_content', function (e) { //flux_toggle - if ($(e.target).closest('.keep_unread, .content, .item.website, .item.link, .dropdown-menu').length > 0) { + if ($(e.target).closest('.content, .item.website, .item.link, .dropdown-menu').length > 0) { return; } if (!context.sides_close_article && $(e.target).is('div.flux_content')) { -- cgit v1.2.3 From 9b86671dc663380019b7aa288bfaafd5e75d94cc Mon Sep 17 00:00:00 2001 From: Patrick Crandol Date: Tue, 30 Oct 2018 18:12:05 -0400 Subject: Remove resizing of #bigMarkAsRead (#2094) Remove theme sizing to make scroll as read work per #1980 --- p/themes/Swage/swage.css | 1 - p/themes/Swage/swage.scss | 1 - 2 files changed, 2 deletions(-) diff --git a/p/themes/Swage/swage.css b/p/themes/Swage/swage.css index f8ff0189f..50b7aceb7 100644 --- a/p/themes/Swage/swage.css +++ b/p/themes/Swage/swage.css @@ -778,7 +778,6 @@ display: none; text-align: center; text-decoration: none; background: #e3e3e3; -padding: 20px !IMPORTANT; } #bigMarkAsRead:hover { background: #22303d; diff --git a/p/themes/Swage/swage.scss b/p/themes/Swage/swage.scss index b5d6c049e..69d863322 100644 --- a/p/themes/Swage/swage.scss +++ b/p/themes/Swage/swage.scss @@ -873,7 +873,6 @@ form { text-align: center; text-decoration: none; background: darken( $color_light, 10%); - padding: 20px !IMPORTANT; &:hover { background: $color_aside; color: $color_light; -- cgit v1.2.3 From 2dc3dd7223a087a8fa2692921e2941b99c08cdaf Mon Sep 17 00:00:00 2001 From: Quentí <33203663+Quenty31@users.noreply.github.com> Date: Sun, 4 Nov 2018 13:45:32 +0100 Subject: Update CREDITS.md (#2111) --- CREDITS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.md b/CREDITS.md index 9d3c07c0e..0923a9241 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -54,6 +54,7 @@ People are sorted by name so please keep this order. * [primaeval](https://github.com/primaeval): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:primaeval) * [purexo](https://github.com/purexo): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:purexo), [Web](https://purexo.mom/) * [Quentin Dufour](https://github.com/superboum): [contributions](https://github.com/FreshRSS/documentation/commits?author=superboum), [Web](http://quentin.dufour.io/) +* [Quentin Pagès]: [contributions](https://github.com/FreshRSS/documentation/commits?author=Quenty31) * [Ramón Cutanda](https://github.com/rcutanda): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:rcutanda) * [romibi](https://github.com/romibi): [contributions](https://github.com/FreshRSS/FreshRSS/commits/dev?author=romibi) * [sirideain](https://github.com/sirideain): [contributions](https://github.com/FreshRSS/FreshRSS/commits/dev?author=sirideain) -- cgit v1.2.3 From 396c714df9894ed053030d8a9daedcf95c397960 Mon Sep 17 00:00:00 2001 From: Quentí <33203663+Quenty31@users.noreply.github.com> Date: Sun, 4 Nov 2018 13:46:08 +0100 Subject: [i18n] Add the Occitan locale (#2110) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Create oc.php L27 : ajout de l’occitan * Create admin.php * Create conf.php * Create feedback.php * Create gen.php * Create index.php * Create install.php * Create sub.php * Delete conf.php * Create conf.php * Update gen.php * Update gen.php * Update gen.php * Update gen.php * Update gen.php * Update gen.php * Update gen.php * Update gen.php * Update gen.php * Update gen.php * Update gen.php * Update gen.php * Update gen.php * Update gen.php * Update oc.php * Update admin.php * Update conf.php * Update feedback.php * Update gen.php * Update index.php * Update install.php * Update sub.php * Update oc.php --- app/i18n/cz/gen.php | 1 + app/i18n/de/gen.php | 1 + app/i18n/en/gen.php | 1 + app/i18n/es/gen.php | 1 + app/i18n/fr/gen.php | 1 + app/i18n/he/gen.php | 1 + app/i18n/it/gen.php | 1 + app/i18n/kr/gen.php | 1 + app/i18n/nl/gen.php | 1 + app/i18n/oc/admin.php | 194 +++++++++++++++++++++++++++++++++++++++++++++++ app/i18n/oc/conf.php | 183 ++++++++++++++++++++++++++++++++++++++++++++ app/i18n/oc/feedback.php | 115 ++++++++++++++++++++++++++++ app/i18n/oc/gen.php | 194 +++++++++++++++++++++++++++++++++++++++++++++++ app/i18n/oc/index.php | 61 +++++++++++++++ app/i18n/oc/install.php | 124 ++++++++++++++++++++++++++++++ app/i18n/oc/sub.php | 84 ++++++++++++++++++++ app/i18n/pt-br/gen.php | 1 + app/i18n/ru/gen.php | 1 + app/i18n/tr/gen.php | 1 + app/i18n/zh-cn/gen.php | 1 + cli/i18n/ignore/oc.php | 56 ++++++++++++++ 21 files changed, 1024 insertions(+) create mode 100644 app/i18n/oc/admin.php create mode 100644 app/i18n/oc/conf.php create mode 100644 app/i18n/oc/feedback.php create mode 100644 app/i18n/oc/gen.php create mode 100644 app/i18n/oc/index.php create mode 100644 app/i18n/oc/install.php create mode 100644 app/i18n/oc/sub.php create mode 100644 cli/i18n/ignore/oc.php diff --git a/app/i18n/cz/gen.php b/app/i18n/cz/gen.php index b9a65f210..eab572be4 100644 --- a/app/i18n/cz/gen.php +++ b/app/i18n/cz/gen.php @@ -124,6 +124,7 @@ return array( 'it' => 'Italiano', 'kr' => '한국어', 'nl' => 'Nederlands', + 'oc' => 'Occitan', 'pt-br' => 'Português (Brasil)', 'ru' => 'Русский', 'tr' => 'Türkçe', diff --git a/app/i18n/de/gen.php b/app/i18n/de/gen.php index 617b2a494..935ab6a75 100644 --- a/app/i18n/de/gen.php +++ b/app/i18n/de/gen.php @@ -124,6 +124,7 @@ return array( 'it' => 'Italiano', 'kr' => '한국어', 'nl' => 'Nederlands', + 'oc' => 'Occitan', 'pt-br' => 'Português (Brasil)', 'ru' => 'Русский', 'tr' => 'Türkçe', diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index 9f7da55a5..9328a35ec 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -124,6 +124,7 @@ return array( 'it' => 'Italiano', 'kr' => '한국어', 'nl' => 'Nederlands', + 'oc' => 'Occitan', 'pt-br' => 'Português (Brasil)', 'ru' => 'Русский', 'tr' => 'Türkçe', diff --git a/app/i18n/es/gen.php b/app/i18n/es/gen.php index fe3d62e2d..35a01c02d 100755 --- a/app/i18n/es/gen.php +++ b/app/i18n/es/gen.php @@ -124,6 +124,7 @@ return array( 'it' => 'Italiano', 'kr' => '한국어', 'nl' => 'Nederlands', + 'oc' => 'Occitan', 'pt-br' => 'Português (Brasil)', 'ru' => 'Русский', 'tr' => 'Türkçe', diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php index 1e1cef590..34395a380 100644 --- a/app/i18n/fr/gen.php +++ b/app/i18n/fr/gen.php @@ -124,6 +124,7 @@ return array( 'it' => 'Italiano', 'kr' => '한국어', 'nl' => 'Nederlands', + 'oc' => 'Occitan', 'pt-br' => 'Português (Brasil)', 'ru' => 'Русский', 'tr' => 'Türkçe', diff --git a/app/i18n/he/gen.php b/app/i18n/he/gen.php index 26b8f99e6..64050dc4f 100644 --- a/app/i18n/he/gen.php +++ b/app/i18n/he/gen.php @@ -124,6 +124,7 @@ return array( 'it' => 'Italiano', 'kr' => '한국어', 'nl' => 'Nederlands', + 'oc' => 'Occitan', 'pt-br' => 'Português (Brasil)', 'ru' => 'Русский', 'tr' => 'Türkçe', diff --git a/app/i18n/it/gen.php b/app/i18n/it/gen.php index ab17441e7..200ce813a 100644 --- a/app/i18n/it/gen.php +++ b/app/i18n/it/gen.php @@ -124,6 +124,7 @@ return array( 'it' => 'Italiano', 'kr' => '한국어', 'nl' => 'Nederlands', + 'oc' => 'Occitan', 'pt-br' => 'Português (Brasil)', 'ru' => 'Русский', 'tr' => 'Türkçe', diff --git a/app/i18n/kr/gen.php b/app/i18n/kr/gen.php index 6a461bdac..f87f24b64 100644 --- a/app/i18n/kr/gen.php +++ b/app/i18n/kr/gen.php @@ -124,6 +124,7 @@ return array( 'it' => 'Italiano', 'kr' => '한국어', 'nl' => 'Nederlands', + 'oc' => 'Occitan', 'pt-br' => 'Português (Brasil)', 'ru' => 'Русский', 'tr' => 'Türkçe', diff --git a/app/i18n/nl/gen.php b/app/i18n/nl/gen.php index fdc4338c3..f18da5c36 100644 --- a/app/i18n/nl/gen.php +++ b/app/i18n/nl/gen.php @@ -124,6 +124,7 @@ return array( 'it' => 'Italiano', 'kr' => '한국어', 'nl' => 'Nederlands', + 'oc' => 'Occitan', 'pt-br' => 'Português (Brasil)', 'ru' => 'Русский', 'tr' => 'Türkçe', diff --git a/app/i18n/oc/admin.php b/app/i18n/oc/admin.php new file mode 100644 index 000000000..3bad14e7c --- /dev/null +++ b/app/i18n/oc/admin.php @@ -0,0 +1,194 @@ + array( + 'disabled' => 'Desactivada', + 'enabled' => 'Activada', + 'name' => 'Nom', + 'description' => 'Descripcion', + 'empty_list' => 'Cap d’extensions pas installadas', + 'no_configure_view' => 'Aquesta extension se pòt pas configurar.', + 'system' => array( + '_' => 'Extensions sistèma', + 'no_rights' => 'Extensions sistèma (contrarotlat per l’administrator)', + ), + 'title' => 'Extensions', + 'user' => 'Extensions utilizaire', + 'community' => 'Extensions utilizaires disponiblas', + 'version' => 'Version', + 'author' => 'Autor', + 'latest' => 'Installada', + 'update' => 'Mesa a jorn disponibla', + ), + 'stats' => array( + 'no_idle' => 'I a pas cap d’article inactiu !', + 'status_favorites' => 'Favorits', + 'status_read' => 'Legit', + '_' => 'Estatisticas', + 'all_feeds' => 'Totes los fluxes', + 'category' => 'Categoria', + 'entry_count' => 'Nombre d’articles', + 'entry_per_category' => 'Articles per categoria', + 'entry_per_day' => 'Nombre d’articles per jorn (30 darrièrs jorns)', + 'entry_per_day_of_week' => 'Per jorn de la setmana (mejana : %.2f messatges)', + 'entry_per_hour' => 'Per ora (mejana : %.2f messatges)', + 'entry_per_month' => 'Per mes (mejana : %.2f messatges)', + 'entry_repartition' => 'Reparticion dels articles', + 'feed' => 'Flux', + 'feed_per_category' => 'Fluxes per categoria', + 'idle' => 'Fluxes inactius', + 'main' => 'Estatisticas principalas', + 'main_stream' => 'Flux màger', + 'menu' => array( + 'idle' => 'Fluxes inactius', + 'main' => 'Estatisticas principalas', + 'repartition' => 'Reparticion dels articles', + ), + 'number_entries' => '%d articles', + 'percent_of_total' => '%% del total', + 'repartition' => 'Reparticion dels articles', + 'status_total' => 'Total', + 'status_unread' => 'Pas legits', + 'title' => 'Estatisticas', + 'top_feed' => 'Los dètz fluxes mai gròsses', + ), + 'system' => array( + '_' => 'Configuracion sistèma', + 'instance-name' => 'Nom de l’instància', + 'registration' => array( + 'number' => 'Nombre max de comptes', + 'help' => '0 vòl dire qu’i a pas cap de limita de compte', + ), + 'auto-update-url' => 'URL del servici de mesa a jorn', + 'max-categories' => 'Limita de categoria per utilizaire', + 'max-feeds' => 'Limita de fluxes per utilizaire', + ), + 'update' => array( + 'apply' => 'Aplicar', + 'none' => 'Cap d’actualizacion d’aplicar', + '_' => 'Sistèma de mesa a jorn', + 'check' => 'Verificar las mesas a jorn', + 'current_version' => 'Vòstra version actuala de FreshRSS es %s.', + 'last' => 'Darrièra verificacion : %s', + 'title' => 'Sistèma de mesa a jorn', + ), + 'user' => array( + 'delete_users' => 'Suprimir un utilizaire', + 'language' => 'Lenga', + 'password_format' => 'Almens 7 caractèrs', + 'selected' => 'Utilizaire seleccionat', + 'username' => 'Nom d’utilizaire', + 'users' => 'Utilizaires', + 'articles_and_size' => '%s articles (%s)', + 'create' => 'Crear un nòu utilizaire', + 'number' => '%d compte ja creat', + 'numbers' => '%d comptes ja creats', + 'password_form' => 'Senhal
(ex. : per la connexion via formulari)', + 'title' => 'Gestion dels utilizaires', + 'update_users' => 'Actualizar un utilizaire', + 'user_list' => 'Lista dels utilizaires', + ), + 'auth' => array( + 'none' => 'Cap (perilhós)', + 'allow_anonymous' => 'Autorizar la lectura anonima dels articles de l’utilizaire per defaut (%s)', + 'allow_anonymous_refresh' => 'Autorizar l’actualizacion anonime dels fluxes', + 'api_enabled' => 'Autorizar l’accès per API(necessari per las aplicacions mobil)', + 'form' => 'Formulari (tradicional, demanda JavaScript)', + 'http' => 'HTTP (per utilizaires avançats amb HTTPS)', + 'title' => 'Autentificacion', + 'title_reset' => 'Reïnicializacion de l’autentificacion', + 'token' => 'Geton d’autentificacion', + 'token_help' => 'Permetre l’accès a la sortida RSS de l’utilizaire per defaut sens cap d’autentificacion :', + 'type' => 'Mòde d’autentification', + 'unsafe_autologin' => 'Autorizar las connexions automaticas pas seguras al format : ', + ), + 'check_install' => array( + 'cache' => array( + 'nok' => 'Volgatz verificar los dreches sul repertòri ./data/cache. Lo servidor HTTP deu poder escriure dedins', + 'ok' => 'Los dreches sul cache son bons.', + ), + 'categories' => array( + 'nok' => 'La tabla “category” es mala configurada.', + 'ok' => 'La tabla category es corrèctament configurada.', + ), + 'connection' => array( + 'nok' => 'Connexion impossibla a la basa de donadas.', + 'ok' => 'La connexion a la basa de donadas es bona.', + ), + 'ctype' => array( + 'nok' => 'Impossible de trobar una bibliotèca per la verificacion del tipe de caractèrs (php-ctype).', + 'ok' => 'Avètz la bibliotèca per la verificacion del tipe de caractèrs (ctype).', + ), + 'curl' => array( + 'nok' => 'Impossible de trobar la bibliotèca cURL( paquet php-curl).', + 'ok' => 'Avètz la bibliotèca cURL.', + ), + 'data' => array( + 'nok' => 'Volgatz verificar los dreches sul repertòri ./data. Lo servidor HTTP deu poder escriure dedins', + 'ok' => 'Los dreches sul repertòri data son bons.', + ), + 'database' => 'Installacion de la basa de donadas', + 'dom' => array( + 'nok' => 'Impossible de trobar una bibliotèca per percórrer lo DOM (paquet php-xml).', + 'ok' => 'Avètz la bibliotèca per percórrer lo DOM.', + ), + 'entries' => array( + 'nok' => 'La tabla entry es pas configurada coma cal.', + 'ok' => 'La tabla entry es corrèctament configurada.', + ), + 'favicons' => array( + 'nok' => 'Volgatz verificar los dreches sul repertòri ./data/favicons. Lo servidor HTTP deu poder escriure dedins', + 'ok' => 'Los dreches sul repertòri dels favicons son bons.', + ), + 'feeds' => array( + 'nok' => 'La tabla feed es pas configurada coma cal.', + 'ok' => 'La tabla feed es corrèctament configurada.', + ), + 'fileinfo' => array( + 'nok' => 'Avètz pas PHP fileinfo (paquet fileinfo).', + 'ok' => 'Avètz la bibliotèca fileinfo.', + ), + 'files' => 'Installacion dels fichièrs', + 'json' => array( + 'nok' => 'Avètz pas l’extension recomandada JSON (paquet php-json).', + 'ok' => 'Avètz l’exension recomandada JSON.', + ), + 'mbstring' => array( + 'nok' => 'Impossible de trobar la bibliotèca recomandada mbstring per Unicode.', + 'ok' => 'Avètz la bibliotèca recomandada mbstring per Unicode.', + ), + 'minz' => array( + 'nok' => 'Avètz pas la bibliotèca Minz.', + 'ok' => 'Avètz la bibliotèca Minz.', + ), + 'pcre' => array( + 'nok' => 'Impossible de trobar una bibliotèca per las expressions regulara (php-pcre).', + 'ok' => 'Avètz la bibliotèca per las expressions regularas (PCRE).', + ), + 'pdo' => array( + 'nok' => 'Impossible de trobar PDO o un dels drivers compatibles (pdo_mysql, pdo_sqlite, pdo_pgsql).', + 'ok' => 'Avètz PDO e almens un des drivers compatibles (pdo_mysql, pdo_sqlite, pdo_pgsql).', + ), + 'php' => array( + '_' => 'Installacion PHP', + 'nok' => 'Vòstra version PHP es la %s más FreshRSS demanda almens la versión %s.', + 'ok' => 'Vòstra version PHP es %s, qu’es compatibla amb FreshRSS.', + ), + 'tables' => array( + 'nok' => 'Manca una o mai tabla dins la basa de donadas.', + 'ok' => 'Las tablas que cal existisson ben dins la basa de donadas.', + ), + 'title' => 'Verificacion de l’installacion', + 'tokens' => array( + 'nok' => 'Volgatz verificar los dreches sul repertòri ./data/tokens. Lo servidor HTTP deu poder escriure dedins', + 'ok' => 'Los dreches sul repertòri dels getons son bons.', + ), + 'users' => array( + 'nok' => 'Volgatz verificar los dreches sul repertòri ./data/users. Lo servidor HTTP deu poder escriure dedins', + 'ok' => 'Los dreches sul repertòri dels utilizaires son bons.', + ), + 'zip' => array( + 'nok' => 'Avètz pas l’extension ZIP (paquet php-zip).', + 'ok' => 'Avètz l’exension ZIP.', + ), + ), +); diff --git a/app/i18n/oc/conf.php b/app/i18n/oc/conf.php new file mode 100644 index 000000000..7b297805d --- /dev/null +++ b/app/i18n/oc/conf.php @@ -0,0 +1,183 @@ + array( + 'users' => 'Utilizaires', + 'articles_and_size' => '%s articles (%s)', + 'current' => 'Utilizaire actual', + 'is_admin' => 'es administrator', + ), + 'archiving' => array( + '_' => 'Archivar', + 'advanced' => 'Avançat', + 'delete_after' => 'Levar los articles aprèp', + 'help' => 'Mai d’opcions son disponiblas dins la configuracion individuala dels fluxes', + 'keep_history_by_feed' => 'Nombre minimum d’articles de servar per flux', + 'optimize' => 'Optimizar la basa de donada', + 'optimize_help' => 'De far de temps en temps per redusir la talha de la basa de donadas', + 'purge_now' => 'Purgar ara', + 'title' => 'Archivar', + 'ttl' => 'Actualizar pas automaticament mai sovent que', + ), + 'display' => array( + '_' => 'Afichatge', + 'icon' => array( + 'bottom_line' => 'Linha enbàs', + 'entry' => 'Icònas d’article', + 'publication_date' => 'Data de publicacion', + 'related_tags' => 'Etiquetas ligadas', + 'sharing' => 'Partatge', + 'top_line' => 'Linha amont', + ), + 'language' => 'Lenga', + 'notif_html5' => array( + 'seconds' => 'segondas (0 significa cap de timeout)', + 'timeout' => 'Temps d’afichatge de las notificacions HTML5', + ), + 'theme' => 'Tèma', + 'title' => 'Afichatge', + 'width' => array( + 'content' => 'Largor del contengut', + 'large' => 'Larga', + 'medium' => 'Mejana', + 'no_limit' => 'Cap de limit', + 'thin' => 'Fina', + ), + 'show_nav_buttons' => 'Mostrar los botons de navigacion', + ), + 'query' => array( + '_' => 'Filtres utilizaires', + 'deprecated' => 'Aqueste filtre es pas valid. La categoria o lo flux concernit es estat suprimit.', + 'display' => 'Mostrar los resultats del filtre', + 'filter' => 'Filtres aplicats :', + 'get_all' => 'Mostrar totes los articles', + 'get_category' => 'Mostrar la categoria « %s »', + 'get_favorite' => 'Mostrar los articles favorits', + 'get_feed' => 'Mostrar lo flux « %s »', + 'no_filter' => 'Cap de filtre aplicat', + 'none' => 'Avètz pas encara creat cap de filtre.', + 'number' => 'Filtre n°%d', + 'order_asc' => 'Mostrar los articles mai ancians en primièr', + 'order_desc' => 'Mostrar los articles mai recents en primièr', + 'remove' => 'Levar lo filtre utilizaire', + 'search' => 'Recèrca de « %s »', + 'state_0' => 'Mostrar totes los articles', + 'state_1' => 'Mostrar los articles pas legits', + 'state_2' => 'Mostrar los articles pas legits', + 'state_3' => 'Mostrar totes los articles', + 'state_4' => 'Mostrar los articles favorits', + 'state_5' => 'Mostrar los articles legits e en favorits', + 'state_6' => 'Mostrar los articles pas legits e en favorit', + 'state_7' => 'Mostrar los articles favorits', + 'state_8' => 'Mostrar los articles pas en favorit', + 'state_9' => 'Mostrar los articles legits e pas en favorit', + 'state_10' => 'Mostrar los articles pas legits e pas en favorit', + 'state_11' => 'Mostrar los articles pas en favorit', + 'state_12' => 'Mostrar totes los articles', + 'state_13' => 'Mostrar los articles legits', + 'state_14' => 'Mostrar los articles pas legits', + 'state_15' => 'Mostrar totes los articles', + 'title' => 'Filtres utilizaire', + ), + 'profile' => array( + '_' => 'Gestion del perfil', + 'delete' => array( + '_' => 'Supression del compte', + 'warn' => 'Lo compte e totas las donadas ligadas seràn suprimits.', + ), + 'password_api' => 'Senhal API
(ex. : per las aplicacions mobil)', + 'password_form' => 'Senhal API
(ex. : per la connexion via formulari)', + 'password_format' => 'Almens 7 caractèrs', + 'title' => 'Pefil', + ), + 'reading' => array( + '_' => 'Lectura', + 'after_onread' => 'Aprèp « marcar coma legit »,', + 'articles_per_page' => 'Nombre d’articles per pagina', + 'auto_load_more' => 'Cargar los articles seguents enbàs de la pagina', + 'auto_remove_article' => 'Rescondre los articles aprèp lectura', + 'mark_updated_article_unread' => 'Marcar los articles actualizats coma pas legits', + 'confirm_enabled' => 'Mostrar una confirmacion per las accions del tipe « o marcar tot coma legit »', + 'display_articles_unfolded' => 'Mostrar los articles desplegats per defaut', + 'display_categories_unfolded' => 'Mostrar las categorias plegadas per defaut', + 'hide_read_feeds' => 'Rescondre las categorias & fluxes sens articles pas legits (fonciona pas amb la configuracion « Mostrar totes los articles »)', + 'img_with_lazyload' => 'Utilizar lo mòde “cargament tardiu” per las imatges', + 'sides_close_article' => 'Clicar fòra de la zòna de tèxte tampa l’article', + 'jump_next' => 'sautar al vesin venent pas legit (flux o categoria)', + 'number_divided_when_reader' => 'Devisat per 2 dins la vista de lectura.', + 'read' => array( + 'article_open_on_website' => 'quand l’article es dobèrt sul site d’origina', + 'article_viewed' => 'quand l’article es mostrat', + 'scroll' => 'en davalant la pagina', + 'upon_reception' => 'en recebre un article novèl', + 'when' => 'Marcar un article coma legit…', + ), + 'show' => array( + '_' => 'Articles de mostrar', + 'adaptive' => 'Adaptar l’afichatge', + 'all_articles' => 'Mostrar totes los articles', + 'unread' => 'Mostrar pas que los pas legits', + ), + 'sort' => array( + '_' => 'Òrdre de tria', + 'newer_first' => 'Mai recents en primièr', + 'older_first' => 'Mai ancians en primièr', + ), + 'title' => 'Lectura', + 'view' => array( + 'default' => 'Vista per defaut', + 'global' => 'Vista generala', + 'normal' => 'Vista normala', + 'reader' => 'Vista lectura', + ), + 'sticky_post' => 'Gardar l\'article amont quand es dobèrt', + ), + 'sharing' => array( + '_' => 'Partatge', + 'add' => 'Ajustar un metòde de partatge', + 'blogotext' => 'Blogotext', + 'diaspora' => 'Diaspora*', + 'email' => 'Corrièl', + 'facebook' => 'Facebook', + 'g+' => 'Google+', + 'more_information' => 'Mai d’informacions', + 'print' => 'Imprimir', + 'remove' => 'Suprimir lo metòde de partatge', + 'shaarli' => 'Shaarli', + 'share_name' => 'Nom del partatge de mostrar', + 'share_url' => 'URL del partatge d’utilizar', + 'title' => 'Partatge', + 'twitter' => 'Twitter', + 'wallabag' => 'wallabag', + ), + 'shortcut' => array( + '_' => 'Acorchis', + 'auto_share' => 'Partejar', + 'close_dropdown' => 'Tampar los menús', + 'collapse_article' => 'Replegar', + 'first_article' => 'Passar al primièr article', + 'focus_search' => 'Accedir a la recèrca', + 'mark_read' => 'Marcar coma legit', + 'mark_favorite' => 'Ajustar als favorits', + 'navigation' => 'Navigacion', + 'other_action' => 'Autras accions', + 'title' => 'Acorchis', + 'views' => 'Vistas', + 'article_action' => 'Accions ligadas a l\'article', + 'auto_share_help' => 'S’i a pas qu\'un mòde de partatge, aquel serà utilizat. Autrament los mòdes son accessibles per lor numèro.', + 'global_view' => 'Passar a la vista generala', + 'help' => 'Mostrar la documentacion', + 'javascript' => 'Devètz activar lo Javascript per utilizar los acorchis', + 'last_article' => 'Passar al darrièr article', + 'load_more' => 'Cargar mai d’articles', + 'navigation_help' => 'Amb lo modificador «Shift», los acorchis de navigacion s’aplican als fluxes.
Amb lo modificador «Alt», los acorchis de navigacion s’aplican a las categorias.', + 'next_article' => 'Passar a l’article seguent', + 'normal_view' => 'Passar a la vista normala', + 'previous_article' => 'Passar a l’article precedent', + 'reading_view' => 'Passar a la vista lectura', + 'rss_view' => 'Dobrir la vista RSS dins un onglet novèl', + 'see_on_website' => 'Veire al site d’origina', + 'shift_for_all_read' => '+ shift per marcar los articles coma legits', + 'user_filter' => 'Accedir als filtres utilizaire', + 'user_filter_help' => 'S’i a pas qu’un filtre utilizaire, aquel serà utilizat. Autrament los filtres son accessibles per lor numèro.', + ), +); diff --git a/app/i18n/oc/feedback.php b/app/i18n/oc/feedback.php new file mode 100644 index 000000000..225be119b --- /dev/null +++ b/app/i18n/oc/feedback.php @@ -0,0 +1,115 @@ + array( + 'optimization_complete' => 'Optimizacion acabada', + ), + 'access' => array( + 'denied' => 'Avètz pas l’autorizacion d’accedir a aquesta pagina', + 'not_found' => 'La pagina que cercatz existís pas', + ), + 'auth' => array( + 'form' => array( + 'not_set' => 'Un problèma es aparegut pendent la configuracion del sistèma d’autentificacion. Tonatz ensajar ai tard.', + 'set' => 'Lo sistèma d’autentificacion per defaut es ara lo formulari.', + ), + 'login' => array( + 'invalid' => 'L’identificant es invalid', + 'success' => 'Sètz connectat', + ), + 'logout' => array( + 'success' => 'Sètz desconnectat', + ), + 'no_password_set' => 'Pas de senhal es pas configurat. Aquesta foncionalitat es pas disponibla.', + ), + 'conf' => array( + 'error' => 'Una error es apareguda pendent la salvagarda de la configuracion', + 'query_created' => 'Lo filtre « %s » es estat creat.', + 'shortcuts_updated' => 'Los acorchis son actualizats', + 'updated' => 'La configuracion es estada actualizada', + ), + 'extensions' => array( + 'already_enabled' => '%s es ja activada', + 'disable' => array( + 'ko' => '%s pòt pas èsser desactivada. Consultatz los jornals d’audit de FreshRSS logs per mai de detalhs.', + 'ok' => '%s es ara desactivada', + ), + 'enable' => array( + 'ko' => '%s pòt pas èsser activada. Consultatz los jornals d’audit de FreshRSS logs per mai de detalhs.', + 'ok' => '%s es ara activada', + ), + 'no_access' => 'Avètz pas accès sus %s', + 'not_enabled' => '%s es pas encara activada', + 'not_found' => '%s existís pas', + ), + 'import_export' => array( + 'export_no_zip_extension' => 'L\'extension ZIP es pas presenta sul servidor. Volgatz ensajar d\'exportar los fichièrs un per un.', + 'feeds_imported' => 'Vòstres fluxes son estats importats seràn actualizats en seguida', + 'feeds_imported_with_errors' => 'Vòstres fluxes son estats importats mas i a agut d’errors', + 'file_cannot_be_uploaded' => 'Telecargament del fichièr impossible', + 'no_zip_extension' => 'L\'extension es pas presenta sul servidor.', + 'zip_error' => 'Una error s’es producha pendent l’importacion del fichièr ZIP.', + ), + 'sub' => array( + 'actualize' => 'Actualizar', + 'articles' => array( + 'marked_read' => 'Los articles seleccionats son estats marcats coma legits.', + 'marked_unread' => 'Los articles seleccionats son estats marcats coma pas legits.', + ), + 'category' => array( + 'created' => 'La categoria « %s » es estada creada.', + 'deleted' => 'La categoria es estada suprimida.', + 'emptied' => 'La categoria es estada voidada', + 'error' => 'Actualizacion de la categoria impossibla', + 'name_exists' => 'Una categoria se ditz ja atal.', + 'no_id' => 'Vos cal precisar l’id de la categoria.', + 'no_name' => 'Vos cal donar un nom a la categoria.', + 'not_delete_default' => 'Podètz pas suprimir la categoria per defaut !', + 'not_exist' => 'Aquesta categoria existís pas !', + 'over_max' => 'Avètz atengut la limita de categoria (%d)', + 'updated' => 'La categoria es estada actualizada.', + ), + 'feed' => array( + 'actualized' => '%s es a jorn', + 'actualizeds' => 'Los fluxes son estats actualizats', + 'added' => 'Lo flux RSS %s es ajustat', + 'already_subscribed' => 'Seguissètz ja %s', + 'deleted' => 'Lo flux es suprimit', + 'error' => 'Error en actualizar', + 'internal_problem' => 'Lo flux pòt pas èsser ajustat. Consultatz los jornals d’audit de FreshRSS per ne saber mai. Podètz forçar l’apondon en ajustant #force_feed a l’URL.', + 'invalid_url' => 'L\'URL %s es invalida', + 'n_actualized' => '%s fluxes son estats actualizats', + 'n_entries_deleted' => '%d articles son estats suprimits', + 'no_refresh' => 'I a pas cap de flux d’actualizar…', + 'not_added' => '%s a pas pogut èsser ajustat', + 'over_max' => 'Avètz atengut vòstra limita de fluxes (%d)', + 'updated' => 'Lo flux es actualizat', + ), + 'purge_completed' => 'Purga realizada (%s articles suprimits)', + ), + 'update' => array( + 'can_apply' => 'FreshRSS es per èsser mes a jorn en version %s.', + 'error' => 'La mesa a jorn a conegut un problèma : %s', + 'file_is_nok' => 'Nòva version %s disponibla, mas volgatz verificar los dreches sul repertòri %s. Lo servidor HTTP deu poder escriure dedins', + 'finished' => 'Mesa a jorn acabada !', + 'none' => 'Cap de mesa a jorn d’aplicar', + 'server_not_found' => 'Impossible de trobar lo servidor de mesa a jorn. [%s]', + ), + 'user' => array( + 'created' => array( + '_' => 'L’utilizaire %s es estat creat', + 'error' => 'L’utilizaire %s pòt pas èsser creat', + ), + 'deleted' => array( + '_' => 'L’utilizaire %s es estat suprimit', + 'error' => 'L’utilizaire %s pòt pas èsser suprimit', + ), + 'updated' => array( + '_' => 'L’utilizaire %s es estat actualizat', + 'error' => 'L’utilizaire %s es pas estat actualizat', + ), + ), + 'profile' => array( + 'error' => 'Impossible d’actualizar vòstre perfil', + 'updated' => 'Vòstre perfil es estat actualizat', + ), +); diff --git a/app/i18n/oc/gen.php b/app/i18n/oc/gen.php new file mode 100644 index 000000000..cdeb43807 --- /dev/null +++ b/app/i18n/oc/gen.php @@ -0,0 +1,194 @@ + array( + 'cancel' => 'Anullar', + 'disable' => 'Desactivar', + 'enable' => 'Activar', + 'filter' => 'Filtre', + 'import' => 'Importar', + 'submit' => 'Mandar', + 'actualize' => 'Actualizar', + 'back_to_rss_feeds' => '← Tornar a vòstres fluxes RSS', + 'create' => 'Crear', + 'empty' => 'Voidar', + 'export' => 'Exportar', + 'manage' => 'Gerir', + 'mark_favorite' => 'Ajustar als favorits', + 'mark_read' => 'Marcar coma legit', + 'remove' => 'Levar', + 'see_website' => 'Veire lo site', + 'truncate' => 'Suprimir totes los articles', + 'update' => 'Actualizar', + ), + 'auth' => array( + 'email' => 'Adreça de corrièl', + 'logout' => 'Se desconnectar', + 'password' => array( + '_' => 'Senhal', + 'format' => 'Almens 7 caractèrs', + ), + 'username' => array( + '_' => 'Nom d’utilizaire', + 'admin' => 'Nom d’utilizaire administrator', + 'format' => '16 caractèrs alfanumerics maximum)', + ), + 'keep_logged_in' => 'Demorar connectat (%s jorns) ', + 'login' => 'Connexion', + 'registration' => array( + '_' => 'Compte nòu', + 'ask' => 'Crear un compte?', + 'title' => 'Creacion de compte', + ), + 'reset' => 'Reïnicializacion de l’autentificacion', + ), + 'menu' => array( + 'about' => 'A prepaus', + 'admin' => 'Administracion', + 'configuration' => 'Configuracion', + 'user_profile' => 'Perfil', + 'queries' => 'Filtres utilizaire', + 'stats' => 'Estatisticas', + 'archiving' => 'Archivar', + 'authentication' => 'Autentificacion', + 'check_install' => 'Verificacion de l’installacion', + 'display' => 'Afichatge', + 'extensions' => 'Extensions', + 'logs' => 'Jornals d’audit', + 'reading' => 'Lectura', + 'search' => 'Recercar de mots o d’#etiquetas', + 'sharing' => 'Partatge', + 'shortcuts' => 'Acorchis', + 'system' => 'Configuracion sistèma', + 'update' => 'Mesa a jorn', + 'user_management' => 'Gestion dels utilizaires', + ), + 'pagination' => array( + 'next' => 'Seguent', + 'previous' => 'Precedent', + 'first' => 'Debuta', + 'last' => 'Fin', + 'load_more' => 'Cargar mai d’articles', + 'mark_all_read' => 'O marcar tot coma legit', + 'nothing_to_load' => 'I a pas mai d’articles', + ), + 'share' => array( + 'email' => 'Corrièl', + 'mastodon' => 'Mastodon', + 'blogotext' => 'Blogotext', + 'diaspora' => 'Diaspora*', + 'facebook' => 'Facebook', + 'g+' => 'Google+', + 'gnusocial' => 'GNU social', + 'jdh' => 'Journal du hacker', + 'Known' => 'Sites basats sus Known', + 'linkedin' => 'LinkedIn', + 'movim' => 'Movim', + 'pocket' => 'Pocket', + 'print' => 'Imprimir', + 'shaarli' => 'Shaarli', + 'twitter' => 'Twitter', + 'wallabag' => 'wallabag v1', + 'wallabagv2' => 'wallabag v2', + ), + 'short' => array( + 'no' => 'Non', + 'yes' => 'Òc', + 'attention' => 'Atencion !', + 'blank_to_disable' => 'Daissar void per desactivar', + 'by_author' => 'Per %s', + 'by_default' => 'Per defaut', + 'damn' => 'Zut !', + 'default_category' => 'Pas triat', + 'not_applicable' => 'Pas disponible', + 'ok' => 'Òc-ben !', + 'or' => 'o', + ), + 'date' => array( + 'Apr' => 'a\b\r\i\a\l', + 'Aug' => 'a\g\o\s\t', + 'Dec' => '\d\e\c\e\m\b\r\e', + 'Feb' => 'f\e\b\r\i\è\r', + 'Jan' => 'g\e\n\i\è\r', + 'Jul' => 'j\u\l\h\e\t', + 'Jun' => 'j\u\n\h', + 'Mar' => 'm\a\r\ç', + 'May' => '\m\a\i', + 'Nov' => '\n\o\v\e\m\b\r\e', + 'Oct' => '\o\c\t\ò\b\r\e', + 'Sep' => '\s\e\t\e\m\b\r\e', + 'apr' => 'abr.', + 'april' => 'abrial', + 'aug' => 'agost', + 'august' => 'agost', + 'before_yesterday' => 'Abans ièr', + 'dec' => 'dec.', + 'december' => 'decembre', + 'feb' => 'feb.', + 'february' => 'febrièr', + 'format_date' => 'j %s \de\ Y', + 'format_date_hour' => 'j %s \de\ Y \a H\:i', + 'fri' => 'dv', + 'jan' => 'gen.', + 'january' => 'genièr', + 'jul' => 'julh', + 'july' => 'julhet', + 'jun' => 'junh', + 'june' => 'junh', + 'last_3_month' => 'Dempuèi los tres darrièrs meses', + 'last_6_month' => 'Dempuèi los sièis darrièrs meses', + 'last_month' => 'Dempuèi lo mes passat', + 'last_week' => 'Dempuèi la setmana passada', + 'last_year' => 'Dempuèi l’annada passada', + 'mar' => 'març', + 'march' => 'març', + 'may' => 'mai', + 'may_' => 'mai', + 'mon' => 'dl', + 'month' => 'meses', + 'nov' => 'nov.', + 'november' => 'novembre', + 'oct' => 'oct.', + 'october' => 'octòbre', + 'sat' => 'ds', + 'sep' => 'set.', + 'september' => 'setembre', + 'sun' => 'dg', + 'thu' => 'dj', + 'today' => 'Uèi', + 'tue' => 'dm', + 'wed' => 'Dc', + 'yesterday' => 'Ièr', + ), + 'freshrss' => array( + '_' => 'FreshRSS', + 'about' => 'A prepaus de FreshRSS', + ), + 'js' => array( + 'category_empty' => 'Categoria voida', + 'confirm_action' => 'Volètz vertadièrament contunhar ? Aquesta accion se pòt pas anullar !', + 'confirm_action_feed_cat' => 'Volètz vertadièrament contunhar ? Perdretz los favorits e filtres ligats. Aquesta accion se pòt pas anullar !', + 'feedback' => array( + 'body_new_articles' => 'I a %%d nòus articles per legir sus FreshRSS.', + 'request_failed' => 'Una requèsta a fach meuca, aquò pòt venir d’un problèma de connexion Internet.', + 'title_new_articles' => 'FreshRSS : nòus articles !', + ), + 'new_article' => 'I a d’articles nòus disponibles, clicatz per actualizar la página.', + 'should_be_activated' => 'JavaScript deu èsser activat', + ), + 'lang' => array( + 'cz' => 'Čeština', + 'de' => 'Deutsch', + 'en' => 'English', + 'es' => 'Español', + 'fr' => 'Français', + 'he' => 'עברית', + 'it' => 'Italiano', + 'kr' => '한국어', + 'nl' => 'Nederlands', + 'oc' => 'Occitan', + 'pt-br' => 'Português (Brasil)', + 'ru' => 'Русский', + 'tr' => 'Türkçe', + 'zh-cn' => '简体中文', + ), +); diff --git a/app/i18n/oc/index.php b/app/i18n/oc/index.php new file mode 100644 index 000000000..934e19dea --- /dev/null +++ b/app/i18n/oc/index.php @@ -0,0 +1,61 @@ + array( + '_' => 'A prepaus', + 'title' => 'A prepaus', + 'website' => 'Site internet', + 'agpl3' => 'AGPL 3', + 'bugs_reports' => 'Senhalament de problèmas', + 'credits' => 'Crèdits', + 'credits_content' => 'Unes elements de l’estil venon del projècte Bootstrap encara que FreshRSS utilize pas aqueste framework. Lasicònas venon del projècte GNOME. La polissa Open Sans utilizada foguèt creada per en Steve Matteson. FreshRSS es basat sus Minz, un framework PHP.', + 'freshrss_description' => 'FreshRSS es un agregador de fluxes RSS per l’auto-albergar tal coma Kriss Feed o Leed. Sa tòca es d’èsser leugièr e de bon utilizar de prima abòrd mas tanben d’èsser potent e parametrable.', + 'github' => 'on Github', + 'license' => 'Licéncia', + 'project_website' => 'Site del projècte', + 'version' => 'Version', + ), + 'menu' => array( + 'search_short' => 'Recercar', + 'about' => 'A prepaus de FreshRSS', + 'add_query' => 'Crear un filtre', + 'before_one_day' => '1 jorn en arrièr', + 'before_one_week' => '1 setmana en arrièr', + 'favorites' => 'Favorits (%s)', + 'global_view' => 'Vista generala', + 'main_stream' => 'Flux màger', + 'mark_all_read' => 'O marcar tot coma legit', + 'mark_cat_read' => 'Marcar la categoria coma legida', + 'mark_feed_read' => 'Marcar lo flux coma legit', + 'mark_selection_unread' => 'Marcar la seleccion coma pas legida', + 'newer_first' => 'Mai recents en primièr', + 'non-starred' => 'Mostrar los pas favorits', + 'normal_view' => 'Vista normala', + 'older_first' => 'Mai ancians en primièr', + 'queries' => 'Filtres utilizaire', + 'read' => 'Mostrar los legits', + 'reader_view' => 'Vista lectura', + 'rss_view' => 'Flux RSS', + 'starred' => 'Mostrar los favorits', + 'stats' => 'Estatisticas', + 'subscription' => 'Gestion dels abonaments', + 'unread' => 'Mostar los pas legits', + ), + 'share' => 'Partejar', + 'feed' => array( + 'add' => 'Podètz ajustar de fluxes.', + 'empty' => 'I a pas cap de flux de mostrar.', + 'rss_of' => 'Flux RSS de %s', + 'title' => 'Vòstres fluxes RSS', + 'title_global' => 'Vista generala', + 'title_fav' => 'Vòstres favorits', + ), + 'log' => array( + '_' => 'Jornals d’audit', + 'clear' => 'Escafar los jornals', + 'empty' => 'Los jornals son voids', + 'title' => 'Jornals d’audit', + ), + 'tag' => array( + 'related' => 'Etiquetas ligadas', + ), +); diff --git a/app/i18n/oc/install.php b/app/i18n/oc/install.php new file mode 100644 index 000000000..52b56b4ec --- /dev/null +++ b/app/i18n/oc/install.php @@ -0,0 +1,124 @@ + array( + '_' => 'Lenga', + 'choose' => 'Causissètz la lenga per FreshRSS', + 'defined' => 'La lenga es corrèctament definida.', + ), + 'action' => array( + 'finish' => 'Acabar l’installacion', + 'fix_errors_before' => 'Mercés de corregir las errors seguentas abans de contunhar.', + 'keep_install' => 'Gardar la configuracion precedenta', + 'next_step' => 'Anar a l’estapa seguenta', + 'reinstall' => 'Reïnstallar FreshRSS', + ), + 'auth' => array( + 'form' => 'Formulari (tradicional, demanda JavaScript)', + 'http' => 'HTTP (per utilizaires avançats amb HTTPS)', + 'none' => 'Cap (perilhós)', + 'password_form' => 'Senhal API
(ex. : per la connexion via formulari)', + 'password_format' => 'Almens 7 caractèrs', + 'type' => 'Mòde d’autentification', + ), + 'bdd' => array( + '_' => 'Basa de donadas', + 'conf' => array( + '_' => 'Configuracion de la basa de donadas', + 'ko' => 'Verificatz las informacions de la basa de donadas.', + 'ok' => 'La configuracion de la basa de donadas es salvagarda.', + ), + 'host' => 'Òste', + 'prefix' => 'Prefixe de tabla', + 'password' => 'Senhal de la basa de donadas', + 'type' => 'Tipe de basa de donadas', + 'username' => 'Nom d’utilizaire de la basa de donadas', + ), + 'check' => array( + '_' => 'Verificacions', + 'already_installed' => 'Sembla que FreshRSS es ja installat !', + 'cache' => array( + 'nok' => 'Volgatz verificar los dreches sul repertòri ./data/cache. Lo servidor HTTP deu poder escriure dedins', + 'ok' => 'Los dreches sul cache son bons.', + ), + 'ctype' => array( + 'nok' => 'Impossible de trobar una bibliotèca per la verificacion del tipe de caractèrs (php-ctype).', + 'ok' => 'Avètz la bibliotèca per la verificacion del tipe de caractèrs (ctype).', + ), + 'curl' => array( + 'nok' => 'Impossible de trobar la bibliotèca curl ( paquet php-curl).', + 'ok' => 'Avètz la bibliotèca cURL.', + ), + 'data' => array( + 'nok' => 'Volgatz verificar los dreches sul repertòri ./data. Lo servidor HTTP deu poder escriure dedins', + 'ok' => 'Los dreches sul repertòri data son bons.', + ), + 'dom' => array( + 'nok' => 'Impossible de trobar una bibliotèca per percórrer lo DOM.', + 'ok' => 'Avètz la bibliotèca per percórrer lo DOM.', + ), + 'favicons' => array( + 'nok' => 'Volgatz verificar los dreches sul repertòri ./data/favicons. Lo servidor HTTP deu poder escriure dedins', + 'ok' => 'Los dreches sul repertòri dels favicons son bons.', + ), + 'fileinfo' => array( + 'nok' => 'Avètz pas PHP fileinfo (paquet fileinfo).', + 'ok' => 'Avètz la bibliotèca fileinfo.', + ), + 'http_referer' => array( + 'nok' => 'Mercés de verificar que modificatz pas vòstre HTTP REFERER.', + 'ok' => 'Lo HTTP REFERER es conegut e sembla correspondre a vòstre servidor.', + ), + 'json' => array( + 'nok' => 'Impossible de trobar l’extension recomandada JSON (paquet php-json).', + 'ok' => 'Avètz l’exension recomandada JSON.', + ), + 'mbstring' => array( + 'nok' => 'Impossible de trobar la bibliotèca recomandada mbstring per Unicode.', + //TODO + //TODO + 'ok' => 'Avètz la bibliotèca recomandada mbstring per Unicode.', + ), + 'minz' => array( + 'nok' => 'Avètz pas la bibliotèca Minz.', + 'ok' => 'Avètz la bibliotèca Minz.', + ), + 'pcre' => array( + 'nok' => 'Impossible de trobar una bibliotèca per las expressions regulara (php-pcre).', + 'ok' => 'Avètz la bibliotèca per las expressions regularas (PCRE).', + ), + 'pdo' => array( + 'nok' => 'Impossible de trobar PDO o un dels drivers compatibles (pdo_mysql, pdo_sqlite, pdo_pgsql).', + 'ok' => 'Avètz PDO e almens un des drivers compatibles (pdo_mysql, pdo_sqlite, pdo_pgsql).', + ), + 'php' => array( + 'nok' => 'Vòstra version PHP es la %s mas FreshRSS demanda almens la version %s.', + 'ok' => 'Vòstra version PHP es %s, qu’es compatibla amb FreshRSS.', + ), + 'users' => array( + 'nok' => 'Volgatz verificar los dreches sul repertòri ./data/users. Lo servidor HTTP deu poder escriure dedins', + 'ok' => 'Los dreches sul repertòri dels utilizaires son bons.', + ), + 'xml' => array( + 'nok' => 'Impossible de trobar una bibliotèca necessària per XML.', + 'ok' => 'Avètz la bibliotèca per percórrer los XML.', + ), + ), + 'conf' => array( + '_' => 'Configuracion generala', + 'ok' => 'La configuracion generala es enregistrada.', + ), + 'congratulations' => 'Òsca !', + 'default_user' => 'Nom d’utilizaire per defaut 16 caractèrs alfanumerics maximum)', + 'delete_articles_after' => 'Levar los articles aprèp', + 'fix_errors_before' => 'Mercés de corregir las errors seguentas abans de contunhar.', + 'javascript_is_better' => 'FreshRSS es mai agradable amb lo JavaScript activat', + 'js' => array( + 'confirm_reinstall' => 'En reïnstallant FreshRSS perdretz la configuracion precedenta. Volètz vertadièrament contunhar ?', + ), + 'not_deleted' => 'Quicòm a trucat, sembla qu’avètz suprimit %s a la man.', + 'ok' => 'L’installacion s’es corrèctament passada.', + 'step' => 'etapa %d', + 'steps' => 'Etapas', + 'title' => 'Installacion · FreshRSS', + 'this_is_the_end' => 'Es la fin', +); diff --git a/app/i18n/oc/sub.php b/app/i18n/oc/sub.php new file mode 100644 index 000000000..6b4bfd072 --- /dev/null +++ b/app/i18n/oc/sub.php @@ -0,0 +1,84 @@ + array( + 'title' => 'API', + 'documentation' => 'Copiar l’URL seguenta per l’utilizaire dins d’una aisina extèrna.', + ), + 'bookmarklet' => array( + 'label' => 'S’abonar', + 'documentation' => 'Depausatz aqueste boton per la barra de marcapaginas o clicatz-lo a drecha e causissètz « Enregistrar aqueste ligam». Puèi clicatz «S’abonar» sus las paginas que volètz seguir.', + 'title' => 'Bookmarklet', + ), + 'category' => array( + 'new' => 'Nòva categoria', + '_' => 'Categoria', + 'add' => 'Ajustar una categoria', + 'empty' => 'Categoria voida', + ), + 'feed' => array( + 'auth' => array( + 'password' => 'Senhal HTTP', + 'username' => 'Identificant HTTP', + 'configuration' => 'Identificacion', + 'help' => 'Permet l’accès als fluxes protegits per una autentificacion HTTP', + 'http' => 'Autentificacion HTTP', + ), + 'description' => 'Descripcion', + 'mute' => 'mut', + 'priority' => array( + '_' => 'Visibilitat', + 'archived' => 'Mostrar pas (archivat)', + 'main_stream' => 'Mostar al flux màger', + 'normal' => 'Mostar dins sa categoria', + ), + 'title' => 'Títol', + 'url' => 'Flux URL', + 'website' => 'URL del site', + 'add' => 'Ajustar un flux RSS', + 'advanced' => 'Avançat', + 'archiving' => 'Archivar', + 'css_path' => 'Selector CSS dels articles sul site d’origina', + 'empty' => 'Aqueste flux es void. Assegurats-vos qu’es totjorn mantengut.', + 'informations' => 'Informacions', + 'keep_history' => 'Nombre minimum d’articles de servar', + 'no_selected' => 'Cap de flux pas seleccionat.', + 'number_entries' => '%d articles', + 'ssl_verify' => 'Verificacion de la seguretat SSL', + 'stats' => 'Estatisticas', + 'think_to_add' => 'Podètz ajustar de fluxes.', + 'timeout' => 'Temps d’espèra en segondas', + 'title_add' => 'Ajustar un flux RSS', + 'ttl' => 'Actualizar pas automaticament mai sovent que', + 'validator' => 'Verificar la validitat del flux', + 'pubsubhubbub' => 'Notificaciones instantáneas amb PubSubHubbub', + 'css_help' => 'Permet de recuperar los fluxes troncats (atencion, demanda mai de temps !)', + 'error' => 'Aqueste flux a rescontrat un problèma. Volgatz verificar que siá totjorn accessible puèi actualizatz-lo.', + 'moved_category_deleted' => 'Quand escafatz una categoria, sos fluxes son automaticament classats dins %s.', + ), + 'import_export' => array( + 'export' => 'Exportar', + 'export_starred' => 'Exportar los favorits', + 'import' => 'Importar', + 'title' => 'Importar / Exportar', + 'export_opml' => 'Exportar la lista de fluxes (OPML)', + 'feed_list' => 'Lista dels %s articles', + 'file_to_import' => 'Fichièr d’importar
(OPML, JSON o ZIP)', + 'file_to_import_no_zip' => 'Fichièr d’importar
(OPML o JSON)', + 'starred_list' => 'Lista dels articles favorits', + ), + 'menu' => array( + 'import_export' => 'Importar / Exportar', + 'subscription_tools' => 'Aisinas d’abonament', + 'bookmark' => 'Sabonar (marcapagina FreshRSS)', + 'subscription_management' => 'Gestion dels abonaments', + ), + 'title' => array( + 'subscription_tools' => 'Aisinas d’abonament', + '_' => 'Gestión dels abonaments', + 'feed_management' => 'Gestion dels fluxes RSS', + ), + 'firefox' => array( + 'title' => 'Lector de flux de Firefox', + 'documentation' => 'Seguir las etapas descrichas aquí per ajustar FreshRSS a la lista dels lectors de flux de Firefox.', + ), +); diff --git a/app/i18n/pt-br/gen.php b/app/i18n/pt-br/gen.php index 59218597b..bf5214ee8 100644 --- a/app/i18n/pt-br/gen.php +++ b/app/i18n/pt-br/gen.php @@ -123,6 +123,7 @@ return array( 'it' => 'Italiano', 'kr' => '한국어', 'nl' => 'Nederlands', + 'oc' => 'Occitan', 'pt-br' => 'Português (Brasil)', 'ru' => 'Русский', 'tr' => 'Türkçe', diff --git a/app/i18n/ru/gen.php b/app/i18n/ru/gen.php index 6c8dd2adf..f2612793a 100644 --- a/app/i18n/ru/gen.php +++ b/app/i18n/ru/gen.php @@ -124,6 +124,7 @@ return array( 'it' => 'Italiano', 'kr' => '한국어', 'nl' => 'Nederlands', + 'oc' => 'Occitan', 'pt-br' => 'Português (Brasil)', 'ru' => 'Русский', 'tr' => 'Türkçe', diff --git a/app/i18n/tr/gen.php b/app/i18n/tr/gen.php index b8dc18c01..7328fb380 100644 --- a/app/i18n/tr/gen.php +++ b/app/i18n/tr/gen.php @@ -124,6 +124,7 @@ return array( 'it' => 'Italiano', 'kr' => '한국어', 'nl' => 'Nederlands', + 'oc' => 'Occitan', 'pt-br' => 'Português (Brasil)', 'ru' => 'Русский', 'tr' => 'Türkçe', diff --git a/app/i18n/zh-cn/gen.php b/app/i18n/zh-cn/gen.php index 078e1d378..c68396e5d 100644 --- a/app/i18n/zh-cn/gen.php +++ b/app/i18n/zh-cn/gen.php @@ -124,6 +124,7 @@ return array( 'it' => 'Italiano', 'kr' => '한국어', 'nl' => 'Nederlands', + 'oc' => 'Occitan', 'pt-br' => 'Português (Brasil)', 'ru' => 'Русский', 'tr' => 'Türkçe', diff --git a/cli/i18n/ignore/oc.php b/cli/i18n/ignore/oc.php new file mode 100644 index 000000000..6413fc5f0 --- /dev/null +++ b/cli/i18n/ignore/oc.php @@ -0,0 +1,56 @@ + Date: Sun, 4 Nov 2018 15:08:16 +0100 Subject: Missing string (#2114) --- app/i18n/oc/index.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/i18n/oc/index.php b/app/i18n/oc/index.php index 934e19dea..b357a48e2 100644 --- a/app/i18n/oc/index.php +++ b/app/i18n/oc/index.php @@ -38,6 +38,7 @@ return array( 'starred' => 'Mostrar los favorits', 'stats' => 'Estatisticas', 'subscription' => 'Gestion dels abonaments', + 'tags' => 'Mas etiquetas', 'unread' => 'Mostar los pas legits', ), 'share' => 'Partejar', -- cgit v1.2.3 From cf899d8d25c57b05dff89b89e2c7e56808f83c50 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 5 Nov 2018 18:10:38 +0100 Subject: TT-RSS import (#2099) * TT-RSS import Import of Tiny Tiny RSS favourites https://github.com/FreshRSS/FreshRSS/issues/2018#issuecomment-432710462 * Fallback feed_url * Simpler JSON * TT-RSS import custom labels * Fix syntax --- app/Controllers/importExportController.php | 162 ++++++++++++++++++++++++----- app/Models/EntryDAO.php | 9 ++ app/Models/FeedDAO.php | 8 +- app/Models/TagDAO.php | 2 +- app/views/helpers/export/articles.phtml | 18 +++- 5 files changed, 171 insertions(+), 28 deletions(-) diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 0fb5ba651..c7b384540 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -109,6 +109,17 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { } } } + foreach ($list_files['ttrss_starred'] as $article_file) { + $json = $this->ttrssXmlToJson($article_file); + if (!$this->importJson($json, true)) { + $ok = false; + if (FreshRSS_Context::$isCli) { + fwrite(STDERR, 'FreshRSS error during TT-RSS articles import' . "\n"); + } else { + Minz_Log::warning('Error during TT-RSS articles import'); + } + } + } return $ok; } @@ -165,17 +176,22 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { private static function guessFileType($filename) { if (substr_compare($filename, '.zip', -4) === 0) { return 'zip'; - } elseif (substr_compare($filename, '.opml', -5) === 0 || - substr_compare($filename, '.xml', -4) === 0) { + } elseif (substr_compare($filename, '.opml', -5) === 0) { return 'opml'; - } elseif (substr_compare($filename, '.json', -5) === 0 && - strpos($filename, 'starred') !== false) { - return 'json_starred'; } elseif (substr_compare($filename, '.json', -5) === 0) { - return 'json_feed'; - } else { - return 'unknown'; + if (strpos($filename, 'starred') !== false) { + return 'json_starred'; + } else { + return 'json_feed'; + } + } elseif (substr_compare($filename, '.xml', -4) === 0) { + if (preg_match('/Tiny|tt-?rss/i', $filename)) { + return 'ttrss_starred'; + } else { + return 'opml'; + } } + return 'unknown'; } /** @@ -364,6 +380,43 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { return !$error; } + private function ttrssXmlToJson($xml) { + $table = (array)simplexml_load_string($xml, null, LIBXML_NOCDATA); + $table['items'] = isset($table['article']) ? $table['article'] : array(); + unset($table['article']); + for ($i = count($table['items']) - 1; $i >= 0; $i--) { + $item = (array)($table['items'][$i]); + $item['updated'] = isset($item['updated']) ? strtotime($item['updated']) : ''; + $item['published'] = $item['updated']; + $item['content'] = array('content' => isset($item['content']) ? $item['content'] : ''); + $item['categories'] = isset($item['tag_cache']) ? array($item['tag_cache']) : array(); + if (!empty($item['marked'])) { + $item['categories'][] = 'user/-/state/com.google/starred'; + } + if (!empty($item['published'])) { + $item['categories'][] = 'user/-/state/com.google/broadcast'; + } + if (!empty($item['label_cache'])) { + $labels_cache = json_decode($item['label_cache'], true); + if (is_array($labels_cache)) { + foreach ($labels_cache as $label_cache) { + if (!empty($label_cache[1])) { + $item['categories'][] = 'user/-/label/' . trim($label_cache[1]); + } + } + } + } + $item['alternate'][0]['href'] = isset($item['link']) ? $item['link'] : ''; + $item['origin'] = array( + 'title' => isset($item['feed_title']) ? $item['feed_title'] : '', + 'feedUrl' => isset($item['feed_url']) ? $item['feed_url'] : '', + ); + $item['id'] = isset($item['guid']) ? $item['guid'] : (isset($item['feed_url']) ? $item['feed_url'] : $item['published']); + $table['items'][$i] = $item; + } + return json_encode($table); + } + /** * This method import a JSON-based file (Google Reader format). * @@ -405,7 +458,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { // Oops, no more place! Minz_Log::warning(_t('feedback.sub.feed.over_max', $limits['max_feeds'])); } else { - $feed = $this->addFeedJson($item['origin'], $google_compliant); + $feed = $this->addFeedJson($item['origin']); } if ($feed == null) { @@ -425,6 +478,15 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { } } + $tagDAO = FreshRSS_Factory::createTagDao(); + $labels = $tagDAO->listTags(); + $knownLabels = array(); + foreach ($labels as $label) { + $knownLabels[$label->name()]['id'] = $label->id(); + $knownLabels[$label->name()]['articles'] = array(); + } + unset($labels); + // For each feed, check existing GUIDs already in database. $existingHashForGuids = array(); foreach ($newFeedGuids as $feedId => $newGuids) { @@ -443,19 +505,36 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $feed_id = $article_to_feed[$item['id']]; $author = isset($item['author']) ? $item['author'] : ''; - $key_content = ($google_compliant && !isset($item['content'])) ? 'summary' : 'content'; + $is_starred = $starred; $tags = $item['categories']; - if ($google_compliant) { - // Remove tags containing "/state/com.google" which are useless. - $tags = array_filter($tags, function($var) { - return strpos($var, '/state/com.google') !== false; - }); + $labels = array(); + for ($i = count($tags) - 1; $i >= 0; $i --) { + $tag = trim($tags[$i]); + if (strpos($tag, 'user/-/') !== false) { + if ($tag === 'user/-/state/com.google/starred') { + $is_starred = true; + } elseif (strpos($tag, 'user/-/label/') === 0) { + $tag = trim(substr($tag, 13)); + if ($tag != '') { + $labels[] = $tag; + } + } + unset($tags[$i]); + } + } + + $url = $item['alternate'][0]['href']; + if (!empty($item['content']['content'])) { + $content = $item['content']['content']; + } elseif (!empty($item['summary']['content'])) { + $content = $item['summary']['content']; } + $content = sanitizeHTML($content, $url); $entry = new FreshRSS_Entry( $feed_id, $item['id'], $item['title'], $author, - $item[$key_content]['content'], $item['alternate'][0]['href'], - $item['published'], $is_read, $starred + $content, $url, + $item['published'], $is_read, $is_starred ); $entry->_id(min(time(), $entry->date(true)) . uSecString()); $entry->_tags($tags); @@ -478,8 +557,21 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { } else { $ok = $this->entryDAO->addEntry($values); } - $error |= ($ok === false); + foreach ($labels as $labelName) { + if (empty($knownLabels[$labelName]['id'])) { + $labelId = $tagDAO->addTag(array('name' => $labelName)); + $knownLabels[$labelName]['id'] = $labelId; + $knownLabels[$labelName]['articles'] = array(); + } + $knownLabels[$labelName]['articles'][] = array( + //'id' => $entry->id(), //ID changes after commitNewEntries() + 'id_feed' => $entry->feed(), + 'guid' => $entry->guid(), + ); + } + + $error |= ($ok === false); } $this->entryDAO->commit(); @@ -488,6 +580,20 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $this->feedDAO->updateCachedValues(); $this->entryDAO->commit(); + $this->entryDAO->beginTransaction(); + foreach ($knownLabels as $labelName => $knownLabel) { + $labelId = $knownLabel['id']; + foreach ($knownLabel['articles'] as $article) { + $entryId = $this->entryDAO->searchIdByGuid($article['id_feed'], $article['guid']); + if ($entryId != null) { + $tagDAO->tagEntry($labelId, $entryId); + } else { + Minz_Log::warning('Could not add label "' . $labelName . '" to entry "' . $article['guid'] . '" in feed ' . $article['id_feed']); + } + } + } + $this->entryDAO->commit(); + return !$error; } @@ -495,16 +601,24 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { * This method import a JSON-based feed (Google Reader format). * * @param array $origin represents a feed. - * @param boolean $google_compliant takes care of some specific values if true. * @return FreshRSS_Feed if feed is in database at the end of the process, * else null. */ - private function addFeedJson($origin, $google_compliant) { + private function addFeedJson($origin) { $return = null; - $key = $google_compliant ? 'htmlUrl' : 'feedUrl'; - $url = $origin[$key]; - $name = $origin['title']; - $website = $origin['htmlUrl']; + if (!empty($origin['feedUrl'])) { + $url = $origin['feedUrl']; + } elseif (!empty($origin['htmlUrl'])) { + $url = $origin['htmlUrl']; + } else { + return null; + } + if (!empty($origin['htmlUrl'])) { + $website = $origin['htmlUrl']; + } elseif (!empty($origin['feedUrl'])) { + $website = $origin['feedUrl']; + } + $name = empty($origin['title']) ? '' : $origin['title']; try { // Create a Feed object and add it in database. diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index a01c2227b..708d01a69 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -671,6 +671,15 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return isset($entries[0]) ? $entries[0] : null; } + public function searchIdByGuid($id_feed, $guid) { + $sql = 'SELECT id FROM `' . $this->prefix . 'entry` WHERE id_feed=? AND guid=?'; + $stm = $this->bd->prepare($sql); + $values = array($id_feed, $guid); + $stm->execute($values); + $res = $stm->fetchAll(PDO::FETCH_COLUMN, 0); + return isset($res[0]) ? $res[0] : null; + } + protected function sqlConcat($s1, $s2) { return 'CONCAT(' . $s1 . ',' . $s2 . ')'; //MySQL } diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index e579f5881..7f00642f4 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -465,9 +465,15 @@ UPDATE `{$this->prefix}feed` SQL; $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute(array(':new_value' => FreshRSS_Feed::TTL_DEFAULT, ':old_value' => -2)))) { + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::error('SQL warning updateTTL 1: ' . $info[2] . ' ' . $sql); + $sql2 = 'ALTER TABLE `' . $this->prefix . 'feed` ADD COLUMN ttl INT NOT NULL DEFAULT ' . FreshRSS_Feed::TTL_DEFAULT; //v0.7.3 $stm = $this->bd->prepare($sql2); - $stm->execute(); + if (!($stm && $stm->execute())) { + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::error('SQL error updateTTL 2: ' . $info[2] . ' ' . $sql2); + } } else { $stm->execute(array(':new_value' => -3600, ':old_value' => -1)); } diff --git a/app/Models/TagDAO.php b/app/Models/TagDAO.php index 1b59c8971..b55d2b35d 100644 --- a/app/Models/TagDAO.php +++ b/app/Models/TagDAO.php @@ -266,7 +266,7 @@ class FreshRSS_TagDAO extends Minz_ModelPdo implements FreshRSS_Searchable { if (is_array($entries) && count($entries) > 0) { $sql .= ' AND et.id_entry IN (' . str_repeat('?,', count($entries) - 1). '?)'; foreach ($entries as $entry) { - $values[] = $entry->id(); + $values[] = is_array($entry) ? $entry['id'] : $entry->id(); } } $stm = $this->bd->prepare($sql); diff --git a/app/views/helpers/export/articles.phtml b/app/views/helpers/export/articles.phtml index b8958f527..59a2c7ad7 100644 --- a/app/views/helpers/export/articles.phtml +++ b/app/views/helpers/export/articles.phtml @@ -16,6 +16,12 @@ $articles = array( echo rtrim(json_encode($articles, $options), " ]}\n\r\t"), "\n"; $first = true; +$tagDAO = FreshRSS_Factory::createTagDao(); +$entryIdsTagNames = $tagDAO->getEntryIdsTagNames($this->entriesRaw); +if ($entryIdsTagNames == false) { + $entryIdsTagNames = array(); +} + foreach ($this->entriesRaw as $entryRaw) { if (empty($entryRaw)) { continue; @@ -32,13 +38,14 @@ foreach ($this->entriesRaw as $entryRaw) { $article = array( 'id' => $entry->guid(), + 'timestampUsec' => '' . $entry->id(), 'categories' => array_values($entry->tags()), 'title' => $entry->title(), - 'author' => $entry->authors(true), //TODO: Make an array like tags? + 'author' => $entry->authors(true), 'published' => $entry->date(true), 'updated' => $entry->date(true), 'alternate' => array(array( - 'href' => $entry->link(), + 'href' => htmlspecialchars_decode($entry->link(), ENT_QUOTES), 'type' => 'text/html', )), 'content' => array( @@ -51,6 +58,13 @@ foreach ($this->entriesRaw as $entryRaw) { 'feedUrl' => $feed == null ? '' : $feed->url(), ) ); + if ($entry->isFavorite()) { + $article['categories'][] = 'user/-/state/com.google/starred'; + } + $tagNames = isset($entryIdsTagNames['e_' . $entry->id()]) ? $entryIdsTagNames['e_' . $entry->id()] : array(); + foreach ($tagNames as $tagName) { + $article['categories'][] = 'user/-/label/' . $tagName; + } $line = json_encode($article, $options); if ($line != '') { -- cgit v1.2.3 From 55992d454811f49fedc157854a6bb068c0f8c74c Mon Sep 17 00:00:00 2001 From: Frans de Jonge Date: Mon, 5 Nov 2018 18:14:35 +0100 Subject: [docs] Bookmarklet (#2116) --- docs/en/users/04_Subscriptions.md | 6 +++++- docs/fr/users/04_Subscriptions.md | 8 ++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/en/users/04_Subscriptions.md b/docs/en/users/04_Subscriptions.md index 0772be4cc..9faa7e7f0 100644 --- a/docs/en/users/04_Subscriptions.md +++ b/docs/en/users/04_Subscriptions.md @@ -8,7 +8,11 @@ # Use bookmarklet -**TODO** +Bookmarklets are little scripts that you can execute to perform useful or frivolous tasks. FreshRSS offers a bookmarklet for subscribing to newsfeeds. + + 1. Open "Subscriptions management". + 2. Click on "Subscription tools". + 3. Drag the "Subscribe" button to your bookmark toolbar or right click and choose your browser's "Bookmark link" action. # Feed management diff --git a/docs/fr/users/04_Subscriptions.md b/docs/fr/users/04_Subscriptions.md index ae4541c29..0f8389462 100644 --- a/docs/fr/users/04_Subscriptions.md +++ b/docs/fr/users/04_Subscriptions.md @@ -6,9 +6,13 @@ **TODO** -# Utiliser le « bookmark » +# Utiliser le « bookmarklet » -**TODO** +Les « bookmarklets » sont de petits scripts que vous pouvez exécuter pour effectuer des tâches utiles ou frivoles. FreshRSS offre un signet ( « bookmark » ) pour s'abonner aux fils de nouvelles. + + 1. Ouvrez "Gestion des abonnements". + 2. Cliquez sur "Outils d'abonnement". + 3. Glissez le bouton "S'abonner" dans la barre d'outils des signets ou cliquez droit et choisissez l'action "Lien vers les signets" de votre navigateur. # Organisation des flux -- cgit v1.2.3 From b672fc190d7df163449e91400c6d6a08a3775835 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 11 Nov 2018 17:31:50 +0100 Subject: Tweaks for Vienna RSS (#2093) * Tweaks for Vienna RSS https://github.com/FreshRSS/FreshRSS/issues/2091 https://github.com/ViennaRSS/vienna-rss/issues/1197 * Fix get feed by URL * Fix get item ids returning starred elements * API add item ids by feed URL * Add API filter `it` https://feedhq.readthedocs.io/en/latest/api/reference.html#stream-items-ids * API add `nt=` filter + refactoring * No ; prefix for author https://github.com/FreshRSS/FreshRSS/issues/2091#issuecomment-435562495 * Add id long form prefix and accept short id form https://github.com/FreshRSS/FreshRSS/issues/2091#issuecomment-435631259 * Fix quote problem https://github.com/FreshRSS/FreshRSS/issues/2091#issuecomment-435683930 * Isolate bug fix for News+ https://github.com/FreshRSS/FreshRSS/issues/2091#issuecomment-435687041 * Rework encoding conventions https://github.com/FreshRSS/FreshRSS/issues/2091#issuecomment-437441834 * Unicode escaping alternative Alternative approach to encode XML special characters and other problematic characters into their Unicode fullwidth version when we cannot use HTML-encoding because clients disagree wether they should HTML-decode or not. https://github.com/FreshRSS/FreshRSS/issues/2091#issuecomment-436059559 --- app/Models/BooleanSearch.php | 8 ++ app/Models/EntryDAO.php | 4 +- app/Models/Feed.php | 2 +- app/Models/Search.php | 8 ++ lib/lib_rss.php | 12 +++ p/api/greader.php | 226 +++++++++++++++++++++++++++---------------- 6 files changed, 171 insertions(+), 89 deletions(-) diff --git a/app/Models/BooleanSearch.php b/app/Models/BooleanSearch.php index 6e016f7e9..88eeea73c 100644 --- a/app/Models/BooleanSearch.php +++ b/app/Models/BooleanSearch.php @@ -45,6 +45,14 @@ class FreshRSS_BooleanSearch { return $this->searches; } + public function add($search) { + if ($search instanceof FreshRSS_Search) { + $this->searches[] = $search; + return $search; + } + return null; + } + public function __toString() { return $this->getRawInput(); } diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 708d01a69..6d77a33cd 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -921,8 +921,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return self::daoToEntries($stm->fetchAll(PDO::FETCH_ASSOC)); } - public function listIdsWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filters = null, $date_min = 0) { //For API - list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filters, $date_min); + public function listIdsWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filters = null) { //For API + list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filters); $stm = $this->bd->prepare($sql); $stm->execute($values); diff --git a/app/Models/Feed.php b/app/Models/Feed.php index e1dd2990d..a5ef33d6b 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -424,7 +424,7 @@ class FreshRSS_Feed extends Minz_Model { $author_names = ''; if (is_array($authors)) { foreach ($authors as $author) { - $author_names .= html_only_entity_decode(strip_tags($author->name == '' ? $author->email : $author->name)) . '; '; + $author_names .= escapeToUnicodeAlternative(strip_tags($author->name == '' ? $author->email : $author->name)) . '; '; } } $author_names = substr($author_names, 0, -2); diff --git a/app/Models/Search.php b/app/Models/Search.php index c52e391fa..f9cda7354 100644 --- a/app/Models/Search.php +++ b/app/Models/Search.php @@ -73,10 +73,18 @@ class FreshRSS_Search { return $this->min_date; } + public function setMinDate($value) { + return $this->min_date = $value; + } + public function getMaxDate() { return $this->max_date; } + public function setMaxDate($value) { + return $this->max_date = $value; + } + public function getMinPubdate() { return $this->min_pubdate; } diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 4087f6faf..52e4408d2 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -102,6 +102,18 @@ function safe_ascii($text) { return filter_var($text, FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); } +function escapeToUnicodeAlternative($text) { + $text = htmlspecialchars_decode($text, ENT_QUOTES); + // https://raw.githubusercontent.com/mihaip/google-reader-api/master/wiki/StreamId.wiki + return trim(str_replace( + //Problematic characters + array("'", '"', '^', '<', '>', '?', '&', '\\', '/', ',', ';'), + //Use their fullwidth Unicode form instead: + array("’", '"', '^', '<', '>', '?', '&', '\', '/', ',', ';'), + $text + )); +} + /** * Test if a given server address is publicly accessible. * diff --git a/p/api/greader.php b/p/api/greader.php index c6701096c..7c5c54951 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -19,6 +19,7 @@ Server-side API compatible with Google Reader API layer 2 * https://github.com/devongovett/reader * https://github.com/theoldreader/api * https://www.inoreader.com/developers/ +* https://feedhq.readthedocs.io/en/latest/api/index.html */ require(__DIR__ . '/../../constants.php'); @@ -198,6 +199,7 @@ function clientLogin($email, $pass) { //http://web.archive.org/web/2013060409104 header('Content-Type: text/plain; charset=UTF-8'); $auth = $email . '/' . sha1(FreshRSS_Context::$system_conf->salt . $email . FreshRSS_Context::$user_conf->apiPasswordHash); echo 'SID=', $auth, "\n", + 'LSID=null', "\n", //Vienna RSS 'Auth=', $auth, "\n"; exit(); } else { @@ -258,7 +260,7 @@ function tagList() { foreach ($res as $cName) { $tags[] = array( - 'id' => 'user/-/label/' . $cName, + 'id' => 'user/-/label/' . htmlspecialchars_decode($cName, ENT_QUOTES), //'sortid' => $cName, 'type' => 'folder', //Inoreader ); @@ -270,7 +272,7 @@ function tagList() { $labels = $tagDAO->listTags(true); foreach ($labels as $label) { $tags[] = array( - 'id' => 'user/-/label/' . $label->name(), + 'id' => 'user/-/label/' . htmlspecialchars_decode($label->name(), ENT_QUOTES), //'sortid' => $cName, 'type' => 'tag', //Inoreader 'unread_count' => $label->nbUnread(), //Inoreader @@ -298,17 +300,17 @@ function subscriptionList() { foreach ($res as $line) { $subscriptions[] = array( 'id' => 'feed/' . $line['id'], - 'title' => $line['name'], + 'title' => escapeToUnicodeAlternative($line['name']), 'categories' => array( array( - 'id' => 'user/-/label/' . $line['c_name'], - 'label' => $line['c_name'], + 'id' => 'user/-/label/' . htmlspecialchars_decode($line['c_name'], ENT_QUOTES), + 'label' => htmlspecialchars_decode($line['c_name'], ENT_QUOTES), ), ), //'sortid' => $line['name'], //'firstitemmsec' => 0, - 'url' => $line['url'], - 'htmlUrl' => $line['website'], + 'url' => htmlspecialchars_decode($line['url'], ENT_QUOTES), + 'htmlUrl' => htmlspecialchars_decode($line['website'], ENT_QUOTES), 'iconUrl' => $faviconsUrl . hash('crc32b', $salt . $line['url']), ); } @@ -345,6 +347,7 @@ function subscriptionEdit($streamNames, $titles, $action, $add = '', $remove = ' $c_name = ''; } } + $c_name = htmlspecialchars($c_name, ENT_COMPAT, 'UTF-8'); $cat = $categoryDAO->searchByName($c_name); $addCatId = $cat == null ? 0 : $cat->id(); } else if ($remove != '' && strpos($remove, 'user/-/label/')) { @@ -355,26 +358,28 @@ function subscriptionEdit($streamNames, $titles, $action, $add = '', $remove = ' badRequest(); } for ($i = count($streamNames) - 1; $i >= 0; $i--) { - $streamName = $streamNames[$i]; //feed/http://example.net/sample.xml ; feed/338 - if (strpos($streamName, 'feed/') === 0) { - $streamName = substr($streamName, 5); + $streamUrl = $streamNames[$i]; //feed/http://example.net/sample.xml ; feed/338 + if (strpos($streamUrl, 'feed/') === 0) { + $streamUrl = substr($streamUrl, 5); $feedId = 0; - if (ctype_digit($streamName)) { + if (ctype_digit($streamUrl)) { if ($action === 'subscribe') { continue; } - $feedId = $streamName; + $feedId = $streamUrl; } else { - $feed = $feedDAO->searchByUrl($streamName); + $streamUrl = htmlspecialchars($streamUrl, ENT_COMPAT, 'UTF-8'); + $feed = $feedDAO->searchByUrl($streamUrl); $feedId = $feed == null ? -1 : $feed->id(); } $title = isset($titles[$i]) ? $titles[$i] : ''; + $title = htmlspecialchars($title, ENT_COMPAT, 'UTF-8'); switch ($action) { case 'subscribe': if ($feedId <= 0) { - $http_auth = ''; //TODO + $http_auth = ''; try { - $feed = FreshRSS_feed_Controller::addFeed($streamName, $title, $addCatId, $c_name, $http_auth); + $feed = FreshRSS_feed_Controller::addFeed($streamUrl, $title, $addCatId, $c_name, $http_auth); continue; } catch (Exception $e) { Minz_Log::error('subscriptionEdit error subscribe: ' . $e->getMessage(), API_LOG); @@ -407,6 +412,7 @@ function subscriptionEdit($streamNames, $titles, $action, $add = '', $remove = ' function quickadd($url) { try { + $url = htmlspecialchars($url, ENT_COMPAT, 'UTF-8'); $feed = FreshRSS_feed_Controller::addFeed($url); exit(json_encode(array( 'numResults' => 1, @@ -442,7 +448,7 @@ function unreadCount() { //http://blog.martindoms.com/2009/10/16/using-the-googl } } $unreadcounts[] = array( - 'id' => 'user/-/label/' . $cat->name(), + 'id' => 'user/-/label/' . htmlspecialchars_decode($cat->name(), ENT_QUOTES), 'count' => $cat->nbNotRead(), 'newestItemTimestampUsec' => $catLastUpdate . '000000', ); @@ -455,7 +461,7 @@ function unreadCount() { //http://blog.martindoms.com/2009/10/16/using-the-googl $tagDAO = FreshRSS_Factory::createTagDao(); foreach ($tagDAO->listTags(true) as $label) { $unreadcounts[] = array( - 'id' => 'user/-/label/' . $label->name(), + 'id' => 'user/-/label/' . htmlspecialchars_decode($label->name(), ENT_QUOTES), 'count' => $label->nbUnread(), ); } @@ -496,28 +502,29 @@ function entriesToArray($entries) { $f_name = '_'; } $item = array( - 'id' => /*'tag:google.com,2005:reader/item/' .*/ dec2hex($entry->id()), //64-bit hexa http://code.google.com/p/google-reader-api/wiki/ItemId + 'id' => 'tag:google.com,2005:reader/item/' . dec2hex($entry->id()), //64-bit hexa http://code.google.com/p/google-reader-api/wiki/ItemId 'crawlTimeMsec' => substr($entry->id(), 0, -3), 'timestampUsec' => '' . $entry->id(), //EasyRSS 'published' => $entry->date(true), - 'title' => $entry->title(), + 'title' => escapeToUnicodeAlternative($entry->title()), 'summary' => array('content' => $entry->content()), 'alternate' => array( array('href' => htmlspecialchars_decode($entry->link(), ENT_QUOTES)), ), 'categories' => array( 'user/-/state/com.google/reading-list', - 'user/-/label/' . $c_name, + 'user/-/label/' . htmlspecialchars_decode($c_name, ENT_QUOTES), ), 'origin' => array( 'streamId' => 'feed/' . $f_id, - 'title' => $f_name, //EasyRSS + 'title' => escapeToUnicodeAlternative($f_name), //EasyRSS //'htmlUrl' => $line['f_website'], ), ); $author = $entry->authors(true); + $author = trim($author, '; '); if ($author != '') { - $item['author'] = $author; + $item['author'] = escapeToUnicodeAlternative($author); } if ($entry->isRead()) { $item['categories'][] = 'user/-/state/com.google/read'; @@ -527,69 +534,117 @@ function entriesToArray($entries) { } $tagNames = isset($entryIdsTagNames['e_' . $entry->id()]) ? $entryIdsTagNames['e_' . $entry->id()] : array(); foreach ($tagNames as $tagName) { - $item['categories'][] = 'user/-/label/' . $tagName; + $item['categories'][] = 'user/-/label/' . htmlspecialchars_decode($tagName, ENT_QUOTES); } $items[] = $item; } return $items; } -function streamContents($path, $include_target, $start_time, $count, $order, $exclude_target, $continuation) { -//http://code.google.com/p/pyrfeed/wiki/GoogleReaderAPI -//http://blog.martindoms.com/2009/10/16/using-the-google-reader-api-part-2/#feed - header('Content-Type: application/json; charset=UTF-8'); - - switch ($path) { - case 'reading-list': - $type = 'A'; - break; - case 'starred': - $type = 's'; - break; - case 'feed': - $type = 'f'; +function streamContentsFilters($type, $streamId, $filter_target, $exclude_target, $start_time, $stop_time) { + switch ($type) { + case 'f': //feed + if ($streamId != '' && !ctype_digit($streamId)) { + $feedDAO = FreshRSS_Factory::createFeedDao(); + $streamId = htmlspecialchars($streamId, ENT_COMPAT, 'UTF-8'); + $feed = $feedDAO->searchByUrl($streamId); + $streamId = $feed == null ? -1 : $feed->id(); + } break; - case 'label': + case 'c': //category or label $categoryDAO = FreshRSS_Factory::createCategoryDao(); - $cat = $categoryDAO->searchByName($include_target); + $streamId = htmlspecialchars($streamId, ENT_COMPAT, 'UTF-8'); + $cat = $categoryDAO->searchByName($streamId); if ($cat != null) { $type = 'c'; - $include_target = $cat->id(); + $streamId = $cat->id(); } else { $tagDAO = FreshRSS_Factory::createTagDao(); - $tag = $tagDAO->searchByName($include_target); + $tag = $tagDAO->searchByName($streamId); if ($tag != null) { $type = 't'; - $include_target = $tag->id(); + $streamId = $tag->id(); } else { $type = 'A'; - $include_target = -1; + $streamId = -1; } } break; + } + + switch ($filter_target) { + case 'user/-/state/com.google/read': + $state = FreshRSS_Entry::STATE_READ; + break; + case 'user/-/state/com.google/unread': + $state = FreshRSS_Entry::STATE_NOT_READ; + break; + case 'user/-/state/com.google/starred': + $state = FreshRSS_Entry::STATE_FAVORITE; + break; default: - $type = 'A'; + $state = FreshRSS_Entry::STATE_ALL; break; } switch ($exclude_target) { case 'user/-/state/com.google/read': - $state = FreshRSS_Entry::STATE_NOT_READ; + $state &= FreshRSS_Entry::STATE_NOT_READ; break; case 'user/-/state/com.google/unread': - $state = FreshRSS_Entry::STATE_READ; + $state &= FreshRSS_Entry::STATE_READ; + break; + case 'user/-/state/com.google/starred': + $state &= FreshRSS_Entry::STATE_NOT_FAVORITE; + break; + } + + $searches = new FreshRSS_BooleanSearch(''); + if ($start_time != '') { + $search = new FreshRSS_Search(''); + $search->setMinDate($start_time); + $searches->add($search); + } + if ($stop_time != '') { + $search = new FreshRSS_Search(''); + $search->setMaxDate($stop_time); + $searches->add($search); + } + + return array($type, $streamId, $state, $searches); +} + +function streamContents($path, $include_target, $start_time, $stop_time, $count, $order, $filter_target, $exclude_target, $continuation) { +//http://code.google.com/p/pyrfeed/wiki/GoogleReaderAPI +//http://blog.martindoms.com/2009/10/16/using-the-google-reader-api-part-2/#feed + header('Content-Type: application/json; charset=UTF-8'); + + switch ($path) { + case 'reading-list': + $type = 'A'; + break; + case 'starred': + $type = 's'; + break; + case 'feed': + $type = 'f'; + break; + case 'label': + $type = 'c'; break; default: - $state = FreshRSS_Entry::STATE_ALL; + $type = 'A'; break; } + list($type, $include_target, $state, $searches) = streamContentsFilters($type, $include_target, $filter_target, $exclude_target, $start_time, $stop_time); + if ($continuation != '') { $count++; //Shift by one element } $entryDAO = FreshRSS_Factory::createEntryDao(); - $entries = $entryDAO->listWhere($type, $include_target, $state, $order === 'o' ? 'ASC' : 'DESC', $count, $continuation, new FreshRSS_BooleanSearch(''), $start_time); + $entries = $entryDAO->listWhere($type, $include_target, $state, $order === 'o' ? 'ASC' : 'DESC', $count, $continuation, $searches); $items = entriesToArray($entries); @@ -614,7 +669,7 @@ function streamContents($path, $include_target, $start_time, $count, $order, $ex exit(); } -function streamContentsItemsIds($streamId, $start_time, $count, $order, $exclude_target, $continuation) { +function streamContentsItemsIds($streamId, $start_time, $stop_time, $count, $order, $filter_target, $exclude_target, $continuation) { //http://code.google.com/p/google-reader-api/wiki/ApiStreamItemsIds //http://code.google.com/p/pyrfeed/wiki/GoogleReaderAPI //http://blog.martindoms.com/2009/10/16/using-the-google-reader-api-part-2/#feed @@ -622,55 +677,32 @@ function streamContentsItemsIds($streamId, $start_time, $count, $order, $exclude $id = ''; if ($streamId === 'user/-/state/com.google/reading-list') { $type = 'A'; - } elseif ('user/-/state/com.google/starred') { + } elseif ($streamId === 'user/-/state/com.google/starred') { $type = 's'; } elseif (strpos($streamId, 'feed/') === 0) { $type = 'f'; - $id = basename($streamId); + $streamId = substr($streamId, 5); } elseif (strpos($streamId, 'user/-/label/') === 0) { $type = 'c'; - $c_name = substr($streamId, 13); - $categoryDAO = FreshRSS_Factory::createCategoryDao(); - $cat = $categoryDAO->searchByName($c_name); - if ($cat != null) { - $type = 'c'; - $id = $cat->id(); - } else { - $tagDAO = FreshRSS_Factory::createTagDao(); - $tag = $tagDAO->searchByName($c_name); - if ($tag != null) { - $type = 't'; - $id = $tag->id(); - } else { - $type = 'A'; - $id = -1; - } - } + $streamId = substr($streamId, 13); } - switch ($exclude_target) { - case 'user/-/state/com.google/read': - $state = FreshRSS_Entry::STATE_NOT_READ; - break; - default: - $state = FreshRSS_Entry::STATE_ALL; - break; - } + list($type, $id, $state, $searches) = streamContentsFilters($type, $streamId, $filter_target, $exclude_target, $start_time, $stop_time); if ($continuation != '') { $count++; //Shift by one element } $entryDAO = FreshRSS_Factory::createEntryDao(); - $ids = $entryDAO->listIdsWhere($type, $id, $state, $order === 'o' ? 'ASC' : 'DESC', $count, $continuation, new FreshRSS_BooleanSearch(''), $start_time); + $ids = $entryDAO->listIdsWhere($type, $id, $state, $order === 'o' ? 'ASC' : 'DESC', $count, $continuation, $searches); if ($continuation != '') { array_shift($ids); //Discard first element that was already sent in the previous response $count--; } - if (empty($ids)) { //For News+ bug https://github.com/noinnion/newsplus/issues/84#issuecomment-57834632 - $ids[] = 0; + if (empty($ids) && isset($_GET['client']) && $_GET['client'] === 'newsplus') { + $ids[] = 0; //For News+ bug https://github.com/noinnion/newsplus/issues/84#issuecomment-57834632 } $itemRefs = array(); foreach ($ids as $id) { @@ -697,7 +729,10 @@ function streamContentsItems($e_ids, $order) { header('Content-Type: application/json; charset=UTF-8'); foreach ($e_ids as $i => $e_id) { - $e_ids[$i] = hex2dec(basename($e_id)); //Strip prefix 'tag:google.com,2005:reader/item/' + if (strpos($e_id, '/') !== null) { + $e_id = hex2dec(basename($e_id)); //Strip prefix 'tag:google.com,2005:reader/item/' + } + $e_ids[$i] = $e_id; } $entryDAO = FreshRSS_Factory::createEntryDao(); @@ -717,7 +752,10 @@ function streamContentsItems($e_ids, $order) { function editTag($e_ids, $a, $r) { foreach ($e_ids as $i => $e_id) { - $e_ids[$i] = hex2dec(basename($e_id)); //Strip prefix 'tag:google.com,2005:reader/item/' + if (strpos($e_id, '/') !== null) { + $e_id = hex2dec(basename($e_id)); //Strip prefix 'tag:google.com,2005:reader/item/' + } + $e_ids[$i] = $e_id; } $entryDAO = FreshRSS_Factory::createEntryDao(); @@ -748,6 +786,7 @@ function editTag($e_ids, $a, $r) { } } if ($tagName != '') { + $tagName = htmlspecialchars($tagName, ENT_COMPAT, 'UTF-8'); $tag = $tagDAO->searchByName($tagName); if ($tag == null) { $tagDAO->addTag(array('name' => $tagName)); @@ -771,6 +810,7 @@ function editTag($e_ids, $a, $r) { default: if (strpos($r, 'user/-/label/') === 0) { $tagName = substr($r, 13); + $tagName = htmlspecialchars($tagName, ENT_COMPAT, 'UTF-8'); $tag = $tagDAO->searchByName($tagName); if ($tag != null) { foreach ($e_ids as $e_id) { @@ -788,7 +828,9 @@ function renameTag($s, $dest) { if ($s != '' && strpos($s, 'user/-/label/') === 0 && $dest != '' && strpos($dest, 'user/-/label/') === 0) { $s = substr($s, 13); + $s = htmlspecialchars($s, ENT_COMPAT, 'UTF-8'); $dest = substr($dest, 13); + $dest = htmlspecialchars($dest, ENT_COMPAT, 'UTF-8'); $categoryDAO = FreshRSS_Factory::createCategoryDao(); $cat = $categoryDAO->searchByName($s); @@ -810,6 +852,7 @@ function renameTag($s, $dest) { function disableTag($s) { if ($s != '' && strpos($s, 'user/-/label/') === 0) { $s = substr($s, 13); + $s = htmlspecialchars($s, ENT_COMPAT, 'UTF-8'); $categoryDAO = FreshRSS_Factory::createCategoryDao(); $cat = $categoryDAO->searchByName($s); if ($cat != null) { @@ -838,6 +881,7 @@ function markAllAsRead($streamId, $olderThanId) { $entryDAO->markReadFeed($f_id, $olderThanId); } elseif (strpos($streamId, 'user/-/label/') === 0) { $c_name = substr($streamId, 13); + $c_name = htmlspecialchars($c_name, ENT_COMPAT, 'UTF-8'); $categoryDAO = FreshRSS_Factory::createCategoryDao(); $cat = $categoryDAO->searchByName($c_name); if ($cat != null) { @@ -902,12 +946,14 @@ if (count($pathInfos) < 3) { * exclude items from a particular feed (obviously not useful in this * request, but xt appears in other listing requests). */ $exclude_target = isset($_GET['xt']) ? $_GET['xt'] : ''; + $filter_target = isset($_GET['it']) ? $_GET['it'] : ''; $count = isset($_GET['n']) ? intval($_GET['n']) : 20; //n=[integer] : The maximum number of results to return. $order = isset($_GET['r']) ? $_GET['r'] : 'd'; //r=[d|n|o] : Sort order of item results. d or n gives items in descending date order, o in ascending order. /* ot=[unix timestamp] : The time from which you want to retrieve * items. Only items that have been crawled by Google Reader after * this time will be returned. */ $start_time = isset($_GET['ot']) ? intval($_GET['ot']) : 0; + $stop_time = isset($_GET['nt']) ? intval($_GET['nt']) : 0; /* Continuation token. If a StreamContents response does not represent * all items in a timestamp range, it will have a continuation attribute. * The same request can be re-issued with the value of that attribute put @@ -920,23 +966,31 @@ if (count($pathInfos) < 3) { if (isset($pathInfos[7])) { if ($pathInfos[6] === 'feed') { $include_target = $pathInfos[7]; - StreamContents($pathInfos[6], $include_target, $start_time, $count, $order, $exclude_target, $continuation); + if ($include_target != '' && !ctype_digit($include_target)) { + $include_target = empty($_SERVER['REQUEST_URI']) ? '' : $_SERVER['REQUEST_URI']; + if (preg_match('#/reader/api/0/stream/contents/feed/([A-Za-z0-9\'!*()%$_.~+-]+)#', $include_target, $matches) && isset($matches[1])) { + $include_target = urldecode($matches[1]); + } else { + $include_target = ''; + } + } + streamContents($pathInfos[6], $include_target, $start_time, $stop_time, $count, $order, $filter_target, $exclude_target, $continuation); } elseif ($pathInfos[6] === 'user' && isset($pathInfos[8]) && isset($pathInfos[9])) { if ($pathInfos[8] === 'state') { if ($pathInfos[9] === 'com.google' && isset($pathInfos[10])) { if ($pathInfos[10] === 'reading-list' || $pathInfos[10] === 'starred') { $include_target = ''; - streamContents($pathInfos[10], $include_target, $start_time, $count, $order, $exclude_target, $continuation); + streamContents($pathInfos[10], $include_target, $start_time, $stop_time, $count, $order, $filter_target, $exclude_target, $continuation); } } } elseif ($pathInfos[8] === 'label') { $include_target = $pathInfos[9]; - streamContents($pathInfos[8], $include_target, $start_time, $count, $order, $exclude_target, $continuation); + streamContents($pathInfos[8], $include_target, $start_time, $stop_time, $count, $order, $filter_target, $exclude_target, $continuation); } } } else { //EasyRSS $include_target = ''; - streamContents('reading-list', $include_target, $start_time, $count, $order, $exclude_target, $continuation); + streamContents('reading-list', $include_target, $start_time, $stop_time, $count, $order, $filter_target, $exclude_target, $continuation); } } elseif ($pathInfos[5] === 'items') { if ($pathInfos[6] === 'ids' && isset($_GET['s'])) { @@ -944,7 +998,7 @@ if (count($pathInfos) < 3) { * be repeated to fetch the item IDs from multiple streams at once * (more efficient from a backend perspective than multiple requests). */ $streamId = $_GET['s']; - streamContentsItemsIds($streamId, $start_time, $count, $order, $exclude_target, $continuation); + streamContentsItemsIds($streamId, $start_time, $stop_time, $count, $order, $filter_target, $exclude_target, $continuation); } else if ($pathInfos[6] === 'contents' && isset($_POST['i'])) { //FeedMe $e_ids = multiplePosts('i'); //item IDs streamContentsItems($e_ids, $order); -- cgit v1.2.3 From 4dcddff53206dca177128ad001587194ef9b6558 Mon Sep 17 00:00:00 2001 From: ryliejamesthomas Date: Mon, 12 Nov 2018 03:32:32 +1100 Subject: Note stating manually adding custom subscription services removed in FF 63 (#2112) * Note stating manually adding custom subscription services removed in FF 63 * Amended to mention bookmarklet and upcoming issues --- docs/en/users/04_Subscriptions.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/en/users/04_Subscriptions.md b/docs/en/users/04_Subscriptions.md index 9faa7e7f0..4b40f691a 100644 --- a/docs/en/users/04_Subscriptions.md +++ b/docs/en/users/04_Subscriptions.md @@ -20,7 +20,9 @@ Bookmarklets are little scripts that you can execute to perform useful or frivol # Firefox subscription service -You can manually add your FreshRSS app to the list of Firefox subscription services which will enable you to subscribe to sites which provide a feed link using the Firefox built-in "Subscribe" button. An in-depth process is described in the [official documentation](https://developer.mozilla.org/en-US/Firefox/Releases/2/Adding_feed_readers_to_Firefox) but you can use the following steps: +NB: From version 63 and onwards Firefox has removed the ability to add your own subscription services that aren't standalone programs. This makes it impossible to add FreshRSS to the feed preview/subscription page, though this page is set to be removed from version 64 anyway (see [bugzilla](https://bugzilla.mozilla.org/show_bug.cgi?id=1477667)). You can use the bookmarklet mentioned above for an easy way to subscribe to feeds. + +If you're using a version pre-63 you can manually add your FreshRSS app to the list of Firefox subscription services, which enables you to subscribe to sites which provide a feed link using the Firefox built-in "Subscribe" button. An in-depth process is described in the [official documentation](https://developer.mozilla.org/en-US/Firefox/Releases/2/Adding_feed_readers_to_Firefox) but you can use the following steps: 1. Open about:config in Firefox -- cgit v1.2.3 From ac62742082c3de4629664e506f6cc0fbfd9e09f7 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 11 Nov 2018 21:06:44 +0100 Subject: Readme https://github.com/FreshRSS/FreshRSS/issues/2085 https://github.com/FreshRSS/FreshRSS/pull/2088 https://github.com/FreshRSS/FreshRSS/pull/2089 https://github.com/FreshRSS/FreshRSS/issues/2091 https://github.com/FreshRSS/FreshRSS/pull/2092 https://github.com/FreshRSS/FreshRSS/pull/2093 https://github.com/FreshRSS/FreshRSS/pull/2094 https://github.com/FreshRSS/FreshRSS/pull/2099 https://github.com/FreshRSS/FreshRSS/pull/2110 --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12284e35c..26d3a1941 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ ## 2018-1X-XX FreshRSS 1.12.1-dev +* API + * Improvements to the Google Reader API / Open Reader API [#2093](https://github.com/FreshRSS/FreshRSS/pull/2093) + * Support for Vienna RSS (client for Mac OS X) [#2091](https://github.com/FreshRSS/FreshRSS/issues/2091) +* Features + * Ability to import XML files exported from Tiny-Tiny-RSS (#2079)[https://github.com/FreshRSS/FreshRSS/issues/2079] +* UI + * Fix regression from 1.12.0 preventing from closing an article [#2085](https://github.com/FreshRSS/FreshRSS/issues/2085) + * Improvements of the Swage theme [#2088](https://github.com/FreshRSS/FreshRSS/pull/2088), [#2094](https://github.com/FreshRSS/FreshRSS/pull/2094) + * Style improvements [#2089](https://github.com/FreshRSS/FreshRSS/pull/2089) +* I18n + * Occitan [#2110](https://github.com/FreshRSS/FreshRSS/pull/2110) ## 2018-10-28 FreshRSS 1.12.0 -- cgit v1.2.3 From 0fce9892ff2b03083706b4f78495539861db98aa Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 12 Nov 2018 09:03:20 +0100 Subject: API encoding tuning (#2120) Use only minimal XML->Unicode encoding for articles title. Follow-up of https://github.com/FreshRSS/FreshRSS/pull/2093 --- app/Models/Feed.php | 2 +- lib/lib_rss.php | 21 +++++++++++++-------- p/api/greader.php | 8 ++++---- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/app/Models/Feed.php b/app/Models/Feed.php index a5ef33d6b..acf3bd981 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -424,7 +424,7 @@ class FreshRSS_Feed extends Minz_Model { $author_names = ''; if (is_array($authors)) { foreach ($authors as $author) { - $author_names .= escapeToUnicodeAlternative(strip_tags($author->name == '' ? $author->email : $author->name)) . '; '; + $author_names .= escapeToUnicodeAlternative(strip_tags($author->name == '' ? $author->email : $author->name), true) . '; '; } } $author_names = substr($author_names, 0, -2); diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 52e4408d2..c445874c8 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -102,16 +102,21 @@ function safe_ascii($text) { return filter_var($text, FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); } -function escapeToUnicodeAlternative($text) { +function escapeToUnicodeAlternative($text, $extended = true) { $text = htmlspecialchars_decode($text, ENT_QUOTES); + + //Problematic characters + $problem = array('&', '<', '>'); + //Use their fullwidth Unicode form instead: + $replace = array('&', '<', '>'); + // https://raw.githubusercontent.com/mihaip/google-reader-api/master/wiki/StreamId.wiki - return trim(str_replace( - //Problematic characters - array("'", '"', '^', '<', '>', '?', '&', '\\', '/', ',', ';'), - //Use their fullwidth Unicode form instead: - array("’", '"', '^', '<', '>', '?', '&', '\', '/', ',', ';'), - $text - )); + if ($extended) { + $problem += array("'", '"', '^', '?', '\\', '/', ',', ';'); + $replace += array("’", '"', '^', '?', '\', '/', ',', ';'); + } + + return trim(str_replace($problem, $replace, $text)); } /** diff --git a/p/api/greader.php b/p/api/greader.php index 7c5c54951..7cd312f2c 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -300,7 +300,7 @@ function subscriptionList() { foreach ($res as $line) { $subscriptions[] = array( 'id' => 'feed/' . $line['id'], - 'title' => escapeToUnicodeAlternative($line['name']), + 'title' => escapeToUnicodeAlternative($line['name'], true), 'categories' => array( array( 'id' => 'user/-/label/' . htmlspecialchars_decode($line['c_name'], ENT_QUOTES), @@ -506,7 +506,7 @@ function entriesToArray($entries) { 'crawlTimeMsec' => substr($entry->id(), 0, -3), 'timestampUsec' => '' . $entry->id(), //EasyRSS 'published' => $entry->date(true), - 'title' => escapeToUnicodeAlternative($entry->title()), + 'title' => escapeToUnicodeAlternative($entry->title(), false), 'summary' => array('content' => $entry->content()), 'alternate' => array( array('href' => htmlspecialchars_decode($entry->link(), ENT_QUOTES)), @@ -517,14 +517,14 @@ function entriesToArray($entries) { ), 'origin' => array( 'streamId' => 'feed/' . $f_id, - 'title' => escapeToUnicodeAlternative($f_name), //EasyRSS + 'title' => escapeToUnicodeAlternative($f_name, true), //EasyRSS //'htmlUrl' => $line['f_website'], ), ); $author = $entry->authors(true); $author = trim($author, '; '); if ($author != '') { - $item['author'] = escapeToUnicodeAlternative($author); + $item['author'] = escapeToUnicodeAlternative($author, false); } if ($entry->isRead()) { $item['categories'][] = 'user/-/state/com.google/read'; -- cgit v1.2.3 From adcbfc43b866ad2654be3f96e90c650cae224141 Mon Sep 17 00:00:00 2001 From: romibi Date: Tue, 13 Nov 2018 22:29:03 +0100 Subject: Improve long dropdown menu lists (#2108) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dropdown menus with lots of entries were a bit difficult to use … Set max height to 75% of Viewport-height and enabled scrolling --- app/views/helpers/index/normal/entry_bottom.phtml | 2 +- p/themes/base-theme/template.css | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/views/helpers/index/normal/entry_bottom.phtml b/app/views/helpers/index/normal/entry_bottom.phtml index 784a41e1f..1f35318e3 100644 --- a/app/views/helpers/index/normal/entry_bottom.phtml +++ b/app/views/helpers/index/normal/entry_bottom.phtml @@ -42,7 +42,7 @@ - + +
    + onlyFeedsWithError): ?> +
  • + +
  • + +
feed) ? ' class="active"' : ''; ?> -- cgit v1.2.3 From 0c62e3e74d03a6b7e01606fe2cb2373564342417 Mon Sep 17 00:00:00 2001 From: Patrick Crandol Date: Tue, 4 Dec 2018 14:00:24 -0500 Subject: Update Readme.conf (#2158) * Update Readme.conf Add information in Readme.conf to hopefully stop bug reports about intended behavior. * Update README.md Co-Authored-By: pattems * Update README.md Co-Authored-By: pattems * Update README.md Co-Authored-By: pattems * Update README.md Co-Authored-By: pattems * Update Readme * Update Documentation Section * Add main Documentation link near top of Document * Make Documentation header a link * Fix spelling mistake I didn't catch * Apply suggestions from code review Co-Authored-By: pattems * Changes per Frenzie comments * Move non-disclaiming disclaimer * Resolve #2159 --- README.md | 49 ++++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 2c0366077..1e86d9f57 100644 --- a/README.md +++ b/README.md @@ -4,15 +4,18 @@ * [Version française](README.fr.md) # FreshRSS -FreshRSS is a self-hosted RSS feed aggregator such as [Leed](http://leed.idleman.fr/) or [Kriss Feed](https://tontof.net/kriss/feed/). +FreshRSS is a self-hosted RSS feed aggregator like [Leed](http://leed.idleman.fr/) or [Kriss Feed](https://tontof.net/kriss/feed/). -It is at the same time lightweight, easy to work with, powerful and customizable. +It is lightweight, easy to work with, powerful, and customizable. It is a multi-user application with an anonymous reading mode. It supports custom tags, and [PubSubHubbub](https://github.com/pubsubhubbub/PubSubHubbub) for instant notifications from compatible Web sites. There is an API for (mobile) clients, and a [Command-Line Interface](cli/README.md). Finally, it supports [extensions](#extensions) for further tuning. +Feature requests, bug reports, and other contributions are welcome. The best way to contribute is to [open an issue on GitHub](https://github.com/FreshRSS/FreshRSS/issues). We are a friendly community. + + * Official website: https://freshrss.org * Demo: https://demo.freshrss.org/ * License: [GNU AGPL 3](https://www.gnu.org/licenses/agpl-3.0.html) @@ -27,37 +30,39 @@ See the [list of releases](../../releases). * For those willing to help testing or developing the latest features, [the dev branch](https://github.com/FreshRSS/FreshRSS/tree/dev) is waiting for you! # Disclaimer -This application was developed to fulfil personal needs primarily, and comes with absolutely no warranty. -Feature requests, bug reports, and other contributions are welcome. The best way is to [open an issue on GitHub](https://github.com/FreshRSS/FreshRSS/issues). -We are a friendly community. +FreshRSS comes with absolutely no warranty. # Requirements * Light server running Linux or Windows * It even works on Raspberry Pi 1 with response time under a second (tested with 150 feeds, 22k articles) * A web server: Apache2 (recommended), nginx, lighttpd (not tested on others) -* PHP 5.3.8+ (PHP 5.4+ recommended, and PHP 5.5+ for performance, and PHP 7 for even higher performance) +* PHP 5.3.8+ (PHP 5.4+ recommended, and PHP 5.5+ for performance, or PHP 7 for even higher performance) * Required extensions: [cURL](https://secure.php.net/curl), [DOM](https://secure.php.net/dom), [XML](https://secure.php.net/xml), [session](https://secure.php.net/session), [ctype](https://secure.php.net/ctype), and [PDO_MySQL](https://secure.php.net/pdo-mysql) or [PDO_SQLite](https://secure.php.net/pdo-sqlite) or [PDO_PGSQL](https://secure.php.net/pdo-pgsql) - * Recommended extensions: [JSON](https://secure.php.net/json), [GMP](https://secure.php.net/gmp) (for API access on platforms < 64 bits), [IDN](https://secure.php.net/intl.idn) (for Internationalized Domain Names), [mbstring](https://secure.php.net/mbstring) (for Unicode strings), [iconv](https://secure.php.net/iconv) (for charset conversion), [ZIP](https://secure.php.net/zip) (for import/export), [zlib](https://secure.php.net/zlib) (for compressed feeds) + * Recommended extensions: [JSON](https://secure.php.net/json), [GMP](https://secure.php.net/gmp) (for API access on 32-bit platforms), [IDN](https://secure.php.net/intl.idn) (for Internationalized Domain Names), [mbstring](https://secure.php.net/mbstring) (for Unicode strings), [iconv](https://secure.php.net/iconv) (for charset conversion), [ZIP](https://secure.php.net/zip) (for import/export), [zlib](https://secure.php.net/zlib) (for compressed feeds) * MySQL 5.5.3+ (recommended), or SQLite 3.7.4+, or PostgreSQL 9.2+ * A recent browser like Firefox / IceCat, Internet Explorer 11 / Edge, Chromium / Chrome, Opera, Safari. * Works on mobile + * All features may not be available on mobile or Internet Explorer 11 / Edge ![FreshRSS screenshot](docs/img/FreshRSS-screenshot.png) -# Documentation -* https://freshrss.github.io/FreshRSS/en/ +# [Documentation](https://freshrss.github.io/FreshRSS/en/) +* [User documentation](https://freshrss.github.io/FreshRSS/en/users/02_First_steps.html), where you can discover all the possibilities offered by FreshRSS +* [Administrator documentation](https://freshrss.github.io/FreshRSS/en/admins/01_Index.html) for detailed installation and maintenance related tasks +* [Developer documentation](https://freshrss.github.io/FreshRSS/en/developers/01_First_steps.html) to guide you in the source code of FreshRSS and to help you if you want to contribute +* [Contributor guidelines](https://freshrss.github.io/FreshRSS/en/contributing.md) for those who want to help improve FreshRSS # [Installation](https://freshrss.github.io/FreshRSS/en/admins/02_Installation.html) 1. Get FreshRSS with git or [by downloading the archive](https://github.com/FreshRSS/FreshRSS/archive/master.zip) -2. Dump the application on your server (expose only the `./p/` folder) -3. Add write access on `./data/` folder to the webserver user +2. Put the application somewhere on your server (expose only the `./p/` folder to the web) +3. Add write access to the `./data/` folder for the webserver user 4. Access FreshRSS with your browser and follow the installation process * or use the [Command-Line Interface](cli/README.md) -5. Everything should be working :) If you encounter any problem, feel free [contact us](https://github.com/FreshRSS/FreshRSS/issues). -6. Advanced configuration settings can be seen in [config.default.php](config.default.php) and modified in `data/config.php`. +5. Everything should be working :) If you encounter any problems, feel free to [contact us](https://github.com/FreshRSS/FreshRSS/issues). +6. Advanced configuration settings can be found in [config.default.php](config.default.php) and modified in `data/config.php`. 7. When using Apache, enable [`AllowEncodedSlashes`](https://httpd.apache.org/docs/trunk/mod/core.html#allowencodedslashes) for better compatibility with mobile clients. -More information about installation and server configuration can be found in [our documentation](https://freshrss.github.io/FreshRSS/en/admins/02_Installation.html). +More detailed information about installation and server configuration can be found in [our documentation](https://freshrss.github.io/FreshRSS/en/admins/02_Installation.html). ## Automated install * [![Docker](https://www.docker.com/sites/default/files/horizontal.png)](./Docker/) @@ -108,16 +113,16 @@ sudo chown -R :www-data . && sudo chmod -R g+r . && sudo chmod -R g+w ./data/ See more commands and git commands in the [Command-Line Interface documentation](cli/README.md). ## Access control -It is needed for the multi-user mode to limit access to FreshRSS. You can: -* use form authentication (needs JavaScript, and PHP 5.5+ recommended) -* use HTTP authentication supported by your web server +This is needed if you will be using the multi-user mode, to limit access to FreshRSS. Options Available: +* form authentication (needs JavaScript, and PHP 5.5+ recommended) +* HTTP authentication supported by your web server * See [Apache documentation](https://httpd.apache.org/docs/trunk/howto/auth.html) * In that case, create a `./p/i/.htaccess` file with a matching `.htpasswd` file. ## Automatic feed update * You can add a Cron job to launch the update script. Check the Cron documentation related to your distribution ([Debian/Ubuntu](https://help.ubuntu.com/community/CronHowto), [Red Hat/Fedora](https://fedoraproject.org/wiki/Administration_Guide_Draft/Cron), [Slackware](https://docs.slackware.com/fr:slackbook:process_control?#cron), [Gentoo](https://wiki.gentoo.org/wiki/Cron), [Arch Linux](https://wiki.archlinux.org/index.php/Cron)…). -It is a good idea to use the Web server user. +It is a good idea to run the cron job as the webserver user. For instance, if you want to run the script every hour: ``` @@ -132,12 +137,14 @@ Create `/etc/cron.d/FreshRSS` with: ``` -# Advices -* For a better security, expose only the `./p/` folder on the Web. +# Advice +* For better security, expose only the `./p/` folder to the Web. * Be aware that the `./data/` folder contains all personal data, so it is a bad idea to expose it. -* The `./constants.php` file defines access to application folder. If you want to customize your installation, every thing happens here. +* The `./constants.php` file defines access to the application folder. If you want to customize your installation, look here first. * If you encounter any problem, logs are accessible from the interface or manually in `./data/users/*/log*.txt` files. * The special folder `./data/users/_/` contains the part of the logs that are shared by all users. +* The date and time in the right-hand column is the date declared by the feed, not the time at which the article was received by FreshRSS, and it is not used for sorting. + * When importing a new feed, all of its articles will appear at the top of the feed list regardless of their declared date. # Backup -- cgit v1.2.3 From 49903fe1aa2b02e476a43ba2dba319c3beb4e2e9 Mon Sep 17 00:00:00 2001 From: Patrick Crandol Date: Tue, 4 Dec 2018 14:35:46 -0500 Subject: Patch Screwdriver Icon (#2162) See: https://github.com/FreshRSS/FreshRSS/pull/2161#discussion_r238788845 --- p/themes/Screwdriver/icons/icon.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p/themes/Screwdriver/icons/icon.svg b/p/themes/Screwdriver/icons/icon.svg index 268814463..b388fa5d3 100644 --- a/p/themes/Screwdriver/icons/icon.svg +++ b/p/themes/Screwdriver/icons/icon.svg @@ -1,4 +1,4 @@ - + -- cgit v1.2.3 From 8bbf567fde704619ce98598593cff2a486f231ba Mon Sep 17 00:00:00 2001 From: Nicolas Frandeboeuf Date: Tue, 4 Dec 2018 20:37:52 +0100 Subject: [BlueLagoon] Fix header's height (#2161) --- p/themes/BlueLagoon/BlueLagoon.css | 12 +++++------- p/themes/BlueLagoon/icons/icon.svg | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/p/themes/BlueLagoon/BlueLagoon.css b/p/themes/BlueLagoon/BlueLagoon.css index 164088f4b..f167f2051 100644 --- a/p/themes/BlueLagoon/BlueLagoon.css +++ b/p/themes/BlueLagoon/BlueLagoon.css @@ -137,8 +137,6 @@ button.as-link[disabled] { .stick .btn:first-child,.stick input:first-child { border-radius: 6px 0 0 6px; } -.stick .btn-important:first-child { -} .stick .btn:last-child, .stick input:last-child { border-radius: 0 6px 6px 0; } @@ -570,7 +568,6 @@ a.btn { /*===============*/ /*=== Header */ .header { - height: 55px; background: linear-gradient(0deg, #EDE7DE 0%, #FFF 100%) #EDE7DE; background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #FFF 100%); border-bottom: solid 1px #BDB7AE; @@ -582,14 +579,14 @@ a.btn { text-align: center; } .header > .item.title .logo { - height: 60px; - width: 60px; + height: 40px; + width: 40px; } .header > .item.title{ width: 250px; } .header > .item.title h1 { - margin: 0.5em 0; + margin: 10px 0; } .header > .item.title h1 a { text-decoration: none; @@ -607,7 +604,8 @@ a.btn { /*=== Body */ #global { background:#F9F7F4; - height: calc(100% - 60px); + /* Header : 60px + 1px border bottom */ + height: calc(100% - 61px); } .aside { box-shadow: 0 2px 2px #171717 inset; diff --git a/p/themes/BlueLagoon/icons/icon.svg b/p/themes/BlueLagoon/icons/icon.svg index 8abfea179..777e85de1 100644 --- a/p/themes/BlueLagoon/icons/icon.svg +++ b/p/themes/BlueLagoon/icons/icon.svg @@ -1,5 +1,5 @@ - + -- cgit v1.2.3 From 2f70da06e6c19bef383e5011e6300eef7a8257cb Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 4 Dec 2018 21:26:10 +0100 Subject: Fix undefined conf (#2163) Small fix for https://github.com/FreshRSS/FreshRSS/pull/2137 --- app/Models/Auth.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Models/Auth.php b/app/Models/Auth.php index d1e26b8e8..9c3e31952 100644 --- a/app/Models/Auth.php +++ b/app/Models/Auth.php @@ -233,6 +233,7 @@ class FreshRSS_FormAuth { $token_file = DATA_PATH . '/tokens/' . $token . '.txt'; $mtime = @filemtime($token_file); + $conf = Minz_Configuration::get('system'); $limits = $conf->limits; $cookie_duration = empty($limits['cookie_duration']) ? 2592000 : $limits['cookie_duration']; if ($mtime + $cookie_duration < time()) { -- cgit v1.2.3 From 97601a7b1a0e1ab8b602cf5e53a866a1b23a3502 Mon Sep 17 00:00:00 2001 From: Nicolas Frandeboeuf Date: Wed, 5 Dec 2018 08:57:35 +0100 Subject: [Origine-compact] Fix minor buttons height issues (#2165) --- CREDITS.md | 1 + p/themes/Origine-compact/origine-compact.css | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CREDITS.md b/CREDITS.md index f4e51f3d5..83bb97a25 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -44,6 +44,7 @@ People are sorted by name so please keep this order. * [MSZ](https://github.com/mszkb): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=mszkb) * [Nico B](https://github.com/youknow0): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:youknow0) * [Nicolas Elie](https://github.com/nicolaselie): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=nicolaselie) +* [Nicolas Frandeboeuf](https://github.com/nicofrand): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=nicofrand), [Web](https://nicofrand.ey) * [Nicolas Lœuillet](https://github.com/nicosomb): [contributions](https://github.com/FreshRSS/documentation/commits?author=nicosomb), [Web](http://www.loeuillet.org/) * [Nicola Spanti](https://github.com/RyDroid): [contributions](https://github.com/FreshRSS/FreshRSS/pulls?q=is:pr+author:RyDroid), [Web](http://www.nicola-spanti.info/) * [Olivier Dossmann](https://github.com/blankoworld): [contributions](https://github.com/FreshRSS/FreshRSS/commits?author=blankoworld), [Web](https://olivier.dossmann.net) diff --git a/p/themes/Origine-compact/origine-compact.css b/p/themes/Origine-compact/origine-compact.css index 26129415a..11f3b3b25 100644 --- a/p/themes/Origine-compact/origine-compact.css +++ b/p/themes/Origine-compact/origine-compact.css @@ -167,7 +167,8 @@ form th { cursor: pointer; overflow: hidden; } -a.btn { +a.btn, +.stick .btn { min-height: 20px; line-height: 20px; } @@ -571,7 +572,7 @@ a.btn { .header > .item.search input { width: 230px; - padding: 1px 5px 0px 5px; + padding: 1px 5px; } .header .item.search input:focus { width: 350px; -- cgit v1.2.3 From 26e3805d1ffbba5c923ea6e54eba7a765392f0b1 Mon Sep 17 00:00:00 2001 From: Patrick Crandol Date: Fri, 7 Dec 2018 18:45:51 -0500 Subject: Delete unnecessary File in BlueLagoon (#2166) I just realized (despite the fact that I've been editing it for the last month keeping it updated) that BlueLagoon has a copy of template.css in it's theme directory that doesn't do anything. --- p/themes/BlueLagoon/template.css | 696 --------------------------------------- 1 file changed, 696 deletions(-) delete mode 100644 p/themes/BlueLagoon/template.css diff --git a/p/themes/BlueLagoon/template.css b/p/themes/BlueLagoon/template.css deleted file mode 100644 index 4bc0fb735..000000000 --- a/p/themes/BlueLagoon/template.css +++ /dev/null @@ -1,696 +0,0 @@ -@charset "UTF-8"; - -/*=== GENERAL */ -/*============*/ -html, body { - margin: 0; - padding: 0; - font-size: 92%; -} - -/*=== Links */ -a { - text-decoration: none; -} -a:hover { - text-decoration: underline; -} - -/*=== Lists */ -ul, ol, dd { - margin: 0; - padding: 0; -} - -/*=== Titles */ -h1 { - margin: 0.6em 0 0.3em; - font-size: 1.5em; - line-height: 1.6em; -} -h2 { - margin: 0.5em 0 0.25em; - font-size: 1.3em; - line-height: 2em; -} -h3 { - margin: 0.5em 0 0.25em; - font-size: 1.1em; - line-height: 2em; -} - -/*=== Paragraphs */ -p { - margin: 1em 0 0.5em; - font-size: 1em; -} - -/*=== Images */ -img { - height: auto; - max-width: 100%; -} -img.favicon { - height: 16px; - width: 16px; - vertical-align: middle; -} - -/*=== Videos */ -iframe, embed, object, video { - max-width: 100%; -} - -/*=== Forms */ -legend { - display: block; - width: 100%; - clear: both; -} -label { - display: block; -} -input { - width: 180px; -} -textarea { - width: 300px; -} -input, select, textarea { - display: inline-block; - max-width: 100%; - font-size: 0.8rem; -} -input[type="radio"], -input[type="checkbox"] { - width: 15px !important; - min-height: 15px !important; -} -input.extend:focus { - width: 300px; -} - -/*=== COMPONENTS */ -/*===============*/ -/*=== Forms */ -.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; - margin: 0 0 0 220px; -} -.form-group .group-controls .control { - display: block; -} - -/*=== Buttons */ -.stick { - display: inline-block; - white-space: nowrap; -} -.btn, -a.btn { - display: inline-block; - cursor: pointer; - overflow: hidden; -} -.btn-important { - font-weight: bold; -} - -/*=== Navigation */ -.nav-list .nav-header, -.nav-list .item { - display: block; -} -.nav-list .item, -.nav-list .item > a { - 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: 0; - position: absolute; - right: 0; - background: #fff; - border: 1px solid #aaa; -} -.dropdown-header { - display: block; -} -.dropdown-menu > .item { - display: block; -} -.dropdown-menu > .item > a, -.dropdown-menu > .item > span { - display: block; -} -.dropdown-menu > .item[aria-checked="true"] > a::before { - content: '✓'; -} -.dropdown-menu .input { - display: block; -} -.dropdown-menu .input select, -.dropdown-menu .input input { - display: block; - max-width: 95%; -} -.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%; -} -.group-controls .alert { - width: 100% -} -.alert-head { - margin: 0; - font-weight: bold; -} -.alert ul { - margin: 5px 20px; -} - -/*=== Icons */ -.icon { - display: inline-block; - width: 16px; - height: 16px; - vertical-align: middle; - line-height: 16px; -} - -/*=== Pagination */ -.pagination { - display: table; - width: 100%; - margin: 0; - padding: 0; - table-layout: fixed; -} -.pagination .item { - display: table-cell; -} -.pagination .pager-first, -.pagination .pager-previous, -.pagination .pager-next, -.pagination .pager-last { - width: 100px; -} - -/*=== STRUCTURE */ -/*===============*/ -/*=== Header */ -.header { - display: table; - width: 100%; - table-layout: fixed; -} -.header > .item { - display: table-cell; -} -.header > .item.title { - width: 250px; - white-space: nowrap; -} -.header > .item.title h1 { - display: inline-block; -} -.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%; - height: 100%; - table-layout: fixed; -} -.aside { - display: table-cell; - height: 100%; - width: 250px; - vertical-align: top; -} -.aside.aside_flux { - background: #fff; -} - -/*=== Aside main page (categories) */ -.categories { - list-style: none; - margin: 0; -} -.category { - display: block; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} -.category .btn:not([data-unread="0"])::after { - content: attr(data-unread); -} - -/*=== Aside main page (feeds) */ -.categories .feeds { - width: 100%; - list-style: none; -} -.categories .feeds:not(.active) { - display: none; -} -.categories .feeds .feed { - display: inline-block; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - vertical-align: middle; -} -.categories .feeds .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; - vertical-align: top; -} -.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; -} - -/*=== New article notification */ -#new-article { - display: none; -} -#new-article > 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; -} -.flux .item { - line-height: 40px; - white-space: nowrap; -} -.flux .item.manage, -.flux .item.link { - width: 40px; - text-align: center; -} -.flux .item.website { - width: 200px; -} -.flux.not_read .item.title, -.flux.current .item.title { - font-weight: bold; -} -.flux:not(.current):hover .item.title { - position: absolute; - max-width: calc(100% - 320px); - background: #fff; -} -.flux .item.title a { - color: #000; - text-decoration: none; -} -.flux .item.date { - width: 145px; - text-align: right; -} -.flux .item > a { - display: block; -} -.flux .item > a { - display: block; - text-decoration: none; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; -} -.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: 20em; - margin: auto; - line-height: 1.7em; - word-wrap: break-word; -} -.content.large { - max-width: 1000px; -} -.content.medium { - max-width: 800px; -} -.content.thin { - max-width: 550px; -} -.content ul, -.content ol, -.content dd { - margin: 0 0 0 15px; - padding: 0 0 5px 15px; -} -.content pre { - overflow: auto; -} - -/*=== Notification and actualize notification */ -.notification { - position: absolute; - top: 1em; - left: 25%; right: 25%; - z-index: 10; - background: #fff; - border: 1px solid #aaa; -} -.notification.closed { - display: none; -} -.notification a.close { - position: absolute; - top: 0; bottom: 0; - right: 0; - display: inline-block; -} - -#actualizeProgress { - position: fixed; -} -#actualizeProgress progress { - max-width: 100%; - vertical-align: middle; -} -#actualizeProgress .progress { - vertical-align: middle; -} - -/*=== Navigation menu (for articles) */ -#nav_entries { - position: fixed; - bottom: 0; left: 0; - display: table; - width: 250px; - background: #fff; - table-layout: fixed; -} -#nav_entries .item { - display: table-cell; - width: 30%; -} -#nav_entries a { - display: block; -} - -/*=== "Load more" part */ -#load_more { - min-height: 40px; -} -.loading { - background: url("loader.gif") center center no-repeat; - font-size: 0; -} -#bigMarkAsRead { - display: block; - padding: 3em 0; - text-align: center; -} -.bigTick { - font-size: 7em; - line-height: 1.6em; -} - -/*=== Statistiques */ -.stat > table { - width: 100%; -} - -/*=== GLOBAL VIEW */ -/*================*/ -/*=== Category boxes */ -#stream.global .box-category { - display: inline-block; - width: 19em; - max-width: 95%; - margin: 20px 10px; - border: 1px solid #ccc; - vertical-align: top; -} -#stream.global .category { - width: 100%; -} -#stream.global .btn { - display: block; -} -#stream.global .box-category .feeds { - display: block; - overflow: auto; -} -#stream.global .box-category .feed { - width: 19em; - max-width: 90%; -} - -/*=== Panel */ -#overlay { - display: none; - position: fixed; - top: 0; bottom: 0; - left: 0; right: 0; - background: rgba(0, 0, 0, 0.9); -} -#panel { - display: none; - position: fixed; - top: 1em; bottom: 1em; - left: 2em; right: 2em; - overflow: auto; - background: #fff; -} -#panel .close { - position: fixed; - top: 0; bottom: 0; - left: 0; right: 0; - display: block; -} -#panel .close img { - display: none; -} - -/*=== DIVERS */ -/*===========*/ -.nav-login, -.nav_menu .search, -.nav_menu .toggle_aside { - display: none; -} - -.aside .toggle_aside { - position: absolute; - right: 0; - display: none; - width: 30px; - height: 30px; - line-height: 30px; - text-align: center; -} - -/*=== MOBILE */ -/*===========*/ -@media(max-width: 840px) { - .header, - .aside .btn-important, - .aside .feeds .dropdown, - .flux_header .item.website span, - .item.date, .day .date, - .dropdown-menu > .no-mobile, - .no-mobile { - display: none; - } - .nav-login { - display: block; - } - .nav_menu .toggle_aside, - .aside .toggle_aside, - .nav_menu .search, - #panel .close img { - display: inline-block; - } - - .aside { - position: fixed; - top: 0; bottom: 0; - left: 0; - width: 0; - overflow: hidden; - z-index: 100; - } - .aside:target { - width: 90%; - overflow: auto; - } - .aside .categories { - margin: 10px 0 75px; - } - - .flux_header .item.website { - width: 40px; - } - - .flux:not(.current):hover .item.title { - position: relative; - width: auto; - white-space: nowrap; - } - - .notification { - top: 0; - left: 0; - right: 0; - } - - #nav_entries { - width: 100%; - } - - #stream.global .box-category { - margin: 10px 0; - } - - #panel { - top: 0; bottom: 0; - left: 0; right: 0; - } - #panel .close { - top: 0; right: 0; - left: auto; bottom: auto; - display: inline-block; - width: 30px; - height: 30px; - } -} - -/*=== PRINTER */ -/*============*/ -@media print { - .header, .aside, - .nav_menu, .day, - .flux_header, - .flux_content .bottom, - .pagination, - #nav_entries { - display: none; - } - html, body { - background: #fff; - color: #000; - font-family: Serif; - } - #global, - .flux_content { - display: block !important; - } - .flux_content .content { - width: 100% !important; - } - .flux_content .content a { - color: #000; - } - .flux_content .content a::after { - content: " [" attr(href) "] "; - font-style: italic; - } -} -- cgit v1.2.3 From 2610db6260c8beeb9590cdc9f4f3aac1e9985510 Mon Sep 17 00:00:00 2001 From: Patrick Crandol Date: Tue, 11 Dec 2018 15:21:59 -0500 Subject: Remove rawurlencode from movim sharing (#2177) --- app/shares.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/shares.php b/app/shares.php index 55deed785..6d234b374 100644 --- a/app/shares.php +++ b/app/shares.php @@ -64,7 +64,7 @@ return array( ), 'movim' => array( 'url' => '~URL~/?share/~LINK~', - 'transform' => array('rawurlencode', 'urlencode'), + 'transform' => array('urlencode'), 'help' => 'https://github.com/edhelas/movim', 'form' => 'advanced', 'method' => 'GET', -- cgit v1.2.3 From 195c0b6867848f1bea0ec2eb861b7dad5bc1db60 Mon Sep 17 00:00:00 2001 From: Patrick Crandol Date: Tue, 11 Dec 2018 15:25:53 -0500 Subject: Make aria-hidden !important (#2176) Fix for #2115. --- p/themes/base-theme/template.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index 87c32ea58..fdc2f884e 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -143,7 +143,7 @@ td.numeric { /*===============*/ [aria-hidden="true"] { - display: none; + display: none !important; } /*=== Forms */ -- cgit v1.2.3 From a1071e7dd9b9efe3b1f61a3f6bb9f936ad6d7c6a Mon Sep 17 00:00:00 2001 From: Patrick Crandol Date: Tue, 11 Dec 2018 18:20:04 -0500 Subject: Add option to share to Pinboard. (#2178) * Prelim. Add Pinboard based on the url found in the "For iPad" section here: https://pinboard.in/howto/ * add i18n string for Pinboard * Add help to pinboard * add title to Pinboard Share Title seems to be an element, but isn't documented in the API. Perhaps it's an alternative to description? It probably won't hurt to include it. * Feedback from @samplereality * Minor Whitespace --- app/i18n/cz/gen.php | 1 + app/i18n/de/gen.php | 1 + app/i18n/en/gen.php | 1 + app/i18n/es/gen.php | 1 + app/i18n/fr/gen.php | 1 + app/i18n/he/gen.php | 1 + app/i18n/it/gen.php | 1 + app/i18n/kr/gen.php | 1 + app/i18n/nl/gen.php | 1 + app/i18n/oc/gen.php | 1 + app/i18n/pt-br/gen.php | 1 + app/i18n/ru/gen.php | 1 + app/i18n/tr/gen.php | 1 + app/i18n/zh-cn/gen.php | 1 + app/shares.php | 7 +++++++ 15 files changed, 21 insertions(+) diff --git a/app/i18n/cz/gen.php b/app/i18n/cz/gen.php index 27ff9414c..08fce0280 100644 --- a/app/i18n/cz/gen.php +++ b/app/i18n/cz/gen.php @@ -172,6 +172,7 @@ return array( 'linkedin' => 'LinkedIn', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pinboard' => 'Pinboard', 'pocket' => 'Pocket', 'print' => 'Tisk', 'shaarli' => 'Shaarli', diff --git a/app/i18n/de/gen.php b/app/i18n/de/gen.php index 59ce371d3..c02a55b2c 100644 --- a/app/i18n/de/gen.php +++ b/app/i18n/de/gen.php @@ -172,6 +172,7 @@ return array( 'linkedin' => 'LinkedIn', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pinboard' => 'Pinboard', 'pocket' => 'Pocket', 'print' => 'Drucken', 'shaarli' => 'Shaarli', diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index f0ce8ed02..32f5ee02e 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -172,6 +172,7 @@ return array( 'linkedin' => 'LinkedIn', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pinboard' => 'Pinboard', 'pocket' => 'Pocket', 'print' => 'Print', 'shaarli' => 'Shaarli', diff --git a/app/i18n/es/gen.php b/app/i18n/es/gen.php index 183e3f794..db36e5f5b 100755 --- a/app/i18n/es/gen.php +++ b/app/i18n/es/gen.php @@ -172,6 +172,7 @@ return array( 'linkedin' => 'LinkedIn', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pinboard' => 'Pinboard', 'pocket' => 'Pocket', 'print' => 'Print', 'shaarli' => 'Shaarli', diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php index fa4dceadd..86d8461e6 100644 --- a/app/i18n/fr/gen.php +++ b/app/i18n/fr/gen.php @@ -172,6 +172,7 @@ return array( 'linkedin' => 'LinkedIn', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pinboard' => 'Pinboard', 'pocket' => 'Pocket', 'print' => 'Imprimer', 'shaarli' => 'Shaarli', diff --git a/app/i18n/he/gen.php b/app/i18n/he/gen.php index 9349cbce7..cf4a1fcda 100644 --- a/app/i18n/he/gen.php +++ b/app/i18n/he/gen.php @@ -172,6 +172,7 @@ return array( 'linkedin' => 'LinkedIn', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pinboard' => 'Pinboard', 'pocket' => 'Pocket', 'print' => 'הדפסה', 'shaarli' => 'Shaarli', diff --git a/app/i18n/it/gen.php b/app/i18n/it/gen.php index 3bf2f155f..9cc40ffe3 100644 --- a/app/i18n/it/gen.php +++ b/app/i18n/it/gen.php @@ -172,6 +172,7 @@ return array( 'linkedin' => 'LinkedIn', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pinboard' => 'Pinboard', 'pocket' => 'Pocket', 'print' => 'Stampa', 'shaarli' => 'Shaarli', diff --git a/app/i18n/kr/gen.php b/app/i18n/kr/gen.php index 744ec6fce..86a50e9c4 100644 --- a/app/i18n/kr/gen.php +++ b/app/i18n/kr/gen.php @@ -172,6 +172,7 @@ return array( 'linkedin' => 'LinkedIn', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pinboard' => 'Pinboard', 'pocket' => 'Pocket', 'print' => '인쇄', 'shaarli' => 'Shaarli', diff --git a/app/i18n/nl/gen.php b/app/i18n/nl/gen.php index 99b1cf9c2..bdf2e0abd 100644 --- a/app/i18n/nl/gen.php +++ b/app/i18n/nl/gen.php @@ -172,6 +172,7 @@ return array( 'linkedin' => 'LinkedIn', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pinboard' => 'Pinboard', 'pocket' => 'Pocket', 'print' => 'Print', 'shaarli' => 'Shaarli', diff --git a/app/i18n/oc/gen.php b/app/i18n/oc/gen.php index 246a74eb2..ffe10941d 100644 --- a/app/i18n/oc/gen.php +++ b/app/i18n/oc/gen.php @@ -172,6 +172,7 @@ return array( 'linkedin' => 'LinkedIn', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pinboard' => 'Pinboard', 'pocket' => 'Pocket', 'print' => 'Imprimir', 'shaarli' => 'Shaarli', diff --git a/app/i18n/pt-br/gen.php b/app/i18n/pt-br/gen.php index 8a0b26b3d..46ae53eb4 100644 --- a/app/i18n/pt-br/gen.php +++ b/app/i18n/pt-br/gen.php @@ -172,6 +172,7 @@ return array( 'linkedin' => 'LinkedIn', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pinboard' => 'Pinboard', 'pocket' => 'Pocket', 'print' => 'Imprimir', 'shaarli' => 'Shaarli', diff --git a/app/i18n/ru/gen.php b/app/i18n/ru/gen.php index f6b1f16ec..b55c6b667 100644 --- a/app/i18n/ru/gen.php +++ b/app/i18n/ru/gen.php @@ -172,6 +172,7 @@ return array( 'linkedin' => 'LinkedIn', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pinboard' => 'Pinboard', 'pocket' => 'Pocket', 'print' => 'Print', 'shaarli' => 'Shaarli', diff --git a/app/i18n/tr/gen.php b/app/i18n/tr/gen.php index 370660aba..a84c39f20 100644 --- a/app/i18n/tr/gen.php +++ b/app/i18n/tr/gen.php @@ -172,6 +172,7 @@ return array( 'linkedin' => 'LinkedIn', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pinboard' => 'Pinboard', 'pocket' => 'Pocket', 'print' => 'Print', 'shaarli' => 'Shaarli', diff --git a/app/i18n/zh-cn/gen.php b/app/i18n/zh-cn/gen.php index a0f74fdfa..1dcd95233 100644 --- a/app/i18n/zh-cn/gen.php +++ b/app/i18n/zh-cn/gen.php @@ -172,6 +172,7 @@ return array( 'linkedin' => 'LinkedIn', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pinboard' => 'Pinboard', 'pocket' => 'Pocket', 'print' => '打印', 'shaarli' => 'Shaarli', diff --git a/app/shares.php b/app/shares.php index 6d234b374..4f7fde3ed 100644 --- a/app/shares.php +++ b/app/shares.php @@ -137,4 +137,11 @@ return array( 'form' => 'simple', 'method' => 'GET', ), + 'pinboard' => array( + 'url' => 'https://pinboard.in/add?next=same&url=~LINK~&title=~TITLE~', + 'transform' => array('urlencode'), + 'help' => 'https://pinboard.in/api/', + 'form' => 'simple', + 'method' => 'GET', + ), ); -- cgit v1.2.3 From 478d3e6611e73974bd3b917c625bf0d099cbf123 Mon Sep 17 00:00:00 2001 From: Patrick Crandol Date: Wed, 12 Dec 2018 06:04:31 -0500 Subject: Decouple scrolling of feeds and articles (#2117) * Remove Sticky Kit Remove sticky-kit, as functionality is unsuitable for separate scrolling. * Remove sticky-kit load in main.js Further removing the sticky-kit kruft * Finish removal of references to Sticky-kit * CSS Changes to template for Independent Scrolling * Addition of JS and supporting CSS and html * More CSS fixes to establish expected behavior Should be able to scroll navbar without it being in sticky mode now. * Fix typo in main.js sortcut.js -> shortcut.js * Fix unexpected tree scrolling behavior * Change name of generic JS function * Improve sticky-aside * CSS changes in themes to accommodate independent Scroll In themes where .aside's width is not the standard 300px, .tree's width must be specified to be equal to .aside * Remove Sticky-Kit from README files * Updates to Sticky-Aside * Update Template to fix screwup * Make Recalculating height actually work * Let sidebar fill height if nav buttons aren't visible * Make accommodating for nav buttons actually work * update Swage theme for Independent Scroll feature * Integrate sticky_aside into main.js * Add Simple Scrollbar * Patch scrollbar color for themes with dark colored asides * Increase Visibility of scrollbar on Dark Themes * Improve async loading, events, and performance * CSS typo * Fix double scrollbar on mobile * Fix regression causing sticky to not be removed * No $ for non-jQuery variables * Fix strange condition + option for nice scrollbar * Initial attempt to use css sticky * Add stickyfill * make the correct element sticky * re-add incorrectly removed sidebar code * Continue fixing mistaken deletions * decrease frequency of recalc * use minified version of simple-scrollbar. * Load stickyfill instead of injecting * put recalc back where it belongs * re-remove script injector * remove padding bottom padding was causing the last item in the feed to be hidden under the nav buttons * Manual merge of css_scrollbar Add auto-detection of -webkit-scrollbar-thumb, otherwise fall back to simple-scrollbar.js * Fix Regression Sticky recalc is still needed when using css scrollbars * Replace method of closing dropdowns Changed from an overlay href to a javascript solution, for better compatibility * Remove Treepadding Treepadding was causing dropdown menus at the bottom of the tree to be obscured. * Undo unnecessary move of dropdown-target * Move Dropdown Handler to a sensibleish place * Fix light Scrollbar color not picking up on Firefox * Minor syntax * Minor Clarification of CSS/ patch BlueLagoon * Change logic for native WebKit scrollbar detection Fix https://github.com/FreshRSS/FreshRSS/pull/2117#issuecomment-444251419 Tested with Firefox 63, Firefox 65, Chrome 71, IE11, Edge 42 * Fixes for other views E.g. reader view * Cleaner way of generating hash for dropdowns * Make dropdown-toggle an actual toggle * Prepare for CSS Scrollbars Module Level 1 * Fix regression causing my labels dropdown not to appear * remove unneeded dropdown-close css rule * Re-apply some lost changes https://github.com/FreshRSS/FreshRSS/pull/2117/commits/3c509989e890b88852e52c67c1c5507d1e0bf28c * Add standard scrollbar compatibility E.g. Firefox 64+ * Make All dropdowns click-to-close * Remove BlueLagoon template * Try to fix Firefox https://github.com/FreshRSS/FreshRSS/pull/2117#discussion_r239539984 * Add CSS rules necessary for consistent function of scrollbar in Firefox * Use inheritance to determine width * Use overlay scrollbar where possible * Test Reduced Listener * Fix Firefox 62 And show subtle scrollbar even when not hovering * Add margin at bottom To allow opening the menus https://github.com/FreshRSS/FreshRSS/pull/2117#issuecomment-444571218 * Minor - tab correction * Spaces -> tabs * Remove unneeded inheritance * Fix indenting * Revert bad merge * Messy WIP to make dropdowns work * Style Cleanup * Break it down * Lets try a move-it move-it * Update p/scripts/main.js Co-Authored-By: pattems * Update p/themes/BlueLagoon/BlueLagoon.css Co-Authored-By: pattems * separate ALL THE THINGS * erroneous commas * and to or * removing double condition that doesn't do what I want * More breaking down * fix var * Fix variable name again * Remove magic number https://github.com/FreshRSS/FreshRSS/pull/2117#discussion_r240052598 * Suuuuper inelegant solution for dropdowns * lets try that again * Inelegant Fix For Dropdowns Now with 100% more working dropdowns * Make sidebar dropdowns work correctly? * Fix reversion * Make JS scrollbar always visible * Remove unneeded CSS Added early in this pull request, didn't get pulled out when it was obsolete * Fix CSS removal I missed * CSS comment update/consistency for dark themes * Clean Up Duplicate code * Make dropdowns properly hide Downside: Can no longer click on header/nav buttons to close * Strip unneeded if statement * jshint -W018 https://github.com/FreshRSS/FreshRSS/pull/2117#discussion_r240392851 * Half-reversion to old dropdown * make overlay href scale to sidebar width * remove init of nonexistent method * remove trailing tabs * move #close href where it belongs in index.phtml * Revert all changes to index.phtml * remove whitespace accidentally added in last commit * Move var's in init_column categories * Finish putting old style dropdowns back * Make CSS changes to use support statements * Cleanup Whitespace * re-add missing class * spaces -> tabs in main.js * tabs -> spaces css * Minor whitespace * Cleanup per @Alkarex * Second attempt to add bottom margin https://github.com/FreshRSS/FreshRSS/pull/2117#discussion_r240820901 * Fix error in IE11 * Simple-scrollbar color match for dark themes --- README.fr.md | 4 +- README.md | 6 +- app/layout/aside_feed.phtml | 3 +- p/scripts/jquery.sticky-kit.min.js | 9 --- p/scripts/main.js | 116 +++++++++++++++++++++++------------ p/scripts/simple-scrollbar.min.js | 2 + p/themes/BlueLagoon/BlueLagoon.css | 26 ++++++++ p/themes/Dark/dark.css | 25 ++++++++ p/themes/Flat/flat.css | 25 ++++++++ p/themes/Screwdriver/screwdriver.css | 25 ++++++++ p/themes/Swage/swage.css | 26 ++++++++ p/themes/Swage/swage.scss | 38 ++++++++++-- p/themes/base-theme/template.css | 99 +++++++++++++++++++++++++++--- 13 files changed, 338 insertions(+), 66 deletions(-) delete mode 100644 p/scripts/jquery.sticky-kit.min.js create mode 100644 p/scripts/simple-scrollbar.min.js diff --git a/README.fr.md b/README.fr.md index 312fbac45..a8a8f87ff 100644 --- a/README.fr.md +++ b/README.fr.md @@ -192,13 +192,13 @@ Tout client supportant une API de type Fever ; Sélection : * [php-http-304](https://alexandre.alapetite.fr/doc-alex/php-http-304/) * [jQuery](https://jquery.com/) * [lib_opml](https://github.com/marienfressinaud/lib_opml) -* [jQuery Plugin Sticky-Kit](https://leafo.net/sticky-kit/) * [keyboard_shortcuts](http://www.openjs.com/scripts/events/keyboard_shortcuts/) * [flotr2](http://www.humblesoftware.com/flotr2) -## Uniquement pour certaines options +## Uniquement pour certaines options ou configurations * [bcrypt.js](https://github.com/dcodeIO/bcrypt.js) * [phpQuery](https://github.com/phpquery/phpquery) +* [simple-scrollbar](https://github.com/buzinas/simple-scrollbar) ## Si les fonctions natives ne sont pas disponibles * [Services_JSON](https://pear.php.net/pepr/pepr-proposal-show.php?id=198) diff --git a/README.md b/README.md index 1e86d9f57..d6e13851e 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ FreshRSS comes with absolutely no warranty. More detailed information about installation and server configuration can be found in [our documentation](https://freshrss.github.io/FreshRSS/en/admins/02_Installation.html). -## Automated install +## Automated install * [![Docker](https://www.docker.com/sites/default/files/horizontal.png)](./Docker/) * [![YunoHost](https://install-app.yunohost.org/install-with-yunohost.png)](https://install-app.yunohost.org/?app=freshrss) * [![Cloudron](https://cloudron.io/img/button.svg)](https://cloudron.io/button.html?app=org.freshrss.cloudronapp) @@ -199,13 +199,13 @@ Supported clients are: * [php-http-304](https://alexandre.alapetite.fr/doc-alex/php-http-304/) * [jQuery](https://jquery.com/) * [lib_opml](https://github.com/marienfressinaud/lib_opml) -* [jQuery Plugin Sticky-Kit](https://leafo.net/sticky-kit/) * [keyboard_shortcuts](http://www.openjs.com/scripts/events/keyboard_shortcuts/) * [flotr2](http://www.humblesoftware.com/flotr2) -## Only for some options +## Only for some options or configurations * [bcrypt.js](https://github.com/dcodeIO/bcrypt.js) * [phpQuery](https://github.com/phpquery/phpquery) +* [simple-scrollbar](https://github.com/buzinas/simple-scrollbar) ## If native functions are not available * [Services_JSON](https://pear.php.net/pepr/pepr-proposal-show.php?id=198) diff --git a/app/layout/aside_feed.phtml b/app/layout/aside_feed.phtml index 7b1645ebd..73b200686 100644 --- a/app/layout/aside_feed.phtml +++ b/app/layout/aside_feed.phtml @@ -21,7 +21,7 @@
-
    + diff --git a/p/scripts/jquery.sticky-kit.min.js b/p/scripts/jquery.sticky-kit.min.js deleted file mode 100644 index e2a3c6de9..000000000 --- a/p/scripts/jquery.sticky-kit.min.js +++ /dev/null @@ -1,9 +0,0 @@ -/* - 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 +var sidebar = document.getElementById('sidebar'); +var useJsScrollbar = true; +try { + /*jshint -W018 */ + useJsScrollbar = sidebar && !CSS.supports('scrollbar-color: auto') && + !(parseInt(getComputedStyle(sidebar, '::-webkit-scrollbar').width) < sidebar.offsetWidth); + /*jshint +W018 */ +} catch (ex) { +} +if (useJsScrollbar) { + inject_script('simple-scrollbar.min.js'); +} + +function sticky_recalc() { + var h = 0; + if ($nav_entries && $nav_entries.length > 0) { + h = $(window).height() - sidebar.getBoundingClientRect().top - $nav_entries.height(); + } else { + h = $(window).height() - sidebar.getBoundingClientRect().top; + } + if (h > 0) { + $(sidebar).height(h); + } +} + +function init_simple_scrollbar() { + if (!window.SimpleScrollbar) { + if (window.console) { + console.log('FreshRSS waiting for simple-scrollbar…'); + } + window.setTimeout(init_simple_scrollbar, 100); + } else { + SimpleScrollbar.initEl(sidebar); + } +} +var scrollTimeout; +function init_sticky_sidebar(){ + if (!sidebar) { + return; + } + if (useJsScrollbar) { + init_simple_scrollbar(); + } + $(window).scroll(function () { + if (scrollTimeout) { + clearTimeout(scrollTimeout); + scrollTimeout = null; + } + scrollTimeout = setTimeout(sticky_recalc, 200); + }); + window.onresize = sticky_recalc; +} function init_confirm_action() { $('body').on('click', '.confirm', function () { @@ -1536,7 +1576,6 @@ function init_beforeDOM() { return; } if (['normal', 'reader', 'global'].indexOf(context.current_view) >= 0) { - inject_script('jquery.sticky-kit.min.js'); init_normal(); } } @@ -1554,6 +1593,7 @@ function init_afterDOM() { $stream = $('#stream'); if ($stream.length > 0) { init_load_more($stream); + init_sticky_sidebar(); init_posts(); init_nav_entries(); init_dynamic_tags(); diff --git a/p/scripts/simple-scrollbar.min.js b/p/scripts/simple-scrollbar.min.js new file mode 100644 index 000000000..36b7df0b8 --- /dev/null +++ b/p/scripts/simple-scrollbar.min.js @@ -0,0 +1,2 @@ +// https://github.com/buzinas/simple-scrollbar +!function(t,e){"object"==typeof exports?module.exports=e(window,document):t.SimpleScrollbar=e(window,document)}(this,function(t,e){function s(t){Object.prototype.hasOwnProperty.call(t,"data-simple-scrollbar")||Object.defineProperty(t,"data-simple-scrollbar",{value:new o(t)})}function i(t,s){function i(t){var e=t.pageY-a;a=t.pageY,n(function(){s.el.scrollTop+=e/s.scrollRatio})}function r(){t.classList.remove("ss-grabbed"),e.body.classList.remove("ss-grabbed"),e.removeEventListener("mousemove",i),e.removeEventListener("mouseup",r)}var a;t.addEventListener("mousedown",function(s){return a=s.pageY,t.classList.add("ss-grabbed"),e.body.classList.add("ss-grabbed"),e.addEventListener("mousemove",i),e.addEventListener("mouseup",r),!1})}function r(t){for(this.target=t,this.direction=window.getComputedStyle(this.target).direction,this.bar='
    ',this.wrapper=e.createElement("div"),this.wrapper.setAttribute("class","ss-wrapper"),this.el=e.createElement("div"),this.el.setAttribute("class","ss-content"),"rtl"===this.direction&&this.el.classList.add("rtl"),this.wrapper.appendChild(this.el);this.target.firstChild;)this.el.appendChild(this.target.firstChild);this.target.appendChild(this.wrapper),this.target.insertAdjacentHTML("beforeend",this.bar),this.bar=this.target.lastChild,i(this.bar,this),this.moveBar(),this.el.addEventListener("scroll",this.moveBar.bind(this)),this.el.addEventListener("mouseenter",this.moveBar.bind(this)),this.target.classList.add("ss-container");var s=window.getComputedStyle(t);"0px"===s.height&&"0px"!==s["max-height"]&&(t.style.height=s["max-height"])}function a(){for(var t=e.querySelectorAll("*[ss-container]"),i=0;i=1?i.bar.classList.add("ss-hidden"):(i.bar.classList.remove("ss-hidden"),i.bar.style.cssText="height:"+Math.max(100*i.scrollRatio,10)+"%; top:"+i.el.scrollTop/e*100+"%;right:"+a+"px;")})}},e.addEventListener("DOMContentLoaded",a),r.initEl=s,r.initAll=a;var o=r;return o}); \ No newline at end of file diff --git a/p/themes/BlueLagoon/BlueLagoon.css b/p/themes/BlueLagoon/BlueLagoon.css index f167f2051..263764a9c 100644 --- a/p/themes/BlueLagoon/BlueLagoon.css +++ b/p/themes/BlueLagoon/BlueLagoon.css @@ -564,6 +564,32 @@ a.btn { color: #0090FF } +/*=== Scrollbar */ + +@supports (scrollbar-width: thin) { + #sidebar { + scrollbar-color: rgba(255, 255, 255, 0.05) rgba(0, 0, 0, 0.0); + } + #sidebar:hover { + scrollbar-color: rgba(255, 255, 255, 0.3) rgba(0, 0, 0, 0.0); + } +} +.ss-scroll { + background: rgba(255, 255, 255, 0.1); +} +.ss-container:hover .ss-scroll, +.ss-container:active .ss-scroll { + background: rgba(255, 255, 255, 0.3); +} +@supports not (scrollbar-width: thin) { + #sidebar::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.1); + } + #sidebar:hover::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.3); + } +} + /*=== STRUCTURE */ /*===============*/ /*=== Header */ diff --git a/p/themes/Dark/dark.css b/p/themes/Dark/dark.css index 31ff514a2..b8366caeb 100644 --- a/p/themes/Dark/dark.css +++ b/p/themes/Dark/dark.css @@ -502,6 +502,31 @@ a.btn { color: #888; } +/*=== Scrollbar */ +@supports (scrollbar-width: thin) { + #sidebar { + scrollbar-color: rgba(255, 255, 255, 0.05) rgba(0, 0, 0, 0.0); + } + #sidebar:hover { + scrollbar-color: rgba(255, 255, 255, 0.3) rgba(0, 0, 0, 0.0); + } +} +.ss-scroll { + background: rgba(255, 255, 255, 0.1); +} +.ss-container:hover .ss-scroll, +.ss-container:active .ss-scroll { + background: rgba(255, 255, 255, 0.3); +} +@supports not (scrollbar-width: thin) { + #sidebar::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.1); + } + #sidebar:hover::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.3); + } +} + /*=== STRUCTURE */ /*===============*/ /*=== Header */ diff --git a/p/themes/Flat/flat.css b/p/themes/Flat/flat.css index be047a394..176a541f7 100644 --- a/p/themes/Flat/flat.css +++ b/p/themes/Flat/flat.css @@ -505,6 +505,31 @@ a.btn { color: #fff; } +/*=== Scrollbar */ +@supports (scrollbar-width: thin) { + #sidebar { + scrollbar-color: rgba(255, 255, 255, 0.05) rgba(0, 0, 0, 0.0); + } + #sidebar:hover { + scrollbar-color: rgba(255, 255, 255, 0.3) rgba(0, 0, 0, 0.0); + } +} +.ss-scroll { + background: rgba(255, 255, 255, 0.1); +} +.ss-container:hover .ss-scroll, +.ss-container:active .ss-scroll { + background: rgba(255, 255, 255, 0.3); +} +@supports not (scrollbar-width: thin) { + #sidebar::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.1); + } + #sidebar:hover::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.3); + } +} + /*=== STRUCTURE */ /*===============*/ /*=== Header */ diff --git a/p/themes/Screwdriver/screwdriver.css b/p/themes/Screwdriver/screwdriver.css index 1bc49c2db..b92dbac3e 100644 --- a/p/themes/Screwdriver/screwdriver.css +++ b/p/themes/Screwdriver/screwdriver.css @@ -559,6 +559,31 @@ a.btn { .tree-folder-items > .item.active > a { } +/*=== Scrollbar */ +@supports (scrollbar-width: thin) { + #sidebar { + scrollbar-color: rgba(255, 255, 255, 0.05) rgba(0, 0, 0, 0.0); + } + #sidebar:hover { + scrollbar-color: rgba(255, 255, 255, 0.3) rgba(0, 0, 0, 0.0); + } +} +.ss-scroll { + background: rgba(255, 255, 255, 0.1); +} +.ss-container:hover .ss-scroll, +.ss-container:active .ss-scroll { + background: rgba(255, 255, 255, 0.3); +} +@supports not (scrollbar-width: thin) { + #sidebar::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.1); + } + #sidebar:hover::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.3); + } +} + /*=== STRUCTURE */ /*===============*/ /*=== Header */ diff --git a/p/themes/Swage/swage.css b/p/themes/Swage/swage.css index 8f262da8c..a8ff0bdd5 100644 --- a/p/themes/Swage/swage.css +++ b/p/themes/Swage/swage.css @@ -529,6 +529,32 @@ text-decoration: none; color: #FCFCFC; } +@supports (scrollbar-width: thin) { + #sidebar { +scrollbar-color: rgba(255, 255, 255, 0.05) rgba(0, 0, 0, 0.0); +} +#sidebar:hover { +scrollbar-color: rgba(255, 255, 255, 0.3) rgba(0, 0, 0, 0.0); +} +} + +.ss-scroll { +background: rgba(255, 255, 255, 0.1); +} +.ss-container:hover .ss-scroll, +.ss-container:active .ss-scroll { +background: rgba(255, 255, 255, 0.3); +} + +@supports not (scrollbar-width: thin) { +#sidebar::-webkit-scrollbar-thumb { +background: rgba(255, 255, 255, 0.1); +} +#sidebar:hover::-webkit-scrollbar-thumb { +background: rgba(255, 255, 255, 0.3); +} +} + .header > .item { vertical-align: middle; } diff --git a/p/themes/Swage/swage.scss b/p/themes/Swage/swage.scss index c0c76cf14..8ddac14db 100644 --- a/p/themes/Swage/swage.scss +++ b/p/themes/Swage/swage.scss @@ -351,7 +351,7 @@ form { > a { min-width: initial; white-space: nowrap; - } + } &:hover { background: $color_nav; color: $color_light; @@ -603,6 +603,32 @@ form { } } +@supports (scrollbar-width: thin) { + #sidebar { + scrollbar-color: rgba(255, 255, 255, 0.05) rgba(0, 0, 0, 0.0); + } + #sidebar:hover { + scrollbar-color: rgba(255, 255, 255, 0.3) rgba(0, 0, 0, 0.0); + } +} + +.ss-scroll { + background: rgba(255, 255, 255, 0.1); +} +.ss-container:hover .ss-scroll, +.ss-container:active .ss-scroll { + background: rgba(255, 255, 255, 0.3); +} + +@supports not (scrollbar-width: thin) { + #sidebar::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.1); + } + #sidebar:hover::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.3); + } +} + .header { > .item { vertical-align: middle; @@ -918,7 +944,7 @@ form { #global { height: 0; } - + .header { height: 55px; background: $color_aside; @@ -936,7 +962,7 @@ form { color: $color_light; padding-left: 5px; } - + input { border-left: 5px solid; border-right: 1px darken( $color_light, 10%); @@ -984,7 +1010,7 @@ form { .dropdown-header, .dropdown-menu > .item { padding: 12px; } - + #new-article { width: 100%; bottom: initial; @@ -1207,5 +1233,5 @@ button.as-link { background: inital; } } - -} \ No newline at end of file + +} diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index fdc2f884e..60c4822ef 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -109,7 +109,7 @@ input[type="checkbox"] { min-height: 15px !important; } .dropdown-menu label > input[type="text"] { - with: 150px; + width: 150px; width: calc(99% - 5em); } .dropdown-menu input[type="checkbox"] { @@ -168,6 +168,13 @@ td.numeric { display: block; } +@supports (position: sticky) { + #mark-read-aside { + position: sticky; + top: 0; + } +} + /*=== Buttons */ .stick { display: inline-block; @@ -273,6 +280,7 @@ a.btn { left: 0; right: 0; display: block; z-index: -10; + cursor: default; } .separator { display: block; @@ -373,16 +381,90 @@ a.btn { cursor: grab; } +/*=== Scrollbar */ +.ss-wrapper { + overflow: hidden; + width: 100%; + height: 100%; + position: relative; + z-index: 1; + float: left; +} + +.ss-content { + height: 100%; + width: calc(100% + 18px); + padding: 0 0 0 0; + position: relative; + overflow-y: scroll; + box-sizing: border-box; +} + +.ss-content.rtl { + width: calc(100% + 18px); + right: auto; +} + +.ss-scroll { + position: relative; + background: rgba(0, 0, 0, 0.1); + width: 9px; + border-radius: 4px; + top: 0; + z-index: 2; + cursor: pointer; + transition: opacity 0.25s linear; +} + +.ss-hidden { + display: none; +} + +.ss-container:hover .ss-scroll, +.ss-container:active .ss-scroll { + background: rgba(0, 0, 0, 0.3); +} + +.ss-grabbed { + -o-user-select: none; + -ms-user-select: none; + -moz-user-select: none; + -webkit-user-select: none; + user-select: none; +} + +@supports (scrollbar-width: thin) { + #sidebar { + overflow-y: scroll; + scrollbar-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.05); + scrollbar-width: thin; + } + #sidebar:hover { + scrollbar-color: rgba(0, 0, 0, 0.3) rgba(0, 0, 0, 0.05); + } +} + +@supports not (scrollbar-width: thin) { + #sidebar::-webkit-scrollbar { + background: rgba(0, 0, 0, 0.05); + width: 8px; + } + #sidebar::-webkit-scrollbar-thumb { + background: rgba(0, 0, 0, 0.1); + border-radius: 5px; + display: unset; + } + #sidebar:hover::-webkit-scrollbar-thumb { + background: rgba(0, 0, 0, 0.3); + } +} + /*=== Tree */ .tree { margin: 0; - padding: 0 0 2em 0; list-style: none; text-align: left; -} - -.treepadding { - padding: 0 0 15em 0; + overflow-x: hidden; } .tree-folder-items { @@ -412,6 +494,10 @@ a.btn { white-space: nowrap; text-overflow: ellipsis; } +.tree-bottom { + visibility: hidden; + margin-bottom: 15em; +} /*=== STRUCTURE */ /*===============*/ @@ -914,7 +1000,6 @@ pre.enclosure-description { } .aside:target { width: 90%; - overflow: auto; } .flux_header .item.website { -- cgit v1.2.3 From 983aa587ee71a83d21b17de29d2a26763b18292e Mon Sep 17 00:00:00 2001 From: Patrick Crandol Date: Sat, 15 Dec 2018 04:56:38 -0500 Subject: Add aside_feed to reader view (#2180) * Add Nav menu to reader mode At this point, it appears to be non-functional in reader mode. * Add aside_feed toggle to reader view * make init_column_categories work in reader view * Make sidebar links redirect to proper view * CSS to support toggleable sidebar in reader view * remove unneeded !important --- app/layout/aside_feed.phtml | 15 ++++++++------- app/layout/nav_menu.phtml | 2 +- app/views/index/reader.phtml | 1 + p/scripts/main.js | 2 +- p/themes/base-theme/template.css | 23 +++++++++++++++++++++++ 5 files changed, 34 insertions(+), 9 deletions(-) diff --git a/app/layout/aside_feed.phtml b/app/layout/aside_feed.phtml index 73b200686..5efaa54d1 100644 --- a/app/layout/aside_feed.phtml +++ b/app/layout/aside_feed.phtml @@ -1,4 +1,5 @@ hide_read_feeds && FreshRSS_Context::isStateEnabled(FreshRSS_Entry::STATE_NOT_READ) && @@ -24,13 +25,13 @@
    - name(); ?> + name(); ?>
@@ -69,7 +70,7 @@
  • @@ -111,7 +112,7 @@