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

Pull screen search feature #1256

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 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
71 changes: 71 additions & 0 deletions assets/css/admin-pull-table.scss
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,74 @@
list-style: disc;
padding-left: 20px;
}

.searchable-select {
position: relative;
display: inline-block;
width: 300px;
vertical-align: top;
}

.searchable-select__input-container {
display: flex;
align-items: center;
box-shadow: 0 0 0 transparent;
border-radius: 4px;
border: 1px solid #8c8f94;
background-color: #fff;
color: #2c3338;
cursor: text;
overflow: hidden;
}

.searchable-select__input {
flex-grow: 1;
border: none;
padding: 8px;
outline: none;
border: none !important;
width: 100%;

&:focus {
outline: none;
border: none !important;
box-shadow: none !important;
}
}

.searchable-select__icon {
padding: 8px;
background-color: #f0f0f0;
cursor: pointer;
}

.searchable-select__input-container:focus-within {
border-color: #007bff;
}

.searchable-select__dropdown {
position: absolute;
top: 100%;
left: 0;
right: 0;
border: 1px solid #ccc;
border-top: none;
max-height: 200px;
overflow-y: auto;
background-color: white;
display: none;
font-size: small;
}

.searchable-select__item {
padding: 8px;
cursor: pointer;
}

.searchable-select__item:hover {
background-color: #f0f0f0;
}

.searchable-select__item.selected {
background-color: #e0e0e0;
}
130 changes: 116 additions & 14 deletions assets/js/admin-pull.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
import jQuery from 'jquery';
import { addQueryArgs } from '@wordpress/url';
import { __ } from '@wordpress/i18n';
import _ from 'underscore';

Check failure on line 6 in assets/js/admin-pull.js

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

assets/js/admin-pull.js#L6

[no-unused-vars] '_' is defined but never used.

const { document } = window;

const chooseConnection = document.getElementById( 'pull_connections' );
const chooseConnection = document.getElementsByClassName(
'searchable-select__input'
)[ 0 ];
const choosePostType = document.getElementById( 'pull_post_type' );
const choosePostTypeBtn = document.getElementById( 'pull_post_type_submit' );
const searchField = document.getElementById( 'post-search-input' );
Expand All @@ -15,21 +18,12 @@
const asDraftCheckboxes = document.querySelectorAll( '[name=dt_as_draft]' );
const pullLinks = document.querySelectorAll( '.distributor_page_pull .pull a' );

jQuery( chooseConnection ).on( 'change', ( event ) => {
document.location =
event.currentTarget.options[
event.currentTarget.selectedIndex
].getAttribute( 'data-pull-url' );

document.body.className += ' ' + 'dt-loading';
} );

if ( chooseConnection && choosePostType && form ) {
if ( choosePostTypeBtn ) {
jQuery( choosePostTypeBtn ).on( 'click', ( event ) => {
event.preventDefault();

document.location = getURL();

Check warning

Code scanning / CodeQL

DOM text reinterpreted as HTML Medium

DOM text
is reinterpreted as HTML without escaping meta-characters.
DOM text
is reinterpreted as HTML without escaping meta-characters.

document.body.className += ' ' + 'dt-loading';
} );
Expand All @@ -41,7 +35,7 @@

const search = searchField.value;

document.location = `${ getURL() }&s=${ search }`;

Check warning

Code scanning / CodeQL

DOM text reinterpreted as HTML Medium

DOM text
is reinterpreted as HTML without escaping meta-characters.
DOM text
is reinterpreted as HTML without escaping meta-characters.
DOM text
is reinterpreted as HTML without escaping meta-characters.

document.body.className += ' dt-loading';
} );
Expand Down Expand Up @@ -84,10 +78,7 @@
const getURL = () => {
const postType =
choosePostType.options[ choosePostType.selectedIndex ].value;
const baseURL =
chooseConnection.options[ chooseConnection.selectedIndex ].getAttribute(
'data-pull-url'
);
const baseURL = chooseConnection.getAttribute( 'data-pull-url' );
let status = 'new';

if ( -1 < ` ${ form.className } `.indexOf( ' status-skipped ' ) ) {
Expand All @@ -98,3 +89,114 @@

return `${ baseURL }&pull_post_type=${ postType }&status=${ status }`;
};

document.addEventListener( 'DOMContentLoaded', async function () {
const container = document.querySelector( '.searchable-select' );
const inputContainer = container.querySelector(
'.searchable-select__input-container'
);
const input = container.querySelector( '.searchable-select__input' );
const icon = container.querySelector(
'.searchable-select__input-container > .dashicons-arrow-down'
);
const dropdown = container.querySelector( '.searchable-select__dropdown' );

const itemss = await fetch( '/wp-admin/admin-ajax.php', {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typeo? If it's meant to be searchResults or similar then use the longer name for clarity.

Suggested change
const itemss = await fetch( '/wp-admin/admin-ajax.php', {
const items = await fetch( '/wp-admin/admin-ajax.php', {

method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'action=dt_load_connections_pull',
} )
.then( ( response ) => response.json() )
.then( ( data ) => {
return data.data;
} );

function htmlDecode( inputText ) {
const doc = new DOMParser().parseFromString( inputText, 'text/html' );

Check failure on line 117 in assets/js/admin-pull.js

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

assets/js/admin-pull.js#L117

[no-undef] 'DOMParser' is not defined.
return doc.documentElement.textContent;
}

function setInputDefault() {
const params = new URL( document.location.toString() ).searchParams;
const connection_id = params.get( 'connection_id' );

if ( connection_id ) {
const connection = itemss.find(
( item ) => item.id == connection_id );

Check failure on line 127 in assets/js/admin-pull.js

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

assets/js/admin-pull.js#L127

[eqeqeq] Expected '===' and instead saw '=='.

Check failure on line 127 in assets/js/admin-pull.js

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

assets/js/admin-pull.js#L127

[prettier/prettier] Replace `·` with `⏎↹↹↹`

if ( connection ) {
input.value = connection.name;
input.setAttribute(
'data-pull-url',
htmlDecode( connection.pull_url )
);
}
}
}

setInputDefault();

function createDropdownItems( items ) {
dropdown.innerHTML = '';
items.forEach( ( item ) => {
const div = document.createElement( 'div' );
div.classList.add( 'searchable-select__item' );
div.textContent = item.name;
div.setAttribute( 'data-url', item.url );

div.addEventListener( 'click', () => {
input.value = item.name;
input.setAttribute(
'data-pull-url',
htmlDecode( item.pull_url )
// item.pull_url
);
document.location = getURL();
Dismissed Show dismissed Hide dismissed

hideDropdown();
} );
dropdown.appendChild( div );
} );
}

function showDropdown() {
createDropdownItems( itemss );
dropdown.style.display = 'block';
}

function hideDropdown() {
dropdown.style.display = 'none';
}

function filterItems( searchTerm ) {
const filteredItems = itemss.filter( ( item ) =>
item.toLowerCase().includes( searchTerm.toLowerCase() )
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm getting an error on this line as item is an object:

{
  "id": "2",
  "name": "ms-distributor.local/two",
  "url": "ms-distributor.local/two",
  "pull_url": "http://ms-distributor.local/wp-admin/admin.php?page=pull&#038;connection_type=internal&#038;connection_id=2",
  "type": "internal"
}

);
createDropdownItems( filteredItems );
}

inputContainer.addEventListener( 'click', function () {
input.focus();
showDropdown();
} );

icon.addEventListener( 'click', function ( event ) {
event.stopPropagation();
input.focus();
showDropdown();
} );

input.addEventListener( 'input', function () {
filterItems( this.value );
} );

input.addEventListener( 'focus', showDropdown );

document.addEventListener( 'click', function ( event ) {
if ( ! container.contains( event.target ) ) {
hideDropdown();
}
} );
} );
2 changes: 1 addition & 1 deletion assets/js/push.js
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ jQuery( window ).on( 'load', () => {
distributorPushWrapper.classList.add( 'loaded' );

const data = {
action: 'dt_load_connections',
action: 'dt_load_connections_push',
loadConnectionsNonce: dt.loadConnectionsNonce,
postId: dt.postId,
};
Expand Down
114 changes: 69 additions & 45 deletions includes/pull-ui.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ function setup() {
function() {
add_action( 'admin_menu', __NAMESPACE__ . '\action_admin_menu' );
add_action( 'admin_enqueue_scripts', __NAMESPACE__ . '\admin_enqueue_scripts' );
add_action( 'wp_ajax_dt_load_connections_pull', __NAMESPACE__ . '\get_connections' );
add_action( 'load-distributor_page_pull', __NAMESPACE__ . '\setup_list_table' );
add_filter( 'set-screen-option', __NAMESPACE__ . '\set_screen_option', 10, 3 );
}
Expand Down Expand Up @@ -425,51 +426,14 @@ function dashboard() {
?>
<?php else : ?>
<?php esc_html_e( 'Pull Content from', 'distributor' ); ?>
<select id="pull_connections" name="connection" method="get">
<?php if ( ! empty( $internal_connection_group ) ) : ?>
<?php if ( ! empty( $external_connection_group ) ) : ?>
<optgroup label="<?php esc_attr_e( 'Network Connections', 'distributor' ); ?>">
<?php endif; ?>
<?php
foreach ( $internal_connection_group as $connection ) :
$selected = false;
$type = 'internal';
$name = untrailingslashit( $connection->site->domain . $connection->site->path );
$id = $connection->site->blog_id;

if ( is_a( $connection_now, '\Distributor\InternalConnections\NetworkSiteConnection' ) && (int) $connection_now->site->blog_id === (int) $id ) {
$selected = true;
}
?>
<option <?php selected( true, $selected ); ?> data-pull-url="<?php echo esc_url( admin_url( 'admin.php?page=pull&connection_type=' . $type . '&connection_id=' . $id ) ); ?>"><?php echo esc_html( $name ); ?></option>
<?php endforeach; ?>
<?php if ( ! empty( $external_connection_group ) ) : ?>
</optgroup>
<?php endif; ?>
<?php endif; ?>

<?php if ( ! empty( $external_connection_group ) ) : ?>
<?php if ( ! empty( $internal_connection_group ) ) : ?>
<optgroup label="<?php esc_attr_e( 'External Connections', 'distributor' ); ?>">
<?php endif; ?>
<?php
foreach ( $external_connection_group as $connection ) :
$type = 'external';
$selected = false;
$name = $connection->name;
$id = $connection->id;

if ( is_a( $connection_now, '\Distributor\ExternalConnection' ) && (int) $connection_now->id === (int) $id ) {
$selected = true;
}
?>
<option <?php selected( true, $selected ); ?> data-pull-url="<?php echo esc_url( admin_url( 'admin.php?page=pull&connection_type=' . $type . '&connection_id=' . $id ) ); ?>"><?php echo esc_html( $name ); ?></option>
<?php endforeach; ?>
<?php if ( ! empty( $internal_connection_group ) ) : ?>
</optgroup>
<?php endif; ?>
<?php endif; ?>
</select>
<div class="searchable-select">
<div class="searchable-select__input-container">
<input class="searchable-select__input" type="text" placeholder="Search...">
<span class="dashicons dashicons-arrow-down"></span>
</div>
<div class="searchable-select__dropdown"></div>
</div>


<?php
$connection_now->pull_post_type = '';
Expand Down Expand Up @@ -624,3 +588,63 @@ function output_pull_errors() {

<?php
}

/**
* Get connections for pull
*/
function get_connections() {
$connections = array();

if ( ! empty( \Distributor\Connections::factory()->get_registered()['networkblog'] ) ) {
$sites = \Distributor\InternalConnections\NetworkSiteConnection::get_available_authorized_sites( 'pull' );

foreach ( $sites as $site_array ) {
$internal_connection = new \Distributor\InternalConnections\NetworkSiteConnection( $site_array['site'] );

$connections[] = [
'id' => $internal_connection->site->blog_id,
'name' => untrailingslashit( $internal_connection->site->domain . $internal_connection->site->path ),
'url' => untrailingslashit( preg_replace( '#(https?:\/\/|www\.)#i', '', get_site_url( $internal_connection->site->blog_id ) ) ),
Comment on lines +606 to +607
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little unclear why name and URL are using the same (or at least similar ) values. site->domain . site->path ought to resolved to get_site_url().

Although we don't display the name, it may be helpful to allow people to search by the name, so a search for Make WordPress Core would return make.wordpress.org/core

'pull_url' => esc_url( admin_url( 'admin.php?page=pull&connection_type=internal&connection_id=' . $internal_connection->site->blog_id ) ),
'type' => 'internal',
];
}
}

$external_connections = new \WP_Query(
array(
'post_type' => 'dt_ext_connection',
'fields' => 'ids',
'no_found_rows' => true,
'posts_per_page' => -1,
)
);

foreach ( $external_connections->posts as $external_connection_id ) {
$external_connection_type = get_post_meta( $external_connection_id, 'dt_external_connection_type', true );

if ( empty( \Distributor\Connections::factory()->get_registered()[ $external_connection_type ] ) ) {
continue;
}

$external_connection_status = get_post_meta( $external_connection_id, 'dt_external_connections', true );

if ( empty( $external_connection_status ) || empty( $external_connection_status['can_get'] ) ) {
continue;
}

$external_connection = \Distributor\ExternalConnection::instantiate( $external_connection_id );

if ( ! is_wp_error( $external_connection ) ) {
$connections[] = [
'id' => $external_connection->id,
'name' => $external_connection->name,
'url' => $external_connection->base_url,
'pull_url' => esc_url( admin_url( 'admin.php?page=pull&connection_type=external&connection_id=' . $external_connection->id ) ),
'type' => 'external',
];
}
}

wp_send_json_success( $connections );
}
2 changes: 1 addition & 1 deletion includes/push-ui.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function() {
add_action( 'wp_enqueue_scripts', __NAMESPACE__ . '\enqueue_scripts' );
add_filter( 'amp_dev_mode_element_xpaths', __NAMESPACE__ . '\add_element_xpaths' );
add_filter( 'script_loader_tag', __NAMESPACE__ . '\add_dev_mode_to_assets', 10, 2 );
add_action( 'wp_ajax_dt_load_connections', __NAMESPACE__ . '\get_connections' );
add_action( 'wp_ajax_dt_load_connections_push', __NAMESPACE__ . '\get_connections' );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming this is for clarity from wp_ajax_dt_load_connections_pull?

We're probably stuck with the old name to ensure backward compatibility with the third party extensions and between different versions of the plugin. Otherwise we could go through a soft deprecation.

add_action( 'wp_ajax_dt_push', __NAMESPACE__ . '\ajax_push' );
add_action( 'admin_bar_menu', __NAMESPACE__ . '\menu_button', 999 );
add_action( 'wp_footer', __NAMESPACE__ . '\menu_content', 10, 1 );
Expand Down
Loading