diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..82c5d44 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,24 @@ +{ + "curly" : true, + "eqeqeq" : true, + "immed" : true, + "latedef" : true, + "newcap" : true, + "noarg" : true, + "sub" : true, + "undef" : true, + "boss" : true, + "eqnull" : true, + "node" : true, + "es5" : false, + "globals" : { + "it" : false, + "xit" : false, + "describe" : false, + "xdescribe" : false, + "beforeEach" : false, + "afterEach" : false, + "expect" : false, + "spyOn" : false + } +} \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index 32d98cd..62eacdd 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -32,13 +32,15 @@ module.exports = function(grunt) { require('load-grunt-tasks')(grunt); // There are basically three phases of building the production theme: + // 0) Testing / linting + grunt.registerTask('test', ['jshint']); // 1) Javascript preparation (concatenating and uglifying scripts) - // (coming soon) + grunt.registerTask('javascript', ['uglify']); // 2) Stylesheet preparation (SASS, autoprefixing, and minification) // (coming soon) // 3) Appending the most recent git commit to the theme version grunt.registerTask('release', ['gitinfo', 'replace']); // The default task performs all three phases. - grunt.registerTask('default', ['release']); + grunt.registerTask('default', ['test', 'javascript', 'release']); }; diff --git a/author.php b/author.php index 2b746a8..6ec373c 100644 --- a/author.php +++ b/author.php @@ -6,16 +6,17 @@ * @since Twenty Twelve 1.0 */ -get_header(); ?> +get_header(); - +get_template_part( 'inc/sub-header' ); +?> +
-
+ - -
-
+
+
' . get_the_author( '', false ) . '' ); ?> - - - - - ">
- /* - If a user has filled out their description, show a bio on their entries. - - if ( get_the_author_meta( 'description' ) ) : ?> -
-
- -
-
-

-

-
-
- - - -
+
+
- - - - - - -
-
post_type ) { the_field( 'external_link' ); -} else { echo get_post_permalink();} ?>"'> - - - - - - <?php the_title();?> - - - - post_type ) { ?> -

- -

- -

- -

- - - - - - + - - - - -
- -
"; - echo "
 Bibliotech"; - } else { - $category = get_the_category(); - $rCat = count( $category ); - $r = rand( 0, $rCat -1 ); - echo '' . $category[ $r ]->cat_name . ''; - } ?> - - -
-
-
- -
- - - - - - - -
+ - - - -
-
- +
diff --git a/functions.php b/functions.php index 464b1bb..023a134 100644 --- a/functions.php +++ b/functions.php @@ -32,11 +32,12 @@ function add_styles() { add_action( 'wp_enqueue_scripts', 'add_styles' ); /** - * Add LazyLoad and MyScripts for all users + * Add LazyLoad and MITLibNews for all users */ function add_scripts() { - wp_enqueue_script( 'lazyload', get_stylesheet_directory_uri() . '/js/lazyload.js', array( 'jquery' ), '', true ); - wp_enqueue_script( 'myScripts', get_stylesheet_directory_uri() . '/js/myScripts.js', array( 'lazyload' ), '', true ); + wp_enqueue_script( 'lazyload', get_stylesheet_directory_uri() . '/js/build/jquery.lazyload.min.js', array( 'jquery' ), '', true ); + wp_enqueue_script( 'mitlibnews-more', get_stylesheet_directory_uri() . '/js/build/mitlibnews-more.min.js', array( 'jquery', 'jquery-ui-datepicker' ), '', true ); + wp_enqueue_script( 'mitlibnews', get_stylesheet_directory_uri() . '/js/build/mitlibnews.min.js', array( 'lazyload', 'mitlibnews-more' ), '', true ); } add_action( 'wp_enqueue_scripts', 'add_scripts' ); diff --git a/inc/more-posts.php b/inc/more-posts.php index bf49fcf..a218486 100644 --- a/inc/more-posts.php +++ b/inc/more-posts.php @@ -10,8 +10,7 @@
-
- - +
+
diff --git a/index.php b/index.php index 535a6b0..f128232 100644 --- a/index.php +++ b/index.php @@ -89,7 +89,7 @@
-
+
settings.failure_limit){return false;}}});} -if(options){if(undefined!==options.failurelimit){options.failure_limit=options.failurelimit;delete options.failurelimit;} -if(undefined!==options.effectspeed){options.effect_speed=options.effectspeed;delete options.effectspeed;} -$.extend(settings,options);} -$container=(settings.container===undefined||settings.container===window)?$window:$(settings.container);if(0===settings.event.indexOf("scroll")){$container.bind(settings.event,function(){return update();});} -this.each(function(){var self=this;var $self=$(self);self.loaded=false;if($self.attr("src")===undefined||$self.attr("src")===false){if($self.is("img")){$self.attr("src",settings.placeholder);}} -$self.one("appear",function(){if(!this.loaded){if(settings.appear){var elements_left=elements.length;settings.appear.call(self,elements_left,settings);} -$("").bind("load",function(){var original=$self.attr("data-"+settings.data_attribute);$self.hide();if($self.is("img")){$self.attr("src",original);}else{$self.css("background-image","url('"+original+"')");} -$self[settings.effect](settings.effect_speed);self.loaded=true;var temp=$.grep(elements,function(element){return!element.loaded;});elements=$(temp);if(settings.load){var elements_left=elements.length;settings.load.call(self,elements_left,settings);}}).attr("src",$self.attr("data-"+settings.data_attribute));}});if(0!==settings.event.indexOf("scroll")){$self.bind(settings.event,function(){if(!self.loaded){$self.trigger("appear");}});}});$window.bind("resize",function(){update();});if((/(?:iphone|ipod|ipad).*os 5/gi).test(navigator.appVersion)){$window.bind("pageshow",function(event){if(event.originalEvent&&event.originalEvent.persisted){elements.each(function(){$(this).trigger("appear");});}});} -$(document).ready(function(){update();});return this;};$.belowthefold=function(element,settings){var fold;if(settings.container===undefined||settings.container===window){fold=(window.innerHeight?window.innerHeight:$window.height())+$window.scrollTop();}else{fold=$(settings.container).offset().top+$(settings.container).height();} -return fold<=$(element).offset().top-settings.threshold;};$.rightoffold=function(element,settings){var fold;if(settings.container===undefined||settings.container===window){fold=$window.width()+$window.scrollLeft();}else{fold=$(settings.container).offset().left+$(settings.container).width();} -return fold<=$(element).offset().left-settings.threshold;};$.abovethetop=function(element,settings){var fold;if(settings.container===undefined||settings.container===window){fold=$window.scrollTop();}else{fold=$(settings.container).offset().top;} -return fold>=$(element).offset().top+settings.threshold+$(element).height();};$.leftofbegin=function(element,settings){var fold;if(settings.container===undefined||settings.container===window){fold=$window.scrollLeft();}else{fold=$(settings.container).offset().left;} -return fold>=$(element).offset().left+settings.threshold+$(element).width();};$.inviewport=function(element,settings){return!$.rightoffold(element,settings)&&!$.leftofbegin(element,settings)&&!$.belowthefold(element,settings)&&!$.abovethetop(element,settings);};$.extend($.expr[":"],{"below-the-fold":function(a){return $.belowthefold(a,{threshold:0});},"above-the-top":function(a){return!$.belowthefold(a,{threshold:0});},"right-of-screen":function(a){return $.rightoffold(a,{threshold:0});},"left-of-screen":function(a){return!$.rightoffold(a,{threshold:0});},"in-viewport":function(a){return $.inviewport(a,{threshold:0});},"above-the-fold":function(a){return!$.belowthefold(a,{threshold:0});},"right-of-fold":function(a){return $.rightoffold(a,{threshold:0});},"left-of-fold":function(a){return!$.rightoffold(a,{threshold:0});}});})(jQuery,window,document); \ No newline at end of file diff --git a/js/mitlibnews-more.js b/js/mitlibnews-more.js new file mode 100644 index 0000000..0546fc1 --- /dev/null +++ b/js/mitlibnews-more.js @@ -0,0 +1,374 @@ +/*! + * Additional Posts Loader + * + * This is called by markup at the bottom of certain page templates. It then + * polls the WP JSON API for more news stories, and transforms the returned + * JSON objects into rendered HTML. + * + */ + +var window, document, jQuery; + +window.mitlibnews = window.mitlibnews || {}; + +window.mitlibnews.loader = { + + /** + * Properties + */ + container : '', + offset: 0, + page: 1, + postcontent: '', + + /** + * Initialize + */ + initialize : function() { + console.log('MIT Libraries News Loader initializing...'); + // Identify container that will receive post cards. + this.container = document.getElementById('mitlibnews-container'); + // The type of query is identified by data attribute on the container. + this.setPostcontent(); + console.log('Initialization complete.'); + }, + + /** + * Simple Post Loader + */ + loadPosts : function(posts_per_page) { + console.log('Loading ' + posts_per_page + ' posts'); + console.log('Query: '); + var query = this.buildQuery(posts_per_page); + console.log(query); + jQuery.ajax({ + url: '/news/wp-json/posts', + data: query, + dataType: 'json', + type: 'GET', + success: function(data) { + console.log(posts_per_page + ' posts requested'); + console.log(data.length + ' posts received'); + if ( data.length < posts_per_page) { + window.mitlibnews.loader.hideMore(); + } + // identify targeted container + var target = window.mitlibnews.loader.getContainer(); + jQuery.each(data, function( index, value ) { + jQuery(target).append( window.mitlibnews.loader.renderCard(value) ); + }); + window.mitlibnews.loader.setPage( window.mitlibnews.loader.getPage() + 1); + console.log('New page: '); + console.log(window.mitlibnews.loader.getPage()); + + }, + error: function() { + console.log("Error"); + } + }); + console.log(''); + }, + + /** + * Load More - Archive + */ + loadArchive : function() { + console.log('Loading Archive posts...'); + jQuery.ajax({ + url: '/news/wp-json/posts', + data: { + filter: { + 'posts_per_page': 9, + 'offset': 10, + } + }, + dataType: 'json', + type: 'GET', + success: function(data) { + console.log(data); + }, + error: function() { + console.log("Error"); + } + }); + }, + + /** + * Build query + * + * This builds the data object used to query the JSON API. + */ + buildQuery : function(posts_per_page) { + var query = {}; + var filter = { + 'posts_per_page': posts_per_page, + }; + // If author mode, add that filter + if ( this.postcontent === 'author' ) { + filter.author = this.container.dataset.postauthor; + } else if ( 'bibliotech' === this.postcontent ) { + query.type = 'bibliotech'; + } + query.filter = filter; + query.page = this.page; + return query; + }, + + /** + * Card Renderer + * + * This takes a JSON object representing a post, and returns relevant markup + */ + renderCard : function(post) { + // Main card containers + var card, cardBody, cardContainer, cardFooter; + // Card content elements + var cardTitle, cardLink, cardExcerpt, cardCategory, cardDate, cardDateContainer, cardDateValue, cardImage, cardIcon; + var cardEventContainer, cardEventDate, cardEventTime, cardEventDateValue, cardEventTimeValue; + // Bibliotech-specific containers + var cardBibliotechIcon, cardBibliotechInner, cardBibliotechLink; + // Random number + var cardRandomIndex; + console.log(post); + + // Card outer element + card = document.createElement( 'div' ); + // TODO: Is this string of classes standard? + jQuery(card).addClass( 'no-padding-left-mobile col-xs-12 col-xs-B-6 col-sm-6 col-md-4 col-lg-4' ); + + // Card inner element + cardBody = document.createElement( 'div' ); + // TODO: Is this string of classes standard? + jQuery(cardBody).addClass( 'flex-item blueTop eventsBox' ); + // TODO: need an onClick attribute? + + // interiorCardContainer + cardContainer = document.createElement( 'div' ); + jQuery(cardContainer).addClass( 'interiorCardContainer' ); + + // Card image + if ( post.meta.listImg ) { + // Image has been declared + jQuery(cardBody).addClass( 'has-image' ); + cardImage = document.createElement( 'img' ); + jQuery(cardImage) + .attr( 'src', post.meta.listImg) + .attr( 'width', '100%' ) + .attr( 'height', '111' ) + .attr( 'alt', post.title ) + .addClass('img-responsive'); + } else { + // No image + jQuery(cardBody).addClass( 'no-image' ); + } + + // Card icon + + // Card title + // There are different classes for spotlights and other cards + cardTitle = document.createElement( 'h2' ); + jQuery(cardTitle).addClass( 'entry-title title-post' ); + if ( 'spotlights' === post.type ) { + jQuery(cardTitle).addClass( 'spotlights' ); + } else { + jQuery(cardTitle).addClass( 'classCheck' ); + } + + // Card link + // This is a custom field for spotlight cards, but a post URL otherwise + cardLink = document.createElement( 'a' ); + if ( 'spotlight' === post.type ) { + // Spotlights link to a custom field + jQuery(cardLink).attr( 'href', post.meta.external_link ); + } else { + jQuery(cardLink).attr( 'href', post.link ); + } + jQuery(cardLink).html( post.title ); + + // Card event + if ( post.meta.event_date ) { + // The event_date field is stored as YYYYMMDD, which is not a format that js Date objects can parse + // So we do this ourselves, remembering that month is zero-based. + cardEventDateValue = new Date( + post.meta.event_date.substring(0,4), + post.meta.event_date.substring(4,6) - 1, + post.meta.event_date.substring(6,8) + ); + // Event container + cardEventContainer = document.createElement( 'div' ); + jQuery(cardEventContainer) + .addClass( 'events classCheck' ) + .html( '' ); + // Event date + cardEventDate = document.createElement( 'span' ); + jQuery(cardEventDate) + .addClass( 'event' ) + .append( document.createTextNode( jQuery.datepicker.formatDate('MM d, yy', new Date( cardEventDateValue ) ) ) ); + // Event time + cardEventTimeValue = ''; + if ( post.meta.event_start_time ) { + cardEventTimeValue += post.meta.event_start_time; + } + if ( post.meta.event_start_time && post.meta.event_end_time ) { + cardEventTimeValue += ' - '; + } + if ( post.meta.event_end_time ) { + cardEventTimeValue += post.meta.event_end_time; + } + cardEventTime = document.createElement( 'span' ); + jQuery(cardEventTime) + .addClass( 'time' ) + .html( cardEventTimeValue ); + } + + // Card excerpt + cardExcerpt = document.createElement( 'div' ); + jQuery(cardExcerpt) + .addClass( 'excerpt-post classCheck' ) + .html( post.excerpt ); + + // Card footer + cardFooter = document.createElement( 'div' ); + jQuery(cardFooter).addClass( 'category-post' ); + + // Card Bibliotech footer + if ( 'bibliotech' === post.type ) { + // Bibliotech icon + cardBibliotechIcon = document.createElement( 'div' ); + // TODO: spelling error + jQuery(cardBibliotechIcon).addClass( 'bilbioImg bilbioTechIcon' ); + + // Bibliotech inner element + cardBibliotechInner = document.createElement( 'div' ); + jQuery(cardBibliotechInner) + .addClass( 'biblioPadding' ) + .append( document.createTextNode( '\u00A0' ) ); + + // Bibliotech link + cardBibliotechLink = document.createElement( 'a' ); + jQuery(cardBibliotechLink) + .attr( 'href', '/news/bibliotech-index/' ) + .attr( 'title', 'Bibliotech' ) + .append( document.createTextNode( 'Bibliotech' ) ); + } + + // Card category link + cardCategory = document.createElement( 'a' ); + // Pick a random category + cardRandomIndex = Math.floor( Math.random() * post.terms.category.length ); + jQuery(cardCategory) + .attr( 'title', post.terms.category[cardRandomIndex].name ) + .attr( 'href', post.terms.category[cardRandomIndex].link ) + .html( post.terms.category[cardRandomIndex].name ); + + // Card date container + cardDateContainer = document.createElement( 'span' ); + jQuery(cardDateContainer).addClass( 'mitDate' ); + // Card time + cardDateValue = jQuery.datepicker.formatDate('MM d, yy', new Date( post.modified ) ); + cardDate = document.createElement( 'time' ); + jQuery(cardDate) + .addClass( 'updated' ) + .attr( 'datetime', cardDateValue ) + .append( document.createTextNode( cardDateValue ) ); + + // Assemble pieces + jQuery(card).append( cardBody ); + jQuery(cardBody).append( cardContainer ); + jQuery(cardBody).append( cardFooter ); + if ( post.meta.listImg ) { + jQuery(cardContainer).append( cardImage ); + } + jQuery(cardContainer).append( cardTitle ); + if ( post.meta.event_date ) { + jQuery(cardContainer).append( cardEventContainer ); + jQuery(cardEventContainer).append( cardEventDate ); + jQuery(cardEventContainer).append( cardEventTime ); + } + jQuery(cardContainer).append( cardExcerpt ); + jQuery(cardTitle).append( cardLink ); + // If bibliotech, append specific footer + if ( 'bibliotech' === post.type ) { + jQuery(cardFooter).addClass( 'Bibliotech' ); + jQuery(cardFooter).append( cardBibliotechIcon ); + jQuery(cardFooter).append( cardBibliotechInner ); + jQuery(cardBibliotechInner).append( cardBibliotechLink ); + } else { + jQuery(cardFooter).append( cardCategory ); + jQuery(cardFooter).append( cardDateContainer ); + jQuery(cardDateContainer).append( cardDate ); + + } + + return card; + }, + + /** + * Hide "Show more" button + */ + hideMore : function() { + jQuery("#mitlibnews-another").remove(); + }, + + /** + * Get Container + */ + getContainer : function() { + return document.getElementById('mitlibnews-container'); + }, + + /** + * Get Offset + */ + getOffset : function() { + console.log("Retrieving offset value of " + this.offset); + return this.offset; + }, + + /** + * Get Page + */ + getPage : function() { + return this.page; + }, + + /** + * Get Container + */ + getPostcontent : function() { + return this.postcontent; + }, + + /** + * Set Offset + */ + setOffset : function(value) { + console.log("Replacing offset value of " + this.offset + " with " + value); + this.offset = value; + return this.getOffset(); + }, + + /** + * Set Page + */ + setPage : function(value) { + console.log("Replacing page value of " + this.page + " with " + value); + this.page = value; + }, + + /** + * Set Post Content + */ + setPostcontent : function(value) { + // The default value is 'all'. + this.postcontent = 'all'; + // If everything is not set, just use the default. + if ( !this.container || !this.container.dataset || !this.container.dataset.postcontent ) { + console.log( 'Post content attribute not found! Using default value.' ); + return true; + } + // If we're still here, use the real value. + this.postcontent = this.container.dataset.postcontent; + return true; + } +}; diff --git a/js/mitlibnews.js b/js/mitlibnews.js new file mode 100644 index 0000000..8da7988 --- /dev/null +++ b/js/mitlibnews.js @@ -0,0 +1,27 @@ +var window, jQuery, APloader; + +(function($) { + + //lazy loading + $("img.img-responsive").lazyload({ + effect : "fadeIn", + effectspeed: 450 , + failure_limit: 999999 + }); + + //category force selection of all news + $('input:checkbox[id=in-category-43]').attr('checked',true); + + // Additional Posts loader + APloader = window.mitlibnews.loader; + // TODO: is initialization necessary? + APloader.initialize(); + // TODO: add parameters for what type of load, and offset/posts_per_page + APloader.loadPosts(9); + + $("#mitlibnews-another").click(function() { + // TODO: read data attribute in 'show more' markup that determines what type of 'more' to show + APloader.loadPosts(9); + }); + +})(jQuery); diff --git a/js/myScripts.js b/js/myScripts.js deleted file mode 100644 index 7d5ed16..0000000 --- a/js/myScripts.js +++ /dev/null @@ -1,35 +0,0 @@ - - -(function($) { - - //lazy loading - $("img.img-responsive").lazyload({ - effect : "fadeIn", - effectspeed: 450 , - failure_limit: 999999 - }); - - //category force selection of all news - $('input:checkbox[id=in-category-43]').attr('checked',true); - -})(jQuery); - - - - - - - - - - - - - - - - - - - - diff --git a/package.json b/package.json index f86127d..41b63a9 100644 --- a/package.json +++ b/package.json @@ -22,10 +22,13 @@ "devDependencies": { "glob": "^7.0.5", "grunt": "^1.0.1", + "grunt-contrib-jshint": "^1.0.0", + "grunt-contrib-uglify": "^2.0.0", "grunt-gitinfo": "^0.1.8", "grunt-replace": "^1.0.1" }, "dependencies": { + "jquery-lazyload": "^1.9.7", "load-grunt-tasks": "^3.5.0" } } diff --git a/tasks/options/jshint.js b/tasks/options/jshint.js new file mode 100644 index 0000000..d098c68 --- /dev/null +++ b/tasks/options/jshint.js @@ -0,0 +1,10 @@ +module.exports = { + all: [ + 'Gruntfile.js', + 'js/mitlibnews.js', + 'js/mitlibnews-more.js' + ], + options: { + jshintrc: '.jshintrc' + } +} diff --git a/tasks/options/uglify.js b/tasks/options/uglify.js new file mode 100644 index 0000000..9c432a1 --- /dev/null +++ b/tasks/options/uglify.js @@ -0,0 +1,14 @@ +module.exports = { + build: { + src: 'js/mitlibnews.js', + dest: 'js/build/mitlibnews.min.js' + }, + loadMore: { + src: 'js/mitlibnews-more.js', + dest: 'js/build/mitlibnews-more.min.js' + }, + lazyLoad: { + src: 'node_modules/jquery-lazyload/jquery.lazyload.js', + dest: 'js/build/jquery.lazyload.min.js' + } +} \ No newline at end of file