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(-) (limited to 'p') 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 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(-) (limited to 'p') 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(-) (limited to 'p') 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(-) (limited to 'p') 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 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(-) (limited to 'p') 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 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(-) (limited to 'p') 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(-) (limited to 'p') 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 @@ - @@ -69,7 +70,7 @@
  • @@ -111,7 +112,7 @@