/** * Skip to previous/next Item * * If several items share the same spot (like same issue datetime) then they'll get all skipped at once. * * @param string prev | next (relative to the current sort order) */ function &get_prevnext_Item($direction = 'next', $types = '', $featured = NULL, $post_navigation = 'same_blog') { global $DB, $ItemCache, $posttypes_specialtypes; if (!$this->single_post) { // We are not on a single post: $r = NULL; return $r; } /** * @var Item */ $current_Item = $this->get_by_idx(0); if (is_null($current_Item)) { // This happens if we are on a single post that we do not actually have permission to view $r = NULL; return $r; } if (in_array($current_Item->ptyp_ID, $posttypes_specialtypes)) { // We are not on a REGULAR post -- we cannot navigate: $r = NULL; return $r; } if (!empty($this->prevnext_Item[$direction][$post_navigation])) { return $this->prevnext_Item[$direction][$post_navigation]; } $next_Query = new ItemQuery($this->Cache->dbtablename, $this->Cache->dbprefix, $this->Cache->dbIDname); // GENERATE THE QUERY: /* * filtering stuff: */ $next_Query->where_chapter2($this->Blog, $this->filters['cat_array'], $this->filters['cat_modifier'], $this->filters['cat_focus']); $next_Query->where_author($this->filters['authors']); $next_Query->where_author_logins($this->filters['authors_login']); $next_Query->where_assignees($this->filters['assignees']); $next_Query->where_assignees_logins($this->filters['assignees_login']); $next_Query->where_author_assignee($this->filters['author_assignee']); $next_Query->where_locale($this->filters['lc']); $next_Query->where_statuses($this->filters['statuses']); // types param is kept only for the case when some custom types should be displayed $next_Query->where_types(!empty($types) ? $types : $this->filters['types']); $next_Query->where_keywords($this->filters['keywords'], $this->filters['phrase'], $this->filters['exact']); // $next_Query->where_ID( $this->filters['post_ID'], $this->filters['post_title'] ); $next_Query->where_datestart($this->filters['ymdhms'], $this->filters['week'], $this->filters['ymdhms_min'], $this->filters['ymdhms_max'], $this->filters['ts_min'], $this->filters['ts_max']); $next_Query->where_visibility($this->filters['visibility_array']); $next_Query->where_featured($featured); /* * ORDER BY stuff: */ if ($direction == 'next' && $this->filters['order'] == 'DESC' || $direction == 'prev' && $this->filters['order'] == 'ASC') { $order = 'DESC'; $operator = ' < '; } else { $order = 'ASC'; $operator = ' > '; } $orderby = str_replace(' ', ',', $this->filters['orderby']); $orderby_array = explode(',', $orderby); // Format each order param with default column names: $orderbyorder_array = preg_replace('#^(.+)$#', $this->Cache->dbprefix . '$1 ' . $order, $orderby_array); // Add an ID parameter to make sure there is no ambiguity in ordering on similar items: $orderbyorder_array[] = $this->Cache->dbIDname . ' ' . $order; $order_by = implode(', ', $orderbyorder_array); // Special case for RAND: $order_by = str_replace($this->Cache->dbprefix . 'RAND ', 'RAND() ', $order_by); $next_Query->order_by($order_by); // LIMIT to 1 single result $next_Query->LIMIT('1'); // fp> TODO: I think some additional limits need to come back here (for timespans) /* * Position right after the current element depending on current sorting params * * If there are several items on the same issuedatetime for example, we'll then differentiate on post ID * WARNING: you cannot combine criterias with AND here; you need stuf like a>a0 OR (a=a0 AND b>b0) */ switch ($orderby_array[0]) { case 'datestart': // special var name: $next_Query->WHERE_and($this->Cache->dbprefix . $orderby_array[0] . $operator . $DB->quote($current_Item->issue_date) . ' OR ( ' . $this->Cache->dbprefix . $orderby_array[0] . ' = ' . $DB->quote($current_Item->issue_date) . ' AND ' . $this->Cache->dbIDname . $operator . $current_Item->ID . ')'); break; case 'title': case 'ptyp_ID': case 'datecreated': case 'datemodified': case 'last_touched_ts': case 'urltitle': case 'priority': $next_Query->WHERE_and($this->Cache->dbprefix . $orderby_array[0] . $operator . $DB->quote($current_Item->{$orderby_array[0]}) . ' OR ( ' . $this->Cache->dbprefix . $orderby_array[0] . ' = ' . $DB->quote($current_Item->{$orderby_array[0]}) . ' AND ' . $this->Cache->dbIDname . $operator . $current_Item->ID . ')'); break; case 'order': // We have to integrate a rounding error margin $comp_order_value = $current_Item->order; $and_clause = ''; if (is_null($comp_order_value)) { // current Item has NULL order if ($operator == ' < ') { // This is needed when browsing through a descending ordered list and we reach the limit where orders are not set/NULL (ex: b2evo screenshots) $and_clause .= $this->Cache->dbprefix . $orderby_array[0] . ' IS NULL AND '; } else { // This is needed when browsing through a descending ordered list and we want to browse back into the posts that have numbers (pb appears if first NULL posts is the highest ID) $and_clause .= $this->Cache->dbprefix . $orderby_array[0] . ' IS NOT NULL OR '; } $and_clause .= $this->Cache->dbIDname . $operator . $current_Item->ID; } else { if ($operator == ' < ') { // This is needed when browsing through a descending ordered list and we reach the limit where orders are not set/NULL (ex: b2evo screenshots) $and_clause .= $this->Cache->dbprefix . $orderby_array[0] . ' IS NULL OR '; } $and_clause .= $this->Cache->dbprefix . $orderby_array[0] . $operator . ($operator == ' < ' ? $comp_order_value - 1.0E-9 : $comp_order_value + 1.0E-9) . ' OR ( ' . $this->Cache->dbprefix . $orderby_array[0] . ($operator == ' < ' ? ' <= ' . ($comp_order_value + 1.0E-9) : ' >= ' . ($comp_order_value - 1.0E-9)) . ' AND ' . $this->Cache->dbIDname . $operator . $current_Item->ID . ')'; } $next_Query->WHERE_and($and_clause); break; case 'RAND': // Random order. Don't show current item again. $next_Query->WHERE_and($this->Cache->dbprefix . 'ID <> ' . $current_Item->ID); break; default: echo 'WARNING: unhandled sorting: ' . htmlspecialchars($orderby_array[0]); } // GET DATA ROWS: // We are going to proceed in two steps (we simulate a subquery) // 1) we get the IDs we need // 2) we get all the other fields matching these IDs // This is more efficient than manipulating all fields at once. // Step 1: $step1_sql = 'SELECT DISTINCT ' . $this->Cache->dbIDname . $next_Query->get_from() . $next_Query->get_where() . $next_Query->get_group_by() . $next_Query->get_order_by() . $next_Query->get_limit(); //echo $DB->format_query( $step1_sql ); // Get list of the IDs we need: $next_ID = $DB->get_var($step1_sql, 0, 0, 'Get ID of next item'); //pre_dump( $next_ID ); // Step 2: get the item (may be NULL): $this->prevnext_Item[$direction][$post_navigation] =& $ItemCache->get_by_ID($next_ID, true, false); return $this->prevnext_Item[$direction][$post_navigation]; }
/** * Display the widget! * * @param array MUST contain at least the basic display params */ function display($params) { global $localtimenow, $DB, $Blog; $this->init_display($params); $blog_ID = intval($this->disp_params['blog_ID']); if (empty($blog_ID)) { // Use current blog by default $blog_ID = $Blog->ID; } $BlogCache =& get_BlogCache(); if (!$BlogCache->get_by_ID($blog_ID, false, false)) { // No blog exists return; } // Display photos: // TODO: permissions, complete statuses... // TODO: A FileList object based on ItemListLight but adding File data into the query? // overriding ItemListLigth::query() for starters ;) // Init caches $FileCache =& get_FileCache(); $ItemCache =& get_ItemCache(); // Query list of files and posts fields: // Note: We use ItemQuery to get attachments from all posts which should be visible ( even in case of aggregate blogs ) $ItemQuery = new ItemQuery($ItemCache->dbtablename, $ItemCache->dbprefix, $ItemCache->dbIDname); $ItemQuery->SELECT('post_ID, post_datestart, post_datemodified, post_main_cat_ID, post_urltitle, post_canonical_slug_ID, post_tiny_slug_ID, post_ityp_ID, post_title, post_excerpt, post_url, file_ID, file_type, file_title, file_root_type, file_root_ID, file_path, file_alt, file_desc, file_path_hash'); $ItemQuery->FROM_add('INNER JOIN T_links ON post_ID = link_itm_ID'); $ItemQuery->FROM_add('INNER JOIN T_files ON link_file_ID = file_ID'); $ItemQuery->where_chapter($blog_ID); if ($this->disp_params['item_visibility'] == 'public') { // Get images only of the public items $ItemQuery->where_visibility(array('published')); } else { // Get image of all available posts for current user $ItemQuery->where_visibility(NULL); } $ItemQuery->WHERE_and('( file_type = "image" ) OR ( file_type IS NULL )'); $ItemQuery->WHERE_and('post_datestart <= \'' . remove_seconds($localtimenow) . '\''); $ItemQuery->WHERE_and('link_position != "cover"'); if (!empty($this->disp_params['item_type'])) { // Get items only with specified type $ItemQuery->WHERE_and('post_ityp_ID = ' . intval($this->disp_params['item_type'])); } $ItemQuery->GROUP_BY('link_ID'); // fp> TODO: because no way of getting images only, we get 4 times more data than requested and hope that 25% at least will be images :/ // asimo> This was updated and we get images and those files where we don't know the file type yet. Now we get 2 times more data than requested. // Maybe it would be good to get only the requested amount of files, because after a very short period the file types will be set for all images. $ItemQuery->LIMIT(intval($this->disp_params['limit']) * 2); $ItemQuery->ORDER_BY(gen_order_clause($this->disp_params['order_by'], $this->disp_params['order_dir'], 'post_', 'post_ID ' . $this->disp_params['order_dir'] . ', link_ID')); // Init FileList with the above defined query $FileList = new DataObjectList2($FileCache); $FileList->sql = $ItemQuery->get(); $FileList->query(false, false, false, 'Media index widget'); $layout = $this->disp_params['thumb_layout']; $nb_cols = $this->disp_params['grid_nb_cols']; $count = 0; $r = ''; /** * @var File */ while ($File =& $FileList->get_next()) { if ($count >= $this->disp_params['limit']) { // We have enough images already! break; } if (!$File->is_image()) { // Skip anything that is not an image // Only images are selected or those files where we don't know the file type yet. // This check is only for those files where we don't know the filte type. The file type will be set during the check. continue; } if ($layout == 'grid') { // Grid layout if ($count % $nb_cols == 0) { $r .= $this->disp_params['grid_colstart']; } $r .= $this->disp_params['grid_cellstart']; } elseif ($layout == 'flow') { // Flow block layout $r .= $this->disp_params['flow_block_start']; } else { // List layout $r .= $this->disp_params['item_start']; } // 1/ Hack a dirty permalink( will redirect to canonical): // $link = url_add_param( $Blog->get('url'), 'p='.$post_ID ); // 2/ Hack a link to the right "page". Very daring!! // $link = url_add_param( $Blog->get('url'), 'paged='.$count ); // 3/ Instantiate a light object in order to get permamnent url: $ItemLight = new ItemLight($FileList->get_row_by_idx($FileList->current_idx - 1)); // index had already been incremented $r .= '<a href="' . $ItemLight->get_permanent_url() . '">'; // Generate the IMG THUMBNAIL tag with all the alt, title and desc if available $r .= $File->get_thumb_imgtag($this->disp_params['thumb_size'], '', '', $ItemLight->title); $r .= '</a>'; if ($this->disp_params['disp_image_title']) { // Dislay title of image or item $title = $File->get('title') ? $File->get('title') : $ItemLight->title; if (!empty($title)) { $r .= '<span class="note">' . $title . '</span>'; } } ++$count; if ($layout == 'grid') { // Grid layout $r .= $this->disp_params['grid_cellend']; if ($count % $nb_cols == 0) { $r .= $this->disp_params['grid_colend']; } } elseif ($layout == 'flow') { // Flow block layout $r .= $this->disp_params['flow_block_end']; } else { // List layout $r .= $this->disp_params['item_end']; } } // Exit if no files found if (empty($r)) { return; } echo $this->disp_params['block_start']; // Display title if requested $this->disp_title(); echo $this->disp_params['block_body_start']; if ($layout == 'grid') { // Grid layout echo $this->disp_params['grid_start']; } elseif ($layout == 'flow') { // Flow block layout echo $this->disp_params['flow_start']; } else { // List layout echo $this->disp_params['list_start']; } echo $r; if ($layout == 'grid') { // Grid layout if ($count && $count % $nb_cols != 0) { echo $this->disp_params['grid_colend']; } echo $this->disp_params['grid_end']; } elseif ($layout == 'flow') { // Flow block layout echo $this->disp_params['flow_end']; } else { // List layout echo $this->disp_params['list_end']; } echo $this->disp_params['block_body_end']; echo $this->disp_params['block_end']; return true; }