{{data.title}}
{{data.domain}}
{{data.subreddit}}
{{#data.over_18}}NSFW{{/data.over_18}}{{#data.stickied}}Stickied{{/data.stickied}}├── .gitignore ├── css ├── _animations.scss ├── _base.scss ├── _buttons.scss ├── _inactive.scss ├── _notification.scss ├── _yosemite.scss ├── desk.scss ├── normalize.css └── reeddit.scss ├── img ├── add.png ├── add@2.png ├── alienHead.png ├── bg.png ├── cancel.png ├── close.png ├── comment.png ├── comment@2x.png ├── delete.png ├── delete@2x.png ├── edit.png ├── icon.png ├── icon144.png ├── refresh.png ├── refresh1.png ├── share.png └── share@2x.png ├── index.html ├── index.jade ├── js ├── dom.js ├── libs.js ├── reeddit.js └── sharing.js ├── package.json └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.sublime-project 2 | *.sublime-workspace 3 | .idea/* 4 | -------------------------------------------------------------------------------- /css/_animations.scss: -------------------------------------------------------------------------------- 1 | .anim-delete { 2 | height: 0; 3 | overflow: hidden; 4 | transition: height 200ms; 5 | } 6 | 7 | .anim-dismiss { 8 | transition: opacity 200ms; 9 | opacity: 0; 10 | } 11 | 12 | @-webkit-keyframes reveal { 13 | 0% { 14 | opacity: 0; 15 | } 16 | 100% { 17 | opacity: 1; 18 | } 19 | } 20 | 21 | @keyframes reveal { 22 | 0% { 23 | opacity: 0; 24 | } 25 | 100% { 26 | opacity: 1; 27 | } 28 | } 29 | 30 | .anim-reveal { 31 | opacity: 0; 32 | -webkit-animation: reveal 700ms ease both; 33 | animation: reveal 700ms ease both; 34 | } 35 | 36 | .loader { 37 | margin: 15px auto; 38 | background-color: #333; 39 | color: #777; 40 | width: 15px; 41 | height: 15px; 42 | border-radius: 100%; 43 | -webkit-animation: loading 1.0s ease-in-out infinite; 44 | animation: loading 1.0s ease-in-out infinite; 45 | text-align: center; 46 | font-weight: 700; 47 | display: block; 48 | } 49 | 50 | .loader-error { 51 | width: 100%; 52 | -webkit-animation: none; 53 | animation: none; 54 | background-color: transparent; 55 | } 56 | 57 | @-webkit-keyframes loading { 58 | 0% { 59 | opacity: 1; 60 | -webkit-transform: scale(0); 61 | } 62 | 100% { 63 | opacity: 0; 64 | -webkit-transform: scale(2); 65 | } 66 | } 67 | 68 | @keyframes loading { 69 | 0% { 70 | opacity: 1; 71 | transform: scale(0); 72 | } 73 | 100% { 74 | opacity: 0; 75 | transform: scale(2); 76 | } 77 | } 78 | 79 | @keyframes shake { 80 | 20% { 81 | transform: translateX(10px); 82 | } 83 | 40% { 84 | transform: translateX(-10px); 85 | } 86 | 60% { 87 | transform: translateX(5px); 88 | } 89 | 80% { 90 | transform: translateX(-5px); 91 | } 92 | } 93 | 94 | @-webkit-keyframes shake { 95 | 20% { 96 | -webkit-transform: translateX(10px); 97 | } 98 | 40% { 99 | -webkit-transform: translateX(-10px); 100 | } 101 | 60% { 102 | -webkit-transform: translateX(5px); 103 | } 104 | 80% { 105 | -webkit-transform: translateX(-5px); 106 | } 107 | } 108 | 109 | .anim-shake { 110 | -webkit-animation: shake 350ms ease-in-out; 111 | animation: shake 350ms ease-in-out; 112 | } 113 | 114 | @-webkit-keyframes bounceOut { 115 | 0% { 116 | -webkit-transform: scale(1); 117 | } 118 | 25% { 119 | -webkit-transform: scale(0.95); 120 | } 121 | 50% { 122 | opacity: 1; 123 | -webkit-transform: scale(1.1); 124 | } 125 | 100% { 126 | opacity: 0; 127 | -webkit-transform: scale(0.3); 128 | } 129 | } 130 | 131 | @keyframes bounceOut { 132 | 0% { 133 | transform: scale(1); 134 | } 135 | 25% { 136 | transform: scale(0.95); 137 | } 138 | 50% { 139 | opacity: 1; 140 | transform: scale(1.1); 141 | } 142 | 100% { 143 | opacity: 0; 144 | transform: scale(0.3); 145 | } 146 | } 147 | 148 | .anim-bounce-out { 149 | -webkit-animation: bounceOut 1s ease-in-out both; 150 | animation: bounceOut 1s ease-in-out both; 151 | } 152 | 153 | @-webkit-keyframes bounceInDown { 154 | 0% { 155 | opacity: 0; 156 | -webkit-transform: translateY(- 2000 px); 157 | } 158 | 60% { 159 | opacity: 1; 160 | -webkit-transform: translateY(30px); 161 | } 162 | 80% { 163 | -webkit-transform: translateY(-10px); 164 | } 165 | 100% { 166 | -webkit-transform: translateY(0); 167 | } 168 | } 169 | 170 | @keyframes bounceInDown { 171 | 0% { 172 | opacity: 0; 173 | transform: translateY(-2000px); 174 | } 175 | 60% { 176 | opacity: 1; 177 | transform: translateY(30px); 178 | } 179 | 80% { 180 | transform: translateY(-10px); 181 | } 182 | 100% { 183 | opacity: 1; 184 | transform: translateY(0); 185 | } 186 | } 187 | 188 | .anim-bounceInDown { 189 | -webkit-animation: bounceInDown 500ms ease-in-out both; 190 | animation: bounceInDown 500ms ease-in-out both; 191 | } 192 | -------------------------------------------------------------------------------- /css/_base.scss: -------------------------------------------------------------------------------- 1 | $main-red: #cf4f5b; 2 | $header-black: #4e4e4e; 3 | $header-height: 44px; 4 | $blue: #4286F5; 5 | $icon-hover-color: $blue; 6 | 7 | @mixin size($width, $height: $width) { 8 | width: $width; 9 | height: $height; 10 | } 11 | 12 | @mixin letterpress($opacity: .5) { 13 | text-shadow: 0 1px 0 rgba(255, 255, 255, $opacity); 14 | } 15 | 16 | @mixin emboss($top-opacity: .5, $bottom-opacity: .5) { 17 | box-shadow: inset rgba(0, 0, 0, $top-opacity) 0 1px 0, 18 | rgba(255, 255, 255, $bottom-opacity) 0 1px 0; 19 | } 20 | 21 | %overflow-ellipsis { 22 | white-space: nowrap; 23 | text-overflow: ellipsis; 24 | overflow-x: hidden; 25 | } 26 | 27 | %disable-letterpress { 28 | text-shadow: none; 29 | } 30 | -------------------------------------------------------------------------------- /css/_buttons.scss: -------------------------------------------------------------------------------- 1 | .button { 2 | @include size(28px, 22px); 3 | border: 1px solid transparent; 4 | border-radius: 4px; 5 | margin: 0 auto; 6 | 7 | &:hover, 8 | &:active { 9 | border: 1px solid #777; 10 | box-shadow: rgba(255, 255, 255, .4) 0 1px; 11 | } 12 | 13 | &:hover { 14 | background-image: linear-gradient(#eee, #959595); 15 | } 16 | 17 | &:active { 18 | background-image: linear-gradient(#959595, #d5d5d5); 19 | box-shadow: inset 0 3px 7px #757575, rgba(white, 0.4) 0 1px; 20 | } 21 | } 22 | 23 | #refresh-icon .icon-btn { 24 | opacity: .8; 25 | 26 | &:active { 27 | opacity: .9; 28 | } 29 | } 30 | 31 | .btn-side-menu-add { 32 | $btn-color: #777; 33 | position: absolute; 34 | right: 0; 35 | padding-left: 10px; 36 | padding-right: 10px; 37 | color: $btn-color; 38 | font-size: 16px; 39 | font-weight: 600; 40 | visibility: hidden; 41 | 42 | &:active { 43 | color: $icon-hover-color; 44 | } 45 | } 46 | 47 | .menu-desc:hover .btn-side-menu-add { 48 | visibility: visible; 49 | } 50 | 51 | .btn-edit-sub:hover { 52 | color: $icon-hover-color; 53 | } 54 | 55 | .comments-button, 56 | .btn-general { 57 | color: #555; 58 | background-image: linear-gradient(whiteSmoke 0%, #CCC 100%); 59 | box-shadow: rgba(255, 255, 255, .4) 0 1px 0 inset, 60 | rgba(255, 255, 255, .3) 0 25px 30px -12px inset, 61 | rgba(0, 0, 0, .6) 0 1px 2px; 62 | } 63 | 64 | .btn-general { 65 | background-color: #bbb; 66 | padding: 3px 10px; 67 | border-radius: 4px; 68 | font-weight: 700; 69 | text-align: center; 70 | border: 0; 71 | 72 | &:active { 73 | background-image: linear-gradient(#3f3f3f 50%, #4b4b4b 100%); 74 | box-shadow: 0 2px 7px black inset, 75 | rgba(255, 255, 255, .4) 0 1px 0; 76 | } 77 | 78 | &:hover, 79 | &:visited { 80 | color: #555; 81 | } 82 | 83 | &:active { 84 | color: #f5f5f5; 85 | } 86 | } 87 | 88 | #btn-save-data { 89 | width: 70%; 90 | margin: 0 auto; 91 | line-height: 20px; 92 | } 93 | 94 | #btn-import-data { 95 | width: 175px; 96 | } 97 | 98 | .btn-footer { 99 | position: absolute; 100 | } 101 | 102 | .btn-share { 103 | @include size(32px, 22px); 104 | -webkit-box-flex: 1; 105 | margin-right: 10px; 106 | display: inline-block; 107 | background-image: url(../img/share.png); 108 | background-size: 18px; 109 | background-repeat: no-repeat; 110 | background-position: center; 111 | 112 | &:active { 113 | background-image: url("../img/share.png"); 114 | } 115 | } 116 | 117 | .replies-button:active { 118 | background-image: linear-gradient(#ccc 0%, #777 100%) !important; 119 | color: white !important; 120 | } 121 | 122 | .btn-load-more { 123 | padding: 5px 10px; 124 | margin: 20px auto; 125 | text-align: center; 126 | width: 80%; 127 | border-radius: 5px; 128 | font-size: 14px; 129 | font-weight: 700; 130 | } 131 | 132 | .btn-edit-channel, 133 | .btn-remove-channel, 134 | .btn-remove-subreddit, 135 | .btn-add-sub { 136 | &:active { 137 | background-color: #ddd; 138 | } 139 | } 140 | 141 | .comments-button { 142 | padding: 3px 10px; 143 | border-radius: 4px; 144 | font-size: 11px; 145 | font-weight: 700; 146 | display: block; 147 | text-align: center; 148 | width: 90px; 149 | margin: 0 auto; 150 | } 151 | -------------------------------------------------------------------------------- /css/_inactive.scss: -------------------------------------------------------------------------------- 1 | .inactive { 2 | 3 | header, 4 | .view-footer { 5 | background-image: linear-gradient(#e5e5e5, #d5d5d5); 6 | box-shadow: none; 7 | } 8 | 9 | header { 10 | border-color: #999; 11 | } 12 | 13 | #header-icon, 14 | #main-title, 15 | #title, 16 | #footer-sub, 17 | #footer-post, 18 | .btn-footer, 19 | .icon-btn { 20 | opacity: .7; 21 | } 22 | 23 | #detail-close { 24 | opacity: .5; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /css/_notification.scss: -------------------------------------------------------------------------------- 1 | .notification { 2 | background-color: rgba(0, 0, 0, .8); 3 | color: white; 4 | border-radius: 4px; 5 | text-align: center; 6 | line-height: 30px; 7 | width: 200px; 8 | padding: 0 10px; 9 | position: relative; 10 | top: 50px; 11 | left: 50%; 12 | margin-left: -100px; 13 | margin-bottom: 10px; 14 | z-index: 11; 15 | } 16 | -------------------------------------------------------------------------------- /css/_yosemite.scss: -------------------------------------------------------------------------------- 1 | $gray-yos: #d2d2d2; 2 | $header-height-yos: 36px; 3 | 4 | .yosemite { 5 | 6 | header { 7 | background: { 8 | color: $gray-yos; 9 | image: none; 10 | } 11 | border: { 12 | top: 0; 13 | bottom: 1px solid #b3b3b3; 14 | } 15 | box-shadow: none; 16 | height: $header-height-yos; 17 | } 18 | 19 | #title-head { 20 | -webkit-box-align: baseline; 21 | } 22 | 23 | #main-title { 24 | top: 7px; 25 | } 26 | 27 | #title { 28 | margin-top: 5px; 29 | } 30 | 31 | #sub-title { 32 | line-height: 20px; 33 | 34 | &:hover { 35 | background-color: #f2f2f2; 36 | } 37 | 38 | &:active { 39 | box-shadow: none; 40 | background-color: #bbb; 41 | } 42 | } 43 | 44 | .view { 45 | top: $header-height-yos; 46 | } 47 | 48 | .corner { 49 | -webkit-box-align: baseline; 50 | } 51 | 52 | .button { 53 | background-image: none; 54 | border: 0; 55 | margin-top: 4px; 56 | 57 | &:hover { 58 | background-color: white; 59 | box-shadow: 0 1px 0 #aaa; 60 | } 61 | 62 | &:active { 63 | background-color: #ddd; 64 | box-shadow: inset 0 1px 0 #f2f2f2, 0 1px 0 #aaa; 65 | } 66 | } 67 | 68 | .comments-button { 69 | box-shadow: none; 70 | border: 1px solid #bbb; 71 | background-image: none; 72 | color: #999; 73 | font-weight: 400; 74 | 75 | &:hover { 76 | background-color: #eee; 77 | } 78 | 79 | &:active { 80 | background: { 81 | image: none; 82 | color: #bbb; 83 | } 84 | } 85 | } 86 | 87 | .replies-button:active { 88 | background-image: none !important; 89 | } 90 | 91 | .comment-poster::before { 92 | border-radius: 3px; 93 | color: white; 94 | background-color: #cf4f5b; 95 | } 96 | 97 | &.inactive { 98 | 99 | header { 100 | background-color: #f5f5f5; 101 | } 102 | } 103 | 104 | @media only screen and (min-width: 1000px) { 105 | 106 | .view { 107 | top: 0; 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /css/desk.scss: -------------------------------------------------------------------------------- 1 | .btn-edit-sub, 2 | .sub, 3 | .channel > p, 4 | .option, 5 | #summary-title, 6 | #sorting p { 7 | transition-duration: 200ms; 8 | } 9 | 10 | .sub:hover, 11 | .channel:hover > p, 12 | .option:hover, 13 | #sorting p:hover { 14 | text-shadow: 0 0 10px rgba(255, 255, 255, 0.75); 15 | } 16 | 17 | .link, 18 | .list-button > span, 19 | .top-buttons > div, 20 | .comments-button, 21 | .item-to-edit > div, 22 | .btn-add-sub, 23 | .close-form, 24 | .btn-general, 25 | #btn-add-new-channel { 26 | cursor: pointer; 27 | } 28 | 29 | #subs, 30 | #channels, 31 | #main-title, 32 | #btn-add-another-sub, 33 | #title, 34 | #summary-sub, 35 | #summary-time, 36 | #summary-author, 37 | .edit-subs-title, 38 | .item-to-edit, 39 | .btn-edit-sub, 40 | .menu-desc, 41 | .loader-error, 42 | .notification, 43 | .option, 44 | .sort-option, 45 | .subreddit p, 46 | .view-footer p, 47 | .move-data h3, 48 | .move-data p { 49 | cursor: default; 50 | } 51 | 52 | #link-summary a:hover #summary-title { text-shadow: 0 1px 7px whiteSmoke; } 53 | 54 | /* Scrolling bars style */ 55 | ::-webkit-scrollbar, 56 | #main-menu::-webkit-scrollbar { width: 7px; } 57 | 58 | /* Track Principal */ 59 | ::-webkit-scrollbar-track { 60 | border-radius: 10px; 61 | background-color: whiteSmoke; 62 | } 63 | 64 | /* Handle Principal */ 65 | ::-webkit-scrollbar-thumb { 66 | border-radius: 10px; 67 | background: rgb(200, 200, 200); 68 | } 69 | 70 | /* Track Menu */ 71 | #main-menu::-webkit-scrollbar-track { 72 | border-radius: 10px; 73 | background-color: #262b30; 74 | } 75 | 76 | /* Handle Menu */ 77 | #main-menu::-webkit-scrollbar-thumb { 78 | border-radius: 10px; 79 | background-color: rgba(0, 0, 0, 0.4); 80 | } 81 | -------------------------------------------------------------------------------- /css/normalize.css: -------------------------------------------------------------------------------- 1 | article, aside, details, figcaption, figure, footer, header, hgroup, nav, section { display: block; } 2 | audio, canvas, video { display: inline-block; *display: inline; *zoom: 1; } 3 | audio:not([controls]) { display: none; } 4 | [hidden] { display: none; } 5 | html { font-size: 100%; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; } 6 | body { margin: 0; font-size: 13px; line-height: 1.231; } 7 | body, button, input, select, textarea { font-family: sans-serif; color: #222; } 8 | a { color: #00e; } 9 | a:visited { color: #551a8b; } 10 | a:hover { color: #06e; } 11 | a:focus { outline: thin dotted; } 12 | a:hover, a:active { outline: 0; } 13 | abbr[title] { border-bottom: 1px dotted; } 14 | b, strong { font-weight: bold; } 15 | blockquote { margin: 1em 40px; } 16 | dfn { font-style: italic; } 17 | hr { display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0; } 18 | ins { background: #ff9; color: #000; text-decoration: none; } 19 | mark { background: #ff0; color: #000; font-style: italic; font-weight: bold; } 20 | pre, code, kbd, samp { font-family: monospace, serif; _font-family: 'courier new', monospace; font-size: 1em; } 21 | pre { white-space: pre; white-space: pre-wrap; word-wrap: break-word; } 22 | q { quotes: none; } 23 | q:before, q:after { content: ""; content: none; } 24 | small { font-size: 85%; } 25 | sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } 26 | sup { top: -0.5em; } 27 | sub { bottom: -0.25em; } 28 | ul, ol { margin: 1em 0; padding: 0 0 0 40px; } 29 | dd { margin: 0 0 0 40px; } 30 | nav ul, nav ol { list-style: none; list-style-image: none; margin: 0; padding: 0; } 31 | img { border: 0; -ms-interpolation-mode: bicubic; vertical-align: middle; } 32 | svg:not(:root) { overflow: hidden; } 33 | figure { margin: 0; } 34 | form { margin: 0; } 35 | fieldset { border: 0; margin: 0; padding: 0; } 36 | label { cursor: pointer; } 37 | legend { border: 0; *margin-left: -7px; padding: 0; } 38 | button, input, select, textarea { font-size: 100%; margin: 0; vertical-align: baseline; *vertical-align: middle; } 39 | button, input { line-height: normal; *overflow: visible; } 40 | table button, table input { *overflow: auto; } 41 | button, input[type="button"], input[type="reset"], input[type="submit"], [role="button"] { cursor: pointer; -webkit-appearance: button; } 42 | input[type="checkbox"], input[type="radio"] { box-sizing: border-box; padding: 0; } 43 | input[type="search"] { -webkit-appearance: textfield; -moz-box-sizing: content-box; -webkit-box-sizing: content-box; box-sizing: content-box; } 44 | input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; } 45 | button::-moz-focus-inner { border: 0; padding: 0; } 46 | textarea { overflow: auto; vertical-align: top; resize: vertical; } 47 | input:valid, textarea:valid { } 48 | input:invalid, textarea:invalid { background-color: #f0dddd; } 49 | table { border-collapse: collapse; border-spacing: 0; } 50 | td { vertical-align: top; } 51 | .nocallout {-webkit-touch-callout: none;} 52 | textarea[contenteditable] {-webkit-appearance: none;} 53 | .gifhidden {position: absolute; left: -100%;} 54 | .ir { display: block; border: 0; text-indent: -999em; overflow: hidden; background-color: transparent; background-repeat: no-repeat; text-align: left; direction: ltr; } 55 | .ir br { display: none; } 56 | .hidden { display: none !important; visibility: hidden; } 57 | .visuallyhidden { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; } 58 | .visuallyhidden.focusable:active, .visuallyhidden.focusable:focus { clip: auto; height: auto; margin: 0; overflow: visible; position: static; width: auto; } 59 | .invisible { visibility: hidden; } 60 | .clearfix:before, .clearfix:after { content: ""; display: table; } 61 | .clearfix:after { clear: both; } 62 | .clearfix { *zoom: 1; } 63 | -------------------------------------------------------------------------------- /css/reeddit.scss: -------------------------------------------------------------------------------- 1 | @import "base"; 2 | @import "buttons"; 3 | @import "inactive"; 4 | @import "yosemite"; 5 | @import "notification"; 6 | 7 | * { 8 | color: #373737; 9 | box-sizing: border-box; 10 | } 11 | 12 | html { 13 | height: 100%; 14 | } 15 | 16 | body { 17 | overflow: hidden; 18 | -webkit-user-select: none; 19 | user-select: none; 20 | margin: 0; 21 | padding: 0; 22 | height: 100%; 23 | background-color: white; 24 | word-wrap: break-word; 25 | -webkit-text-size-adjust: none; 26 | font-family: "Lucida Grande"; 27 | position: relative; 28 | } 29 | 30 | a { 31 | color: #999; 32 | } 33 | 34 | .link:visited div .link-title { 35 | color: #888; 36 | } 37 | 38 | /*--------------------- Vistas ---------------------------*/ 39 | 40 | .view { 41 | position: absolute; 42 | width: 100%; 43 | top: $header-height; 44 | bottom: 0; 45 | left: 0; 46 | right: 0; 47 | z-index: 1; 48 | transition-duration: 300ms; 49 | } 50 | 51 | .main-view, 52 | .detail-view { 53 | -webkit-perspective: 1000; 54 | -webkit-backface-visibility: hidden; 55 | background-color: #fafafa; 56 | } 57 | 58 | .main-view { 59 | -webkit-transform: translate3d(-100%, 0, 0); 60 | transform: translate3d(-100%, 0, 0); 61 | } 62 | 63 | .detail-view { 64 | -webkit-transform: translate3d(100%, 0, 0); 65 | transform: translate3d(100%, 0, 0); 66 | } 67 | 68 | .wrapper { 69 | height: 100%; 70 | overflow-x: hidden; 71 | overflow-y: auto; 72 | position: relative; 73 | } 74 | 75 | /*--------------------- Comentarios ----------------------*/ 76 | 77 | #comments-container { 78 | max-width: 600px; 79 | margin: 0 auto; 80 | } 81 | 82 | #comments-container > .comments-level > .comment-wrap { 83 | padding-right: 10px; 84 | border-left: 0; 85 | border-bottom-color: #ddd; 86 | } 87 | 88 | .comment-wrap { 89 | $comment-border: #ececec; 90 | padding: 10px 0 10px 10px; 91 | border-bottom: 1px solid $comment-border; 92 | border-left: 1px solid $comment-border; 93 | } 94 | 95 | .comments-level .comment-wrap:last-child { 96 | border-radius: 0 0 0 4px; 97 | } 98 | 99 | .comment-data { 100 | display: -webkit-box; 101 | display: box; 102 | width: 100%; 103 | font-size: 12px; 104 | } 105 | 106 | .comment-data > div { 107 | -webkit-box-flex: 1; 108 | box-flex: 1; 109 | width: 50%; 110 | } 111 | 112 | .comment-author p { 113 | color: $main-red; 114 | font-weight: 700; 115 | } 116 | 117 | .comment-poster { 118 | position: relative; 119 | } 120 | 121 | .comment-poster::before { 122 | content: "OP"; 123 | position: absolute; 124 | top: -2px; 125 | left: 0; 126 | color: $main-red; 127 | border: 1px solid; 128 | padding: 2px 4px; 129 | border-radius: 2px; 130 | font-size: 10px; 131 | font-weight: 700; 132 | } 133 | 134 | .comment-poster p { 135 | color: $main-red; 136 | font-weight: 700; 137 | position: relative; 138 | left: 28px; 139 | } 140 | 141 | .comment-info { 142 | text-align: right; 143 | width: 50%; 144 | } 145 | 146 | .comment-info a { 147 | color: #aaa; 148 | text-decoration: none; 149 | } 150 | 151 | .comment-body { 152 | -webkit-user-select: text; 153 | user-select: text; 154 | 155 | a { 156 | color: #777; 157 | padding: 2px 3px; 158 | margin-left: -3px; 159 | 160 | &:hover { 161 | border-radius: 4px; 162 | background-color: #e5e5e5; 163 | text-decoration: none; 164 | } 165 | } 166 | 167 | p { 168 | margin: 10px 0; 169 | color: #3D525E; 170 | } 171 | } 172 | 173 | #link-summary { 174 | background-color: #3C444C; 175 | padding-top: 10px; 176 | } 177 | 178 | #link-summary p { 179 | margin: 0; 180 | padding-left: 10px; 181 | } 182 | 183 | #link-summary a { 184 | text-decoration: none; 185 | display: block; 186 | } 187 | 188 | #summary-title { 189 | font-size: 1.2em; 190 | line-height: 22px; 191 | color: #fafafa; 192 | padding-right: 10px; 193 | } 194 | 195 | #summary-time { 196 | color: white; 197 | text-align: center; 198 | } 199 | 200 | #summary-domain { 201 | color: #F7545E; 202 | display: inline; 203 | } 204 | 205 | #summary-author { 206 | color: #E2E2E0; 207 | line-height: 14px; 208 | -webkit-box-flex: 1; 209 | } 210 | 211 | #summary-sub { 212 | color: #FAFAFA; 213 | text-align: left; 214 | } 215 | 216 | #summary-comment-num { 217 | text-align: right; 218 | text-decoration: none; 219 | display: block; 220 | } 221 | 222 | #summary-extra { 223 | display: -webkit-box; 224 | display: box; 225 | background-color: rgba(0, 0, 0, 0.4); 226 | padding: 0 10px; 227 | width: 100%; 228 | font-size: 12px; 229 | border-top: 1px solid #434c55; 230 | border-bottom: 1px solid #0f1113; 231 | } 232 | 233 | #summary-extra p, 234 | #summary-comment-num { 235 | color: #FAFAFA; 236 | -webkit-box-flex: 1; 237 | margin: 0; 238 | padding: 5px 0; 239 | width: 33%; 240 | } 241 | 242 | #summary-footer { 243 | display: -webkit-box; 244 | display: box; 245 | padding-bottom: 10px; 246 | padding-top: 1px; 247 | border-bottom: 1px solid #262b30; 248 | } 249 | 250 | #selftext { 251 | padding: 10px; 252 | margin: 10px; 253 | border-radius: 5px; 254 | border: 1px solid #bbb; 255 | background-color: #ddd; 256 | -webkit-user-select: text; 257 | user-select: text; 258 | box-shadow: inset 0 1px 1px #fff, 0 1px 10px rgba(0, 0, 0, 0.3); 259 | } 260 | 261 | #selftext p { 262 | margin-top: 5px; 263 | } 264 | 265 | #selftext p:last-child { 266 | margin-bottom: 5px; 267 | } 268 | 269 | .preview-container { 270 | padding: 10px; 271 | } 272 | 273 | .image-preview { 274 | margin: 0 auto; 275 | display: block; 276 | border-radius: 3px; 277 | box-shadow: 0 1px 10px rgba(0, 0, 0, 0.6); 278 | max-width: 100%; 279 | } 280 | 281 | /*--------------------- Menu -----------------------------*/ 282 | 283 | #main-menu { 284 | box-shadow: inset -3px 0 10px black; 285 | height: calc(100% - 32px); 286 | } 287 | 288 | .main-view.show-menu { 289 | -webkit-transform: translate3d(140px, 0px, 0px); 290 | transform: translate3d(140px, 0px, 0px); 291 | } 292 | 293 | #edit-subs { 294 | @include size(140px, 32px); 295 | position: fixed; 296 | bottom: 0; 297 | background-color: #262b30; 298 | z-index: 1; 299 | border-top: 1px solid rgba(0, 0, 0, .5); 300 | box-shadow: rgba(255, 255, 255, 0.1) 0px 1px 0px inset; 301 | text-align: center; 302 | } 303 | 304 | .btn-edit-sub { 305 | @include size(50%, 28px); 306 | font-size: 22px; 307 | color: #777; 308 | display: inline-block; 309 | margin: 0; 310 | position: absolute; 311 | top: 50%; 312 | margin-top: -14px; 313 | } 314 | 315 | #btn-add-subs { 316 | left: 0; 317 | } 318 | 319 | #btn-edit-subs { 320 | right: 0; 321 | font-size: 16px; 322 | line-height: 26px; 323 | } 324 | 325 | #subs, 326 | #channels { 327 | padding: 0; 328 | margin: 0; 329 | } 330 | 331 | .sub { 332 | margin: 0; 333 | padding: 8px 10px; 334 | text-transform: capitalize; 335 | white-space: nowrap; 336 | overflow: hidden; 337 | text-overflow: ellipsis; 338 | } 339 | 340 | .sub, 341 | .channel > p, 342 | .option, 343 | #sorting p { 344 | font-size: 12px; 345 | text-shadow: 0 1px 2px #000; 346 | color: whiteSmoke; 347 | } 348 | 349 | .channel { 350 | margin: 0; 351 | font-size: 14px; 352 | padding: 5px 10px; 353 | } 354 | 355 | .channel > p { 356 | margin: 0; 357 | } 358 | 359 | .channel > div { 360 | padding-left: 10px; 361 | } 362 | 363 | .channel > div p { 364 | @extend %overflow-ellipsis; 365 | font-size: 10px; 366 | color: #BBB; 367 | margin: 4px 0; 368 | text-transform: capitalize; 369 | letter-spacing: 1px; 370 | line-height: 14px; 371 | } 372 | 373 | .channel-active { 374 | border-left: 3px solid #4286F5; 375 | } 376 | 377 | .channel-active > p { 378 | text-shadow: 0 0 10px #CCC; 379 | } 380 | 381 | .sub-active { 382 | text-shadow: 0 0 7px #CCC; 383 | border-left: 3px solid #4286F5; 384 | } 385 | 386 | #menu-container { 387 | @include size(140px, 100%); 388 | overflow-y: auto; 389 | overflow-x: hidden; 390 | position: absolute; 391 | z-index: 0; 392 | background-color: #262b30; 393 | } 394 | 395 | #sorting p { 396 | margin: 0; 397 | padding: 8px 10px; 398 | text-transform: capitalize; 399 | } 400 | 401 | .sorting-choice { 402 | border-left: 3px solid; 403 | } 404 | 405 | #main-overflow { 406 | width: 100%; 407 | } 408 | 409 | /*--------------------- Principal -------------------------*/ 410 | 411 | .link { 412 | display: -webkit-box; 413 | display: box; 414 | text-decoration: none; 415 | width: 85%; 416 | padding: 10px; 417 | cursor: none; 418 | -webkit-tap-highlight-color: transparent; 419 | -webkit-box-flex: 1; 420 | box-flex: 1; 421 | 422 | &:active { 423 | background-image: linear-gradient(#599ad2, #3d6fba); 424 | } 425 | 426 | &:focus { 427 | background-color: #eee; 428 | outline: thin; 429 | } 430 | } 431 | 432 | .link-wrap { 433 | border-bottom: 1px solid #dfe6eb; 434 | border-top: 1px solid #fff; 435 | display: -webkit-box; 436 | display: box; 437 | width: 100%; 438 | } 439 | 440 | .link-wrap:first-child { 441 | border-top: 0; 442 | } 443 | 444 | .link-thumb { 445 | -webkit-box-flex: 1; 446 | box-flex: 1; 447 | width: 70px; 448 | max-width: 70px; 449 | min-width: 70px; 450 | } 451 | 452 | .link-thumb div { 453 | @include size(60px); 454 | background-position: center; 455 | background-repeat: no-repeat; 456 | background-size: 70px; 457 | background-color: #333; 458 | margin: 0; 459 | border-radius: 5px; 460 | box-shadow: inset 0 0 3px #333; 461 | } 462 | 463 | .link-title { 464 | font-weight: 600; 465 | font-size: 14px; 466 | -webkit-box-flex: 1; 467 | box-flex: 1; 468 | margin: 0; 469 | color: #3D525E; 470 | } 471 | 472 | .link-info { 473 | -webkit-box-flex: 1; 474 | box-flex: 1; 475 | width: 67%; 476 | } 477 | 478 | .link-domain { 479 | margin: 0; 480 | color: $main-red; 481 | } 482 | 483 | .link-sub { 484 | margin: 0; 485 | color: #6a7f8a; 486 | display: inline; 487 | } 488 | 489 | %bg-blue-gradient { 490 | background-image: linear-gradient(#599ad2, #3d6fba); 491 | } 492 | 493 | .sub, 494 | .channel, 495 | .sort-option { 496 | 497 | &:active { 498 | @extend %bg-blue-gradient; 499 | } 500 | } 501 | 502 | #imp-exp:active { 503 | @extend %bg-blue-gradient; 504 | } 505 | 506 | $active-link-color: #add0eb; 507 | 508 | .link:active, 509 | .link-selected { 510 | @extend %bg-blue-gradient; 511 | 512 | .link-title { 513 | color: white; 514 | text-shadow: 0 1px 0 #000; 515 | } 516 | 517 | .link-domain, 518 | .link-sub, 519 | .link-domain, 520 | .link-sub { 521 | color: $active-link-color; 522 | } 523 | } 524 | 525 | .channel:active div p { 526 | color: $active-link-color; 527 | } 528 | 529 | $nsfw: #D13; 530 | $stickied: #71B0D3; 531 | 532 | .link-label { 533 | font-size: 11px; 534 | margin-left: 5px; 535 | font-weight: 700; 536 | 537 | &.nsfw { 538 | color: $nsfw; 539 | } 540 | 541 | &.stickied { 542 | color: $stickied; 543 | letter-spacing: .3px; 544 | } 545 | } 546 | 547 | .summary-label { 548 | border-radius: 5px; 549 | padding: 1px 3px; 550 | 551 | &.nsfw { 552 | background-color: $nsfw; 553 | color: white; 554 | } 555 | 556 | &.stickied { 557 | background-color: $stickied; 558 | color: white; 559 | } 560 | } 561 | 562 | /*---------------------------- Cabecera -----------------------------*/ 563 | 564 | header { 565 | top: 0; 566 | width: 100%; 567 | position: fixed; 568 | z-index: 2; 569 | display: -webkit-box; 570 | display: box; 571 | height: $header-height; 572 | background-image: url(../img/bg.png); 573 | background-color: #e7e7e7; 574 | border-bottom: 1px solid #777; 575 | border-top: 1px solid #777; 576 | box-shadow: rgba(255, 255, 255, .5) 0 32px 20px -10px inset, 577 | 0 44px 0 rgba(0, 0, 0, .33) inset; 578 | } 579 | 580 | header > div { 581 | -webkit-box-flex: 1; 582 | box-flex: 1; 583 | width: 70%; 584 | display: -webkit-box; 585 | display: box; 586 | -webkit-box-align: center; 587 | box-align: center; 588 | } 589 | 590 | #title { 591 | @extend %overflow-ellipsis; 592 | color: $header-black; 593 | text-shadow: 0 1px 1px #eee; 594 | text-align: center; 595 | font-size: 16px; 596 | width: 100%; 597 | margin: 0; 598 | font-weight: 700; 599 | } 600 | 601 | #header-icon { 602 | background-image: url('../img/alienHead.png'); 603 | background-size: 35px; 604 | background-repeat: no-repeat; 605 | width: 35px; 606 | height: 30px; 607 | margin: 0 auto; 608 | } 609 | 610 | /*-- Botones --*/ 611 | 612 | #nav-back { 613 | transition-duration: 300ms; 614 | } 615 | 616 | .corner { 617 | // width: 15%; 618 | -webkit-box-flex: 1; 619 | box-flex: 1; 620 | display: -webkit-box; 621 | display: box; 622 | -webkit-box-align: center; 623 | box-align: center; 624 | } 625 | 626 | #refresh-icon .icon-btn { 627 | background-image: url('../img/refresh1.png'); 628 | @include size(12px, 16px); 629 | background-repeat: no-repeat; 630 | background-size: 12px; 631 | margin: 0 auto; 632 | } 633 | 634 | #back-arrow, 635 | #refresh-icon { 636 | display: -webkit-box; 637 | display: box; 638 | -webkit-box-align: center; 639 | box-align: center; 640 | } 641 | 642 | #back-arrow { 643 | 644 | .icon-btn { 645 | height: 0; 646 | width: 0; 647 | margin: 0 auto; 648 | border-bottom: 5px solid transparent; 649 | border-right: 10px solid $header-black; 650 | border-top: 5px solid transparent; 651 | } 652 | 653 | &:active .icon-btn { 654 | border-right-color: darken($header-black, 10%); 655 | } 656 | } 657 | 658 | .to-comments { 659 | width: 15%; 660 | display: -webkit-box; 661 | display: box; 662 | -webkit-box-align: center; 663 | box-align: center; 664 | -webkit-box-flex: 1; 665 | box-flex: 1; 666 | 667 | &:active { 668 | background-color: #ddd; 669 | } 670 | } 671 | 672 | .to-comments div { 673 | background-image: url('../img/comment.png'); 674 | width: 24px; 675 | height: 24px; 676 | background-repeat: no-repeat; 677 | background-size: 24px; 678 | margin: 0 auto; 679 | } 680 | 681 | #main-title { 682 | position: fixed; 683 | width: 40%; 684 | font-size: 14px; 685 | top: 14px; 686 | font-weight: 700; 687 | white-space: nowrap; 688 | text-overflow: ellipsis; 689 | overflow: hidden; 690 | } 691 | 692 | #sub-title { 693 | @include letterpress(); 694 | margin: 0 0 0 5px; 695 | padding: 0 5px; 696 | color: $header-black; 697 | border-radius: 5px; 698 | 699 | &:hover { 700 | background-color: lighten($header-black, 25%); 701 | } 702 | 703 | &:active { 704 | @include emboss(); 705 | background-color: lighten($header-black, 20%); 706 | } 707 | } 708 | 709 | /*--- Subreddits ---*/ 710 | 711 | .subreddit { 712 | padding-left: 10px; 713 | border-bottom: 1px solid #CCC; 714 | border-top: 1px solid white; 715 | display: -webkit-box; 716 | display: box; 717 | width: 100%; 718 | } 719 | 720 | .subreddit > div:first-child { 721 | width: 85%; 722 | padding: 10px 5px 10px 0; 723 | -webkit-box-flex: 1; 724 | box-flex: 1; 725 | } 726 | 727 | .btn-add-sub { 728 | width: 15%; 729 | display: -webkit-box; 730 | display: box; 731 | -webkit-box-align: center; 732 | box-align: center; 733 | -webkit-box-flex: 1; 734 | box-flex: 1; 735 | } 736 | 737 | .btn-add-sub > div { 738 | background-image: url('../img/add.png'); 739 | background-repeat: no-repeat; 740 | background-size: 24px; 741 | width: 24px; 742 | height: 24px; 743 | margin: 0 auto; 744 | } 745 | 746 | .subreddit-desc { 747 | margin: 5px 0; 748 | } 749 | 750 | .subreddit-title { 751 | font-weight: 700; 752 | margin: 5px 0; 753 | color: $main-red; 754 | } 755 | 756 | .new-form { 757 | width: 300px; 758 | background-color: #ddd; 759 | box-shadow: 0 0 15px black; 760 | position: absolute; 761 | z-index: 10000; 762 | border-radius: 7px; 763 | padding: 5px; 764 | left: 50%; 765 | margin-left: -150px; 766 | } 767 | 768 | #form-new-channel { 769 | min-height: 160px; 770 | top: 85px; 771 | } 772 | 773 | #form-new-channel input { 774 | width: 100%; 775 | margin-top: 5px; 776 | font-size: 15px; 777 | outline: none; 778 | } 779 | 780 | #txt-channel { 781 | border: 2px solid #AAA !important; 782 | border-radius: 5px; 783 | padding: 5px 10px; 784 | } 785 | 786 | #subs-for-channel { 787 | border-radius: 5px 5px 0 0; 788 | border: 1px solid #AAA; 789 | border-bottom: 0; 790 | margin-top: 5px; 791 | padding: 0 10px; 792 | background-color: #FFF; 793 | max-height: 350px; 794 | overflow-y: auto; 795 | } 796 | 797 | #subs-for-channel input { 798 | border: 0; 799 | border-bottom: 1px solid #CCC; 800 | padding: 5px; 801 | } 802 | 803 | #subs-for-channel input:last-child { 804 | border-bottom: 0; 805 | padding-bottom: 10px; 806 | } 807 | 808 | #btn-add-new-channel { 809 | padding: 5px 10px; 810 | } 811 | 812 | #btn-add-another-sub { 813 | border-bottom-left-radius: 5px; 814 | border-bottom-right-radius: 5px; 815 | padding: 8px 15px; 816 | font-size: 14px; 817 | font-weight: bold; 818 | color: #333; 819 | text-shadow: 0 1px 0 #fff; 820 | border: 1px solid #aaa; 821 | background-image: linear-gradient(#e5e5e5, #bbb); 822 | box-shadow: inset 0 1px 0 0 #fff; 823 | } 824 | 825 | #btn-add-another-sub:active { 826 | box-shadow: inset 0 0 8px 4px #c5c5c5; 827 | } 828 | 829 | .channel-added-msg { 830 | color: white; 831 | font-weight: 700; 832 | padding: 5px 10px; 833 | margin: 0; 834 | background-color: #33B300; 835 | border-radius: 5px; 836 | } 837 | 838 | #form-new-sub { 839 | height: 50px; 840 | top: 50%; 841 | margin-top: -100px; 842 | } 843 | 844 | #form-new-sub input { 845 | width: 100%; 846 | height: 40px; 847 | font-size: 20px; 848 | outline: none; 849 | } 850 | 851 | #add-sub-manual { 852 | padding: 10px; 853 | } 854 | 855 | #remove-wrap { 856 | height: 100%; 857 | } 858 | 859 | .edit-subs-title { 860 | padding: 10px; 861 | font-weight: 700; 862 | font-size: 16px; 863 | margin: 0; 864 | text-align: center; 865 | color: #777; 866 | background-color: rgba(220, 220, 220, 0.4); 867 | text-shadow: 0 1px 1px whiteSmoke; 868 | } 869 | 870 | .remove-list { 871 | margin: 0; 872 | padding: 0; 873 | } 874 | 875 | .item-to-edit { 876 | display: -webkit-box; 877 | display: box; 878 | border-bottom: 1px solid #DDD; 879 | border-top: 1px solid white; 880 | -webkit-box-align: center; 881 | box-align: center; 882 | height: 60px; 883 | } 884 | 885 | .item-to-edit > p { 886 | width: 85%; 887 | text-transform: capitalize; 888 | font-size: 14px; 889 | font-weight: 700; 890 | padding-left: 10px; 891 | } 892 | 893 | .item-to-edit .channel-name { 894 | width: 70%; 895 | } 896 | 897 | .item-to-edit > div { 898 | width: 15%; 899 | height: 100%; 900 | background-repeat: no-repeat; 901 | background-position: center; 902 | } 903 | 904 | .item-to-edit .btn-remove-channel, 905 | .item-to-edit .btn-remove-subreddit { 906 | background-image: url('../img/delete.png'); 907 | background-size: 22px; 908 | } 909 | 910 | .item-to-edit .btn-edit-channel { 911 | background-image: url('../img/edit.png'); 912 | background-size: 16px; 913 | } 914 | 915 | /*--- Constantes ---*/ 916 | 917 | .invisible { 918 | opacity: 0; 919 | } 920 | 921 | .hide { 922 | display: none !important; 923 | } 924 | 925 | .show-view { 926 | -webkit-transform: translate3d(0, 0, 0); 927 | transform: translate3d(0, 0, 0); 928 | } 929 | 930 | .slide-transition { 931 | transition-duration: 300ms; 932 | } 933 | 934 | #modal { 935 | position: absolute; 936 | top: 0; 937 | left: 0; 938 | width: 100%; 939 | height: 100%; 940 | background-color: rgba(0, 0, 0, .7); 941 | transition-duration: 300ms; 942 | opacity: 0; 943 | z-index: 9999; 944 | } 945 | 946 | .close-form { 947 | position: absolute; 948 | top: -30px; 949 | z-index: 10001; 950 | right: 0; 951 | color: whiteSmoke; 952 | background-image: url('../img/cancel.png'); 953 | width: 60px; 954 | background-repeat: no-repeat; 955 | padding-left: 20px; 956 | font-weight: 700; 957 | background-size: 18px; 958 | } 959 | 960 | .form-left-corner { 961 | position: absolute; 962 | top: -30px; 963 | z-index: 10001; 964 | left: 0; 965 | } 966 | 967 | .option { 968 | padding: 10px; 969 | letter-spacing: 1px; 970 | } 971 | 972 | .option:last-child { 973 | margin-bottom: 15px; 974 | } 975 | 976 | .menu-desc { 977 | color: rgba(255, 255, 255, 0.82); 978 | font-size: 11px; 979 | text-transform: uppercase; 980 | text-shadow: rgba(0, 0, 0, 0.7) 0px 1px 0px; 981 | margin: 0px; 982 | width: 100%; 983 | padding-left: 10px; 984 | height: 35px; 985 | line-height: 35px; 986 | box-sizing: border-box; 987 | background: rgba(0, 0, 0, 0.20); 988 | border-top: 1px solid #111; 989 | border-bottom: 1px solid #111; 990 | box-shadow: rgba(255, 255, 255, 0.1) 0px 1px 0px, rgba(255, 255, 255, 0.1) 0px 1px 0px inset; 991 | position: relative; 992 | } 993 | 994 | .move-data { 995 | top: 80px; 996 | padding: 10px; 997 | } 998 | 999 | .move-data h3, 1000 | .move-data p { 1001 | text-shadow: 0 1px 0 #fff; 1002 | } 1003 | 1004 | .move-data h3 { 1005 | text-align: center; 1006 | margin: 5px 0; 1007 | } 1008 | 1009 | .move-data p { 1010 | text-align: left; 1011 | margin: 10px 0; 1012 | } 1013 | 1014 | .move-data-exp { 1015 | border-bottom: 1px solid #999; 1016 | padding: 10px 10px 20px; 1017 | } 1018 | 1019 | .move-data-imp { 1020 | border-top: 1px solid #fff; 1021 | padding: 10px; 1022 | text-align: center; 1023 | } 1024 | 1025 | .move-data-field { 1026 | @include size(100%, 70px); 1027 | } 1028 | 1029 | .view-footer { 1030 | @include size(100%, 26px); 1031 | display: none; 1032 | position: absolute; 1033 | bottom: 0; 1034 | background-image: linear-gradient(#d5d5d5, #b0b0b0); 1035 | border-top: 1px solid #aaa; 1036 | box-shadow: inset 0 1px 1px #eee; 1037 | } 1038 | 1039 | .view-footer p { 1040 | line-height: 25px; 1041 | margin: 0 auto; 1042 | text-align: center; 1043 | font-size: 12px; 1044 | width: 70%; 1045 | white-space: nowrap; 1046 | text-overflow: ellipsis; 1047 | overflow: hidden; 1048 | } 1049 | 1050 | .footer-refresh { 1051 | background-image: url('../img/refresh1.png'); 1052 | top: 4px; 1053 | right: 10px; 1054 | width: 12px; 1055 | height: 15px; 1056 | background-size: 12px 15px; 1057 | } 1058 | 1059 | #detail-close { 1060 | background-image: url('../img/close.png'); 1061 | opacity: .7; 1062 | top: 3px; 1063 | left: 7px; 1064 | width: 18px; 1065 | height: 18px; 1066 | background-size: 18px; 1067 | } 1068 | 1069 | @media only screen and (-webkit-min-device-pixel-ratio: 2) { 1070 | 1071 | .to-comments div { 1072 | background-image: url('../img/comment@2x.png'); 1073 | } 1074 | 1075 | .btn-add-sub > div { 1076 | background-image: url('../img/add@2.png') 1077 | } 1078 | ; 1079 | 1080 | .item-to-edit .btn-remove-channel, 1081 | .item-to-edit .btn-remove-subreddit { 1082 | background-image: url('../img/delete@2x.png'); 1083 | } 1084 | 1085 | .btn-share { 1086 | background-image: url(../img/share@2x.png); 1087 | } 1088 | } 1089 | 1090 | /* Tablet Portrait / 'LargeScreen' */ 1091 | @media only screen and (min-width: 490px) { 1092 | 1093 | .main-view { 1094 | -webkit-transform: none !important; 1095 | transform: none !important; 1096 | } 1097 | 1098 | #sub-title { 1099 | pointer-events: none; 1100 | } 1101 | } 1102 | 1103 | @media only screen and (min-width: 490px) and (max-width: 759px) { 1104 | 1105 | #menu-container, 1106 | #edit-subs { 1107 | width: 28%; 1108 | } 1109 | 1110 | .main-view, 1111 | .detail-view { 1112 | left: 28%; 1113 | width: 72%; 1114 | } 1115 | } 1116 | 1117 | @media only screen and (min-width: 760px) and (max-width: 999px) { 1118 | 1119 | #menu-container, 1120 | #edit-subs { 1121 | width: 22%; 1122 | } 1123 | 1124 | .main-view, 1125 | .detail-view { 1126 | left: 22%; 1127 | width: 78%; 1128 | } 1129 | } 1130 | 1131 | /* Tablet Landscape / 'WideScreen' */ 1132 | 1133 | @media only screen and (min-width: 1000px) { 1134 | 1135 | body { 1136 | border-top: 1px solid #aaa; 1137 | 1138 | &.inactive { 1139 | border-top-color: #ddd; 1140 | } 1141 | } 1142 | 1143 | #menu-container, 1144 | #edit-subs { 1145 | width: 16%; 1146 | } 1147 | 1148 | .main-view { 1149 | width: 34%; 1150 | left: 16%; 1151 | } 1152 | 1153 | .detail-view { 1154 | width: 50%; 1155 | right: 0; 1156 | left: auto; 1157 | border-left: 1px solid #999; 1158 | -webkit-transform: none; 1159 | transform: none; 1160 | } 1161 | 1162 | header, 1163 | .to-comments { 1164 | display: none; 1165 | } 1166 | 1167 | .link { 1168 | width: 100%; 1169 | } 1170 | 1171 | .view { 1172 | top: 0; 1173 | transition-duration: 0s; 1174 | } 1175 | 1176 | #edit-subs { 1177 | height: 26px !important; 1178 | } 1179 | 1180 | #btn-edit-subs { 1181 | line-height: 20px; 1182 | } 1183 | 1184 | .btn-edit-sub { 1185 | font-size: 18px; 1186 | margin-top: -11px; 1187 | height: 22px; 1188 | } 1189 | 1190 | .wrapper { 1191 | height: calc(100% - 26px) !important; 1192 | } 1193 | 1194 | .view-footer { 1195 | display: block; 1196 | } 1197 | } 1198 | 1199 | /* Wide-ass stuff */ 1200 | @media only screen and (min-width: 1150px) { 1201 | #main-menu, 1202 | #edit-subs { 1203 | width: 180px; 1204 | } 1205 | 1206 | .main-view { 1207 | width: 390px; 1208 | left: 180px; 1209 | } 1210 | 1211 | .detail-view { 1212 | left: 570px; 1213 | width: auto; 1214 | } 1215 | } 1216 | 1217 | @media only screen and (min-height: 890px) { 1218 | #main-menu { 1219 | height: 96%; 1220 | } 1221 | 1222 | #edit-subs { 1223 | height: 4%; 1224 | } 1225 | } 1226 | 1227 | @import "animations"; 1228 | -------------------------------------------------------------------------------- /img/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/berbaquero/Reeddit-app/eb353f24f1b8a57210b5bfdd8935358369b05743/img/add.png -------------------------------------------------------------------------------- /img/add@2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/berbaquero/Reeddit-app/eb353f24f1b8a57210b5bfdd8935358369b05743/img/add@2.png -------------------------------------------------------------------------------- /img/alienHead.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/berbaquero/Reeddit-app/eb353f24f1b8a57210b5bfdd8935358369b05743/img/alienHead.png -------------------------------------------------------------------------------- /img/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/berbaquero/Reeddit-app/eb353f24f1b8a57210b5bfdd8935358369b05743/img/bg.png -------------------------------------------------------------------------------- /img/cancel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/berbaquero/Reeddit-app/eb353f24f1b8a57210b5bfdd8935358369b05743/img/cancel.png -------------------------------------------------------------------------------- /img/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/berbaquero/Reeddit-app/eb353f24f1b8a57210b5bfdd8935358369b05743/img/close.png -------------------------------------------------------------------------------- /img/comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/berbaquero/Reeddit-app/eb353f24f1b8a57210b5bfdd8935358369b05743/img/comment.png -------------------------------------------------------------------------------- /img/comment@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/berbaquero/Reeddit-app/eb353f24f1b8a57210b5bfdd8935358369b05743/img/comment@2x.png -------------------------------------------------------------------------------- /img/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/berbaquero/Reeddit-app/eb353f24f1b8a57210b5bfdd8935358369b05743/img/delete.png -------------------------------------------------------------------------------- /img/delete@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/berbaquero/Reeddit-app/eb353f24f1b8a57210b5bfdd8935358369b05743/img/delete@2x.png -------------------------------------------------------------------------------- /img/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/berbaquero/Reeddit-app/eb353f24f1b8a57210b5bfdd8935358369b05743/img/edit.png -------------------------------------------------------------------------------- /img/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/berbaquero/Reeddit-app/eb353f24f1b8a57210b5bfdd8935358369b05743/img/icon.png -------------------------------------------------------------------------------- /img/icon144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/berbaquero/Reeddit-app/eb353f24f1b8a57210b5bfdd8935358369b05743/img/icon144.png -------------------------------------------------------------------------------- /img/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/berbaquero/Reeddit-app/eb353f24f1b8a57210b5bfdd8935358369b05743/img/refresh.png -------------------------------------------------------------------------------- /img/refresh1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/berbaquero/Reeddit-app/eb353f24f1b8a57210b5bfdd8935358369b05743/img/refresh1.png -------------------------------------------------------------------------------- /img/share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/berbaquero/Reeddit-app/eb353f24f1b8a57210b5bfdd8935358369b05743/img/share.png -------------------------------------------------------------------------------- /img/share@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/berbaquero/Reeddit-app/eb353f24f1b8a57210b5bfdd8935358369b05743/img/share@2x.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 |"+a+"\n
";return"\n\n"+a+"\n\n"+c});a=b=b.replace(/~0/,"");a=b=a.replace(/((^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+)/gm,function(a,b){var c;c=b.replace(/^[ \t]*>[ \t]?/gm,"~0");c=c.replace(/~0/g,"");c=c.replace(/^[ \t]+$/gm,"");c=i(c);c=
18 | c.replace(/(^|\n)/g,"$1 ");c=c.replace(/(\s*[^\r]+?<\/pre>)/gm,function(a,b){var c;c=b.replace(/^ /mg,"~0");return c=c.replace(/~0/g,"")});c="\n"+c+"\n";c=c.replace(/(^\n+|\n+$)/g,"");return"\n\n~K"+(r.push(c)-1)+"K\n\n"});a=e(a);b=a.replace(/^\n+/g,"");b=b.replace(/\n+$/g,"");b=b.split(/\n{2,}/g);for(var d=[],g=/~K(\d+)K/,x=b.length,j=0;j"),f+="",d.push(f))}if(!c){x=d.length; 19 | for(j=0;j "+a+""});a=a.replace(/(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|-]|-[^>])(?:[^-]|-[^-])*)--)>)/gi,function(a){var b=a.replace(/(.)<\/?code>(?=.)/g,"$1`");return b=m(b,"!"== 20 | a.charAt(1)?"\\`*_/":"\\`*_")});a=a.replace(/\\(\\)/g,y);a=a.replace(/\\([`*_{}\[\]()>#+-.!])/g,y);a=a.replace(/(!\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,p);a=a.replace(/(!\[(.*?)\]\s?\([ \t]*()(\S+?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,p);a=a.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,z);a=a.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()((?:\([^)]*\)|[^()\s])*?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,z);a=a.replace(/(\[([^\[\]]+)\])()()()()()/g,z);a=a.replace(/(^|\s)(https?|ftp)(:\/\/[-A-Z0-9+&@#\/%?=~_|\[\]\(\)!:,\.;]*[-A-Z0-9+&@#\/%=~_|\[\]])($|\W)/gi, 21 | "$1<$2$3>$4");a=a.replace(/<((https?|ftp):[^'">\s]+)>/gi,function(a,b){return''+k.plainLinkText(b)+""});a=a.replace(/~P/g,"://");a=E(a);a=a.replace(/([\W_]|^)(\*\*|__)(?=\S)([^\r]*?\S[\*_]*)\2([\W_]|$)/g,"$1$3$4");a=a.replace(/([\W_]|^)(\*|_)(?=\S)([^\r\*_]*?\S)\2([\W_]|$)/g,"$1$3$4");return a=a.replace(/ +\n/g,"
\n")}function z(a,c,b,d,g,e,h,f){void 0==f&&(f="");a=b.replace(/:\/\//g,"~P");d=d.toLowerCase();if(""==g)if(""==d&&(d=a.toLowerCase().replace(/ ?\n/g, 22 | " ")),void 0!=l.get(d))g=l.get(d),void 0!=n.get(d)&&(f=n.get(d));else if(-1"+a+"")}function A(a){return a.replace(/>/g,">").replace(/"}function B(a){var a=a+"~0",c=/^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;s?a=a.replace(c,function(a,c,g){a=-1 "+c+""+a+">\n"}):(c=/(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/g,a=a.replace(c,function(a,c,g,e){a=-1 \n"+g+""+a+">\n"}));return a=a.replace(/~0/,"")}function F(a,c){s++;var a=a.replace(/\n{2,}$/,"\n"),b=t[c],d=!1,a=(a+"~0").replace(RegExp("(^[ \\t]*)("+b+")[ \\t]+([^\\r]+?(\\n+))(?=(~0|\\1("+b+")[ \\t]+))","gm"),function(a,b,c,f){a=f;(b=/\n\n$/.test(a))||-1 "+a+"\n"}),a=a.replace(/~0/g,"");s--;return a}function C(a){a=a.replace(/&/g,"&");a=a.replace(//g,">");return a=m(a,"*_{}[]\\",!1)}function E(a){a=a.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g,"&");return a=a.replace(/<(?![a-z\/?\$!])/gi,"<")}function w(a){a=a.replace(/^(\t|[ ]{1,4})/gm,"~0");return a=a.replace(/~0/g,"")}function D(a){if(!/\t/.test(a))return a;var c=[" "," "," ", 26 | " "],b=0,d;return a.replace(/[\n\t]/g,function(a,e){if("\n"===a)return b=e+1,a;d=(e-b)%4;b=e+1;return c[d]})}function m(a,c,b){c="(["+c.replace(/([\[\]\\])/g,"\\$1")+"])";b&&(c="\\\\"+c);return a=a.replace(RegExp(c,"g"),y)}function y(a,c){return"~E"+c.charCodeAt(0)+"E"}var k=this.hooks=new u;k.addNoop("plainLinkText");k.addNoop("preConversion");k.addNoop("postConversion");var l,n,r,s;this.makeHtml=function(a){if(l)throw Error("Recursive call to converter.makeHtml");l=new v;n=new v;r=[];s=0;a=k.preConversion(a); 27 | a=a.replace(/~/g,"~T");a=a.replace(/\$/g,"~D");a=a.replace(/\r\n/g,"\n");a=a.replace(/\r/g,"\n");a=D("\n\n"+a+"\n\n");a=a.replace(/^[ \t]+$/mg,"");a=e(a);a=a.replace(/^[ ]{0,3}\[(.+)\]:[ \t]*\n?[ \t]*(\S+?)>?(?=\s|$)[ \t]*\n?[ \t]*((\n*)["(](.+?)[")][ \t]*)?(?:\n+)/gm,function(a,b,d,e,h,i){b=b.toLowerCase();l.set(b,E(d));if(h)return e;i&&n.set(b,i.replace(/"/g,"""));return""});a=i(a);a=a.replace(/~E(\d+)E/g,function(a,b){var d=parseInt(b);return String.fromCharCode(d)});a=a.replace(/~D/g,"$$"); 28 | a=a.replace(/~T/g,"~");a=k.postConversion(a);r=n=l=null;return a};var t={ol:"\\d+[.]",ul:"[*+-]"},G=/(?:["'*()[\]:]|~D)/g}})(); 29 | // resizeEnd 30 | (function(a,b){"use strict";if(!(a.addEventListener&&b.createEvent&&a.dispatchEvent)){return}var c=function(){var c=b.createEvent("Event");c.initEvent("resizeend",false,false);a.dispatchEvent(c)};var d=function(){return Math.abs(+a.orientation||0)%180};var e=d();var f;var g;a.addEventListener("resize",function(){f=d();if(f!==e){c();e=f}else{clearTimeout(g);g=setTimeout(c,100)}},false)})(window,document); 31 | // TimeSince 32 | function timeSince(c,d){var b=Math.floor(c/1E3-d),a=b/31536E3;if(1=0)xhr.responseJSON=JSON.parse(xhr.responseText);if(o.success)o.success($._xhrResp(xhr),"success",xhr)}else if(o.error)o.error(xhr,xhr.status,xhr.statusText); 38 | if(o.complete)o.complete(xhr,xhr.statusText)}else if(o.progress)o.progress(++n)};var url=o.url,data=null;xhr.open(o.type,url);xhr.send(data)}})(window); -------------------------------------------------------------------------------- /js/reeddit.js: -------------------------------------------------------------------------------- 1 | (function (win) { 2 | 3 | var T = { // Templates 4 | 5 | Posts: "{{#children}} {{/children}} {{data.title}}
{{data.domain}}
{{data.subreddit}}
{{#data.over_18}}NSFW{{/data.over_18}}{{#data.stickied}}Stickied{{/data.stickied}}More", 6 | 7 | Subreddits: { 8 | 9 | list: "{{#.}}{{/.}}", 10 | 11 | toRemoveList: " {{.}}
Subreddits
{{#.}}
", 12 | 13 | toAddList: "{{#children}}{{/.}}{{.}}
{{/children}}" 14 | }, 15 | 16 | Channels: { 17 | 18 | singleEditItem: "{{data.display_name}}
{{data.public_description}}
", 19 | 20 | single: '{{name}}
', 21 | 22 | list: '{{#.}} {{name}}
{{#subs}}{{.}}
{{/subs}}{{/.}}' 23 | }, 24 | 25 | linkSummary: " {{name}}
{{#subs}}{{.}}
{{/subs}}{{title}}
{{domain}}
{{#over_18}}NSFW{{/over_18}}{{#stickied}}Stickied{{/stickied}}{{subreddit}}
{{num_comments}} comments", 26 | 27 | formAgregarSubManual: '', 28 | 29 | formAddNewChannel: 'Add Subredditclose', 30 | 31 | formEditChannel: 'Add ChannelcloseAdd additional subreddit', 32 | 33 | botonCargarMasSubs: "Update ChannelcloseAdd additional subredditMore", 34 | 35 | noLink: "No Post Selected", 36 | 37 | moveData: "", 38 | 39 | updater: "closeExport & Backup
Tip: save on your Dropbox folder, so you can import your subscriptions to any other Reeddit instance (e.g. your mobile or tablet).
Save DataImport & Restore
Load your subscription from any other Reeddit instance - after choosing the file, Reedit will refresh.
", 40 | 41 | notification: 'close{{version.label}} available
Updated on: {{update.date}}
• {{update.title}}:
{{update.message}}
Download new version{{text}}' 42 | }; 43 | 44 | var doc = win.document, 45 | body = doc.body; 46 | 47 | var gui = require('nw.gui'), 48 | mainWindow = gui.Window.get(), 49 | version = 1960; 50 | 51 | // Pseudo-Globals 52 | var editingSubs = false, 53 | urlInit = "http://www.reddit.com/", 54 | urlEnd = ".json", 55 | urlLimitEnd = ".json?limit=30", 56 | loadedLinks = {}, 57 | replies = {}, 58 | showingMenu = false, 59 | store = win.localStorage, 60 | esModal = false, 61 | loadingComments = false, 62 | loadingLinks = false, 63 | currentThread, isWideScreen = checkWideScreen(), 64 | isLargeScreen = checkLargeScreen(), 65 | currentSortingChoice = 'hot', 66 | // Pseudo-Enums 67 | move = { 68 | left: 1, 69 | right: 2 70 | }, 71 | view = { 72 | main: 1, 73 | comments: 2 74 | }, 75 | selection = { 76 | sub: 1, 77 | channel: 2 78 | }, 79 | css = { 80 | showView: "show-view", 81 | showMenu: "show-menu", 82 | hide: "hide" 83 | }, 84 | currentView = view.main; 85 | 86 | var defaultSubs = ["frontPage", "IAmA", "AskReddit", "worldNews", "todayilearned", "reactiongifs", "FanTheories", "ShowerThoughts", "ExplainLikeImFive", "Philosophy", "DataIsBeautiful", "InternetIsBeautiful", "Documentaries", "history", "DIY", "personalfinance"]; 87 | 88 | var defaultChannel = [{ 89 | name: "Media", 90 | subs: ["music", "movies", "television", "games", "books", "videos"] 91 | }, { 92 | name: "Technology", 93 | subs: ["Tech", "Futurology", "space", "gadgets"] 94 | }, { 95 | name: "Science", 96 | subs: ["Science", "AskScience"] 97 | }, { 98 | name: "Pictures", 99 | subs: ["pics", "photoshopbattles", "EarthPorn", "aww"] 100 | }, { 101 | name: "Meta", 102 | subs: ["announcements", "blog"] 103 | }]; 104 | 105 | var M = { // Model 106 | 107 | Posts: { 108 | 109 | list: {}, 110 | 111 | setList: function (posts) { 112 | for (var i = 0; i < posts.children.length; i++) { 113 | var post = posts.children[i]; 114 | if (M.Posts.list[post.data.id]) { // Si ya se ha cargado este link localmente 115 | // Se actualizan los datos dinamicos 116 | M.Posts.list[post.data.id].num_comments = post.data.num_comments; 117 | M.Posts.list[post.data.id].created_utc = post.data.created_utc; 118 | } else { // Si no se han cargado los links localmente 119 | M.Posts.list[post.data.id] = { 120 | title: post.data.title, 121 | selftext: post.data.selftext, 122 | created_utc: post.data.created_utc, 123 | domain: post.data.domain, 124 | subreddit: post.data.subreddit, 125 | num_comments: post.data.num_comments, 126 | url: post.data.url, 127 | self: post.data.is_self, 128 | link: post.data.permalink, 129 | author: post.data.author, 130 | over_18: post.data.over_18, 131 | stickied: post.data.stickied 132 | }; 133 | } 134 | } 135 | }, 136 | 137 | idLast: '', 138 | shareTitle: '', 139 | shareURL: '' 140 | }, 141 | 142 | Subreddits: { 143 | 144 | list: [], 145 | 146 | add: function (sub) { 147 | if (!M.Subreddits.listHasSub(sub)) { 148 | M.Subreddits.list.push(sub); 149 | store.setItem("subreeddits", JSON.stringify(M.Subreddits.list)); 150 | } 151 | }, 152 | 153 | setList: function (subs) { 154 | M.Subreddits.list = subs; 155 | store.setItem("subreeddits", JSON.stringify(M.Subreddits.list)); 156 | }, 157 | 158 | remove: function (sub) { 159 | var idx = M.Subreddits.list.indexOf(sub); 160 | M.Subreddits.list.splice(idx, 1); 161 | store.setItem("subreeddits", JSON.stringify(M.Subreddits.list)); 162 | }, 163 | 164 | listHasSub: function (sub) { 165 | if (M.Subreddits.list) { 166 | var i = M.Subreddits.list.indexOf(sub); 167 | return i > -1; 168 | } 169 | return false; 170 | }, 171 | 172 | getAllString: function () { 173 | var allSubs = ''; 174 | for (var i = 0; i < M.Subreddits.list.length; i++) { 175 | var sub = M.Subreddits.list[i]; 176 | if (sub.toUpperCase() === 'frontPage'.toUpperCase()) continue; 177 | allSubs += sub + '+'; 178 | } 179 | return allSubs.substring(0, allSubs.length - 1); 180 | }, 181 | 182 | idLast: '' 183 | }, 184 | 185 | Channels: { 186 | 187 | list: [], 188 | 189 | getURL: function (channel) { 190 | if (channel.subs.length === 1) { // Reddit API-related hack 191 | // If there's one subreddit in a "Channel", and this subreddit name's invalid, reddit.com responds with a search-results HTML - not json data - and throws a hard-to-catch error... 192 | return "r/" + channel.subs[0] + "+" + channel.subs[0]; // Repeating the one subreddit in the URL avoids this problem :) 193 | } else { 194 | return "r/" + channel.subs.join("+"); 195 | } 196 | }, 197 | 198 | add: function (channel) { 199 | M.Channels.list.push(channel); 200 | store.setItem('channels', JSON.stringify(M.Channels.list)); 201 | }, 202 | 203 | remove: function (name) { 204 | for (var j = 0; j < M.Channels.list.length; j++) { 205 | if (M.Channels.list[j].name === name) { 206 | M.Channels.list.splice(j, 1); 207 | break; 208 | } 209 | } 210 | store.setItem('channels', JSON.stringify(M.Channels.list)); 211 | }, 212 | 213 | getByName: function (name) { 214 | var foundChannel; 215 | for (var i = 0; i < M.Channels.list.length; i++) { 216 | if (M.Channels.list[i].name.toLowerCase() === name.toLowerCase()) { 217 | foundChannel = M.Channels.list[i]; 218 | break; 219 | } 220 | } 221 | return foundChannel; 222 | } 223 | }, 224 | 225 | currentSelection: { 226 | 227 | loadSaved: function () { 228 | var loadedSelection = store.getItem('currentSelection'); 229 | if (loadedSelection) loadedSelection = JSON.parse(loadedSelection); 230 | M.currentSelection.name = loadedSelection ? loadedSelection.name : 'frontPage'; 231 | M.currentSelection.type = loadedSelection ? loadedSelection.type : selection.sub; 232 | }, 233 | 234 | setSubreddit: function (sub) { 235 | M.currentSelection.name = sub; 236 | M.currentSelection.type = selection.sub; 237 | store.setItem('currentSelection', JSON.stringify(M.currentSelection)); 238 | }, 239 | 240 | setChannel: function (channel) { 241 | M.currentSelection.name = channel.name; 242 | M.currentSelection.type = selection.channel; 243 | store.setItem('currentSelection', JSON.stringify(M.currentSelection)); 244 | } 245 | } 246 | }; 247 | 248 | var V = { // View 249 | mainWrap: $id("main-wrap"), 250 | detailWrap: $id("detail-wrap"), 251 | mainView: $q(".main-view"), 252 | detailView: $q(".detail-view"), 253 | subtitle: $id("main-title"), 254 | subtitleText: $id("sub-title"), 255 | headerSection: $id("title-head"), 256 | title: $id("title"), 257 | headerIcon: $id("header-icon"), 258 | container: $id("container"), 259 | btnNavBack: $id("nav-back"), 260 | footerSub: $id("footer-sub"), 261 | footerPost: $id("footer-post"), 262 | 263 | Channels: { 264 | 265 | menuContainer: $id("channels"), 266 | 267 | add: function (channel) { 268 | $append(V.Channels.menuContainer, Mustache.to_html(T.Channels.single, channel)); 269 | if (editingSubs) V.Channels.addToEditList(channel.name); 270 | }, 271 | 272 | loadList: function () { 273 | $html(V.Channels.menuContainer, Mustache.to_html(T.Channels.list, M.Channels.list)); 274 | }, 275 | 276 | remove: function (name) { 277 | var deletedChannel = $q('.channel-to-remove[data-title="' + name + '"]'); 278 | $addClass(deletedChannel, "anim-delete"); 279 | setTimeout(function () { 280 | $remove(deletedChannel); 281 | }, 200); 282 | $remove($q('.channel[data-title="' + name + '"]').parentNode); 283 | }, 284 | 285 | showNewChannelForm: function () { 286 | V.Actions.showModal(T.formAddNewChannel, function () { 287 | $id('txt-channel').focus(); 288 | }); 289 | }, 290 | 291 | addToEditList: function (name) { 292 | $append($q(".channel-edit-list"), T.Channels.singleEditItem.replace(/\{\{name\}\}/g, name)); 293 | } 294 | }, 295 | 296 | Subreddits: { 297 | 298 | listContainer: $id("subs"), 299 | 300 | insert: function (subs, active) { 301 | var subsList = V.Subreddits.listContainer; 302 | if (subs instanceof Array) { 303 | $append(subsList, Mustache.to_html(T.Subreddits.list, subs)); 304 | } else { 305 | if (!M.Subreddits.listHasSub(subs)) { 306 | var li = $el("li"), 307 | p = $el("p", "sub"); 308 | li.setAttribute("data-name", subs); 309 | if (active) $addClass(p, "sub-active"); 310 | $text(p, subs); 311 | $append(li, p); 312 | $append(subsList, li); 313 | M.Subreddits.add(subs); 314 | V.Actions.showNotification("'" + subs + "' added"); 315 | } else { 316 | V.Actions.showNotification("Subreddit already added"); 317 | } 318 | } 319 | }, 320 | 321 | remove: function (sub) { 322 | var deletedSub = $q(".sub-to-remove[data-name='" + sub + "']"); 323 | $addClass(deletedSub, "anim-delete"); 324 | setTimeout(function () { 325 | $remove(deletedSub); 326 | }, 200); 327 | $remove($q("#subs > li[data-name='" + sub + "']")); 328 | }, 329 | 330 | cleanSelected: function () { 331 | $removeClass($q(".sub-active"), "sub-active"); 332 | $removeClass($q(".channel-active"), "channel-active"); 333 | }, 334 | 335 | showManualInput: function () { 336 | V.Actions.showModal(T.formAgregarSubManual, function () { 337 | $id('txt-new-sub').focus(); 338 | }); 339 | }, 340 | 341 | showAddingList: function () { 342 | var main = V.mainWrap; 343 | $empty(main); 344 | $append(main, V.Subreddits.addingList); 345 | $append(main, T.botonCargarMasSubs); 346 | V.Anims.reveal(main); 347 | }, 348 | 349 | addingList: '' 350 | }, 351 | 352 | Posts: { 353 | 354 | show: function (links, paging) { // links: API raw data 355 | var linksCount = links.children.length, 356 | main = V.mainWrap; 357 | 358 | if (paging) $remove($q(".loader")); 359 | else $empty(main); 360 | 361 | if (linksCount === 0) { 362 | var message = $q('.loader'); 363 | if (message) { 364 | $text(message, "No Links available."); 365 | $addClass(message, "loader-error"); 366 | $append(main, $el("div", "", "main-overflow")); 367 | } else { 368 | $prepend(main, 'No Links available.'); 369 | } 370 | } else { 371 | $append(main, Mustache.to_html(T.Posts, links)); // Add new links to the list 372 | 373 | // Remove thumbnail space for those links with invalid backgrounds. 374 | var thumbs = $qAll('.link-thumb > div'), 375 | bgImg = 'background-image: '; 376 | for (var i = 0; i < thumbs.length; i++) { 377 | var thumb = thumbs[i], 378 | bg = thumb.getAttribute('style'); 379 | if (bg === bgImg + 'url()' || bg === bgImg + 'url(default)' || bg === bgImg + 'url(nsfw)' || bg === bgImg + 'url(self)') { 380 | $remove(thumb.parentNode); 381 | } 382 | } 383 | } 384 | // Remove 'More links' button if there are less than 30 links 385 | if (linksCount < 30) $remove($id("more-links")); 386 | if (!paging) V.Anims.reveal(main); 387 | } 388 | }, 389 | 390 | Actions: { 391 | 392 | setSubTitle: function (title) { 393 | $text(V.subtitleText, title); 394 | $text(V.footerSub, title); 395 | }, 396 | 397 | backToMainView: function () { 398 | $addClass(V.btnNavBack, "invisible"); 399 | $removeClass(V.subtitle, "invisible"); 400 | $empty(V.headerSection); 401 | $append(V.headerSection, V.headerIcon); 402 | V.Anims.slideFromLeft(); 403 | }, 404 | 405 | moveMenu: function (direction) { 406 | if (direction === move.left) { 407 | $removeClass(V.mainView, css.showMenu); 408 | setTimeout(function () { 409 | showingMenu = false; 410 | }); 411 | } 412 | if (direction === move.right) { 413 | $addClass(V.mainView, css.showMenu); 414 | setTimeout(function () { 415 | showingMenu = true; 416 | }); 417 | } 418 | }, 419 | 420 | loadForAdding: function () { 421 | if (!isLargeScreen) V.Actions.moveMenu(move.left); 422 | if (currentView === view.comments) V.Actions.backToMainView(); 423 | 424 | setTimeout(function () { 425 | var main = V.mainWrap; 426 | main.scrollTop = 0; // Go to the container top 427 | 428 | if (V.Subreddits.addingList) { // is cache'd 429 | V.Subreddits.showAddingList(); 430 | } else { 431 | var loader = $el("div", "loader"); 432 | $prepend(main, loader); 433 | 434 | JSONP.get(urlInit + "reddits/.json?limit=50", function (list) { 435 | M.Subreddits.idLast = list.data.after; 436 | V.Subreddits.addingList = Mustache.to_html(T.Subreddits.toAddList, list.data); 437 | V.Subreddits.showAddingList(); 438 | }, function () { // On Error 439 | $addClass(loader, "loader-error"); 440 | $text(loader, "Error loading subreddits."); 441 | }); 442 | } 443 | loadingLinks = false; 444 | }, isLargeScreen ? 1 : 301); 445 | V.Subreddits.cleanSelected(); 446 | V.Actions.setSubTitle("Add Subs"); 447 | setEditingSubs(true); 448 | }, 449 | 450 | loadForEditing: function () { 451 | if (!isLargeScreen) V.Actions.moveMenu(move.left); 452 | if (currentView === view.comments) V.Actions.backToMainView(); 453 | 454 | setTimeout(function () { 455 | V.mainWrap.scrollTop = 0; // Up to container top 456 | var htmlSubs = Mustache.to_html(T.Subreddits.toRemoveList, M.Subreddits.list); 457 | var htmlChannels = ''; 458 | if (M.Channels.list && M.Channels.list.length > 0) { 459 | htmlChannels = Mustache.to_html("Channels
{{#.}} " + T.Channels.singleEditItem + "{{/.}}
", M.Channels.list); 460 | } 461 | var html = '' + htmlChannels + htmlSubs + ""; 462 | $html(V.mainWrap, html); 463 | V.Anims.reveal(V.mainWrap); 464 | 465 | V.Subreddits.cleanSelected(); 466 | loadingLinks = false; 467 | }, isLargeScreen ? 1 : 301); 468 | V.Actions.setSubTitle('Edit Subs'); 469 | setEditingSubs(true); 470 | }, 471 | 472 | showModal: function (template, callback) { 473 | var delay = 1; 474 | if (!isLargeScreen && showingMenu) { 475 | V.Actions.moveMenu(move.left); 476 | delay = 301; 477 | } 478 | setTimeout(function () { 479 | if (esModal) return; 480 | var modal = $el("div", '', "modal"); 481 | $append(modal, template); 482 | $append(body, modal); 483 | esModal = true; 484 | setTimeout(function () { 485 | modal.style.opacity = 1; 486 | V.Anims.bounceInDown($q(".new-form")); 487 | }, 1); 488 | if (callback) callback(); 489 | }, delay); 490 | }, 491 | 492 | removeModal: function () { 493 | var modal = $id('modal'); 494 | modal.style.opacity = ''; 495 | esModal = false; 496 | setTimeout(function () { 497 | $remove(modal); 498 | }, 301); 499 | }, 500 | 501 | setDetailFooter: function (title) { 502 | $text(V.footerPost, title ? title : T.noLink); 503 | var btns = $qAll("#detail-footer .btn-footer"); 504 | for (var i = 0, l = btns.length; i < l; i++) { 505 | if (title) $removeClass(btns[i], css.hide); 506 | else $addClass(btns[i], css.hide); 507 | } 508 | }, 509 | 510 | showNotification: function (text) { 511 | $append(body, T.notification.replace('{{text}}', text)); 512 | var notification = $q('.notification'); 513 | V.Anims.bounceInDown(notification); 514 | setTimeout(function () { 515 | V.Anims.dismiss(notification, function () { 516 | $remove($q('.notification')); 517 | }); 518 | }, (1500 + 500)); 519 | } 520 | }, 521 | 522 | Anims: { 523 | 524 | slideFromLeft: function () { 525 | var show = css.showView; 526 | $addClass(V.mainView, show); 527 | $removeClass(V.detailView, show); 528 | currentView = view.main; 529 | }, 530 | 531 | slideFromRight: function () { 532 | var show = css.showView; 533 | $removeClass(V.mainView, show); 534 | $addClass(V.detailView, show); 535 | currentView = view.comments; 536 | }, 537 | 538 | reveal: function (el) { 539 | var reveal = "anim-reveal"; 540 | $addClass(el, reveal); 541 | setTimeout(function () { 542 | $removeClass(el, reveal); 543 | }, 700); 544 | }, 545 | 546 | shake: function (el) { 547 | var shake = "anim-shake"; 548 | $addClass(el, shake); 549 | setTimeout(function () { 550 | $removeClass(el, shake); 551 | }, 350); 552 | }, 553 | 554 | shakeForm: function () { 555 | V.Anims.shake($q(".new-form")); 556 | }, 557 | 558 | bounceOut: function (el, callback) { 559 | var bounceOut = "anim-bounce-out"; 560 | $addClass(el, bounceOut); 561 | if (callback) setTimeout(callback, 1000); 562 | }, 563 | 564 | bounceInDown: function (el) { 565 | $addClass(el, "anim-bounceInDown"); 566 | setTimeout(function () { 567 | el.style.opacity = 1; 568 | $removeClass(el, "anim-bounceInDown"); 569 | }, 500); 570 | }, 571 | 572 | dismiss: function (el, callback) { 573 | el.style.opacity = ''; 574 | $addClass(el, "anim-dismiss"); 575 | if (callback) setTimeout(callback, 200); 576 | } 577 | } 578 | }; 579 | 580 | var C = { // "Controller" 581 | 582 | Posts: { 583 | 584 | load: function (baseUrl, paging) { 585 | if (loadingLinks) return; 586 | loadingLinks = true; 587 | loadingComments = false; 588 | setEditingSubs(false); 589 | var main = V.mainWrap, 590 | loader = $el("div", "loader"); 591 | if (paging) { 592 | // Se quita el boton de 'More' actual 593 | $remove($id("more-links")); 594 | $append(main, loader); 595 | } else { 596 | main.scrollTop = 0; // Sube al top del contenedor 597 | setTimeout(function () { 598 | $prepend(main, loader); 599 | }, showingMenu ? 301 : 1); 600 | paging = ''; // Si no hay paginacion, se pasa una cadena vacia, para no paginar 601 | } 602 | JSONP.get(baseUrl + C.Sorting.get() + urlLimitEnd + paging, function (result) { 603 | C.Posts.show(result, paging); 604 | }, function () { // On error 605 | loadingLinks = false; 606 | $addClass(loader, "loader-error"); 607 | $text(loader, "Error loading links. Refresh to try again."); 608 | }); 609 | }, 610 | 611 | loadFromManualInput: function (loadedLinks) { 612 | C.Posts.show(loadedLinks); 613 | setEditingSubs(false); 614 | }, 615 | 616 | show: function (result, paging) { 617 | var links = result.data; 618 | loadingLinks = false; 619 | M.Posts.idLast = links.after; 620 | 621 | V.Posts.show(links, paging); 622 | M.Posts.setList(links); 623 | } 624 | }, 625 | 626 | Comments: { 627 | 628 | load: function (data, baseElement, idParent) { 629 | var now = new Date().getTime(), 630 | converter = new Markdown.Converter(), 631 | comments = $el("section", "comments-level"); 632 | 633 | for (var i = 0; i < data.length; i++) { 634 | var c = data[i]; 635 | 636 | if (c.kind !== "t1") continue; 637 | 638 | var html = converter.makeHtml(c.data.body), 639 | isPoster = M.Posts.list[currentThread].author === c.data.author, 640 | permalink = "http://reddit.com" + M.Posts.list[currentThread].link + c.data.id; 641 | 642 | var comment = $el("div", "comment-wrap"), 643 | wrap = $el("div"), 644 | cData = $el("div", "comment-data"), 645 | cPoster = $el("div", isPoster ? "comment-poster" : "comment-author"), 646 | pPoster = $el("p"), 647 | cInfo = $el("div", "comment-info"), 648 | aSince = $el("a"), 649 | cBody = $el("div", "comment-body"); 650 | 651 | $text(pPoster, c.data.author); 652 | 653 | aSince.setAttribute("href", permalink); 654 | aSince.setAttribute("target", "_blank"); 655 | $text(aSince, timeSince(now, c.data.created_utc)); 656 | 657 | $html(cBody, html); 658 | 659 | // Piece together 660 | $append(cPoster, pPoster); 661 | $append(cData, cPoster); 662 | $append(cInfo, aSince); 663 | $append(cData, cInfo); 664 | $append(wrap, cData); 665 | $append(comment, wrap); 666 | $append(comment, cBody); 667 | 668 | if (c.data.replies && c.data.replies.data.children[0].kind !== "more") { 669 | var btnReply = $el("span", "comments-button"); 670 | $addClass(btnReply, "replies-button"); 671 | btnReply.setAttribute("data-comment-id", c.data.id); 672 | $text(btnReply, "See replies"); 673 | 674 | $append(comment, btnReply); 675 | 676 | replies[c.data.id] = c.data.replies.data.children; 677 | } 678 | 679 | $append(comments, comment); 680 | } 681 | 682 | $append(baseElement, comments); 683 | 684 | if (idParent) loadedLinks[idParent] = comments; 685 | 686 | }, 687 | 688 | show: function (id, refresh) { 689 | var delay = 0; 690 | if (showingMenu) { 691 | V.Actions.moveMenu(move.left); 692 | delay = 301; 693 | } 694 | if (!M.Posts.list[id]) return; // Quick fix for missing id 695 | setTimeout(function () { 696 | 697 | // Stop if it hasn't finished loading this comments for the first time before trying to load them again 698 | if (loadingComments && currentThread && currentThread === id) return; 699 | 700 | loadingComments = true; 701 | currentThread = id; 702 | 703 | $removeClass(V.btnNavBack, "invisible"); // Show 704 | 705 | var detail = V.detailWrap; 706 | $empty(detail); 707 | 708 | if (loadedLinks[id] && !refresh) { 709 | $append(detail, M.Posts.list[id].summary); 710 | $append($id("comments-container"), loadedLinks[id]); 711 | C.Misc.updatePostSummary(M.Posts.list[id], id); 712 | loadingComments = false; 713 | } else { 714 | C.Misc.setPostSummary(M.Posts.list[id], id); 715 | var url = "http://www.reddit.com" + M.Posts.list[id].link + urlEnd, 716 | loader = $el("div", "loader"); 717 | $append(detail, loader); 718 | JSONP.get(url, function (result) { 719 | loadingComments = false; 720 | if (currentThread !== id || currentView === view.main) return; // In case of trying to load a different thread before this one loaded. 721 | C.Misc.updatePostSummary(result[0].data.children[0].data, id); 722 | $remove(loader); 723 | var comments = result[1].data.children; 724 | C.Comments.load(comments, $id("comments-container"), id); 725 | }, function () { // On Error 726 | loadingComments = false; 727 | $addClass(loader, "loader-error"); 728 | $text(loader, "Error loading comments. Refresh to try again."); 729 | }); 730 | } 731 | 732 | if (!refresh) V.Actions.setDetailFooter(M.Posts.list[id].title); 733 | 734 | if (!refresh && currentView !== view.comments) V.Anims.slideFromRight(); 735 | 736 | if (isWideScreen) { 737 | // Refresh active link indicator 738 | $removeClass($q(".link.link-selected"), "link-selected"); 739 | $addClass($q('.link[data-id="' + id + '"]'), "link-selected"); 740 | } 741 | 742 | $empty(V.headerSection); 743 | $append(V.headerSection, V.title); 744 | $text(V.title, M.Posts.list[id].title); 745 | $addClass(V.subtitle, "invisible"); 746 | }, delay); 747 | } 748 | }, 749 | 750 | Subreddits: { 751 | 752 | loadSaved: function () { // Only should execute when first loading the app 753 | var subs = store.getItem("subreeddits"); 754 | if (subs) subs = JSON.parse(subs); 755 | M.Subreddits.list = subs; 756 | if (!M.Subreddits.list) M.Subreddits.setList(defaultSubs); // If it hasn't been loaded to the 'local store', save default subreddits 757 | V.Subreddits.insert(M.Subreddits.list); 758 | }, 759 | 760 | loadPosts: function (sub) { 761 | if (sub !== M.currentSelection.name || editingSubs) { 762 | var url; 763 | if (sub.toUpperCase() === 'frontPage'.toUpperCase()) url = urlInit + "r/" + M.Subreddits.getAllString() + "/"; 764 | else url = urlInit + "r/" + sub + "/"; 765 | C.Posts.load(url); 766 | C.currentSelection.setSubreddit(sub); 767 | } 768 | V.Actions.setSubTitle(sub); 769 | }, 770 | 771 | remove: function (sub) { 772 | M.Subreddits.remove(sub); 773 | V.Subreddits.remove(sub); 774 | if (M.currentSelection.type === selection.sub && M.currentSelection.name === sub) C.currentSelection.setSubreddit('frontPage'); // If it was the current selection 775 | }, 776 | 777 | addFromNewForm: function () { 778 | var txtSub = $id("txt-new-sub"), 779 | subName = txtSub.value; 780 | if (!subName) { 781 | txtSub.setAttribute("placeholder", "Enter a subreddit title!"); 782 | V.Anims.shakeForm(); 783 | return; 784 | } 785 | 786 | V.Anims.bounceOut($q(".new-form"), V.Actions.removeModal); 787 | 788 | JSONP.get(urlInit + "r/" + subName + "/" + C.Sorting.get() + urlLimitEnd, function (data) { 789 | C.Posts.loadFromManualInput(data); 790 | V.Actions.setSubTitle(subName); 791 | V.Subreddits.cleanSelected(); 792 | C.currentSelection.setSubreddit(subName); 793 | V.Subreddits.insert(subName, true); 794 | }, function () { // On Error 795 | alert('Oh oh, the subreddit you entered is not valid...'); 796 | }); 797 | } 798 | }, 799 | 800 | Channels: { 801 | 802 | add: function (title, subreddits) { 803 | var channel = { 804 | name: title, 805 | subs: subreddits 806 | }; 807 | M.Channels.add(channel); 808 | V.Channels.add(channel); 809 | }, 810 | 811 | loadSaved: function () { // Should only execute when first loading the app 812 | M.Channels.list = store.getItem('channels'); 813 | if (M.Channels.list) M.Channels.list = JSON.parse(M.Channels.list); 814 | else M.Channels.list = defaultChannel; // Load default channel(s) 815 | V.Channels.loadList(); 816 | }, 817 | 818 | loadPosts: function (channel) { 819 | C.Posts.load(urlInit + M.Channels.getURL(channel) + '/'); 820 | V.Actions.setSubTitle(channel.name); 821 | C.currentSelection.setChannel(channel); 822 | }, 823 | 824 | remove: function (name) { 825 | M.Channels.remove(name); 826 | V.Channels.remove(name); 827 | // If it was the current selection 828 | if (M.currentSelection.type === selection.channel && M.currentSelection.name === name) C.currentSelection.setSubreddit('frontPage'); 829 | }, 830 | 831 | edit: function (name) { 832 | var channelToEdit = M.Channels.getByName(name); 833 | V.Actions.showModal(T.formEditChannel, function () { 834 | // Fill form with current values 835 | $id("txt-channel").value = channelToEdit.name; 836 | 837 | M.Channels.editing = channelToEdit.name; 838 | var inputsContainer = $id("subs-for-channel"); 839 | 840 | for (var i = 0, l = channelToEdit.subs.length; i < l; i++) { 841 | 842 | var inputTemplate = ""; 843 | 844 | $append(inputsContainer, inputTemplate.replace("{{subName}}", channelToEdit.subs[i])); 845 | } 846 | }); 847 | } 848 | }, 849 | 850 | currentSelection: { 851 | 852 | setSubreddit: function (sub) { 853 | M.currentSelection.setSubreddit(sub); 854 | }, 855 | 856 | setChannel: function (channel) { 857 | M.currentSelection.setChannel(channel); 858 | } 859 | }, 860 | 861 | Sorting: { 862 | 863 | get: function () { 864 | return (currentSortingChoice !== 'hot' ? (currentSortingChoice + '/') : ''); 865 | }, 866 | 867 | change: function (sorting) { 868 | currentSortingChoice = sorting; 869 | if (editingSubs) return; // No subreddit or channel selected - just change the sorting type 870 | // Only refresh with the new sorting, when a subreddit or channel is selected 871 | var delay = 1; 872 | if (showingMenu) { 873 | V.Actions.moveMenu(move.left); 874 | delay = 301; 875 | } 876 | setTimeout(function () { 877 | refreshCurrentStream(); 878 | }, delay); 879 | } 880 | }, 881 | 882 | Misc: { 883 | 884 | setPostSummary: function (data, postID) { 885 | // Main content 886 | var summaryHTML = Mustache.to_html(T.linkSummary, data); 887 | var imageLink = checkImageLink(M.Posts.list[postID].url); 888 | if (imageLink) { // If it's an image link 889 | summaryHTML += ""; 890 | } 891 | if (data.selftext) { // If it has selftext 892 | var selfText; 893 | if (M.Posts.list[postID].selftextParsed) { 894 | selfText = M.Posts.list[postID].selftext; 895 | } else { 896 | var summaryConverter1 = new Markdown.Converter(); 897 | selfText = summaryConverter1.makeHtml(data.selftext); 898 | M.Posts.list[postID].selftext = selfText; 899 | M.Posts.list[postID].selftextParsed = true; 900 | } 901 | summaryHTML += " " + selfText + " "; 902 | } 903 | summaryHTML += ""; 904 | $append(V.detailWrap, summaryHTML); 905 | C.Misc.updatePostTime(data.created_utc); 906 | M.Posts.list[postID].summary = summaryHTML; 907 | $text(V.footerPost, data.title); 908 | }, 909 | 910 | updatePostSummary: function (data, postID) { 911 | $id("summary-comment-num").innerText = data.num_comments + (data.num_comments === 1 ? ' comment' : ' comments'); 912 | // Time ago 913 | C.Misc.updatePostTime(data.created_utc); 914 | M.Posts.list[postID].num_comments = data.num_comments; 915 | M.Posts.list[postID].created_utc = data.created_utc; 916 | }, 917 | 918 | updatePostTime: function (time) { 919 | $id("summary-time").innerText = timeSince(new Date().getTime(), time); 920 | } 921 | } 922 | }; 923 | 924 | function checkWideScreen() { 925 | return mainWindow.width >= 1000; 926 | } 927 | 928 | function checkLargeScreen() { 929 | return mainWindow.width >= 490; 930 | } 931 | 932 | function checkImageLink(url) { 933 | var matching = url.match(/\.(svg|jpe?g|png|gif)(?:[?#].*)?$|(?:imgur\.com|www.quickmeme\.com\/meme|qkme\.me)\/([^?#\/.]*)(?:[?#].*)?(?:\/)?$/); 934 | if (!matching) return ''; 935 | if (matching[1]) { // normal image link 936 | return url; 937 | } else if (matching[2]) { // imgur or quickmeme link 938 | if (matching[0].slice(0, 5) === "imgur") return 'http://imgur.com/' + matching[2] + '.jpg'; 939 | else return 'http://i.qkme.me/' + matching[2] + '.jpg'; 940 | } else { 941 | return null; 942 | } 943 | } 944 | 945 | function setEditingSubs(editing) { // editing: boolean 946 | editingSubs = editing; 947 | if (isWideScreen) { 948 | // If it's showing the add or remove subreddits/channels panel, hide the refresh button 949 | var refreshBtn = $q('#main-footer .footer-refresh'); 950 | refreshBtn.style.display = editing ? 'none' : ''; 951 | } 952 | } 953 | 954 | function doByCurrentSelection(caseSub, caseChannel) { 955 | switch (M.currentSelection.type) { 956 | case selection.sub: 957 | caseSub(); 958 | break; 959 | case selection.channel: 960 | caseChannel(); 961 | break; 962 | } 963 | } 964 | 965 | body.addEventListener("submit", function (ev) { 966 | if (ev.target.parentNode.id === "form-new-sub") { 967 | ev.preventDefault(); 968 | C.Subreddits.addFromNewForm(); 969 | } 970 | }); 971 | 972 | function goToComments(id) { 973 | location.hash = '#comments:' + id; 974 | } 975 | 976 | function refreshCurrentStream() { 977 | if (editingSubs) return; 978 | doByCurrentSelection(function () { // if it's subreddit 979 | if (M.currentSelection.name.toUpperCase() === 'frontPage'.toUpperCase()) C.Posts.load(urlInit + "r/" + M.Subreddits.getAllString() + "/"); 980 | else C.Posts.load(urlInit + "r/" + M.currentSelection.name + "/"); 981 | }, function () { // if it's channel 982 | C.Channels.loadPosts(M.Channels.getByName(M.currentSelection.name)); 983 | }); 984 | } 985 | 986 | var openURL = function (url) { 987 | gui.Shell.openExternal(url); 988 | }; 989 | 990 | var openWindow = function (url, width, height) { 991 | gui.Window.open(url, { 992 | position: 'center', 993 | width: width || 800, 994 | height: height || 600, 995 | frame: true, 996 | toolbar: false, 997 | resize: true 998 | }); 999 | }; 1000 | 1001 | var importExportData = function () { 1002 | V.Actions.showModal(T.moveData); 1003 | }; 1004 | 1005 | var saveData = function () { 1006 | var data = "{\"channels\": " + store.getItem("channels") + ", \"subreddits\": " + store.getItem("subreeddits") + "}"; 1007 | fs.writeFile("data.json", data, function (err) { 1008 | if (err) alert(err); 1009 | else { 1010 | if (!saveLink) { 1011 | saveLink = document.createElement("a"); 1012 | saveLink.href = "data.json"; 1013 | saveLink.setAttribute("download", "reedditdata.json"); 1014 | } 1015 | saveLink.click(); 1016 | } 1017 | }); 1018 | }; 1019 | 1020 | // Clicks 1021 | 1022 | clickable(body, "#btn-save-data", saveData); 1023 | 1024 | clickable(body, "#btn-add-new-sub", C.Subreddits.addFromNewForm); 1025 | 1026 | delegate(body, ".btn-share", "click", function (e) { 1027 | M.Posts.shareTitle = M.Posts.list[currentThread].title; 1028 | M.Posts.shareURL = M.Posts.list[currentThread].url; 1029 | shareMenu.popup(e.x, e.y); 1030 | }); 1031 | 1032 | V.detailWrap.addEventListener("click", function (e) { 1033 | // All link anchors from the detail view 1034 | if (e.target.tagName === "A") { 1035 | e.preventDefault(); 1036 | openURL(e.target.getAttribute("href")); 1037 | } 1038 | }); 1039 | 1040 | clickable(body, "#header-link", function (target) { 1041 | openURL(target.getAttribute("href")); 1042 | }); 1043 | 1044 | clickable(body, "#btn-submit-channel", function (target) { 1045 | var txtChannelName = $id("txt-channel"), 1046 | operation = target.getAttribute("data-op"); 1047 | var channelName = txtChannelName.value; 1048 | if (!channelName) { 1049 | txtChannelName.placeholder = "Enter a Channel name!"; 1050 | V.Anims.shakeForm(); 1051 | return; 1052 | } 1053 | 1054 | var subreddits = []; 1055 | var subs = $qAll("#subs-for-channel input"); 1056 | for (var i = 0; i < subs.length; i++) { 1057 | var sub = subs[i].value; 1058 | if (!sub) continue; 1059 | subreddits.push(sub); 1060 | } 1061 | if (subreddits.length === 0) { 1062 | subs[0].placeholder = "Enter at least one subreddit!"; 1063 | V.Anims.shakeForm(); 1064 | return; 1065 | } 1066 | 1067 | switch (operation) { 1068 | case "save": 1069 | // Look for Channel name in the saved ones 1070 | var savedChannel = M.Channels.getByName(channelName); 1071 | if (savedChannel) { // If it's already saved 1072 | txtChannelName.value = ""; 1073 | txtChannelName.placeholder = "'" + channelName + "' already exists."; 1074 | V.Anims.shakeForm(); 1075 | return; 1076 | } 1077 | 1078 | C.Channels.add(channelName, subreddits); 1079 | 1080 | break; 1081 | 1082 | case "update": 1083 | // Remove current and add new 1084 | C.Channels.remove(M.Channels.editing); 1085 | C.Channels.add(channelName, subreddits); 1086 | 1087 | break; 1088 | } 1089 | 1090 | // confirmation feedback 1091 | $remove(target); 1092 | $append($q(".form-left-corner"), "'" + channelName + "' " + operation + "d. Cool!
"); 1093 | 1094 | V.Anims.bounceOut($q(".new-form"), V.Actions.removeModal); 1095 | }); 1096 | 1097 | clickable(body, "#btn-add-another-sub", function () { 1098 | var container = $id("subs-for-channel"); 1099 | $append(container, ""); 1100 | container.scrollTop = container.innerHeight; 1101 | }); 1102 | 1103 | clickable(V.detailWrap, ".replies-button", function (target) { 1104 | var parent = target, 1105 | commentID = parent.getAttribute('data-comment-id'), 1106 | comments = replies[commentID]; 1107 | C.Comments.load(comments, parent.parentNode); 1108 | $remove(parent); 1109 | }); 1110 | 1111 | clickable(V.Subreddits.listContainer, ".sub", function (target) { 1112 | var sub = target; 1113 | V.Actions.moveMenu(move.left); 1114 | C.Subreddits.loadPosts(sub.firstChild.textContent); 1115 | V.Subreddits.cleanSelected(); 1116 | $addClass(sub, "sub-active"); 1117 | if (currentView === view.comments) V.Actions.backToMainView(); 1118 | }); 1119 | 1120 | clickable(V.Channels.menuContainer, ".channel", function (target) { 1121 | var channel = target; 1122 | var channelName = channel.getAttribute("data-title"); 1123 | V.Actions.moveMenu(move.left); 1124 | if (channelName === M.currentSelection.name && !editingSubs) return; 1125 | V.Subreddits.cleanSelected(); 1126 | $addClass(channel, "channel-active"); 1127 | if (currentView === view.comments) V.Actions.backToMainView(); 1128 | C.Channels.loadPosts(M.Channels.getByName(channelName)); 1129 | }); 1130 | 1131 | clickable(body, ".btn-to-main", function () { 1132 | location.hash = "#"; 1133 | }); 1134 | 1135 | clickable(body, ".btn-refresh", function (target) { 1136 | var origin = target.getAttribute("data-origin"); 1137 | switch (origin) { 1138 | case "footer-main": 1139 | refreshCurrentStream(); 1140 | break; 1141 | case "footer-detail": 1142 | if (!currentThread) return; 1143 | C.Comments.show(currentThread, true); 1144 | break; 1145 | default: 1146 | if (currentView === view.comments) { 1147 | if (!currentThread) return; 1148 | C.Comments.show(currentThread, true); 1149 | } 1150 | if (currentView === view.main) { 1151 | refreshCurrentStream(); 1152 | } 1153 | } 1154 | }); 1155 | 1156 | clickable(V.mainWrap, ".link", function (target) { 1157 | var comm = target, 1158 | id = comm.getAttribute("data-id"), 1159 | link = M.Posts.list[id]; 1160 | if (link.self || isWideScreen) { 1161 | goToComments(id); 1162 | } else { 1163 | var url = comm.getAttribute("href"); 1164 | openURL(url); 1165 | } 1166 | }); 1167 | 1168 | clickable(V.mainWrap, ".to-comments", function (target) { 1169 | var id = target.getAttribute('data-id'); 1170 | goToComments(id); 1171 | }); 1172 | 1173 | V.subtitleText.addEventListener("click", function () { 1174 | if (isLargeScreen) return; 1175 | V.Actions.moveMenu(showingMenu ? move.left : move.right); 1176 | }); 1177 | 1178 | $id("btn-add-subs").addEventListener("click", function (e) { 1179 | subsMenu.popup(e.x, e.y - 70); 1180 | }); 1181 | 1182 | $id("btn-edit-subs").addEventListener("click", V.Actions.loadForEditing); 1183 | 1184 | clickable(V.mainWrap, "#more-links", function () { 1185 | doByCurrentSelection(function () { 1186 | var url; 1187 | if (M.currentSelection.name.toUpperCase() === 'frontPage'.toUpperCase()) url = urlInit + "r/" + M.Subreddits.getAllString() + "/"; 1188 | else url = urlInit + "r/" + M.currentSelection.name + "/"; 1189 | C.Posts.load(url, '&after=' + M.Posts.idLast); 1190 | }, function () { 1191 | var channel = M.Channels.getByName(M.currentSelection.name); 1192 | C.Posts.load(urlInit + M.Channels.getURL(channel) + '/', '&after=' + M.Posts.idLast); 1193 | }); 1194 | } 1195 | ); 1196 | 1197 | clickable(V.mainWrap, '#more-subs', function (target) { 1198 | $remove(target); 1199 | var main = V.mainWrap, 1200 | loader = $el("div", "loader"); 1201 | $append(main, loader); 1202 | JSONP.get(urlInit + 'reddits/' + urlEnd + '?&after=' + M.Subreddits.idLast, function (list) { 1203 | var nuevosSubs = Mustache.to_html(T.Subreddits.toAddList, list.data); 1204 | M.Subreddits.idLast = list.data.after; 1205 | $remove(loader); 1206 | $append(main, nuevosSubs); 1207 | $append(main, T.botonCargarMasSubs); 1208 | V.Subreddits.addingList += nuevosSubs; 1209 | }, function () { 1210 | $addClass(loader, "loader-error"); 1211 | $text(loader, 'Error loading more subreddits.'); 1212 | }); 1213 | } 1214 | ); 1215 | 1216 | clickable(V.mainWrap, ".btn-add-sub", function (target) { 1217 | var parent = target.parentNode, 1218 | subTitle = parent.querySelector(".subreddit-title"), 1219 | newSub = subTitle.innerText; 1220 | V.Subreddits.insert(newSub); 1221 | } 1222 | ); 1223 | 1224 | clickable(V.mainWrap, ".btn-remove-subreddit", function (target) { 1225 | C.Subreddits.remove(target.getAttribute('data-name')); 1226 | } 1227 | ); 1228 | 1229 | clickable(V.mainWrap, ".btn-remove-channel", function (target) { 1230 | C.Channels.remove(target.getAttribute('data-title')); 1231 | } 1232 | ); 1233 | 1234 | clickable(V.mainWrap, ".btn-edit-channel", function (target) { 1235 | C.Channels.edit(target.getAttribute('data-title')); 1236 | } 1237 | ); 1238 | 1239 | clickable(body, ".close-form", V.Actions.removeModal); 1240 | 1241 | delegate($id("sorting"), ".sort-option", "click", function (e) { 1242 | e.preventDefault(); 1243 | var choice = e.target; 1244 | var sortingChoice = choice.textContent; 1245 | if (sortingChoice === currentSortingChoice) return; 1246 | var choices = $qAll(".sorting-choice"); 1247 | for (var i = 0, l = choices.length; i < l; i++) { 1248 | $removeClass(choices[i], "sorting-choice"); 1249 | } 1250 | $addClass(choice, "sorting-choice"); 1251 | C.Sorting.change(sortingChoice); 1252 | }); 1253 | 1254 | $id("imp-exp").addEventListener("click", importExportData); 1255 | 1256 | body.addEventListener("change", function (ev) { 1257 | if (ev.target.id === "btn-import-data") { 1258 | var importPath = ev.target.value; 1259 | if (!importPath) return; 1260 | fs.readFile(importPath, function (err, cont) { 1261 | if (err) throw err; 1262 | else { 1263 | try { 1264 | data = JSON.parse(cont.toString()); 1265 | if (data.subreddits) { 1266 | refresh = true; 1267 | store.setItem("subreeddits", JSON.stringify(data.subreddits)); 1268 | } 1269 | if (data.channels) { 1270 | refresh = true; 1271 | store.setItem("channels", JSON.stringify(data.channels)); 1272 | } 1273 | if (refresh) win.location.reload(); 1274 | } catch (e) { 1275 | alert("Oops. Wrong file, maybe? - Try choosing another one!"); 1276 | } 1277 | } 1278 | }); 1279 | } 1280 | }); 1281 | 1282 | // Do stuff after finishing resizing the windows 1283 | win.addEventListener("resizeend", function () { 1284 | isWideScreen = checkWideScreen(); 1285 | isLargeScreen = checkLargeScreen(); 1286 | if (isLargeScreen && showingMenu) V.Actions.moveMenu(move.left); 1287 | viewOnlyPosts.checked = false; 1288 | viewMenuAndPosts.checked = false; 1289 | viewMenuPostsAndComments.checked = false; 1290 | if (!isLargeScreen) viewOnlyPosts.checked = true; 1291 | else if (isLargeScreen && !isWideScreen) viewMenuAndPosts.checked = true; 1292 | else viewMenuPostsAndComments.checked = true; 1293 | }, false); 1294 | 1295 | // Pseudo-hash-router 1296 | win.addEventListener('hashchange', function () { 1297 | if (location.hash === "") { 1298 | V.Actions.backToMainView(); 1299 | $removeClass($q('.link-selected'), 'link-selected'); 1300 | V.Actions.setDetailFooter(""); 1301 | setTimeout(function () { 1302 | $empty(V.detailWrap); 1303 | }, isWideScreen ? 1 : 301); 1304 | } else { 1305 | var match = location.hash.match(/(#comments:)((?:[a-zA-Z0-9]*))/); 1306 | if (match && match[2]) { 1307 | var id = match[2]; 1308 | C.Comments.show(id); 1309 | } 1310 | } 1311 | }, false); 1312 | 1313 | V.headerIcon.addEventListener("dblclick", function () { 1314 | mainWindow.height = 1048; 1315 | }); 1316 | 1317 | delegate(V.mainWrap, ".link", "contextmenu", function (e, target) { 1318 | M.Posts.shareURL = target.href; 1319 | M.Posts.shareTitle = target.querySelector(".link-title").innerText; 1320 | shareMenu.popup(e.x + 1, e.y); 1321 | }); 1322 | 1323 | $id("btn-new-sub").addEventListener("click", function () { 1324 | V.Subreddits.showManualInput(); 1325 | }); 1326 | 1327 | $id("btn-new-channel").addEventListener("click", function () { 1328 | V.Channels.showNewChannelForm(); 1329 | }); 1330 | 1331 | // App init 1332 | win.onload = function () { 1333 | 1334 | $remove(V.title); 1335 | 1336 | var winConfig = store.getItem("win:config"); 1337 | 1338 | if (winConfig) { 1339 | winConfig = JSON.parse(winConfig); 1340 | 1341 | var mainWinWidth = winConfig.w, 1342 | mainWinHeight = winConfig.h, 1343 | mainWinX = winConfig.x, 1344 | mainWinY = winConfig.y; 1345 | 1346 | if (mainWinHeight && mainWinWidth) { 1347 | mainWindow.width = mainWinWidth; 1348 | mainWindow.height = mainWinHeight; 1349 | } 1350 | 1351 | if (mainWinX && mainWinY) { 1352 | mainWindow.x = mainWinX; 1353 | mainWindow.y = mainWinY; 1354 | } 1355 | } 1356 | 1357 | if (checkWideScreen()) $text(V.footerPost, T.noLink); 1358 | 1359 | M.currentSelection.loadSaved(); 1360 | 1361 | C.Subreddits.loadSaved(); 1362 | C.Channels.loadSaved(); 1363 | 1364 | // Cargar links y marcar como activo al subreddit actual - la 1ra vez sera el 'frontPage' 1365 | doByCurrentSelection(function () { // En caso de ser un subreddit 1366 | var i = M.Subreddits.list.indexOf(M.currentSelection.name); 1367 | if (i > -1) { 1368 | var activeSub = doc.getElementsByClassName('sub')[i]; 1369 | $addClass(activeSub, "sub-active"); 1370 | } 1371 | // Load links 1372 | if (M.currentSelection.name.toUpperCase() === 'frontPage'.toUpperCase()) { 1373 | C.currentSelection.setSubreddit('frontPage'); 1374 | C.Posts.load(urlInit + "r/" + M.Subreddits.getAllString() + "/"); 1375 | } else { 1376 | C.Posts.load(urlInit + "r/" + M.currentSelection.name + "/"); 1377 | } 1378 | V.Actions.setSubTitle(M.currentSelection.name); 1379 | }, function () { // If it's a channel 1380 | var channel; 1381 | for (var i = 0; i < M.Channels.list.length; i++) { 1382 | channel = M.Channels.list[i]; 1383 | if (channel.name === M.currentSelection.name) { 1384 | var active = doc.getElementsByClassName('channel')[i]; 1385 | $addClass(active, 'channel-active'); 1386 | break; 1387 | } 1388 | } 1389 | C.Channels.loadPosts(channel); 1390 | }); 1391 | 1392 | // Check for Yosemite 1393 | if (/10_1\d_/.test(navigator.userAgent)) { 1394 | $addClass(body, "yosemite"); 1395 | } 1396 | 1397 | mainWindow.show(); 1398 | mainWindow.focus(); 1399 | }; 1400 | 1401 | // Share Menu 1402 | var shareMenu = new gui.Menu(); 1403 | shareMenu.append(new gui.MenuItem({ 1404 | label: 'Reading List', 1405 | click: function () { 1406 | sharing.readingList(M.Posts.shareURL, function () { 1407 | V.Actions.showNotification("Added to Reading List"); 1408 | }); 1409 | } 1410 | })); 1411 | 1412 | shareMenu.append(new gui.MenuItem({ 1413 | label: 'Twitter', 1414 | click: function () { 1415 | var url = M.Posts.shareURL, 1416 | title = M.Posts.shareTitle; 1417 | openWindow("https://twitter.com/intent/tweet?text=\"" + encodeURI(title) + "\" —&url=" + url + "&via=ReedditApp&related=ReedditApp", 520, 430); 1418 | } 1419 | })); 1420 | 1421 | shareMenu.append(new gui.MenuItem({ 1422 | label: 'Email', 1423 | click: function () { 1424 | var title = M.Posts.shareTitle, 1425 | url = M.Posts.shareURL; 1426 | openURL("mailto:?subject=" + title + "&body=" + url + "%0A%0a%0A%0aShared via @ReedditApp."); 1427 | } 1428 | })); 1429 | 1430 | shareMenu.append(new gui.MenuItem({ 1431 | label: 'Copy Link', 1432 | click: function () { 1433 | sharing.clipboard(M.Posts.shareURL); 1434 | V.Actions.showNotification("Copied to Clipboard"); 1435 | } 1436 | })); 1437 | 1438 | var subsMenu = new gui.Menu(); 1439 | subsMenu.append(new gui.MenuItem({ 1440 | label: "Add Subreddit from List", 1441 | click: V.Actions.loadForAdding 1442 | })); 1443 | 1444 | subsMenu.append(new gui.MenuItem({ 1445 | label: "Add Subreddit Manually", 1446 | click: V.Subreddits.showManualInput 1447 | })); 1448 | 1449 | subsMenu.append(new gui.MenuItem({ 1450 | type: 'separator' 1451 | })); 1452 | 1453 | subsMenu.append(new gui.MenuItem({ 1454 | label: 'Create Channel', 1455 | click: V.Channels.showNewChannelForm 1456 | })); 1457 | 1458 | // Title Menu 1459 | var submenu = new gui.Menu(); 1460 | submenu.append(new gui.MenuItem({ 1461 | label: 'Add Subreddits', 1462 | click: V.Actions.loadForAdding 1463 | })); 1464 | 1465 | submenu.append(new gui.MenuItem({ 1466 | type: 'separator' 1467 | })); 1468 | 1469 | submenu.append(new gui.MenuItem({ 1470 | label: 'Insert Subreddit Manually', 1471 | click: V.Subreddits.showManualInput 1472 | })); 1473 | 1474 | submenu.append(new gui.MenuItem({ 1475 | label: 'Create Channel', 1476 | click: V.Channels.showNewChannelForm 1477 | })); 1478 | 1479 | submenu.append(new gui.MenuItem({ 1480 | type: 'separator' 1481 | })); 1482 | 1483 | submenu.append(new gui.MenuItem({ 1484 | label: 'Edit Subscriptions', 1485 | click: V.Actions.loadForEditing 1486 | })); 1487 | submenu.append(new gui.MenuItem({ 1488 | type: 'separator' 1489 | })); 1490 | 1491 | submenu.append(new gui.MenuItem({ 1492 | label: 'Import & Export Data', 1493 | click: importExportData 1494 | })); 1495 | 1496 | var menu = new gui.Menu({ 1497 | type: 'menubar' 1498 | }); 1499 | 1500 | menu.append(new gui.MenuItem({ 1501 | label: 'Subscriptions', 1502 | submenu: submenu 1503 | })); 1504 | 1505 | var viewSubmenu = new gui.Menu(), 1506 | viewOnlyPosts = new gui.MenuItem({ 1507 | label: 'Only Posts', 1508 | type: 'checkbox', 1509 | click: function () { 1510 | mainWindow.width = 354; 1511 | } 1512 | }), 1513 | viewMenuAndPosts = new gui.MenuItem({ 1514 | label: 'Sidebar and Posts', 1515 | type: 'checkbox', 1516 | click: function () { 1517 | mainWindow.width = 490; 1518 | } 1519 | }), 1520 | viewMenuPostsAndComments = new gui.MenuItem({ 1521 | label: 'Sidebar, Posts and Comments', 1522 | type: 'checkbox', 1523 | click: function () { 1524 | mainWindow.width = 1000; 1525 | } 1526 | }); 1527 | 1528 | viewSubmenu.append(viewOnlyPosts); 1529 | viewSubmenu.append(viewMenuAndPosts); 1530 | viewSubmenu.append(viewMenuPostsAndComments); 1531 | menu.append(new gui.MenuItem({ 1532 | label: 'View', 1533 | submenu: viewSubmenu 1534 | })); 1535 | 1536 | gui.Window.get().menu = menu; // Add menu to main app window/title bar 1537 | 1538 | mainWindow.on("close", function () { 1539 | // Save latest window size and position before closing 1540 | 1541 | var winConfig = { 1542 | w: mainWindow.width, 1543 | h: mainWindow.height, 1544 | x: mainWindow.x, 1545 | y: mainWindow.y 1546 | }; 1547 | 1548 | store.setItem("win:config", JSON.stringify(winConfig)); 1549 | 1550 | mainWindow.close(true); 1551 | }); 1552 | 1553 | mainWindow.on("blur", function () { 1554 | $addClass(body, "inactive"); 1555 | }); 1556 | 1557 | mainWindow.on("focus", function () { 1558 | $removeClass(body, "inactive"); 1559 | }); 1560 | 1561 | var fs = require("fs"), 1562 | saveLink; 1563 | 1564 | // Check updates 1565 | setTimeout(function () { 1566 | ajax({ 1567 | url: "http://mac.reedditapp.com/version.json", 1568 | dataType: "json", 1569 | success: function (data) { 1570 | if (!data.update.trigger || data.version.number <= version) return; 1571 | // show update button 1572 | var btnShowUpdate = $el("div", "btn-general"); 1573 | btnShowUpdate.innerText = "New Reeddit version available"; 1574 | btnShowUpdate.style.margin = "10px"; 1575 | btnShowUpdate.addEventListener("click", function () { 1576 | V.Actions.showModal(Mustache.to_html(T.updater, data), function () { 1577 | $id("btn-download").addEventListener("click", function () { 1578 | openURL(this.getAttribute("data-link")); 1579 | }); 1580 | }); 1581 | }); 1582 | $prepend(V.mainWrap, btnShowUpdate); 1583 | } 1584 | }); 1585 | }, 3000); 1586 | 1587 | })(window); 1588 | -------------------------------------------------------------------------------- /js/sharing.js: -------------------------------------------------------------------------------- 1 | var sharing = (function() { 2 | 3 | var scriptString = 'tell application "Safari" to add reading list item "{{URL}}"', 4 | applescript, 5 | clipboard; 6 | 7 | var getAppleScript = function() { 8 | if (!applescript) { 9 | applescript = require('applescript'); 10 | } 11 | return applescript; 12 | }; 13 | 14 | var getClipboard = function() { 15 | if (!clipboard) { 16 | var gui = require('nw.gui'); 17 | clipboard = gui.Clipboard.get(); 18 | } 19 | return clipboard; 20 | }; 21 | 22 | var addToReadingList = function(url, next) { 23 | var script = scriptString.replace('{{URL}}', url); 24 | getAppleScript().execString(script, function(err, succ) { 25 | if (next) next(); 26 | }); 27 | }; 28 | 29 | var copyToClipboard = function(url) { 30 | getClipboard().set(url, 'text'); 31 | }; 32 | 33 | return { 34 | readingList: addToReadingList, 35 | clipboard: copyToClipboard 36 | }; 37 | 38 | })(); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "index.html", 3 | "name": "Reeddit", 4 | "description": "Minimal, elastic Reddit reader client", 5 | "version": "1.9.2", 6 | "maintainers": [{ 7 | "name": "Bernardo Baquero Stand", 8 | "web": "http://berbaquero.com" 9 | }], 10 | "window": { 11 | "title": " ", 12 | "icon": "img/icon.png", 13 | "toolbar": false, 14 | "frame": true, 15 | "width": 491, 16 | "height": 825, 17 | "position": "center", 18 | "min_width": 354, 19 | "min_height": 480, 20 | "max_width": 3000, 21 | "max_height": 2500, 22 | "resizable": true, 23 | "show": false 24 | }, 25 | "devDependencies": { 26 | "applescript": "~0.2.1" 27 | } 28 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Reeddit for Mac 2 | 3 | This is a version of [Reeddit](https://github.com/berbaquero/reeddit/), built for OS X, using [node-webkit](https://github.com/rogerwang/node-webkit). 4 | 5 | [Download Reeddit.app](https://github.com/berbaquero/Reeddit-app/releases/download/v1.9.6/Reeddit.app.zip). 6 | 7 | For now, you will need to update manually - download each new version. I hope to work on a way to auto-update later. 8 | 9 | # Reeddit 10 | 11 | * #### Minimalist 12 | While aiming for simplicity, Reeddit cares to show you only the most important information from the posts and comments. No upvotes or points. 13 | 14 | * #### Elastic 15 | Reeddit has 3 different elastic layouts - you can use it on any window size. So it's comfortable to use on a smartphone, tablet or desktop. 16 | 17 | * #### Read-only 18 | Being a personal side-project of mine, Reeddit can be used for browsing subreddits and viewing links/post and its comments, but not for voting or commenting... for now ;) -- However, the subreddits and channels you add are saved locally, so you don't lose any of that data. 19 | 20 | * #### Channels 21 | You can group different subreddits into a Channel, so you can browse their links in a single view, instead of having to browse each one separately. This is specially useful when you add subject-related subreddits. 22 | 23 | For screenshots and additional info, visit [Reeddit's Homepage](http://berbaquero.github.com/reeddit/about). 24 | 25 | ## Tools 26 | 27 | To build Reeddit, I used these awesome resources: 28 | 29 | * [pagedown](http://code.google.com/p/pagedown/) -- Client-side Markdown-to-HTML conversion. 30 | * [Mustache.js](https://github.com/janl/mustache.js/) -- Lightweigth client-side templating. 31 | * [reziseend.js](https://github.com/porada/resizeend) -- Better 'resize' handler. 32 | * [Iconmonstr](http://iconmonstr.com/) -- Awesome icons. 33 | 34 | ### Compatibility 35 | 36 | Reeddit.app works on OS X 10.7 and up. 37 | 38 | ### License 39 | 40 | Licensed under the [MIT License](http://berbaquero.mit-license.org/). 41 | --------------------------------------------------------------------------------