/* global jQuery */
( function ( $, wp, friends ) {
const $document = $( document );
let alreadySearching = '';
let alreadyLoading = false;
const bottomOffsetLoadNext = 2000;
let searchResultFocused = false;
wp = wp || { ajax: { send() {}, post() {} } };
$document.on(
'keydown',
'input#master-search, input.master-search, .form-autocomplete a',
function ( e ) {
const code = e.keyCode ? e.keyCode : e.which;
const results = $( this )
.closest( '.form-autocomplete' )
.find( '.menu .menu-item a' );
if ( 40 === code ) {
if ( false === searchResultFocused ) {
searchResultFocused = 0;
} else if ( searchResultFocused + 1 < results.length ) {
searchResultFocused += 1;
}
} else if ( 38 === code ) {
if ( false === searchResultFocused ) {
searchResultFocused = -1;
} else {
searchResultFocused -= 1;
if ( -1 === searchResultFocused ) {
$( this ).closest( '.form-autocomplete' ).find( 'input.master-search, input#master-search' ).focus();
return false;
}
}
} else {
return;
}
searchResultFocused = ( results.length + searchResultFocused ) % results.length;
const el = results.get( searchResultFocused );
if ( el ) {
el.focus();
} else {
searchResultFocused = results.length;
}
return false;
}
);
$document.on( 'keyup', 'input#master-search, input.master-search', function () {
const input = $( this );
const query = input.val().trim();
if ( alreadySearching === query ) {
return;
}
const menu = input.closest( '.form-autocomplete' ).find( '.menu' );
if ( ! query ) {
menu.hide();
return;
}
const searchIndicator = input
.closest( '.form-autocomplete-input' )
.find( '.form-icon' );
wp.ajax.send( 'friends-autocomplete', {
data: {
_ajax_nonce: input.data( 'nonce' ),
q: query,
},
beforeSend() {
searchIndicator.addClass( 'loading' );
alreadySearching = query;
},
success( results ) {
searchIndicator.removeClass( 'loading' );
searchResultFocused = false;
if ( results ) {
menu.html( results ).show();
} else {
menu.hide();
}
},
} );
} );
$document.on( 'keydown', function ( e ) {
const searchDialog = $( '.search-dialog' );
if ( searchDialog.length ) {
if (
(e.metaKey && 75 === e.keyCode ) // cmd-k.
|| ( e.ctrlKey && 75 === e.keyCode ) // ctrl-p.
) {
// move all the childnodes of section.navbar-section search into the .search-dialog:
searchDialog.append( $( '.navbar-section.search' ).children() );
// create a new dialog
if ( searchDialog.is( ':visible' ) ) {
searchDialog.hide();
$( '.navbar-section.search' ).append( searchDialog.children() );
} else {
searchDialog.show();
}
$( 'input#master-search' ).focus();
return false;
}
if ( 27 === e.keyCode ) {
searchDialog.hide();
$( '.navbar-section.search' ).append( $( '.search-dialog' ).children() );
}
}
if ( 69 === e.keyCode && ! e.metaKey && ! e.ctrlKey && ! $( e.target ).is( 'input, textarea' ) ) {
const links = $( 'header .post-edit-link' );
if ( 1 === links.length ) {
links[ 0 ].click();
}
}
} );
const refresh_feeds_now = function() {
let $this = $( this );
function set_status( t ) {
if ( ! $this.length ) {
$this = $( 'a.friends-refresh' );
}
if ( ! $this.find( 'span' ).length ) {
$this.html( ' ' );
$this.find( 'i' ).css( 'margin-left', '1em' );
$this.find( 'i' ).css( 'margin-right', '1em' );
}
$this.find( 'span' ).text( t );
}
set_status( friends.text_refreshing );
$.ajax( {
url: friends.rest_base + 'get-feeds',
beforeSend: function(xhr){
xhr.setRequestHeader( 'X-WP-Nonce', friends.rest_nonce );
},
}
).done( function( feeds ) {
const feed_count = feeds.length;
let alreadyLoading = false;
function update_page() {
if ( alreadyLoading ) {
return;
}
wp.ajax.send( 'friends-load-next-page', {
data: {
query_vars: friends.query_vars,
page: friends.current_page - 1,
qv_sign: friends.qv_sign,
},
beforeSend() {
alreadyLoading = true;
},
success( newPosts ) {
alreadyLoading = false;
if ( newPosts ) {
$( 'section.posts' )
.html( newPosts );
}
},
} );
}
function fetch_next() {
if ( ! feeds.length ) {
$this.html( friends.text_refreshed + '' );
alreadyLoading = false;
update_page();
return;
}
const feed = feeds.shift();
$.ajax( {
url: friends.rest_base + 'refresh-feed',
method: 'POST',
data: { id: feed.id },
beforeSend: function(xhr){
xhr.setRequestHeader( 'X-WP-Nonce', friends.rest_nonce );
},
} ).always( function( data ) {
set_status( ( feed_count - feeds.length ) + ' / ' + feed_count );
if ( data.new_posts ) {
update_page();
}
setTimeout( fetch_next, 1 );
} );
}
fetch_next();
} );
return false;
};
$document.on( 'click', 'a.friends-refresh', refresh_feeds_now );
if ( 'true' === friends.refresh_now ) {
refresh_feeds_now.apply( $( 'a.friends-refresh' ) );
}
$( function () {
$( '.activitypub-follower-check' ).each( function () {
const $pill = $( this );
wp.ajax.send( 'friends_check_activitypub_follower', {
data: {
_ajax_nonce: $pill.data( 'nonce' ),
actor_url: $pill.data( 'actor-url' ),
},
success( result ) {
$pill
.removeClass( 'is-loading is-error' )
.toggleClass( 'is-following', !! result.follows )
.toggleClass( 'is-not-following', ! result.follows )
.text( result.label )
.attr( 'title', result.title );
},
error( result ) {
const message = Array.isArray( result )
? result.map( function( error ) { return error.message || error.code; } ).join( ', ' )
: friends.text_error;
$pill
.removeClass( 'is-loading is-following is-not-following' )
.addClass( 'is-error' )
.text( friends.text_error )
.attr( 'title', message );
},
} );
} );
const standard_count = $( '.chip.post-count-standard' );
if ( standard_count.text().substr( 0, 3 ) === '...' || standard_count.text().substr( 0, 1 ) === '…' ) {
wp.ajax.send( 'friends-get-post-counts', {
data: {
_ajax_nonce: standard_count.data( 'nonce' )
},
success( r ) {
for ( const i in r ) {
if ( ! r[ i ] ) {
$( '.chip.post-count-' + i ).remove();
continue;
}
$( '.chip.post-count-' + i ).text( r[ i ] );
}
},
} );
return false;
}
});
$( function () {
$( '#only_subscribe' ).on( 'change', function () {
$( this )
.closest( 'form' )
.find( '#submit' )
.text( this.checked ? '1' : '2' );
} );
$( '#post-format-switcher select' ).on( 'change', function () {
const re = new RegExp( '/type/[^/$]+' ),
v = $( this ).val();
let url;
const urlPart = v ? '/type/' + v + '/' : '/';
if ( window.location.href.match( re ) ) {
url = window.location.href.replace( re, urlPart );
} else {
url = window.location.href.replace( /\/$/, '' ) + urlPart;
}
window.location.href = url;
} );
} );
$document.on( 'click', 'a.friends-trash-post', function () {
const button = $( this );
wp.ajax.send( 'trash-post', {
data: {
_ajax_nonce: button.data( 'trash-nonce' ),
id: button.data( 'id' ),
},
success() {
button
.text( friends.text_undo )
.attr( 'class', 'friends-untrash-post' );
},
} );
return false;
} );
$document.on( 'click', 'a.friends-untrash-post', function () {
const button = $( this );
wp.ajax.send( 'untrash-post', {
data: {
_ajax_nonce: button.data( 'untrash-nonce' ),
id: button.data( 'id' ),
},
success() {
button
.text( friends.text_trash_post )
.attr( 'class', 'friends-trash-post' );
},
} );
return false;
} );
let openMenu = null;
$document.on( 'click', 'a.friends-dropdown-toggle', function ( e ) {
const $this = $( this );
const dropdown = $this.next( '.menu' );
if ( dropdown.is( ':visible' ) ) {
dropdown.hide();
openMenu = null;
} else {
$( '.menu:not(.menu-nav)' ).hide();
dropdown.show();
openMenu = dropdown;
}
e.stopPropagation();
return false;
});
$document.on( 'click', function ( e ) {
if ( e.target.closest( '.friends-dropdown' ) ) {
return true;
}
if ( openMenu ) {
openMenu.hide();
}
} );
function loadComments( commentsLink, callback ) {
const $this = $( commentsLink );
let content = $this.closest( 'article' ).find( '.comments-content' );
if ( ! content.length ) {
content = $this.closest( '.wp-block-friends-post-comments' ).find( '.comments-content' );
}
if ( ! content.length ) {
content = $this.closest( 'li' ).find( '.comments-content' );
}
if ( content.data( 'loaded' ) ) {
content.toggle();
} else {
content.show();
content.html( ' ' );
content.find( 'i' ).css( 'margin-left', '1em' );
content.find( 'i' ).css( 'margin-right', '1em' );
content.find( 'span' ).text( friends.text_loading_comments );
let stillLoading = setTimeout( function () {
content.find( 'span' ).text( friends.text_still_loading );
}, 2000 );
wp.ajax.send( 'friends-load-comments', {
data: {
_ajax_nonce: $this.data( 'cnonce' ),
post_id: $this.data( 'id' ),
},
success( comments ) {
content.html( comments ).data( 'loaded', true );
clearTimeout( stillLoading );
callback();
},
error( message ) {
content.html( message ).data( 'loaded', true );
clearTimeout( stillLoading );
},
} );
}
}
$document.on( 'click', 'article a.comments, .wp-block-friends-post-comments a.comments', function ( e ) {
if ( e.metaKey || e.altKey || e.shiftKey ) {
return;
}
loadComments.call( this );
return false;
} );
$document.on( 'change', 'select.friends-change-post-format', function () {
const select = $( this );
wp.ajax.send( 'friends-change-post-format', {
data: {
_ajax_nonce: select.data( 'change-post-format-nonce' ),
id: select.data( 'id' ),
format: select.val(),
},
success() {
// TODO: add some visual indication.
},
} );
return false;
} );
$( window ).scroll( function () {
if (
$( document ).scrollTop() <
$( document ).height() - bottomOffsetLoadNext
) {
return;
}
nextPage();
} );
$( document ).on( 'click', '.nav-previous', function () {
nextPage();
return false;
} );
function nextPage() {
if ( alreadyLoading ) {
return;
}
if ( friends.current_page >= friends.max_page ) {
return;
}
wp.ajax.send( 'friends-load-next-page', {
data: {
query_vars: friends.query_vars,
page: friends.current_page,
qv_sign: friends.qv_sign,
},
beforeSend() {
$( 'section.posts .posts-navigation .nav-previous' ).addClass(
'loading'
);
alreadyLoading = true;
},
success( newPosts ) {
$(
'section.posts .posts-navigation .nav-previous'
).removeClass( 'loading' );
if ( newPosts ) {
$( 'section.posts > article' ).last().after( newPosts );
if (
++friends.current_page < friends.max_page &&
/' + emojiChar + ' 1' );
$picker.closest( '.friends-dropdown' ).before( $btn );
}
},
error() {
$this.removeClass( 'loading' );
},
} );
return false;
} );
} );
$( function () {
$document.on( 'click', 'a.friends-reblog', function () {
const $this = $( this );
wp.ajax.send( 'friends-reblog', {
data: {
_ajax_nonce: $this.data( 'nonce' ),
post_id: $this.data( 'id' ),
},
success( result ) {
if ( result.redirect ) {
location.href = result.redirect;
}
$this
.find( 'i.friends-reblog-status' )
.addClass( 'dashicons dashicons-saved' );
},
} );
return false;
} );
} );
$( function () {
$document.on( 'click', 'a.friends-boost', function () {
const $this = $( this );
$this.addClass( 'loading' );
wp.ajax.send( 'friends-boost', {
data: {
_ajax_nonce: $this.data( 'nonce' ),
post_id: $this.data( 'id' ),
},
success( result ) {
$this.removeClass( 'loading' );
if ( 'boosted' === result ) {
$this
.find( 'i.friends-boost-status' )
.removeClass( 'dashicons-warning' )
.addClass( 'dashicons dashicons-saved' );
} else if ( 'unboosted' === result ) {
$this
.find( 'i.friends-boost-status' )
.removeClass( 'dashicons dashicons-warning dashicons-saved' )
} else {
$this
.find( 'i.friends-boost-status' )
.addClass( 'dashicons dashicons-warning' )
.removeClass( 'dashicons-saved' )
.attr( 'title', result );
}
},
fail( result ) {
$this.removeClass( 'loading' );
$this
.find( 'i.friends-boost-status' )
.addClass( 'dashicons dashicons-warning' )
.removeClass( 'dashicons-saved' )
.attr( 'title', result );
}
} );
return false;
} );
} );
$document.on( 'click', 'a.send-new-message', function () {
$( '#friends-send-new-message' )
.toggle()
.find(
'textarea:visible, .block-editor-default-block-appender__content'
)
.focus();
return false;
} );
$document.on( 'click', 'button.delete-conversation', function () {
// eslint-disable-next-line no-alert
return window.confirm( friends.text_del_convers );
} );
function getMessageDraftKey( form, field ) {
const key = $( form ).data( 'friends-message-draft-key' );
if ( ! key ) {
return '';
}
return key + ':' + field;
}
function getMessageDraftStorage() {
try {
return window.localStorage;
} catch ( e ) {
return false;
}
}
function restoreMessageDrafts() {
const storage = getMessageDraftStorage();
if ( ! storage ) {
return;
}
$( 'form[data-friends-message-draft-key]' ).each( function () {
const form = this;
const messageKey = getMessageDraftKey( form, 'message' );
const subjectKey = getMessageDraftKey( form, 'subject' );
const message = storage.getItem( messageKey );
const subject = storage.getItem( subjectKey );
if ( message ) {
$( form ).find( 'textarea[name="friends_message_message"]' ).val( message );
}
if ( subject ) {
$( form ).find( 'input[name="friends_message_subject"]:not([type="hidden"])' ).val( subject );
}
} );
}
$document.on( 'input', 'textarea[name="friends_message_message"], input[name="friends_message_subject"]', function () {
const storage = getMessageDraftStorage();
if ( ! storage ) {
return;
}
const form = this.form;
const field = 'friends_message_subject' === this.name ? 'subject' : 'message';
const key = getMessageDraftKey( form, field );
if ( ! key ) {
return;
}
if ( this.value ) {
storage.setItem( key, this.value );
} else {
storage.removeItem( key );
}
} );
$document.on( 'submit', 'form[data-friends-message-draft-key]', function () {
const storage = getMessageDraftStorage();
if ( ! storage ) {
return;
}
storage.removeItem( getMessageDraftKey( this, 'message' ) );
storage.removeItem( getMessageDraftKey( this, 'subject' ) );
} );
$document.on( 'click', 'a.display-message', function () {
const $this = $( this ).closest( 'div' );
const conversation = $this.find( 'div.conversation' );
if ( conversation.is( ':visible' ) ) {
conversation.hide();
} else {
conversation.show();
const messages = conversation.find( '.messages' ).get( 0 );
// scroll smoothly to the bottom of the overflow div:
$( messages ).animate( { scrollTop: messages.scrollHeight }, 1000 );
$this.find( 'a.display-message' ).removeClass( 'unread' );
wp.ajax.send( 'friends-mark-read', {
data: {
_ajax_nonce: $this.data( 'nonce' ),
post_id: $this.data( 'id' ),
},
success() {},
} );
conversation
.find(
'textarea:visible, .block-editor-default-block-appender__content'
)
.focus();
}
return false;
} );
function getRelativeTime( timestamp ) {
const seconds = Math.max( 1, Math.floor( Date.now() / 1000 ) - timestamp );
const minute = 60;
const hour = 60 * minute;
const day = 24 * hour;
const week = 7 * day;
const month = 30 * day;
const year = 365 * day;
if ( seconds < minute ) {
return seconds + ' seconds';
}
if ( seconds < hour ) {
const minutes = Math.floor( seconds / minute );
return minutes + ' minute' + ( 1 === minutes ? '' : 's' );
}
if ( seconds < day ) {
const hours = Math.floor( seconds / hour );
return hours + ' hour' + ( 1 === hours ? '' : 's' );
}
if ( seconds < week ) {
const days = Math.floor( seconds / day );
return days + ' day' + ( 1 === days ? '' : 's' );
}
if ( seconds < month ) {
const weeks = Math.floor( seconds / week );
return weeks + ' week' + ( 1 === weeks ? '' : 's' );
}
if ( seconds < year ) {
const months = Math.floor( seconds / month );
return months + ' month' + ( 1 === months ? '' : 's' );
}
const years = Math.floor( seconds / year );
return years + ' year' + ( 1 === years ? '' : 's' );
}
function updateRelativeTimes( scope ) {
$( scope || document ).find( 'time[data-friends-relative-time]' ).each( function () {
const timestamp = parseInt( $( this ).data( 'friends-relative-time' ), 10 );
if ( ! timestamp ) {
return;
}
$( this ).text( getRelativeTime( timestamp ) + ( $( this ).data( 'friends-relative-time-suffix' ) || '' ) );
} );
}
function markCurrentDmThreadRead() {
const $thread = $( '.friends-dm-thread' );
if ( ! $thread.length ) {
return;
}
if ( '1' !== String( $thread.data( 'unread' ) ) ) {
return;
}
wp.ajax.send( 'friends-mark-read', {
data: {
_ajax_nonce: $thread.data( 'nonce' ),
post_id: $thread.data( 'id' ),
},
success() {
$( '.friends-dm-conversation.is-selected' )
.removeClass( 'is-unread' )
.find( '.friends-dm-unread-count' )
.remove();
$thread.data( 'unread', '0' ).attr( 'data-unread', '0' );
},
} );
}
const dmMobileQuery = window.matchMedia ? window.matchMedia( '(max-width: 840px)' ) : null;
function isMobileDmView() {
return dmMobileQuery && dmMobileQuery.matches;
}
function hasFocusedDmHash() {
const $thread = $( '.friends-dm-thread' );
return !! $thread.length && window.location.hash === '#' + $thread.attr( 'id' );
}
function isDmConversationVisible() {
return ! isMobileDmView() || hasFocusedDmHash();
}
function scrollCurrentDmThreadToBottom() {
const messages = $( '.friends-dm-thread' ).find( '.friends-dm-messages' ).get( 0 );
if ( messages ) {
messages.scrollTop = messages.scrollHeight;
}
}
function updateDmHashState() {
const $view = $( '.friends-dm-view' );
if ( ! $view.length ) {
return;
}
$view.toggleClass( 'is-focused-conversation', hasFocusedDmHash() );
if ( isDmConversationVisible() ) {
scrollCurrentDmThreadToBottom();
markCurrentDmThreadRead();
}
}
function updateDmViewportHeight() {
if ( ! $( '.friends-dm-view' ).length ) {
return;
}
const viewport = window.visualViewport || window;
const height = viewport.height || window.innerHeight;
if ( height ) {
document.documentElement.style.setProperty( '--friends-dm-viewport-height', height + 'px' );
}
}
function watchDmViewportHeight() {
if ( ! $( '.friends-dm-view' ).length ) {
return;
}
let frame = null;
const scheduleUpdate = function () {
if ( frame ) {
window.cancelAnimationFrame( frame );
}
frame = window.requestAnimationFrame( updateDmViewportHeight );
};
updateDmViewportHeight();
$( window ).on( 'resize orientationchange', scheduleUpdate );
if ( window.visualViewport ) {
window.visualViewport.addEventListener( 'resize', scheduleUpdate );
window.visualViewport.addEventListener( 'scroll', scheduleUpdate );
}
if ( dmMobileQuery && dmMobileQuery.addEventListener ) {
dmMobileQuery.addEventListener( 'change', updateDmHashState );
} else if ( dmMobileQuery && dmMobileQuery.addListener ) {
dmMobileQuery.addListener( updateDmHashState );
}
}
$document.on( 'focus blur', '.friends-dm-reply input, .friends-dm-reply select, .friends-dm-reply textarea', function () {
const reply = $( this ).closest( '.friends-dm-reply' ).get( 0 );
window.setTimeout( function () {
updateDmViewportHeight();
if ( reply ) {
reply.scrollIntoView( { block: 'end' } );
}
}, 300 );
} );
let dmDeliveryTooltipTimeout = null;
function hideDmDeliveryTooltip() {
window.clearTimeout( dmDeliveryTooltipTimeout );
dmDeliveryTooltipTimeout = null;
$( '.friends-dm-delivery-tooltip' ).remove();
$( '.friends-dm-delivery-status.is-showing-title' ).removeClass( 'is-showing-title' );
}
function showDmDeliveryTooltip( element ) {
const $status = $( element );
const title = $status.attr( 'title' );
if ( ! title ) {
return;
}
hideDmDeliveryTooltip();
$status.addClass( 'is-showing-title' );
const rect = element.getBoundingClientRect();
const $tooltip = $( '' ).text( title );
$( document.body ).append( $tooltip );
const margin = 8;
const width = $tooltip.outerWidth();
const height = $tooltip.outerHeight();
const left = Math.min( Math.max( margin, rect.right - width ), window.innerWidth - width - margin );
let top = rect.top - height - margin;
if ( top < margin ) {
top = rect.bottom + margin;
}
$tooltip.css( {
left: left + 'px',
top: top + 'px',
} );
dmDeliveryTooltipTimeout = window.setTimeout( hideDmDeliveryTooltip, 5000 );
}
$document.on( 'click', '.friends-dm-delivery-status[title]', function ( event ) {
const $status = $( this );
if ( ! $status.attr( 'title' ) ) {
return;
}
event.preventDefault();
event.stopPropagation();
if ( $status.hasClass( 'is-showing-title' ) ) {
hideDmDeliveryTooltip();
} else {
showDmDeliveryTooltip( this );
}
} );
$document.on( 'click', hideDmDeliveryTooltip );
$( window ).on( 'resize scroll', hideDmDeliveryTooltip );
function updateDmDeliveryStatusElement( $status, delivery ) {
if ( ! delivery || ! delivery.status ) {
return;
}
const classes = ( $status.attr( 'class' ) || '' )
.split( /\s+/ )
.filter( function ( className ) {
return className && ! className.match( /^is-/ );
} );
classes.push( 'is-' + delivery.status );
$status
.attr( 'class', classes.join( ' ' ) )
.attr( 'title', delivery.title || '' )
.attr( 'aria-label', delivery.label || '' )
.text( $status.hasClass( 'friends-dm-delivery-icon' ) ? '' : delivery.label || '' );
}
let isRefreshingDmDeliveryStatuses = false;
function refreshDmDeliveryStatuses() {
const $statuses = $( '.friends-dm-delivery-status[data-delivery-message-id]' );
if ( isRefreshingDmDeliveryStatuses || ! $statuses.length || ! friends.message_delivery_nonce ) {
return;
}
const postIds = $statuses.map( function () {
return $( this ).data( 'delivery-message-id' );
} ).get().filter( function ( postId, index, postIds ) {
return postId && postIds.indexOf( postId ) === index;
} );
if ( ! postIds.length ) {
return;
}
isRefreshingDmDeliveryStatuses = true;
wp.ajax.send( 'friends-get-message-delivery-statuses', {
data: {
_ajax_nonce: friends.message_delivery_nonce,
post_ids: postIds,
},
success( response ) {
const statuses = response.statuses || {};
Object.keys( statuses ).forEach( function ( postId ) {
updateDmDeliveryStatusElement(
$( '.friends-dm-delivery-status[data-delivery-message-id="' + postId + '"]' ),
statuses[ postId ]
);
} );
},
error() {
isRefreshingDmDeliveryStatuses = false;
},
} ).always( function () {
isRefreshingDmDeliveryStatuses = false;
} );
}
$( function () {
restoreMessageDrafts();
updateRelativeTimes( document );
watchDmViewportHeight();
updateDmHashState();
$( window ).on( 'hashchange', updateDmHashState );
const $thread = $( '.friends-dm-thread' );
if ( ! $thread.length ) {
return;
}
window.setInterval( updateRelativeTimes, 60000 );
window.setInterval( refreshDmDeliveryStatuses, 5000 );
refreshDmDeliveryStatuses();
} );
$document.on( 'mouseenter', 'h2#page-title a.dashicons, a.wp-block-friends-author-star.dashicons', function () {
if ( $( this ).hasClass( 'not-starred' ) ) {
if ( $( this ).hasClass( 'dashicons-star-empty' ) ) {
$( this )
.removeClass( 'dashicons-star-empty' )
.addClass( 'dashicons-star-filled' );
}
} else if ( $( this ).hasClass( 'starred' ) ) {
if ( $( this ).hasClass( 'dashicons-star-filled' ) ) {
$( this )
.removeClass( 'dashicons-star-filled' )
.addClass( 'dashicons-star-empty' );
}
}
} );
$document.on( 'mouseleave', 'h2#page-title a.dashicons, a.wp-block-friends-author-star.dashicons', function () {
if ( $( this ).hasClass( 'not-starred' ) ) {
if ( $( this ).hasClass( 'dashicons-star-filled' ) ) {
$( this )
.removeClass( 'dashicons-star-filled' )
.addClass( 'dashicons-star-empty' );
}
} else if ( $( this ).hasClass( 'starred' ) ) {
if ( $( this ).hasClass( 'dashicons-star-empty' ) ) {
$( this )
.removeClass( 'dashicons-star-empty' )
.addClass( 'dashicons-star-filled' );
}
}
} );
$document.on(
'click',
'h2#page-title a.dashicons.starred, h2#page-title a.dashicons.not-starred, a.wp-block-friends-author-star.starred, a.wp-block-friends-author-star.not-starred',
function () {
let removeClass = 'dashicons-star-filled starred';
let addClass = 'dashicons-star-empty not-starred';
const $this = $( this );
if ( $this.hasClass( 'not-starred' ) ) {
const s = removeClass;
removeClass = addClass;
addClass = s;
}
wp.ajax.send( 'friends-star', {
data: {
friend_id: $this.data( 'id' ),
_ajax_nonce: $this.data( 'nonce' ),
starred: $this.hasClass( 'starred' ) ? 0 : 1,
},
beforeSend() {
$this
.removeClass(
removeClass +
' dashicons-star-filled dashicons-star-empty'
)
.addClass( 'form-icon loading' );
},
success() {
$this
.removeClass( 'form-icon loading' )
.addClass( addClass );
},
} );
return false;
}
);
// Folder selector for subscriptions.
$document.on( 'change', '.friends-move-to-folder', function () {
const $select = $( this );
const friendId = $select.data( 'id' );
const nonce = $select.data( 'nonce' );
let folderId = $select.val();
if ( 'new' === folderId ) {
const name = prompt( friends.text_new_folder || 'Folder name:' );
if ( ! name ) {
$select.val( $select.data( 'current' ) || 0 );
return;
}
wp.ajax.send( 'friends-create-folder', {
data: {
name: name,
_ajax_nonce: nonce,
},
success( r ) {
// Add the new option and select it.
$select.find( 'option[value="new"]' ).before(
''
);
$select.val( r.term_id );
$select.data( 'current', r.term_id );
// Now move the subscription to it.
wp.ajax.send( 'friends-move-to-folder', {
data: {
friend_id: friendId,
folder_id: r.term_id,
_ajax_nonce: nonce,
},
} );
},
} );
return;
}
$select.data( 'current', folderId );
wp.ajax.send( 'friends-move-to-folder', {
data: {
friend_id: friendId,
folder_id: folderId,
_ajax_nonce: nonce,
},
} );
} );
function getAcct( href ) {
const url = new URL( href );
const username = url.pathname.replace( /\/$/, '' ).split( '/' ).pop();
return '@' + username.replace( /^@/, '' ) + '@' + url.hostname;
}
function insertTextInGutenberg( text ) {
let element, val, regex;
if ( jQuery( '.is-root-container p' ).length ) {
element = jQuery( '.is-root-container p' )[ 0 ];
element.focus();
window.getSelection().collapse( element.firstChild, element.textContent.length );
document.execCommand( 'insertText', false, text + ' ' );
} else {
val = text + ' ' + jQuery( '.friends-status-content' ).val();
jQuery( '.friends-status-content' ).val( val.replace( /^(@[^@]+@[^ ]+ )+/g, text + ' ' ) );
}
}
$document.on( 'click', '.quick-reply,a.comments', function () {
const card = $( this ).closest( '.card' );
card.click();
$( this ).closest( '.friends-dropdown' ).hide();
openMenu = null;
let comments = $( this ).closest( '.card' ).find( '.comments' );
if ( ! comments.length ) {
comments = $( this ).closest( 'li' ).find( '.comments' );
}
if ( comments.length ) {
$( 'html, body' ).animate( {
scrollTop: comments.offset().top - 100,
}, 500 );
}
loadComments( comments, function() {
// focus #comment textarea but put the cursor at the end
const comment = card.find( '#comment' );
comment.focus();
const val = comment.val();
comment.val( '' ).val( val );
} );
return false;
} );
$document.on( 'click', '.quick-post-panel-toggle', function () {
$( '#quick-post-panel' ).toggleClass( 'open' );
return false;
} );
// when the ".followers details" html element is expanded
$document.on( 'click', '.followers details', function () {
const $this = $( this );
if ( $this.find( '.loading-posts' ).length ) {
wp.ajax.send( 'friends-preview-activitypub', {
data: {
_ajax_nonce: $this.data( 'nonce' ),
url: $this.data( 'id' ),
followers: $this.data( 'followers' ),
following: $this.data( 'following' ),
},
success( result ) {
$this.find( '.loading-posts' ).hide().after( result.posts );
$this.find( '.their-followers' ).text( result.followers );
$this.find( '.their-following' ).text( result.following );
},
error( result ) {
$this.find( '.loading-posts' ).text( result.map(function( error ) { return error.message || error.code; } ).join( ',' ) );
}
} );
}
} );
$document.on( 'click', '.follower-delete', function () {
const $this = $( this );
if ( ! confirm( friends.text_confirm_delete_follower.replace( /%s/, $this.data( 'handle' )) ) ) {
return false;
}
wp.ajax.send( 'friends-delete-follower', {
data: {
_ajax_nonce: $this.data( 'nonce' ),
id: $this.data( 'id' ),
},
success() {
$this.closest( 'details' ).remove();
},
} );
return false;
} );
$document.on( 'click', '.friends-widget summary', function () {
const $this = $( this ).closest( 'details' );
const previously_open = $this.prop( 'open' );
wp.ajax.send( 'friends-set-widget-open-state', {
data: {
_ajax_nonce: $this.data( 'nonce' ),
widget: $this.data( 'id' ),
state: previously_open ? 'closed' : 'open',
},
success() {},
} );
} );
$document.on( 'click', '.refresh-feeds', function ( e ) {
e.preventDefault();
const $this = $( this );
const originalText = $this.text();
$this.text( friends.text_refreshing || 'Refreshing' );
wp.ajax.send( 'friends-refresh-feeds', {
data: {
_ajax_nonce: $this.data( 'nonce' ),
user: $this.data( 'user' ),
},
success() {
$this.text( friends.text_refreshed || 'Refreshed' );
setTimeout( function () {
window.location.reload();
}, 500 );
},
error( result ) {
$this.text( originalText );
},
} );
} );
let subscriptionPreviewId = 0;
let subscriptionPasteReviewTimer = null;
function friendsText( key, fallback ) {
return friends && friends[ key ] ? friends[ key ] : fallback;
}
function ajaxErrorText( result ) {
if ( $.isArray( result ) ) {
return result.join( ', ' );
}
if ( result && result.message ) {
return result.message;
}
if ( result ) {
return String( result );
}
return friendsText( 'text_error', 'An error occurred.' );
}
function getSubscriptionNonce() {
return $( '#add-subscription-form input[name=_wpnonce]' ).val();
}
function looksLikeOpml( text ) {
if ( ! text ) {
return false;
}
const trimmed = text.trim();
if ( trimmed.charAt( 0 ) !== '<' ) {
return false;
}
return /<\s*(opml|outline)\b/i.test( trimmed );
}
function parsePastedPeopleList( text ) {
const seen = {};
const items = [];
const lines = text.split( /\r?\n/ );
for ( let i = 0; i < lines.length; i++ ) {
const line = lines[ i ]
.replace( /^\s*[-*]\s+/, '' )
.replace( /^\s*\d+[.)]\s+/, '' )
.trim();
if ( ! line || seen[ line ] ) {
continue;
}
seen[ line ] = true;
items.push( {
url: line,
text: line,
} );
}
return items.length > 1 ? items : [];
}
function parseOpmlItems( opmlText ) {
const parser = new DOMParser();
const doc = parser.parseFromString( opmlText, 'application/xml' );
if ( doc.getElementsByTagName( 'parsererror' ).length ) {
return {
error: friendsText( 'text_opml_invalid', 'Could not parse the OPML file.' ),
};
}
const outlines = doc.querySelectorAll( 'outline[xmlUrl]' );
if ( ! outlines.length ) {
return {
error: friendsText( 'text_opml_no_feeds', 'No feeds were found in the OPML file.' ),
};
}
const items = [];
$( outlines ).each( function () {
const xmlUrl = this.getAttribute( 'xmlUrl' ) || '';
const htmlUrl = this.getAttribute( 'htmlUrl' ) || '';
items.push( {
url: htmlUrl || xmlUrl,
feedUrl: xmlUrl,
htmlUrl: htmlUrl,
text: this.getAttribute( 'text' ) || this.getAttribute( 'title' ) || xmlUrl,
} );
} );
return { items: items };
}
function setSubscriptionPreviewError( message ) {
$( '#preview-subscription' ).empty().append( $( '' ).text( message ) );
}
function createSelect( options, selected, className ) {
const $select = $( '' ).addClass( 'form-select ' + className );
let selectedFound = false;
$.each( options, function ( value, label ) {
const $option = $( '' ).attr( 'value', value ).text( label );
if ( selected === value ) {
$option.prop( 'selected', true );
selectedFound = true;
}
$select.append( $option );
} );
if ( selected && ! selectedFound ) {
$select.append( $( '' ).attr( 'value', selected ).prop( 'selected', true ).text( selected ) );
}
return $select;
}
function generateUserLogin( value ) {
return String( value || '' )
.toLowerCase()
.replace( /[^a-z0-9.]+/g, '-' )
.replace( /^-+|-+$/g, '' );
}
function htmlToPlainText( value ) {
const doc = new DOMParser().parseFromString( String( value || '' ), 'text/html' );
if ( ! doc.body ) {
return String( value || '' );
}
$( doc.body ).find( 'script, style, noscript' ).remove();
return doc.body.textContent.replace( /\s+/g, ' ' ).trim();
}
function appendMetadataText( $details, label, value ) {
if ( ! value ) {
return;
}
if ( $details.contents().length ) {
$details.append( document.createTextNode( ' | ' ) );
}
$details.append( document.createTextNode( label + ': ' + value ) );
}
function getDefaultParser() {
const parsers = friends.registered_parsers || { simplepie: 'SimplePie' };
const parserKeys = Object.keys( parsers );
return parserKeys.length ? parserKeys[ 0 ] : 'simplepie';
}
function getFeedOptionUrl( $item ) {
const $input = $item.find( '.subscription-feed-url' );
if ( $input.length ) {
return $.trim( $input.val() );
}
return $.trim( $item.data( 'feedUrl' ) || '' );
}
function resetSubscriptionFeedPreview( $item ) {
const $preview = $item.find( '.subscription-feed-preview' );
$preview.removeData( 'loaded' ).empty().addClass( 'hidden' );
$item.find( '.subscription-feed-preview-toggle' ).text( friendsText( 'text_preview_feed', 'Preview feed' ) );
}
function renderSubscriptionFeedOption( panelId, feedIndex, feedUrl, feed, options ) {
const settings = $.extend( { hidden: false, unsupported: false, custom: false }, options || {} );
const feedDetails = $.extend( { url: feedUrl }, feed || {} );
const feedId = panelId + '-feed-' + feedIndex;
const parser = settings.unsupported || settings.custom ? getDefaultParser() : ( feedDetails.parser || getDefaultParser() );
const title = feedDetails.title || feedUrl || friendsText( 'text_custom_feed', 'Custom feed' );
const $item = $( '' )
.toggleClass( 'hidden rel-alternate', settings.hidden )
.toggleClass( 'unsupported-feed-option', settings.unsupported )
.toggleClass( 'custom-feed-option', settings.custom )
.data( {
feedUrl: feedUrl,
feed: feedDetails,
} );
const $checkbox = $( '' )
.attr( 'id', feedId )
.prop( 'checked', settings.custom ? true : ( ! settings.unsupported && !! feedDetails.autoselect ) );
const $label = $( '' ).attr( 'for', feedId ).append( $checkbox ).append( ' ' );
if ( feedUrl ) {
$label.append(
$( '' )
.attr( 'href', feedUrl )
.text( title )
);
} else {
$label.append( $( '' ).text( title ) );
}
if ( feedDetails.type ) {
$label.append( ' ' ).append( $( '' ).text( '(' + feedDetails.type + ')' ) );
}
$item.append( $label );
const $controls = $( '' );
if ( settings.unsupported || settings.custom ) {
$controls.append(
$( '' )
.text( friendsText( 'text_feed_url', 'Feed URL' ) )
.append(
$( '' )
.val( feedUrl )
.attr( 'placeholder', 'https://example.com/feed.xml' )
)
);
}
$controls.append(
$( '' )
.text( friendsText( 'text_post_format', 'Post Format' ) )
.append( createSelect( friends.post_formats || { standard: 'Standard' }, feedDetails[ 'post-format' ] || 'standard', 'subscription-feed-post-format' ) )
);
$controls.append(
$( '' )
.text( friendsText( 'text_feed_parser', 'Parser' ) )
.append( createSelect( friends.registered_parsers || { simplepie: 'SimplePie' }, parser, 'subscription-feed-parser' ) )
);
$controls.append(
$( '' )
.text( friendsText( 'text_preview_feed', 'Preview feed' ) )
);
$item.append( $controls );
const $details = $( '' );
appendMetadataText( $details, 'Type', feedDetails.type );
appendMetadataText( $details, 'rel', feedDetails.rel );
appendMetadataText( $details, 'URL', feedUrl );
appendMetadataText( $details, 'Parser', feedDetails.parser );
if ( feedDetails[ 'additional-info' ] ) {
$details.append( $( '
' ) ).append( document.createTextNode( feedDetails[ 'additional-info' ] ) );
}
$item.append( $details );
$item.append( $( '' ) );
return $item;
}
function renderSubscriptionCard( response, nonce, fallbackDisplayName ) {
const feeds = response.feeds || {};
const displayName = response.display_name || fallbackDisplayName || response.user_login || response.url;
const userLogin = response.user_login || generateUserLogin( displayName || response.url );
const panelId = 'subscription-preview-' + ( ++subscriptionPreviewId );
const $panel = $( '' )
.attr( 'id', panelId )
.data( {
url: response.url,
nonce: nonce,
} );
const $header = $( '' );
if ( response.avatar ) {
$header.append( $( '
' ).attr( 'src', response.avatar ) );
}
const $title = $( '' );
$title.append( $( '' ).text( displayName ) );
$title.append( $( '' ).text( response.url ) );
$header.append( $title );
$panel.append( $header );
if ( response.description ) {
$panel.append( $( '' ).text( htmlToPlainText( response.description ) ) );
}
const $settings = $( '' );
const $displayNameInput = $( '' ).val( displayName );
const $userLoginInput = $( '' )
.val( userLogin )
.data( 'original', userLogin );
$settings.append(
$( '' )
.text( friendsText( 'text_display_name', 'Display Name' ) )
.append( $displayNameInput )
);
$settings.append(
$( '' )
.text( friendsText( 'text_username', 'Username' ) )
.append( $userLoginInput )
);
$panel.append( $settings );
const $feedList = $( '' );
const unsupportedFeeds = [];
let supportedCount = 0;
let hiddenFeedCount = 0;
$.each( feeds, function ( feedUrl, feed ) {
if ( ! feed || 'unsupported' === feed.parser ) {
unsupportedFeeds.push( {
url: feedUrl,
feed: feed || {},
} );
return;
}
supportedCount++;
const hidden = supportedCount > 1 && ! feed.autoselect;
if ( hidden ) {
hiddenFeedCount++;
}
$feedList.append( renderSubscriptionFeedOption( panelId, supportedCount, feedUrl, feed, { hidden: hidden } ) );
} );
if ( supportedCount ) {
$panel.append( $feedList );
} else {
$panel.append( $( '' ).text( friendsText( 'text_no_supported_feeds', 'No supported feeds discovered.' ) ) );
}
const $feedActions = $( '' );
if ( hiddenFeedCount ) {
$feedActions.append(
$( '' )
.text( friendsText( 'text_show_more_feeds', 'Show more feeds' ) )
);
}
if ( supportedCount || unsupportedFeeds.length ) {
$feedActions.append(
$( '' )
.text( friendsText( 'text_feed_metadata', 'Display feed metadata' ) )
);
}
if ( unsupportedFeeds.length ) {
$feedActions.append(
$( '' )
.text( friendsText( 'text_show_unsupported_feeds', 'Show unsupported feeds' ) )
);
const $unsupported = $( '' );
$.each( unsupportedFeeds, function ( index, item ) {
$unsupported.append( renderSubscriptionFeedOption( panelId, supportedCount + index + 1, item.url, item.feed, { unsupported: true } ) );
} );
$panel.append( $unsupported );
}
$feedActions.append(
$( '' )
.text( friendsText( 'text_add_feed_url', 'Add feed URL' ) )
);
if ( $feedActions.children().length ) {
$panel.append( $feedActions );
}
const $previewActions = $( '' )
.append( $( '' ).text( friendsText( 'text_skip', 'Skip' ) ) )
.append( $( '' ).text( friendsText( 'text_follow', 'Follow' ) ) )
.append( $( '' ) );
$panel.append( $previewActions );
return $panel;
}
function collectSubscriptionFeeds( $panel ) {
const feeds = [];
$panel.find( '.subscription-feed-option' ).each( function () {
const $item = $( this );
const feed = $.extend( {}, $item.data( 'feed' ) || {} );
feed.url = getFeedOptionUrl( $item );
if ( ! feed.url ) {
return;
}
feed.selected = $item.find( '.subscription-feed-selected' ).is( ':checked' );
feed[ 'post-format' ] = $item.find( '.subscription-feed-post-format' ).val();
feed.parser = $item.find( '.subscription-feed-parser' ).val();
feeds.push( feed );
} );
return feeds;
}
function renderFeedPreviewItems( $preview, items ) {
$preview.empty();
if ( ! items || ! items.length ) {
$preview.append( $( '' ).text( friendsText( 'text_no_preview_items', 'No preview items were found.' ) ) );
return;
}
const $list = $( '' );
$.each( items, function ( index, item ) {
const $item = $( '' );
const $summary = $( '' );
if ( item.permalink ) {
$summary.append(
$( '' )
.attr( 'href', item.permalink )
.text( item.title || item.permalink )
);
} else {
$summary.text( item.title || '' );
}
const meta = [];
if ( item.date ) {
meta.push( item.date );
}
if ( item.author ) {
meta.push( item.author );
}
if ( item.post_format ) {
meta.push( item.post_format );
}
if ( meta.length ) {
$summary.append( $( '' ).text( meta.join( ' | ' ) ) );
}
$item.append( $summary );
if ( item.excerpt ) {
$item.append( $( '' ).text( item.excerpt ) );
}
$list.append( $item );
} );
$preview.append( $list );
}
function previewSubscriptionFeed( $item, $button ) {
const $preview = $item.find( '.subscription-feed-preview' );
const feedUrl = getFeedOptionUrl( $item );
if ( ! feedUrl ) {
$preview.removeClass( 'hidden' ).empty().append( $( '' ).text( friendsText( 'text_feed_url_required', 'Please enter a feed URL.' ) ) );
return;
}
if ( $preview.data( 'loaded' ) ) {
const isHidden = $preview.hasClass( 'hidden' );
$preview.toggleClass( 'hidden', ! isHidden );
$button.text( isHidden ? friendsText( 'text_hide_preview', 'Hide preview' ) : friendsText( 'text_preview_feed', 'Preview feed' ) );
return;
}
$button.prop( 'disabled', true );
$preview.removeClass( 'hidden' ).text( friendsText( 'text_loading', 'Loading...' ) );
wp.ajax.send( 'friends-preview-subscription-feed', {
data: {
_ajax_nonce: $item.closest( '.subscription-preview' ).data( 'nonce' ),
url: feedUrl,
parser: $item.find( '.subscription-feed-parser' ).val(),
},
success( response ) {
renderFeedPreviewItems( $preview, response.items );
$preview.data( 'loaded', true );
$button.prop( 'disabled', false ).text( friendsText( 'text_hide_preview', 'Hide preview' ) );
},
error( result ) {
$preview.empty().append( $( '' ).text( ajaxErrorText( result ) ) );
$button.prop( 'disabled', false );
},
} );
}
function subscribeSubscriptionPanel( $panel, $button, done ) {
const feeds = collectSubscriptionFeeds( $panel );
let selectedFeedCount = 0;
for ( let i = 0; i < feeds.length; i++ ) {
if ( feeds[ i ].selected ) {
selectedFeedCount++;
}
}
const $status = $panel.find( '.subscription-preview-status' );
if ( ! selectedFeedCount ) {
$status.addClass( 'error' ).text( friendsText( 'text_no_feed_selected', 'Please select at least one feed.' ) );
if ( done ) {
done( false );
}
return;
}
$button.prop( 'disabled', true );
$status.removeClass( 'error' ).text( friendsText( 'text_loading', 'Loading...' ) );
wp.ajax.send( 'friends-subscribe-frontend', {
data: {
_ajax_nonce: $panel.data( 'nonce' ),
url: $panel.data( 'url' ),
display_name: $panel.find( '.subscription-display-name' ).val(),
user_login: $panel.find( '.subscription-user-login' ).val(),
feeds: feeds,
},
success( response ) {
const avatar = $panel.find( '.avatar' ).attr( 'src' );
const $success = $( '' );
if ( avatar ) {
$success.append( $( '
' ).attr( 'src', avatar ) );
}
$success.append( $( '' ).attr( 'href', response.url ).text( response.message ) );
$panel.addClass( 'is-subscribed' ).empty().append( $success );
if ( done ) {
done( true );
}
},
error( result ) {
$status.addClass( 'error' ).text( ajaxErrorText( result ) );
$button.prop( 'disabled', false );
if ( done ) {
done( false );
}
},
} );
}
function discoverSubscription( url, nonce, fallbackDisplayName, $target, done ) {
wp.ajax.send( 'friends-preview-subscription', {
data: {
_ajax_nonce: nonce,
url: url,
},
success( response ) {
$target.append( renderSubscriptionCard( response, nonce, fallbackDisplayName ) );
if ( done ) {
done( true );
}
},
error( result ) {
if ( done ) {
done( false, ajaxErrorText( result ) );
} else {
setSubscriptionPreviewError( ajaxErrorText( result ) );
}
},
} );
}
function renderSingleSubscriptionPreview( url ) {
const $preview = $( '#preview-subscription' ).empty();
const $results = $( '' );
$preview.append( $( '' ).text( friendsText( 'text_loading', 'Loading...' ) ) );
$preview.append( $results );
discoverSubscription( url, getSubscriptionNonce(), '', $results, function ( success, message ) {
$preview.find( '.loading' ).remove();
if ( ! success ) {
setSubscriptionPreviewError( message || friendsText( 'text_error', 'An error occurred.' ) );
}
} );
}
function renderBulkPicker( items ) {
const $preview = $( '#preview-subscription' ).empty();
const $controls = $( '' );
$controls.append( $( '' ).text( friendsText( 'text_opml_deselect_all', 'Deselect all' ) ) );
$controls.append( ' ' );
$controls.append( $( '' ).text( friendsText( 'text_review_selected', 'Review selected' ) ) );
$controls.append( ' ' );
$controls.append( $( '' ).text( friendsText( 'text_follow_selected', 'Follow selected' ) ) );
const $list = $( '' );
$.each( items, function ( index, item ) {
const itemId = 'bulk-feed-' + index;
const $checkbox = $( '' )
.attr( 'id', itemId )
.data( item );
const $label = $( '' )
.attr( 'for', itemId )
.append( $checkbox )
.append( ' ' )
.append( document.createTextNode( item.text || item.url ) );
if ( item.htmlUrl ) {
$label.append( ' ' ).append(
$( '' ).append(
$( '' )
.attr( 'href', item.htmlUrl )
.text( item.htmlUrl )
)
);
}
$list.append(
$( '' )
.append( $label )
.append( ' ' )
.append( $( '' ) )
.append( $( '' ) )
);
} );
$preview.append( $controls ).append( $list );
}
function updateBulkFeedRowState( $row ) {
const isChecked = $row.find( '.bulk-feed-cb' ).is( ':checked' );
const hasPreview = !! $row.find( '.bulk-feed-review .subscription-preview' ).length;
const previewIsVisible = ! $row.find( '.bulk-feed-review' ).hasClass( 'hidden' );
const isReviewing = isChecked && hasPreview && previewIsVisible;
$row.toggleClass( 'is-reviewing', isReviewing );
$row.find( '.label-for-bulkfeed, .bulk-feed-status' ).toggleClass( 'hidden', isReviewing );
}
function reviewBulkSubscription( $item, nonce, done ) {
const data = $item.find( '.bulk-feed-cb' ).data();
const $status = $item.find( '.bulk-feed-status' );
const $review = $item.find( '.bulk-feed-review' ).empty();
$status.removeClass( 'error' ).text( friendsText( 'text_discovering', 'Discovering feeds...' ) );
updateBulkFeedRowState( $item );
discoverSubscription( data.url, nonce, data.text, $review, function ( success, message ) {
if ( success ) {
$status.text( friendsText( 'text_ready_to_follow', 'Ready' ) );
} else {
$status.addClass( 'error' ).text( message || friendsText( 'text_error', 'An error occurred.' ) );
}
updateBulkFeedRowState( $item );
done();
} );
}
$document.on( 'submit', '#add-subscription-form', function ( e ) {
e.preventDefault();
const value = $( this ).find( '[name="url"]' ).val();
if ( ! value ) {
return;
}
if ( looksLikeOpml( value ) ) {
const parsedOpml = parseOpmlItems( value );
if ( parsedOpml.error ) {
setSubscriptionPreviewError( parsedOpml.error );
return;
}
renderBulkPicker( parsedOpml.items );
return;
}
const pastedItems = parsePastedPeopleList( value );
if ( pastedItems.length ) {
renderBulkPicker( pastedItems );
return;
}
renderSingleSubscriptionPreview( value.trim() );
} );
$document.on( 'paste', '#subscription-url', function () {
const input = this;
clearTimeout( subscriptionPasteReviewTimer );
subscriptionPasteReviewTimer = setTimeout( function () {
if ( $( input ).val().trim() ) {
$( input ).closest( 'form' ).trigger( 'submit' );
}
}, 25 );
} );
$document.on( 'change', '#opml-file', function () {
const file = this.files && this.files[ 0 ];
if ( ! file ) {
return;
}
const reader = new FileReader();
reader.onload = function ( e ) {
const parsedOpml = parseOpmlItems( e.target.result );
if ( parsedOpml.error ) {
setSubscriptionPreviewError( parsedOpml.error );
return;
}
renderBulkPicker( parsedOpml.items );
};
reader.readAsText( file );
} );
$document.on( 'keyup', '.subscription-display-name', function () {
const $login = $( this ).closest( '.subscription-preview' ).find( '.subscription-user-login' );
if ( this.value && $login.data( 'original' ) === $login.val() ) {
const generatedLogin = generateUserLogin( this.value );
$login.val( generatedLogin );
$login.data( 'original', generatedLogin );
}
} );
$document.on( 'click', '.show-alternate-feeds', function () {
$( this ).closest( '.subscription-preview' ).find( '.rel-alternate' ).toggleClass( 'hidden' );
return false;
} );
$document.on( 'click', '.show-feed-details', function () {
const $this = $( this );
const $details = $this.closest( '.subscription-preview' ).find( '.subscription-feed-details' );
const isHidden = $details.first().hasClass( 'hidden' );
$details.toggleClass( 'hidden', ! isHidden );
$this.text( isHidden ? friendsText( 'text_hide_feed_metadata', 'Hide feed metadata' ) : friendsText( 'text_feed_metadata', 'Display feed metadata' ) );
return false;
} );
$document.on( 'click', '.show-unsupported-feeds', function () {
$( this ).closest( '.subscription-preview' ).find( '.unsupported-feed-list' ).toggleClass( 'hidden' );
return false;
} );
$document.on( 'change', '.subscription-feed-parser', function () {
resetSubscriptionFeedPreview( $( this ).closest( '.subscription-feed-option' ) );
} );
$document.on( 'input change', '.subscription-feed-url', function () {
const $item = $( this ).closest( '.subscription-feed-option' );
const feedUrl = getFeedOptionUrl( $item );
const feed = $.extend( {}, $item.data( 'feed' ) || {} );
feed.url = feedUrl;
$item.data( 'feedUrl', feedUrl ).data( 'feed', feed );
$item.find( '.subscription-feed-title-link' ).attr( 'href', feedUrl || '#' );
$item.find( '.subscription-feed-selected' ).prop( 'checked', !! feedUrl );
resetSubscriptionFeedPreview( $item );
} );
$document.on( 'click', '.add-custom-feed', function () {
const $panel = $( this ).closest( '.subscription-preview' );
let $list = $panel.find( '.custom-feed-list' );
if ( ! $list.length ) {
$list = $( '' );
$list.insertBefore( $panel.find( '.subscription-feed-actions' ) );
}
const feedIndex = $panel.find( '.subscription-feed-option' ).length + 1;
const panelId = $panel.attr( 'id' ) || 'subscription-preview';
const $item = renderSubscriptionFeedOption(
panelId,
feedIndex,
'',
{
title: friendsText( 'text_custom_feed', 'Custom feed' ),
parser: getDefaultParser(),
rel: 'manual',
type: 'custom',
},
{ custom: true }
);
$list.append( $item );
$item.find( '.subscription-feed-url' ).trigger( 'focus' );
return false;
} );
$document.on( 'click', '.subscription-feed-preview-toggle', function () {
previewSubscriptionFeed( $( this ).closest( '.subscription-feed-option' ), $( this ) );
return false;
} );
$document.on( 'click', '.subscribe-btn', function () {
subscribeSubscriptionPanel( $( this ).closest( '.subscription-preview' ), $( this ) );
return false;
} );
$document.on( 'click', '.bulk-toggle-all', function () {
const $this = $( this );
const $checkboxes = $( '.bulk-feed-cb' );
const allChecked = $checkboxes.length === $checkboxes.filter( ':checked' ).length;
$checkboxes.prop( 'checked', ! allChecked ).trigger( 'change' );
$this.text( allChecked ? friendsText( 'text_opml_select_all', 'Select all' ) : friendsText( 'text_opml_deselect_all', 'Deselect all' ) );
return false;
} );
$document.on( 'change', '.bulk-feed-cb', function () {
const $row = $( this ).closest( '.bulk-feed-row' );
$row.find( '.bulk-feed-review' ).toggleClass( 'hidden', ! this.checked );
if ( ! this.checked ) {
$row.find( '.bulk-feed-status' ).text( '' ).removeClass( 'error' );
}
updateBulkFeedRowState( $row );
} );
$document.on( 'click', '.bulk-skip-entry', function () {
const $panel = $( this ).closest( '.subscription-preview' );
const $row = $panel.closest( '.bulk-feed-row' );
if ( $row.length ) {
$row.find( '.bulk-feed-cb' ).prop( 'checked', false ).trigger( 'change' );
} else {
$panel.addClass( 'hidden' );
}
return false;
} );
$document.on( 'click', '.bulk-preview-selected', function () {
const $button = $( this ).prop( 'disabled', true );
const nonce = getSubscriptionNonce();
const queue = [];
$( '.bulk-feed-list > .bulk-feed-row' ).each( function () {
const $item = $( this );
if ( $item.find( '.bulk-feed-cb' ).is( ':checked' ) ) {
queue.push( $item );
}
} );
if ( ! queue.length ) {
alert( friendsText( 'text_opml_no_selected', 'Please select at least one feed.' ) );
$button.prop( 'disabled', false );
return false;
}
let index = 0;
function next() {
if ( index >= queue.length ) {
if ( $( '.bulk-feed-review .subscription-preview .subscribe-btn' ).length ) {
$( '.bulk-follow-selected' ).removeClass( 'hidden' );
}
$button.prop( 'disabled', false );
return;
}
reviewBulkSubscription( queue[ index++ ], nonce, next );
}
next();
return false;
} );
$document.on( 'click', '.bulk-follow-selected', function () {
const $button = $( this ).prop( 'disabled', true );
const queue = [];
$( '.bulk-feed-list > .bulk-feed-row' ).each( function () {
if ( $( this ).find( '.bulk-feed-cb' ).is( ':checked' ) ) {
$( this ).find( '.bulk-feed-review .subscription-preview' ).has( '.subscribe-btn' ).not( '.is-subscribed' ).each( function () {
queue.push( this );
} );
}
} );
let index = 0;
function next() {
if ( index >= queue.length ) {
$button.prop( 'disabled', false );
return;
}
const $panel = $( queue[ index++ ] );
subscribeSubscriptionPanel( $panel, $panel.find( '.subscribe-btn' ), next );
}
next();
return false;
} );
} )( jQuery, window.wp, window.friends );