summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/jetpack/modules/tiled-gallery')
-rw-r--r--plugins/jetpack/modules/tiled-gallery/math/class-constrained-array-rounding.php75
-rw-r--r--plugins/jetpack/modules/tiled-gallery/tiled-gallery.php588
-rw-r--r--plugins/jetpack/modules/tiled-gallery/tiled-gallery/rtl/tiled-gallery-rtl.css88
-rw-r--r--plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery.css85
-rw-r--r--plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery.js150
5 files changed, 986 insertions, 0 deletions
diff --git a/plugins/jetpack/modules/tiled-gallery/math/class-constrained-array-rounding.php b/plugins/jetpack/modules/tiled-gallery/math/class-constrained-array-rounding.php
new file mode 100644
index 00000000..dab5fd27
--- /dev/null
+++ b/plugins/jetpack/modules/tiled-gallery/math/class-constrained-array-rounding.php
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * Lets you round the numeric elements of an array to integers while preserving their sum.
+ *
+ * Usage:
+ *
+ * Jetpack_Constrained_Array_Rounding::get_rounded_constrained_array( $bound_array )
+ * if a specific sum doesn't need to be specified for the bound array
+ *
+ * Jetpack_Constrained_Array_Rounding::get_rounded_constrained_array( $bound_array, $sum )
+ * If the sum of $bound_array must equal $sum after rounding.
+ *
+ * If $sum is less than the sum of the floor of the elements of the array, the class defaults to using the sum of the array elements.
+ */
+class Jetpack_Constrained_Array_Rounding {
+ public static function get_rounded_constrained_array( $bound_array, $sum = false ) {
+ // Convert associative arrays before working with them and convert them back before returning the values
+ $keys = array_keys( $bound_array );
+ $bound_array = array_values( $bound_array );
+
+ $bound_array_int = self::get_int_floor_array( $bound_array );
+
+ $lower_sum = array_sum( wp_list_pluck( $bound_array_int, 'floor' ) );
+ if ( ! $sum || ( $sum < $lower_sum ) ) {
+ // If value of sum is not supplied or is invalid, calculate the sum that the returned array is constrained to match
+ $sum = array_sum( $bound_array );
+ }
+ $diff_sum = $sum - $lower_sum;
+
+ self::adjust_constrained_array( $bound_array_int, $diff_sum );
+
+ $bound_array_fin = wp_list_pluck( $bound_array_int, 'floor' );
+ return array_combine( $keys, $bound_array_fin );
+ }
+
+ private static function get_int_floor_array( $bound_array ) {
+ $bound_array_int_floor = array();
+ foreach ( $bound_array as $i => $value ){
+ $bound_array_int_floor[$i] = array(
+ 'floor' => (int) floor( $value ),
+ 'fraction' => $value - floor( $value ),
+ 'index' => $i,
+ );
+ }
+
+ return $bound_array_int_floor;
+ }
+
+ private static function adjust_constrained_array( &$bound_array_int, $adjustment ) {
+ usort( $bound_array_int, array( 'self', 'cmp_desc_fraction' ) );
+
+ $start = 0;
+ $end = $adjustment - 1;
+ $length = count( $bound_array_int );
+
+ for ( $i = $start; $i <= $end; $i++ ) {
+ $bound_array_int[ $i % $length ]['floor']++;
+ }
+
+ usort( $bound_array_int, array( 'self', 'cmp_asc_index' ) );
+ }
+
+ private static function cmp_desc_fraction( $a, $b ) {
+ if ( $a['fraction'] == $b['fraction'] )
+ return 0;
+ return $a['fraction'] > $b['fraction'] ? -1 : 1;
+ }
+
+ private static function cmp_asc_index( $a, $b ) {
+ if ( $a['index'] == $b['index'] )
+ return 0;
+ return $a['index'] < $b['index'] ? -1 : 1;
+ }
+}
diff --git a/plugins/jetpack/modules/tiled-gallery/tiled-gallery.php b/plugins/jetpack/modules/tiled-gallery/tiled-gallery.php
new file mode 100644
index 00000000..342e8a65
--- /dev/null
+++ b/plugins/jetpack/modules/tiled-gallery/tiled-gallery.php
@@ -0,0 +1,588 @@
+<?php
+
+// Include the class file containing methods for rounding constrained array elements.
+// Here the constrained array element is the dimension of a row, group or an image in the tiled gallery.
+include_once dirname( __FILE__ ) . '/math/class-constrained-array-rounding.php';
+
+class Jetpack_Tiled_Gallery {
+
+ public function __construct() {
+ add_action( 'admin_init', array( $this, 'settings_api_init' ) );
+ add_filter( 'jetpack_gallery_types', array( $this, 'jetpack_gallery_types' ), 9 );
+ }
+
+ public function tiles_enabled() {
+ // Check the setting status
+ return '' != get_option( 'tiled_galleries' );
+ }
+
+ public function set_atts( $atts ) {
+ global $post;
+
+ $this->atts = shortcode_atts( array(
+ 'order' => 'ASC',
+ 'orderby' => 'menu_order ID',
+ 'id' => $post->ID,
+ 'include' => '',
+ 'exclude' => '',
+ 'type' => '',
+ 'grayscale' => false,
+ 'link' => '',
+ ), $atts );
+
+ $this->atts['id'] = (int) $this->atts['id'];
+ $this->float = is_rtl() ? 'right' : 'left';
+
+ // Default to rectangular is tiled galleries are checked
+ if ( $this->tiles_enabled() && ( ! $this->atts['type'] || 'default' == $this->atts['type'] ) )
+ $this->atts['type'] = 'rectangular';
+
+ if ( !$this->atts['orderby'] ) {
+ $this->atts['orderby'] = sanitize_sql_orderby( $this->atts['orderby'] );
+ if ( !$this->atts['orderby'] )
+ $this->atts['orderby'] = 'menu_order ID';
+ }
+
+ if ( 'RAND' == $this->atts['order'] )
+ $this->atts['orderby'] = 'none';
+ }
+
+ public function get_attachments() {
+ extract( $this->atts );
+
+ if ( !empty( $include ) ) {
+ $include = preg_replace( '/[^0-9,]+/', '', $include );
+ $_attachments = get_posts( array('include' => $include, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby) );
+
+ $attachments = array();
+ foreach ( $_attachments as $key => $val ) {
+ $attachments[$val->ID] = $_attachments[$key];
+ }
+ } elseif ( !empty( $exclude ) ) {
+ $exclude = preg_replace( '/[^0-9,]+/', '', $exclude );
+ $attachments = get_children( array('post_parent' => $id, 'exclude' => $exclude, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby) );
+ } else {
+ $attachments = get_children( array('post_parent' => $id, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby ) );
+ }
+ return $attachments;
+ }
+
+ public function get_attachment_link( $attachment_id, $orig_file ) {
+ if ( isset( $this->atts['link'] ) && $this->atts['link'] == 'file' )
+ return $orig_file;
+ else
+ return get_attachment_link( $attachment_id );
+ }
+
+ public function default_scripts_and_styles() {
+ wp_enqueue_script( 'tiled-gallery', plugins_url( 'tiled-gallery/tiled-gallery.js', __FILE__ ), array( 'jquery' ) );
+ wp_enqueue_style( 'tiled-gallery', plugins_url( 'tiled-gallery/tiled-gallery.css', __FILE__ ), array(), '2012-09-21' );
+ }
+
+ public function gallery_shortcode( $val, $atts ) {
+ if ( ! empty( $val ) ) // something else is overriding post_gallery, like a custom VIP shortcode
+ return $val;
+
+ global $post;
+
+ $this->set_atts( $atts );
+
+ $attachments = $this->get_attachments();
+ if ( empty( $attachments ) )
+ return '';
+
+ if ( is_feed() || defined( 'IS_HTML_EMAIL' ) )
+ return '';
+
+ if ( method_exists( $this, $this->atts['type'] . '_talavera' ) ) {
+ // Enqueue styles and scripts
+ $this->default_scripts_and_styles();
+ $gallery_html = call_user_func_array( array( $this, $this->atts['type'] . '_talavera' ), array( $attachments ) );
+
+ if ( $gallery_html && class_exists( 'Jetpack' ) && class_exists( 'Jetpack_Photon' ) ) {
+ // Tiled Galleries in Jetpack require that Photon be active.
+ // If it's not active, run it just on the gallery output.
+ if ( ! in_array( 'photon', Jetpack::get_active_modules() ) )
+ $gallery_html = Jetpack_Photon::filter_the_content( $gallery_html );
+ }
+
+ return $gallery_html;
+ }
+
+ return '';
+ }
+
+ public function rectangular_talavera( $attachments ) {
+ $grouper = new Jetpack_Tiled_Gallery_Grouper( $attachments );
+
+ Jetpack_Tiled_Gallery_Shape::reset_last_shape();
+
+ $output = $this->generate_carousel_container();
+ foreach ( $grouper->grouped_images as $row ) {
+ $output .= '<div class="gallery-row" style="' . esc_attr( 'width: ' . $row->width . 'px; height: ' . ( $row->height - 4 ) . 'px;' ) . '">';
+ foreach( $row->groups as $group ) {
+ $count = count( $group->images );
+ $output .= '<div class="gallery-group images-' . esc_attr( $count ) . '" style="' . esc_attr( 'width: ' . $group->width . 'px; height: ' . $group->height . 'px;' ) . '">';
+ foreach ( $group->images as $image ) {
+
+ $size = 'large';
+ if ( $image->width < 250 )
+ $size = 'small';
+
+ $image_title = $image->post_title;
+ $orig_file = wp_get_attachment_url( $image->ID );
+ $link = $this->get_attachment_link( $image->ID, $orig_file );
+
+ $img_src = add_query_arg( array( 'w' => $image->width, 'h' => $image->height ), $orig_file );
+
+ $output .= '<div class="tiled-gallery-item tiled-gallery-item-' . esc_attr( $size ) . '"><a href="' . esc_url( $link ) . '"><img ' . $this->generate_carousel_image_args( $image ) . ' src="' . esc_url( $img_src ) . '" width="' . esc_attr( $image->width ) . '" height="' . esc_attr( $image->height ) . '" align="left" title="' . esc_attr( $image_title ) . '" /></a>';
+
+ if ( $this->atts['grayscale'] == true ) {
+ $img_src_grayscale = jetpack_photon_url( $img_src, array( 'filter' => 'grayscale' ) );
+ $output .= '<a href="'. esc_url( $link ) . '"><img ' . $this->generate_carousel_image_args( $image ) . ' class="grayscale" src="' . esc_url( $img_src_grayscale ) . '" width="' . esc_attr( $image->width ) . '" height="' . esc_attr( $image->height ) . '" align="left" title="' . esc_attr( $image_title ) . '" /></a>';
+ }
+
+ if ( trim( $image->post_excerpt ) )
+ $output .= '<div class="tiled-gallery-caption">' . wptexturize( $image->post_excerpt ) . '</div>';
+
+ $output .= '</div>';
+ }
+ $output .= '</div>';
+ }
+ $output .= '</div>';
+ }
+ $output .= '</div>';
+ return $output;
+ }
+
+ public function square_talavera( $attachments ) {
+ $content_width = self::get_content_width();
+ $images_per_row = 3;
+ $margin = 2;
+
+ $margin_space = ( $images_per_row * $margin ) * 2;
+ $size = floor( ( $content_width - $margin_space ) / $images_per_row );
+ $remainder = count( $attachments ) % $images_per_row;
+ if ( $remainder > 0 ) {
+ $remainder_space = ( $remainder * $margin ) * 2;
+ $remainder_size = ceil( ( $content_width - $remainder_space - $margin ) / $remainder );
+ }
+ $output = $this->generate_carousel_container();
+ $c = 1;
+ foreach( $attachments as $image ) {
+ if ( $remainder > 0 && $c <= $remainder )
+ $img_size = $remainder_size;
+ else
+ $img_size = $size;
+
+ $orig_file = wp_get_attachment_url( $image->ID );
+ $link = $this->get_attachment_link( $image->ID, $orig_file );
+ $image_title = $image->post_title;
+
+ $img_src = add_query_arg( array( 'w' => $img_size, 'h' => $img_size, 'crop' => 1 ), $orig_file );
+
+ $output .= '<div class="tiled-gallery-item">';
+ $output .= '<a border="0" href="' . esc_url( $link ) . '"><img ' . $this->generate_carousel_image_args( $image ) . ' style="' . esc_attr( 'margin: ' . $margin . 'px' ) . '" src="' . esc_url( $img_src ) . '" width=' . esc_attr( $img_size ) . ' height=' . esc_attr( $img_size ) . ' title="' . esc_attr( $image_title ) . '" /></a>';
+
+ // Grayscale effect
+ if ( $this->atts['grayscale'] == true ) {
+ $src = urlencode( $image->guid );
+ $output .= '<a border="0" href="' . esc_url( $link ) . '"><img ' . $this->generate_carousel_image_args( $image ) . ' style="margin: 2px" class="grayscale" src="' . esc_url( 'http://en.wordpress.com/imgpress?url=' . urlencode( $image->guid ) . '&resize=' . $img_size . ',' . $img_size . '&filter=grayscale' ) . '" width=' . esc_attr( $img_size ) . ' height=' . esc_attr( $img_size ) . ' title="' . esc_attr( $image_title ) . '" /></a>';
+ }
+
+ // Captions
+ if ( trim( $image->post_excerpt ) )
+ $output .= '<div class="tiled-gallery-caption">' . wptexturize( $image->post_excerpt ) . '</div>';
+ $output .= '</div>';
+ $c ++;
+ }
+ $output .= '</div>';
+ return $output;
+ }
+
+ public function circle_talavera( $attachments ) {
+ return $this->square_talavera( $attachments );
+ }
+
+ public function rectangle_talavera( $attachments ) {
+ return $this->rectangular_talavera( $attachments );
+ }
+
+ function generate_carousel_container() {
+ global $post;
+
+ $html = '<div '. $this->gallery_classes() . ' data-original-width="' . esc_attr( self::get_content_width() ) . '">';
+ $blog_id = (int) get_current_blog_id();
+ $extra_data = array( 'data-carousel-extra' => array( 'blog_id' => $blog_id, 'permalink' => get_permalink( $post->ID ) ) );
+
+ foreach ( (array) $extra_data as $data_key => $data_values ) {
+ $html = str_replace( '<div ', '<div ' . esc_attr( $data_key ) . "='" . json_encode( $data_values ) . "' ", $html );
+ }
+
+ return $html;
+ }
+
+ function generate_carousel_image_args( $image ) {
+ $attachment_id = $image->ID;
+ $orig_file = wp_get_attachment_url( $attachment_id );
+ $meta = wp_get_attachment_metadata( $attachment_id );
+ $size = isset( $meta['width'] ) ? intval( $meta['width'] ) . ',' . intval( $meta['height'] ) : '';
+ $img_meta = ( ! empty( $meta['image_meta'] ) ) ? (array) $meta['image_meta'] : array();
+ $comments_opened = intval( comments_open( $attachment_id ) );
+
+ $medium_file_info = wp_get_attachment_image_src( $attachment_id, 'medium' );
+ $medium_file = isset( $medium_file_info[0] ) ? $medium_file_info[0] : '';
+
+ $large_file_info = wp_get_attachment_image_src( $attachment_id, 'large' );
+ $large_file = isset( $large_file_info[0] ) ? $large_file_info[0] : '';
+ $attachment_title = wptexturize( $image->post_title );
+ $attachment_desc = wpautop( wptexturize( $image->post_content ) );
+
+ // Not yet providing geo-data, need to "fuzzify" for privacy
+ if ( ! empty( $img_meta ) ) {
+ foreach ( $img_meta as $k => $v ) {
+ if ( 'latitude' == $k || 'longitude' == $k )
+ unset( $img_meta[$k] );
+ }
+ }
+
+ $img_meta = json_encode( array_map( 'strval', $img_meta ) );
+
+ $output = sprintf(
+ 'data-attachment-id="%1$d" data-orig-file="%2$s" data-orig-size="%3$s" data-comments-opened="%4$s" data-image-meta="%5$s" data-image-title="%6$s" data-image-description="%7$s" data-medium-file="%8$s" data-large-file="%9$s"',
+ esc_attr( $attachment_id ),
+ esc_url( wp_get_attachment_url( $attachment_id ) ),
+ esc_attr( $size ),
+ esc_attr( $comments_opened ),
+ esc_attr( $img_meta ),
+ esc_attr( $attachment_title ),
+ esc_attr( $attachment_desc ),
+ esc_url( $medium_file ),
+ esc_url( $large_file )
+ );
+ return $output;
+ }
+
+ public function gallery_classes() {
+ $classes = 'class="tiled-gallery type-' . esc_attr( $this->atts['type'] ) . '"';
+ return $classes;
+ }
+
+ public static function gallery_already_redefined() {
+ global $shortcode_tags;
+ if ( ! isset( $shortcode_tags[ 'gallery' ] ) || $shortcode_tags[ 'gallery' ] !== 'gallery_shortcode' )
+ return true;
+ }
+
+ public static function init() {
+ if ( self::gallery_already_redefined() )
+ return;
+
+ $gallery = new Jetpack_Tiled_Gallery;
+ add_filter( 'post_gallery', array( $gallery, 'gallery_shortcode' ), 1001, 2 );
+ }
+
+ public static function get_content_width() {
+ global $content_width;
+
+ $tiled_gallery_content_width = $content_width;
+
+ if ( ! $tiled_gallery_content_width )
+ $tiled_gallery_content_width = 500;
+
+ return apply_filters( 'tiled_gallery_content_width', $tiled_gallery_content_width );
+ }
+
+ /**
+ * Media UI integration
+ */
+ function jetpack_gallery_types( $types ) {
+ $types['rectangular'] = __( 'Tiles', 'jetpack' );
+ $types['square'] = __( 'Square Tiles', 'jetpack' );
+ $types['circle'] = __( 'Circles', 'jetpack' );
+ return $types;
+ }
+
+ /**
+ * Add a checkbox field to the Carousel section in Settings > Media
+ * for setting tiled galleries as the default.
+ */
+ function settings_api_init() {
+ global $wp_settings_sections;
+
+ // Add the setting field [tiled_galleries] and place it in Settings > Media
+ if ( isset( $wp_settings_sections['media']['carousel_section'] ) )
+ $section = 'carousel_section';
+ else
+ $section = 'default';
+
+ add_settings_field( 'tiled_galleries', __( 'Tiled Galleries', 'jetpack' ), array( $this, 'setting_html' ), 'media', $section );
+ register_setting( 'media', 'tiled_galleries', 'esc_attr' );
+ }
+
+ function setting_html() {
+ echo '<label><input name="tiled_galleries" type="checkbox" value="1" ' .
+ checked( 1, '' != get_option( 'tiled_galleries' ), false ) . ' /> ' .
+ __( 'Display all your gallery pictures in a cool mosaic.', 'jetpack' ) . '</br></label>';
+ }
+}
+
+class Jetpack_Tiled_Gallery_Shape {
+ static $shapes_used = array();
+
+ public function __construct( $images ) {
+ $this->images = $images;
+ $this->images_left = count( $images );
+ }
+
+ public function sum_ratios( $number_of_images = 3 ) {
+ return array_sum( array_slice( wp_list_pluck( $this->images, 'ratio' ), 0, $number_of_images ) );
+ }
+
+ public function next_images_are_symmetric() {
+ return $this->images_left > 2 && $this->images[0]->ratio == $this->images[2]->ratio;
+ }
+
+ public function is_not_as_previous( $n = 1 ) {
+ return ! in_array( get_class( $this ), array_slice( self::$shapes_used, -$n ) );
+ }
+
+ public function is_wide_theme() {
+ global $content_width;
+ return $content_width > 1000;
+ }
+
+ public static function set_last_shape( $last_shape ) {
+ self::$shapes_used[] = $last_shape;
+ }
+
+ public static function reset_last_shape() {
+ self::$shapes_used = array();
+ }
+}
+
+class Jetpack_Tiled_Gallery_Three extends Jetpack_Tiled_Gallery_Shape {
+ public $shape = array( 1, 1, 1 );
+
+ public function is_possible() {
+ $ratio = $this->sum_ratios( 3 );
+ return $this->images_left > 2 && $this->is_not_as_previous() &&
+ ( ( $ratio < 2.5 ) || ( $ratio < 5 && $this->next_images_are_symmetric() ) || $this->is_wide_theme() );
+ }
+}
+
+class Jetpack_Tiled_Gallery_Four extends Jetpack_Tiled_Gallery_Shape {
+ public $shape = array( 1, 1, 1, 1 );
+
+ public function is_possible() {
+ return $this->is_not_as_previous() && $this->sum_ratios( 4 ) < 3.5 &&
+ ( $this->images_left == 4 || ( $this->images_left != 8 && $this->images_left > 5 ) );
+ }
+}
+
+class Jetpack_Tiled_Gallery_Five extends Jetpack_Tiled_Gallery_Shape {
+ public $shape = array( 1, 1, 1, 1, 1 );
+
+ public function is_possible() {
+ return $this->is_wide_theme() && $this->is_not_as_previous() && $this->sum_ratios( 5 ) < 5 &&
+ ( $this->images_left == 5 || ( $this->images_left != 10 && $this->images_left > 6 ) );
+ }
+}
+
+class Jetpack_Tiled_Gallery_Two_One extends Jetpack_Tiled_Gallery_Shape {
+ public $shape = array( 2, 1 );
+
+ public function is_possible() {
+ return $this->is_not_as_previous( 3 ) && $this->images_left >= 2 &&
+ $this->images[2]->ratio < 1.6 && $this->images[0]->ratio >=0.9 && $this->images[1]->ratio >= 0.9;
+ }
+}
+
+class Jetpack_Tiled_Gallery_One_Two extends Jetpack_Tiled_Gallery_Shape {
+ public $shape = array( 1, 2 );
+
+ public function is_possible() {
+ return $this->is_not_as_previous( 3 ) && $this->images_left >= 2 &&
+ $this->images[0]->ratio < 1.6 && $this->images[1]->ratio >=0.9 && $this->images[2]->ratio >= 0.9;
+ }
+}
+
+class Jetpack_Tiled_Gallery_One_Three extends Jetpack_Tiled_Gallery_Shape {
+ public $shape = array( 1, 3 );
+
+ public function is_possible() {
+ return $this->is_not_as_previous() && $this->images_left >= 3 &&
+ $this->images[0]->ratio < 0.8 && $this->images[1]->ratio >=0.9 && $this->images[2]->ratio >= 0.9 && $this->images[3]->ratio >= 0.9;
+ }
+}
+
+class Jetpack_Tiled_Gallery_Symmetric_Row extends Jetpack_Tiled_Gallery_Shape {
+ public $shape = array( 1, 2, 1 );
+
+ public function is_possible() {
+ return $this->is_not_as_previous() && $this->images_left >= 3 && $this->images_left != 5 &&
+ $this->images[0]->ratio < 0.8 && $this->images[0]->ratio == $this->images[3]->ratio;
+ }
+}
+
+class Jetpack_Tiled_Gallery_Grouper {
+ public $margin = 4;
+ public function __construct( $attachments ) {
+ $content_width = Jetpack_Tiled_Gallery::get_content_width();
+ $ua_info = new Jetpack_User_Agent_Info();
+
+ $this->last_shape = '';
+ $this->images = $this->get_images_with_sizes( $attachments );
+ $this->grouped_images = $this->get_grouped_images();
+ $this->apply_content_width( $content_width - 5 ); //reduce the margin hack to 5px. It will be further reduced when we fix more themes and the rounding error.
+ }
+
+ public function get_current_row_size() {
+ $images_left = count( $this->images );
+ if ( $images_left < 3 )
+ return array_fill( 0, $images_left, 1 );
+
+ foreach ( array( 'One_Three', 'One_Two', 'Five', 'Four', 'Three', 'Two_One', 'Symmetric_Row' ) as $shape_name ) {
+ $class_name = "Jetpack_Tiled_Gallery_$shape_name";
+ $shape = new $class_name( $this->images );
+ if ( $shape->is_possible() ) {
+ Jetpack_Tiled_Gallery_Shape::set_last_shape( $class_name );
+ return $shape->shape;
+ }
+ }
+
+ Jetpack_Tiled_Gallery_Shape::set_last_shape( 'Two' );
+ return array( 1, 1 );
+ }
+
+ public function get_images_with_sizes( $attachments ) {
+ $images_with_sizes = array();
+
+ foreach ( $attachments as $image ) {
+ $meta = wp_get_attachment_metadata( $image->ID );
+ $image->width_orig = ( $meta['width'] > 0 )? $meta['width'] : 1;
+ $image->height_orig = ( $meta['height'] > 0 )? $meta['height'] : 1;
+ $image->ratio = $image->width_orig / $image->height_orig;
+ $image->ratio = $image->ratio? $image->ratio : 1;
+ $images_with_sizes[] = $image;
+ }
+
+ return $images_with_sizes;
+ }
+
+ public function read_row() {
+ $vector = $this->get_current_row_size();
+
+ $row = array();
+ foreach ( $vector as $group_size ) {
+ $row[] = new Jetpack_Tiled_Gallery_Group( array_splice( $this->images, 0, $group_size ) );
+ }
+
+ return $row;
+ }
+
+ public function get_grouped_images() {
+ $grouped_images = array();
+
+ while( !empty( $this->images ) ) {
+ $grouped_images[] = new Jetpack_Tiled_Gallery_Row( $this->read_row() );
+ }
+
+ return $grouped_images;
+ }
+
+ // todo: split in functions
+ // todo: do not stretch images
+ public function apply_content_width( $width ) {
+ foreach ( $this->grouped_images as $row ) {
+ $row->width = $width;
+ $row->raw_height = 1 / $row->ratio * ( $width - $this->margin * ( count( $row->groups ) - $row->weighted_ratio ) );
+ $row->height = round( $row->raw_height );
+
+ $this->calculate_group_sizes( $row );
+ }
+ }
+
+ public function calculate_group_sizes( $row ) {
+ // Storing the calculated group heights in an array for rounding them later while preserving their sum
+ // This fixes the rounding error that can lead to a few ugly pixels sticking out in the gallery
+ $group_widths_array = array();
+ foreach ( $row->groups as $group ) {
+ $group->height = $row->height;
+ // Storing the raw calculations in a separate property to prevent rounding errors from cascading down and for diagnostics
+ $group->raw_width = ( $row->raw_height - $this->margin * count( $group->images ) ) * $group->ratio + $this->margin;
+ $group_widths_array[] = $group->raw_width;
+ }
+ $rounded_group_widths_array = Jetpack_Constrained_Array_Rounding::get_rounded_constrained_array( $group_widths_array, $row->width );
+
+ foreach ( $row->groups as $group ) {
+ $group->width = array_shift( $rounded_group_widths_array );
+ $this->calculate_image_sizes( $group );
+ }
+ }
+
+ public function calculate_image_sizes( $group ) {
+ // Storing the calculated image heights in an array for rounding them later while preserving their sum
+ // This fixes the rounding error that can lead to a few ugly pixels sticking out in the gallery
+ $image_heights_array = array();
+ foreach ( $group->images as $image ) {
+ $image->width = $group->width - $this->margin;
+ // Storing the raw calculations in a separate property for diagnostics
+ $image->raw_height = ( $group->raw_width - $this->margin ) / $image->ratio;
+ $image_heights_array[] = $image->raw_height;
+ }
+
+ $image_height_sum = $group->height - count( $image_heights_array ) * $this->margin;
+ $rounded_image_heights_array = Jetpack_Constrained_Array_Rounding::get_rounded_constrained_array( $image_heights_array, $image_height_sum );
+
+ foreach ( $group->images as $image ) {
+ $image->height = array_shift( $rounded_image_heights_array );
+ }
+ }
+}
+
+class Jetpack_Tiled_Gallery_Row {
+ public function __construct( $groups ) {
+ $this->groups = $groups;
+ $this->ratio = $this->get_ratio();
+ $this->weighted_ratio = $this->get_weighted_ratio();
+ }
+
+ public function get_ratio() {
+ $ratio = 0;
+ foreach ( $this->groups as $group ) {
+ $ratio += $group->ratio;
+ }
+ return $ratio > 0? $ratio : 1;
+ }
+
+ public function get_weighted_ratio() {
+ $weighted_ratio = 0;
+ foreach ( $this->groups as $group ) {
+ $weighted_ratio += $group->ratio * count( $group->images );
+ }
+ return $weighted_ratio > 0 ? $weighted_ratio : 1;
+ }
+}
+
+class Jetpack_Tiled_Gallery_Group {
+ public function __construct( $images ) {
+ $this->images = $images;
+ $this->ratio = $this->get_ratio();
+ }
+
+ public function get_ratio() {
+ $ratio = 0;
+ foreach ( $this->images as $image ) {
+ if ( $image->ratio )
+ $ratio += 1/$image->ratio;
+ }
+ if ( !$ratio )
+ return 1;
+
+ return 1/$ratio;
+ }
+}
+
+add_action( 'init', array( 'Jetpack_Tiled_Gallery', 'init' ) );
+
diff --git a/plugins/jetpack/modules/tiled-gallery/tiled-gallery/rtl/tiled-gallery-rtl.css b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/rtl/tiled-gallery-rtl.css
new file mode 100644
index 00000000..007c0ccf
--- /dev/null
+++ b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/rtl/tiled-gallery-rtl.css
@@ -0,0 +1,88 @@
+/* This file was automatically generated on Jan 05 2013 15:45:53 */
+
+/* =Tiled Gallery Default Styles
+-------------------------------------------------------------- */
+
+.tiled-gallery {
+ clear: both;
+ margin: 0;
+ overflow: hidden;
+}
+.tiled-gallery img {
+ margin: 2px !important; /* Ensure that this value isn't overridden by themes that give content images blanket margins */
+}
+.tiled-gallery .gallery-group {
+ float: right;
+ overflow-y: hidden;
+ position: relative;
+}
+.tiled-gallery .tiled-gallery-item {
+ float: right;
+ margin: 0;
+ position: relative;
+}
+.tiled-gallery .gallery-row {
+ overflow: hidden;
+ margin-bottom: 2px;
+}
+.tiled-gallery .tiled-gallery-item a { /* Needs to reset some properties for theme compatibility */
+ background: transparent;
+ border: none;
+ color: none;
+ margin: 0;
+ padding: 0;
+ text-decoration: none;
+ width: auto;
+}
+.tiled-gallery .tiled-gallery-item img,
+.tiled-gallery .tiled-gallery-item img:hover { /* Needs to reset some properties for theme compatibility */
+ background: none;
+ border: none;
+ box-shadow: none;
+ max-width: 100%;
+ padding: 0;
+ vertical-align: middle;
+}
+.tiled-gallery-caption { /* Captions */
+ background: #eee;
+ background: rgba( 255,255,255,0.8 );
+ color: #333;
+ font-size: 13px;
+ font-weight: 400;
+ overflow: hidden;
+ padding: 10px 0;
+ position: absolute;
+ bottom: 0;
+ text-indent: 10px;
+ text-overflow: ellipsis;
+ width: 100%;
+ white-space: nowrap;
+}
+.tiled-gallery .tiled-gallery-item-small .tiled-gallery-caption { /* Smaller captions */
+ font-size: 11px;
+}
+
+
+/* =Greyscale
+-------------------------------------------------------------- */
+
+.tiled-gallery .tiled-gallery-item img.grayscale {
+ position: absolute;
+ right: 0;
+ top: 0;
+}
+.tiled-gallery .tiled-gallery-item img.grayscale:hover {
+ opacity: 0;
+}
+
+
+/* =Circles Layout
+-------------------------------------------------------------- */
+
+.tiled-gallery.type-circle .tiled-gallery-item img {
+ border-radius: 50% !important; /* Ensure that circles are displayed in themes that add border-radius to all images as a default */
+}
+.tiled-gallery.type-circle .tiled-gallery-caption {
+ display: none;
+ opacity: 0;
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery.css b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery.css
new file mode 100644
index 00000000..3a1924df
--- /dev/null
+++ b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery.css
@@ -0,0 +1,85 @@
+/* =Tiled Gallery Default Styles
+-------------------------------------------------------------- */
+
+.tiled-gallery {
+ clear: both;
+ margin: 0;
+ overflow: hidden;
+}
+.tiled-gallery img {
+ margin: 2px !important; /* Ensure that this value isn't overridden by themes that give content images blanket margins */
+}
+.tiled-gallery .gallery-group {
+ float: left;
+ position: relative;
+}
+.tiled-gallery .tiled-gallery-item {
+ float: left;
+ margin: 0;
+ position: relative;
+}
+.tiled-gallery .gallery-row {
+ overflow: hidden;
+ margin-bottom: 2px;
+}
+.tiled-gallery .tiled-gallery-item a { /* Needs to reset some properties for theme compatibility */
+ background: transparent;
+ border: none;
+ color: none;
+ margin: 0;
+ padding: 0;
+ text-decoration: none;
+ width: auto;
+}
+.tiled-gallery .tiled-gallery-item img,
+.tiled-gallery .tiled-gallery-item img:hover { /* Needs to reset some properties for theme compatibility */
+ background: none;
+ border: none;
+ box-shadow: none;
+ max-width: 100%;
+ padding: 0;
+ vertical-align: middle;
+}
+.tiled-gallery-caption { /* Captions */
+ background: #eee;
+ background: rgba( 255,255,255,0.8 );
+ color: #333;
+ font-size: 13px;
+ font-weight: 400;
+ overflow: hidden;
+ padding: 10px 0;
+ position: absolute;
+ bottom: 0;
+ text-indent: 10px;
+ text-overflow: ellipsis;
+ width: 100%;
+ white-space: nowrap;
+}
+.tiled-gallery .tiled-gallery-item-small .tiled-gallery-caption { /* Smaller captions */
+ font-size: 11px;
+}
+
+
+/* =Greyscale
+-------------------------------------------------------------- */
+
+.tiled-gallery .tiled-gallery-item img.grayscale {
+ position: absolute;
+ left: 0;
+ top: 0;
+}
+.tiled-gallery .tiled-gallery-item img.grayscale:hover {
+ opacity: 0;
+}
+
+
+/* =Circles Layout
+-------------------------------------------------------------- */
+
+.tiled-gallery.type-circle .tiled-gallery-item img {
+ border-radius: 50% !important; /* Ensure that circles are displayed in themes that add border-radius to all images as a default */
+}
+.tiled-gallery.type-circle .tiled-gallery-caption {
+ display: none;
+ opacity: 0;
+} \ No newline at end of file
diff --git a/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery.js b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery.js
new file mode 100644
index 00000000..90f8ed76
--- /dev/null
+++ b/plugins/jetpack/modules/tiled-gallery/tiled-gallery/tiled-gallery.js
@@ -0,0 +1,150 @@
+( function($) {
+
+var TiledGallery = function() {
+ this.resizeTimeout = null;
+
+ this.populate();
+
+ var self = this;
+
+ $( window ).on( 'resize', function () {
+ clearTimeout( self.resizeTimeout );
+
+ self.resizeTimeout = setTimeout( function () { self.resize(); }, 150 );
+ } );
+
+ // Make any new galleries loaded by Infinite Scroll flexible
+ $( 'body' ).on( 'post-load', $.proxy( self.initialize, self ) );
+
+ // Populate and set up captions on newdash galleries.
+ $( document ).on( 'page-rendered.wpcom-newdash', $.proxy( self.populate, self ) );
+
+ this.resize();
+};
+
+TiledGallery.prototype.populate = function() {
+ this.gallery = $( '.tiled-gallery' );
+ this.item = this.gallery.find( '.tiled-gallery-item' );
+ this.caption = this.gallery.find( '.tiled-gallery-caption' );
+
+ this.Captions();
+};
+
+TiledGallery.prototype.initialize = function() {
+ var self = this;
+
+ self.populate();
+
+ // After each image load, run resize in case all images in the gallery are loaded.
+ self.gallery.find( 'img' ).off( 'load.tiled-gallery' ).on( 'load.tiled-gallery', function () {
+ self.resize();
+ } );
+
+ // Run resize now in case all images loaded from cache.
+ self.resize();
+};
+
+/**
+ * Story
+ */
+TiledGallery.prototype.Captions = function() {
+ /* Hide captions */
+ this.caption.hide();
+
+ this.item.on( 'hover', function() {
+ $( this ).find( '.tiled-gallery-caption' ).slideToggle( 'fast' );
+ });
+};
+
+TiledGallery.prototype.resize = function() {
+ var resizeableElements = '.gallery-row, .gallery-group, .tiled-gallery-item img';
+
+ this.gallery.each( function ( galleryIndex, galleryElement ) {
+ var thisGallery = $( galleryElement );
+
+ // All images must be loaded before proceeding.
+ var imagesLoaded = true;
+
+ thisGallery.find( 'img' ).each( function () {
+ if ( ! this.complete ) {
+ imagesLoaded = false;
+ return false;
+ }
+ } );
+
+ if ( ! imagesLoaded ) {
+ var loadCallback = arguments.callee;
+
+ // Once all of the images have loaded,
+ // re-call this containing function.
+ $( window ).load( function () {
+ loadCallback( null, thisGallery );
+ } );
+
+ return;
+ }
+
+ if ( ! thisGallery.data( 'sizes-set' ) ) {
+ // Maintain a record of the original widths and heights of these elements
+ // for proper scaling.
+ thisGallery.data( 'sizes-set', true );
+
+ thisGallery.find( resizeableElements ).each( function () {
+ var thisGalleryElement = $( this );
+
+ // Don't change margins, but remember what they were so they can be
+ // accounted for in size calculations. When the screen width gets
+ // small enough, ignoring the margins can cause images to overflow
+ // into new rows.
+ var extraWidth = ( parseInt( thisGalleryElement.css( 'marginLeft' ), 10 ) || 0 ) + ( parseInt( thisGalleryElement.css( 'marginRight' ), 10 ) || 0 );
+ var extraHeight = ( parseInt( thisGalleryElement.css( 'marginTop' ), 10 ) || 0 ) + ( parseInt( thisGalleryElement.css( 'marginBottom' ), 10 ) || 0 )
+
+ // In some situations, tiled galleries in Firefox have shown scrollbars on the images because
+ // the .outerWidth() call on the image returns a value larger than the container. Restrict
+ // widths used in the resizing functions to the maximum width of the container.
+ var parentElement = $( thisGalleryElement.parents( resizeableElements ).get( 0 ) );
+
+ if ( parentElement && parentElement.data( 'original-width' ) ) {
+ thisGalleryElement
+ .data( 'original-width', Math.min( parentElement.data( 'original-width' ), thisGalleryElement.outerWidth( true ) ) )
+ .data( 'original-height', Math.min( parentElement.data( 'original-height' ), thisGalleryElement.outerHeight( true ) ) );
+ }
+ else {
+ thisGalleryElement
+ .data( 'original-width', thisGalleryElement.outerWidth( true ) )
+ .data( 'original-height', thisGalleryElement.outerHeight( true ) );
+ }
+
+ thisGalleryElement
+ .data( 'extra-width', extraWidth )
+ .data( 'extra-height', extraHeight );
+ } );
+ }
+
+ // Resize everything in the gallery based on the ratio of the current content width
+ // to the original content width;
+ var originalWidth = thisGallery.data( 'original-width' );
+ var currentWidth = thisGallery.parent().width();
+ var resizeRatio = Math.min( 1, currentWidth / originalWidth );
+
+ thisGallery.find( resizeableElements ).each( function () {
+ var thisGalleryElement = $( this );
+
+ thisGalleryElement
+ .width( Math.floor( resizeRatio * thisGalleryElement.data( 'original-width' ) ) - thisGalleryElement.data( 'extra-width' ) )
+ .height( Math.floor( resizeRatio * thisGalleryElement.data( 'original-height' ) ) - thisGalleryElement.data( 'extra-height' ) );
+ } );
+ } );
+};
+
+/**
+ * Ready, set...
+ */
+$( document ).ready( function() {
+
+ // Instance!
+ var TiledGalleryInstance = new TiledGallery;
+
+});
+
+})(jQuery); \ No newline at end of file