Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Boosting any URL and improve search field #287

Merged
merged 7 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions feed-parsers/class-feed-parser-activitypub.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,15 @@ public function __construct( Feed $friends_feed ) {
\add_action( 'trashed_comment', array( $this, 'trashed_comment' ), 10, 2 );

\add_filter( 'friends_reblog_button_label', array( $this, 'friends_reblog_button_label' ), 10, 2 );
\add_filter( 'friends_search_autocomplete', array( $this, 'friends_search_autocomplete' ), 10, 2 );
\add_action( 'friends_after_header', array( $this, 'frontend_reply_form' ) );
\add_action( 'friends_after_header', array( $this, 'frontend_boost_form' ) );
\add_action( 'wp_ajax_friends-in-reply-to-preview', array( $this, 'ajax_in_reply_to_preview' ) );

\add_filter( 'friends_reblog', array( $this, 'unqueue_activitypub_create' ), 9 );
\add_action( 'mastodon_api_reblog', array( $this, 'mastodon_api_reblog' ) );
\add_action( 'mastodon_api_unreblog', array( $this, 'mastodon_api_unreblog' ) );
\add_filter( 'friends_activitypub_announce_any_url', array( $this, 'queue_announce' ) );
\add_filter( 'friends_reblog', array( $this, 'reblog' ), 20, 2 );
\add_filter( 'friends_unreblog', array( $this, 'unreblog' ), 20, 2 );
\add_filter( 'friends_reblog', array( $this, 'maybe_unqueue_friends_reblog_post' ), 9, 2 );
Expand Down Expand Up @@ -1534,6 +1539,139 @@ public function friends_reblog_button_label( $button_label ) {
return $button_label;
}


/**
* Get metadata for in_reply_to_preview.
*
* @param string $url The url.
*
* @return array|WP_Error The in reply to metadata.
*/
public function get_activitypub_ajax_metadata( $url ) {
$meta = apply_filters( 'friends_get_activitypub_metadata', array(), $url );
if ( is_wp_error( $meta ) ) {
return $meta;
}

if ( ! $meta || ! isset( $meta['attributedTo'] ) ) {
return new \WP_Error( 'no-activitypub', 'No ActivityPub metadata found.' );
}

$html = force_balance_tags( wp_kses_post( $meta['content'] ) );

$webfinger = apply_filters( 'friends_get_activitypub_metadata', array(), $meta['attributedTo'] );
$mention = '';
if ( $webfinger && ! is_wp_error( $webfinger ) ) {
$mention = '@' . $webfinger['preferredUsername'] . '@' . parse_url( $url, PHP_URL_HOST );
}

return array(
'url' => $url,
'html' => $html,
'author' => $meta['attributedTo'],
'mention' => $mention,
);
}

/**
* The Ajax function to fill the in-reply-to-preview.
*/
public function ajax_in_reply_to_preview() {
$url = wp_unslash( $_POST['url'] );

if ( ! wp_parse_url( $url ) ) {
wp_send_json_error();
exit;
}

$meta = $this->get_activitypub_ajax_metadata( $_POST['url'] );

if ( is_wp_error( $meta ) ) {
wp_send_json_error( $meta->get_error_message() );
exit;
}
wp_send_json_success( $meta );
}

public function frontend_reply_form( $args ) {
if ( isset( $_GET['in_reply_to'] ) && wp_parse_url( $_GET['in_reply_to'] ) ) {
$args['in_reply_to'] = $this->get_activitypub_ajax_metadata( $_GET['in_reply_to'] );
$args['in_reply_to']['html'] = '<figcaption>' . make_clickable( $_GET['in_reply_to'] ) . '</figcaption><blockquote>' . $args['in_reply_to']['html'] . '</blockquote>';
$args['form_class'] = 'open';
Friends::template_loader()->get_template_part( 'frontend/activitypub/reply', true, $args );
}
}

public function frontend_boost_form( $args ) {
if ( isset( $_GET['boost'] ) && wp_parse_url( $_GET['boost'] ) ) {
$args['boost'] = $this->get_activitypub_ajax_metadata( $_GET['boost'] );
$args['boost']['html'] = '<figcaption>' . make_clickable( $_GET['boost'] ) . '</figcaption><blockquote>' . $args['boost']['html'] . '</blockquote>';
$args['form_class'] = 'open';
Friends::template_loader()->get_template_part( 'frontend/activitypub/boost', true, $args );
}
}

public function friends_search_autocomplete( $results, $q ) {
function url_truncate( $url, $max_length = 30 ) {
$p = wp_parse_url( $url );
$parts = array( $p['host'] );
if ( trim( $p['path'] ) ) {
$parts = array_merge( $parts, explode( '/', $p['path'] ) );
}

$url = join( '/', $parts );
$reduce = 4;
while ( strlen( $url ) > $max_length ) {
$last_part = array_pop( $parts );
$last_part = substr( $last_part, strlen( $last_part ) - $reduce );
foreach ( $parts as $k => $part ) {
$parts[ $k ] = substr( $part, 0, strlen( $part ) - $reduce );
}
$url = join( '../', array_filter( $parts ) ) . '../..' . $last_part;
array_push( $parts, $last_part );
$reduce = 1;

}

return $url;
}

$url = preg_match( '#^(?:https?:\/\/)?(?:w{3}\.)?[\w-]+(?:\.[\w-]+)+((?:\/[^\s\/]*)*)#i', $q, $m );
$url_with_path = isset( $m[1] ) && $m[1];

if ( ( $url && ! $url_with_path ) || preg_match( '/^@?' . self::ACTIVITYPUB_USERNAME_REGEXP . '$/i', $q ) ) {
$result = '<a href="' . esc_url( admin_url( 'admin.php?page=add-friend&url=' . urlencode( $q ) ) ) . '" class="has-icon-left">';
$result .= '<span class="ab-icon dashicons dashicons-users"></span>';
$result .= 'Follow ';
$result .= ' <small>';
$result .= esc_html( $q );
$result .= '</small></a>';
$results[] = $result;
}

if ( $url_with_path ) {
$result = '<a href="' . esc_url( home_url( '/friends/type/status/?boost=' . urlencode( $q ) ) ) . '" class="has-icon-left">';
$result .= '<span class="ab-icon dashicons dashicons-controls-repeat"></span>';
$result .= 'Boost ';
$result .= ' <small>';
$result .= esc_html( url_truncate( $q ) );
$result .= '</small></a>';
$results[] = $result;
}

if ( $url_with_path ) {
$result = '<a href="' . esc_url( home_url( '/friends/type/status/?in_reply_to=' . urlencode( $q ) ) ) . '" class="has-icon-left">';
$result .= '<span class="ab-icon dashicons dashicons-admin-comments"></span>';
$result .= 'Reply to ';
$result .= ' <small>';
$result .= esc_html( url_truncate( $q ) );
$result .= '</small></a>';
$results[] = $result;
}

return $results;
}

public function mastodon_api_react( $post_id, $reaction ) {
apply_filters( 'friends_react', null, $post_id, $reaction );
}
Expand Down Expand Up @@ -1638,6 +1776,7 @@ public function activitypub_announce( $url, $user_id ) {
$activity->set_type( 'Announce' );
$activity->set_actor( $actor );
$activity->set_object( $url );
$activity->set_id( $actor . '#activitypub_announce-' . \preg_replace( '~^https?://~', '', $url ) );

$follower_inboxes = \Activitypub\Collection\Followers::get_inboxes( $user_id );
$mentioned_inboxes = \Activitypub\Mention::get_inboxes( $activity->get_cc() );
Expand Down
2 changes: 1 addition & 1 deletion friends.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion friends.css.map

Large diffs are not rendered by default.

39 changes: 30 additions & 9 deletions friends.js
Original file line number Diff line number Diff line change
Expand Up @@ -513,28 +513,42 @@
}

function insertTextInGutenberg( text ) {
const element = jQuery( '.is-root-container p' )[ 0 ];
const len = element.textContent.length;
element.focus();
window.getSelection().collapse( element.firstChild, len );
document.execCommand( 'insertText', false, 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', '#in_reply_to_preview a', function () {
$document.on( 'click', '.activitypub_preview a', function () {
if ( ! $( this ).hasClass( 'mention' ) ) {
return true;
}
insertTextInGutenberg( getAcct( $( this ).attr( 'href' ) ) );
return false;
} );

$document.on( 'keyup', 'input#friends_in_reply_to', function () {
$document.on( 'keyup', 'input.activitypub_preview_url', function () {
const input = $( this );
const form = input.closest( 'form' );
const preview = form.find( '.activitypub_preview' );
const url = input.val().trim();

if ( alreadySearching === url ) {
return;
}

preview.html( '<figcaption><a href=""></a></figcaption><blockquote>' );
preview.find( 'blockquote' ).text( friends.text_checking_url );
preview.find( 'a' ).attr( 'href', url ).text( url );
form.find( '.boost-link' ).attr( 'href', '?boost=' + escape( url ) );
form.find( '.reply-to-link' ).attr( 'href', '?in_reply_to=' + escape( url ) );

const searchIndicator = input
.closest( '.form-autocomplete-input' )
.find( '.form-icon' );
Expand All @@ -550,12 +564,19 @@
success( results ) {
searchIndicator.removeClass( 'loading' );
if ( results ) {
$( '#in_reply_to_preview' ).html( results.html ).show();
preview.find( 'blockquote' ).html( results.html ).show();
input.closest( 'form' ).find( 'button' ).prop( 'disabled', false );
insertTextInGutenberg( getAcct( results.author ) );
} else {
$( '#in_reply_to_preview' ).hide();
preview.hide();
input.closest( 'form' ).find( 'button' ).prop( 'disabled', false );
}
},
error( results ) {
searchIndicator.removeClass( 'loading' );
input.closest( 'form' ).find( 'button' ).prop( 'disabled', true );
preview.find( 'blockquote' ).text( results ).show();
},
} );
} );

Expand Down
13 changes: 13 additions & 0 deletions friends.scss
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,19 @@ h2#page-title a.dashicons {
font-color: $dark-color;
font-size: .6rem;
}

.activitypub_preview {
background-color: #f7f8f9;
padding: .5em;
margin-top: 1em;
margin-bottom: 1em;
figcaption {
float: right;
a:any-link {
color: #999;
}
}
}
}

img.avatar {
Expand Down
Loading
Loading