Skip to content

Pull screen search feature #1256

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

Open
wants to merge 13 commits into
base: develop
Choose a base branch
from
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;
}
138 changes: 124 additions & 14 deletions assets/js/admin-pull.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@

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,15 +17,6 @@
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 ) => {
Expand All @@ -36,7 +29,7 @@
}

if ( searchField && searchBtn ) {
jQuery( searchBtn ).on( 'click', ( event ) => {

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.
event.preventDefault();

const search = searchField.value;
Expand All @@ -48,7 +41,7 @@
}

if ( asDraftCheckboxes && pullLinks ) {
jQuery( asDraftCheckboxes ).on( 'change', ( event ) => {

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.
if ( event.currentTarget.checked ) {
for ( let i = 0; i < asDraftCheckboxes.length; ++i ) {
asDraftCheckboxes[ i ].checked = true;
Expand Down Expand Up @@ -84,10 +77,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 +88,123 @@

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 pullConnectionItems = 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' ); // eslint-disable-line no-undef
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 = pullConnectionItems.find(
( item ) => item.id === connection_id
);

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' );
// Display name and URL in the dropdown item
div.textContent = `${ item.name } (${ item.url })`;
div.setAttribute( 'data-url', item.url );

div.addEventListener( 'click', () => {
// Display name and URL in the input field
input.value = `${ item.name } (${ item.url })`;
// But set only URL as the actual value
input.setAttribute( 'data-url', item.url );
input.setAttribute(
'data-pull-url',
htmlDecode( item.pull_url )
);
document.location = getURL();

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

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

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

function filterItems( searchTerm ) {
const searchTermLower = searchTerm.toLowerCase();
const filteredItems = pullConnectionItems.filter( ( item ) => {
// Search on both name and URL
return (
item.name.toLowerCase().includes( searchTermLower ) ||
item.url.toLowerCase().includes( searchTermLower )
);
} );
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->blogname ),
'url' => untrailingslashit( preg_replace( '#(https?:\/\/|www\.)#i', '', get_site_url( $internal_connection->site->blog_id ) ) ),
'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 );
}
Loading
Loading