PluginProbe
Friends / 4.3.2
Friends v4.3.2
4.3.2 4.3.1 4.3.0 4.2.2 4.2.1 4.2.0 4.1.0 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.8.0 2.8.1 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.0 2.9.1 All 88 releases
friends / templates / google-reader / google-reader.js

google-reader.js in Friends 4.3.2, at templates/google-reader/google-reader.js

241 lines 7.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Google Reader theme JS for the Friends plugin.
3 *
4 * Keyboard shortcuts:
5 * j/k - Select next/previous item (expands it)
6 * n/p - Select next/previous item without opening
7 * space - Page down, or next item if at bottom of current
8 * shift-space - Page up
9 * o/enter - Toggle open/close current item
10 * s - Star (navigate to author page)
11 * v - Open original in new tab
12 * shift-a - Mark all as read (trash all visible)
13 * u - Toggle sidebar
14 * ? - Show keyboard shortcuts help
15 */
16 ( function( $ ) {
17 var currentIndex = -1;
18
19 function getItems() {
20 return $( 'section.posts article.card' );
21 }
22
23 function scrollToItem( $item ) {
24 if ( ! $item.length ) {
25 return;
26 }
27 $( 'html, body' ).animate( {
28 scrollTop: $item.offset().top - 80
29 }, 150 );
30 }
31
32 function expandItem( $item ) {
33 if ( ! $item.hasClass( 'uncollapsed' ) ) {
34 $item.addClass( 'uncollapsed' );
35 }
36 }
37
38 function collapseItem( $item ) {
39 $item.removeClass( 'uncollapsed' );
40 }
41
42 function collapseAll() {
43 getItems().removeClass( 'uncollapsed' );
44 }
45
46 function selectItem( index, expand ) {
47 var items = getItems();
48 if ( index < 0 || index >= items.length ) {
49 return;
50 }
51
52 if ( expand ) {
53 collapseAll();
54 }
55
56 currentIndex = index;
57 var $item = items.eq( index );
58
59 items.removeClass( 'gr-current' );
60 $item.addClass( 'gr-current' );
61 scrollToItem( $item );
62
63 if ( expand ) {
64 expandItem( $item );
65 }
66 }
67
68 function isItemBottomVisible( $item ) {
69 var itemBottom = $item.offset().top + $item.outerHeight();
70 var viewBottom = $( window ).scrollTop() + $( window ).height();
71 return itemBottom <= viewBottom;
72 }
73
74 // Keyboard shortcuts.
75 $( document ).on( 'keydown', function( e ) {
76 if ( $( e.target ).is( 'input, textarea, select, [contenteditable]' ) ) {
77 return;
78 }
79
80 var items = getItems();
81 if ( ! items.length && e.key !== '?' && e.key !== 'u' ) {
82 return;
83 }
84
85 switch ( e.key ) {
86 case 'j': // Next item, expand.
87 e.preventDefault();
88 selectItem( currentIndex + 1, true );
89 break;
90
91 case 'k': // Previous item, expand.
92 e.preventDefault();
93 if ( currentIndex > 0 ) {
94 selectItem( currentIndex - 1, true );
95 }
96 break;
97
98 case 'n': // Next item, don't expand.
99 e.preventDefault();
100 selectItem( currentIndex + 1, false );
101 break;
102
103 case 'p': // Previous item, don't expand.
104 e.preventDefault();
105 if ( currentIndex > 0 ) {
106 selectItem( currentIndex - 1, false );
107 }
108 break;
109
110 case ' ': // Space: page down or next item.
111 e.preventDefault();
112 if ( e.shiftKey ) {
113 // Page up.
114 window.scrollBy( 0, -$( window ).height() * 0.8 );
115 } else if ( currentIndex >= 0 && items.eq( currentIndex ).hasClass( 'uncollapsed' ) && ! isItemBottomVisible( items.eq( currentIndex ) ) ) {
116 // Page down within current expanded item.
117 window.scrollBy( 0, $( window ).height() * 0.8 );
118 } else {
119 // Move to next item.
120 selectItem( currentIndex + 1, true );
121 }
122 break;
123
124 case 'o': // Toggle current item.
125 case 'Enter':
126 if ( currentIndex >= 0 ) {
127 e.preventDefault();
128 var $item = items.eq( currentIndex );
129 if ( $item.hasClass( 'uncollapsed' ) ) {
130 collapseItem( $item );
131 } else {
132 collapseAll();
133 expandItem( $item );
134 }
135 }
136 break;
137
138 case 's': // Star: toggle ⭐ reaction on current post.
139 if ( currentIndex >= 0 ) {
140 e.preventDefault();
141 var $star = items.eq( currentIndex ).find( 'button.friends-reaction[data-emoji="2b50"], button.friends-reaction-picker[data-emoji="2b50"]' ).first();
142 if ( $star.length ) {
143 $star.trigger( 'click' );
144 }
145 }
146 break;
147
148 case 'v': // Open original in new tab.
149 if ( currentIndex >= 0 ) {
150 e.preventDefault();
151 var $link = items.eq( currentIndex ).find( '.card-title a, h4 a' ).first();
152 if ( $link.length ) {
153 window.open( $link.attr( 'href' ), '_blank' );
154 }
155 }
156 break;
157
158 case 'u': // Toggle sidebar.
159 e.preventDefault();
160 $( '.off-canvas-sidebar' ).toggle();
161 $( '.off-canvas-content' ).toggleClass( 'gr-sidebar-hidden' );
162 break;
163
164 case '?': // Show shortcuts help.
165 e.preventDefault();
166 var $help = $( '#gr-shortcuts-help' );
167 if ( $help.length ) {
168 $help.toggle();
169 } else {
170 $( 'body' ).append(
171 '<div id="gr-shortcuts-help" style="position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);background:light-dark(#fff,#292a2d);border:1px solid light-dark(#d4d4d4,#3c4043);border-radius:4px;padding:20px;z-index:10000;max-width:500px;font-size:13px;box-shadow:0 4px 12px rgba(0,0,0,.3)">' +
172 '<h3 style="margin:0 0 12px;font-size:16px">Keyboard Shortcuts</h3>' +
173 '<table style="width:100%;border-collapse:collapse">' +
174 '<tr><td style="padding:2px 12px 2px 0"><b>j / k</b></td><td>Next / previous item</td></tr>' +
175 '<tr><td style="padding:2px 12px 2px 0"><b>n / p</b></td><td>Next / previous without opening</td></tr>' +
176 '<tr><td style="padding:2px 12px 2px 0"><b>space</b></td><td>Page down or next item</td></tr>' +
177 '<tr><td style="padding:2px 12px 2px 0"><b>shift-space</b></td><td>Page up</td></tr>' +
178 '<tr><td style="padding:2px 12px 2px 0"><b>o / enter</b></td><td>Open / close item</td></tr>' +
179 '<tr><td style="padding:2px 12px 2px 0"><b>s</b></td><td>Toggle ⭐ reaction</td></tr>' +
180 '<tr><td style="padding:2px 12px 2px 0"><b>v</b></td><td>Open original in new tab</td></tr>' +
181 '<tr><td style="padding:2px 12px 2px 0"><b>u</b></td><td>Toggle sidebar</td></tr>' +
182 '<tr><td style="padding:2px 12px 2px 0"><b>?</b></td><td>Show this help</td></tr>' +
183 '</table>' +
184 '<p style="margin:12px 0 0;color:light-dark(#999,#666);font-size:11px">Press any key to close</p>' +
185 '</div>'
186 );
187 // Close on any key or click.
188 $( document ).one( 'keydown click', function() {
189 $( '#gr-shortcuts-help' ).remove();
190 } );
191 }
192 return; // Don't let the one() handler fire immediately.
193 }
194 } );
195
196 // Block link clicks on collapsed items — expand instead.
197 $( document ).on( 'click', 'section.posts.all-collapsed article.card:not(.uncollapsed) .post-meta a', function( e ) {
198 e.preventDefault();
199 e.stopPropagation();
200 $( this ).closest( 'article.card' ).trigger( 'click' );
201 return false;
202 } );
203
204 // Accordion click: collapse all others, toggle clicked item.
205 $( document ).on( 'click', 'section.posts.all-collapsed article.card', function( e ) {
206 if ( $( e.target ).closest( 'a, button, input, textarea, form, label, .friends-dropdown' ).length ) {
207 return;
208 }
209
210 var items = getItems();
211 var index = items.index( this );
212 var $card = $( this );
213
214 currentIndex = index;
215 items.removeClass( 'gr-current' );
216 $card.addClass( 'gr-current' );
217
218 // Collapse all others.
219 items.not( this ).removeClass( 'uncollapsed' );
220
221 // Toggle this one.
222 $card.toggleClass( 'uncollapsed' );
223
224 e.stopPropagation();
225 return false;
226 } );
227
228 // Toggle compact/expanded mode.
229 $( document ).on( 'click', 'a.toggle-compact', function() {
230 $( 'section.posts' ).toggleClass( 'all-collapsed' );
231 if ( $( 'section.posts' ).is( '.all-collapsed' ) ) {
232 $( 'a.toggle-compact' ).text( friends.text_expanded_mode );
233 // Collapse all when switching to compact.
234 getItems().removeClass( 'uncollapsed' );
235 } else {
236 $( 'a.toggle-compact' ).text( friends.text_compact_mode );
237 }
238 return false;
239 } );
240 } )( jQuery );
241