diff --git a/.eslintrc.json b/.eslintrc.json
index 1f13912..32330f8 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -4,7 +4,7 @@
"browser": true
},
"globals": {
- "sclivetickerAjax": "readonly",
+ "scliveticker": "readonly",
"wp": "readonly"
},
"extends": [
diff --git a/includes/class-scliveticker.php b/includes/class-scliveticker.php
index 109e4e7..7ef9e11 100644
--- a/includes/class-scliveticker.php
+++ b/includes/class-scliveticker.php
@@ -205,16 +205,6 @@ class SCLiveticker {
} else {
$show_feed = 1 === self::$options['show_feed'];
}
-
- $output = '
'scliveticker_tick',
'posts_per_page' => $limit,
@@ -229,12 +219,24 @@ class SCLiveticker {
$wp_query = new WP_Query( $args );
+ $ticks = '';
+ $last = null;
while ( $wp_query->have_posts() ) {
$wp_query->the_post();
- $output .= self::tick_html( get_the_time( 'd.m.Y H:i' ), get_the_title(), get_the_content() );
+ $ticks .= self::tick_html( get_the_time( 'd.m.Y H:i' ), get_the_title(), get_the_content() );
+ if ( is_null( $last ) ) {
+ $last = get_post_modified_time( 'Y-m-d\TH:i:s', true );
+ }
}
- $output .= '
';
+ $output = '';
// Show RSS feed link, if configured.
if ( $show_feed ) {
@@ -262,7 +264,7 @@ class SCLiveticker {
if ( self::$shortcode_present || self::$widget_present || self::block_present() ) {
wp_enqueue_script(
'scliveticker-js',
- SCLIVETICKER_BASE . 'scripts/liveticker.min.js',
+ SCLIVETICKER_BASE . 'scripts/liveticker.js',
array(),
self::VERSION,
true
@@ -271,10 +273,11 @@ class SCLiveticker {
// Add endpoint to script.
wp_localize_script(
'scliveticker-js',
- 'sclivetickerAjax',
+ 'scliveticker',
array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'scliveticker_update-ticks' ),
+ 'api' => rest_url(),
'poll_interval' => self::$options['poll_interval'] * 1000,
)
);
@@ -435,9 +438,9 @@ class SCLiveticker {
*/
private static function tick_html( $time, $title, $content, $is_widget = false ) {
return ''
- . '' . esc_html( $time ) . ''
- . '' . esc_html( $title ) . '
'
- . '' . $content . '
';
+ . '' . esc_html( $time ) . ''
+ . '' . esc_html( $title ) . ''
+ . '' . $content . '
';
}
/**
diff --git a/scripts/liveticker.js b/scripts/liveticker.js
index 9f2eebe..629873b 100644
--- a/scripts/liveticker.js
+++ b/scripts/liveticker.js
@@ -4,11 +4,9 @@
* @class
*/
( function() {
- var ajaxURL = sclivetickerAjax.ajax_url;
- var nonce = sclivetickerAjax.nonce;
- var pollInterval = sclivetickerAjax.poll_interval;
+ var apiURL;
+ var pollInterval;
var ticker;
- var widgets;
/**
* Initialize iveticker JS component.
@@ -19,67 +17,42 @@
var updateNow = false;
// Opt out if AJAX pobject not present.
- if ( 'undefined' === typeof sclivetickerAjax ) {
+ if ( 'undefined' === typeof scliveticker ) {
return;
}
- // Extract AJAX settings.
- ajaxURL = sclivetickerAjax.ajax_url;
- nonce = sclivetickerAjax.nonce;
- pollInterval = sclivetickerAjax.poll_interval;
+ // Extract settings.
+ apiURL = scliveticker.api + 'wp/v2/scliveticker_tick';
+ pollInterval = scliveticker.poll_interval;
// Get ticker elements.
ticker = [].map.call(
document.querySelectorAll( 'div.wp-block-scliveticker-ticker.sclt-ajax' ),
function( elem ) {
- var list = elem.querySelector( 'ul' );
- var last = Number( elem.getAttribute( 'data-sclt-last' ) );
-
- if ( ! list ) {
- list = document.createElement( 'ul' );
- elem.appendChild( list );
- }
-
- if ( 0 === last ) {
+ elem = parseElement( elem, false );
+ if ( '0' === elem.lastPoll ) {
updateNow = true;
}
-
- return {
- s: elem.getAttribute( 'data-sclt-ticker' ),
- l: elem.getAttribute( 'data-sclt-limit' ),
- t: last,
- e: list,
- };
+ return elem;
}
);
// Get widget elements.
- widgets = [].map.call(
- document.querySelectorAll( 'div.wp-widget-scliveticker-ticker.sclt-ajax' ),
- function( elem ) {
- var list = elem.querySelector( 'ul' );
- var last = Number( elem.getAttribute( 'data-sclt-last' ) );
-
- if ( ! list ) {
- list = document.createElement( 'ul' );
- elem.appendChild( list );
+ ticker.concat(
+ [].map.call(
+ document.querySelectorAll( 'div.wp-widget-scliveticker-ticker.sclt-ajax' ),
+ function( elem ) {
+ elem = parseElement( elem, true );
+ if ( 0 === elem.lastPoll ) {
+ updateNow = true;
+ }
+ return elem;
}
-
- if ( 0 === last ) {
- updateNow = true;
- }
-
- return {
- w: elem.getAttribute( 'data-sclt-ticker' ),
- l: elem.getAttribute( 'data-sclt-limit' ),
- t: last,
- e: list,
- };
- }
+ )
);
// Trigger update, if necessary.
- if ( ( 0 < ticker.length || widgets.length ) && 0 < pollInterval ) {
+ if ( ( 0 < ticker.length ) && 0 < pollInterval ) {
if ( updateNow ) {
update();
} else {
@@ -89,97 +62,108 @@
};
/**
- * Update liveticker on current page via AJAX call.
+ * Parse an HTML element containing a liveticker.
+ *
+ * @param {HTMLElement} elem The element.
+ * @param {boolean} widget Is the element a widget?
+ * @return {{ticker: string, lastPoll: number, ticks: any, limit: string, isWidget: *}} Ticker descriptor object.
+ */
+ var parseElement = function( elem, widget ) {
+ var list = elem.querySelector( 'ul' );
+ var last = elem.getAttribute( 'data-sclt-last' );
+
+ if ( ! list ) {
+ list = document.createElement( 'ul' );
+ elem.appendChild( list );
+ }
+
+ return {
+ ticker: elem.getAttribute( 'data-sclt-ticker' ),
+ limit: elem.getAttribute( 'data-sclt-limit' ),
+ lastPoll: last,
+ ticks: list,
+ isWidget: widget,
+ };
+ };
+
+ /**
+ * Update liveticker on current page via REST API call.
*
* @return {void}
*/
var update = function() {
- // Extract ticker-slug, limit and timestamp of last poll.
- var updateReq = 'action=sclt_update-ticks&_ajax_nonce=' + nonce;
- var i, j;
- var xhr = new XMLHttpRequest();
-
- for ( i = 0; i < ticker.length; i++ ) {
- updateReq = updateReq +
- '&update[' + i + '][s]=' + ticker[ i ].s +
- '&update[' + i + '][l]=' + ticker[ i ].l +
- '&update[' + i + '][t]=' + ticker[ i ].t;
- }
- for ( j = 0; j < widgets.length; j++ ) {
- updateReq = updateReq +
- '&update[' + ( i + j ) + '][w]=' + widgets[ j ].w +
- '&update[' + ( i + j ) + '][l]=' + widgets[ j ].l +
- '&update[' + ( i + j ) + '][t]=' + widgets[ j ].t;
- }
-
- // Issue AJAX request.
- xhr.open( 'POST', ajaxURL, true );
- xhr.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded;' );
- xhr.onreadystatechange = function() {
- var updateResp;
- if ( XMLHttpRequest.DONE === this.readyState && 200 === this.status ) {
- try {
- updateResp = JSON.parse( this.responseText );
- if ( updateResp ) {
- updateResp.forEach(
- function( u ) {
- ticker.forEach(
- function( t ) {
- if ( t.s === u.s ) {
- t.t = u.t; // Update last poll timestamp.
- updateHTML( t, u ); // Update HTML markup.
- }
- }
- );
- widgets.forEach(
- function( t ) {
- if ( t.w === u.w ) {
- t.t = u.t;
- updateHTML( t, u );
- }
+ // Iterate over available tickers.
+ ticker.forEach(
+ function( t ) {
+ var xhr = new XMLHttpRequest();
+ var query = '?ticker=' + encodeURI( t.ticker ) +
+ '&limit=' + encodeURI( t.limit ) +
+ '&last=' + encodeURI( t.lastPoll );
+ xhr.open( 'GET', apiURL + query, true );
+ xhr.addEventListener(
+ 'load',
+ function() {
+ var updateResp;
+ try {
+ updateResp = JSON.parse( this.responseText );
+ if ( updateResp ) {
+ updateResp.reverse();
+ updateResp.forEach(
+ function( u ) {
+ addTick( t, u );
}
);
}
- );
+ setTimeout( update, pollInterval ); // Re-trigger update.
+ } catch ( e ) {
+ // eslint-disable-next-line no-console
+ console.warn( 'Liveticker AJAX update failed, stopping automatic updates.' );
+ }
}
- setTimeout( update, pollInterval ); // Re-trigger update.
- } catch ( e ) {
- // eslint-disable-next-line no-console
- console.warn( 'Liveticker AJAX update failed, stopping automatic updates.' );
- }
+ );
+ xhr.send();
}
- };
- xhr.send( updateReq );
+ );
};
/**
* Do actual update of HTML code.
*
- * @param {Object} t Ticker or Widget reference.
- * @param {number} t.l Limit of entries to display.
- * @param {HTMLElement} t.e HTML element of the ticker/widget.
- * @param {Object} u Update entity.
- * @param {string} u.h HTML code to append.
- * @param {number} u.t Timetsamp of last update.
+ * @param {Object} t Ticker or Widget reference.
+ * @param {Object} u Update entity.
* @return {void}
*/
- var updateHTML = function( t, u ) {
+ var addTick = function( t, u ) {
// Parse new DOM-part.
- var n = document.createElement( 'ul' );
- n.innerHTML = u.h;
+ var li = document.createElement( 'li' );
+ var time = document.createElement( 'span' );
+ var title = document.createElement( 'span' );
+ var content = document.createElement( 'div' );
+ var cls = t.isWidget ? 'sclt-widget' : 'sclt-tick';
- // Prepend new ticks to container.
- while ( n.hasChildNodes() ) {
- t.e.prepend( n.lastChild );
- }
+ li.classList.add( cls );
+ time.classList.add( cls + '-time' );
+ time.innerText = u.modified_rendered;
+ title.classList.add( cls + '-title' );
+ title.innerText = u.title.rendered;
+ content.classList.add( cls + '-content' );
+ content.innerHTML = u.content.rendered;
+ li.appendChild( time );
+ li.appendChild( title );
+ li.appendChild( content );
- t.e.parentNode.setAttribute( 'data-sclt-last', u.t );
+ // Prepend new tick to container.
+ t.ticks.prepend( li );
+
+ // Update last poll time.
+ t.lastPoll = u.date_gmt;
+ t.ticks.parentNode.setAttribute( 'data-sclt-last', u.date_gmt );
// Remove tail, if limit is set.
- if ( 0 < t.l ) {
- [].slice.call( t.e.getElementsByTagName( 'li' ), t.l ).forEach(
- function( li ) {
- li.remove();
+ if ( 0 < t.limit ) {
+ [].slice.call( t.ticks.getElementsByTagName( 'li' ), t.limit ).forEach(
+ function( l ) {
+ l.remove();
}
);
}