/** * list sections as topics in a forum * * @param resource the SQL result * @return string the rendered text **/ function layout($result) { global $context; // empty list if (!SQL::count($result)) { $output = array(); return $output; } // output as a string $text = ''; // build a list of sections $family = ''; $first = TRUE; while ($item = SQL::fetch($result)) { // change the family if ($item['family'] != $family) { $family = $item['family']; // close last table only if a section has been already listed if (!$first) { $text .= Skin::table_suffix(); } // show the family $text .= '<h2><span>' . $family . ' </span></h2>' . "\n" . Skin::table_prefix('yabb') . Skin::table_row(array(i18n::s('Board'), 'center=' . i18n::s('Topics'), i18n::s('Last post')), 'header'); } elseif ($first) { $text .= Skin::table_prefix('yabb'); $text .= Skin::table_row(array(i18n::s('Board'), 'center=' . i18n::s('Topics'), i18n::s('Last post')), 'header'); } // done with this case $first = FALSE; // reset everything $prefix = $label = $suffix = $icon = ''; // signal restricted and private sections if ($item['active'] == 'N') { $prefix .= PRIVATE_FLAG; } elseif ($item['active'] == 'R') { $prefix .= RESTRICTED_FLAG; } // indicate the id in the hovering popup $hover = i18n::s('View the section'); if (Surfer::is_member()) { $hover .= ' [section=' . $item['id'] . ']'; } // the url to view this item $url = Sections::get_permalink($item); // use the title as a link to the page $title =& Skin::build_link($url, Codes::beautify_title($item['title']), 'basic', $hover); // also use a clickable thumbnail, if any if ($item['thumbnail_url']) { $prefix = Skin::build_link($url, '<img src="' . $item['thumbnail_url'] . '" alt="" title="' . encode_field($hover) . '" class="left_image" />', 'basic', $hover) . $prefix; } // flag sections updated recently if ($item['expiry_date'] > NULL_DATE && $item['expiry_date'] <= $context['now']) { $suffix = EXPIRED_FLAG . ' '; } elseif ($item['create_date'] >= $context['fresh']) { $suffix = NEW_FLAG . ' '; } elseif ($item['edit_date'] >= $context['fresh']) { $suffix = UPDATED_FLAG . ' '; } // board introduction if ($item['introduction']) { $suffix .= '<br style="clear: none;" />' . Codes::beautify_introduction($item['introduction']); } // more details $details = ''; $more = array(); // board moderators if ($moderators = Sections::list_editors_by_name($item, 0, 7, 'comma5')) { $more[] = sprintf(i18n::ns('Moderator: %s', 'Moderators: %s', count($moderators)), $moderators); } // children boards if ($children =& Sections::list_by_title_for_anchor('section:' . $item['id'], 0, COMPACT_LIST_SIZE, 'comma')) { $more[] = sprintf(i18n::ns('Child board: %s', 'Child boards: %s', count($children)), Skin::build_list($children, 'comma')); } // as a compact list if (count($more)) { $details .= '<ul class="compact">'; foreach ($more as $list_item) { $details .= '<li>' . $list_item . '</li>' . "\n"; } $details .= '</ul>' . "\n"; } // all details if ($details) { $details = BR . '<span class="details">' . $details . "</span>\n"; } // count posts here, and in children sections $anchors = Sections::get_branch_at_anchor('section:' . $item['id']); if (!($count = Articles::count_for_anchor($anchors))) { $count = 0; } // get last post $last_post = '--'; $article =& Articles::get_newest_for_anchor($anchors, TRUE); if ($article['id']) { // flag articles updated recently if ($article['expiry_date'] > NULL_DATE && $article['expiry_date'] <= $context['now']) { $flag = EXPIRED_FLAG . ' '; } elseif ($article['create_date'] >= $context['fresh']) { $flag = NEW_FLAG . ' '; } elseif ($article['edit_date'] >= $context['fresh']) { $flag = UPDATED_FLAG . ' '; } else { $flag = ''; } // title $last_post = Skin::build_link(Articles::get_permalink($article), Codes::beautify_title($article['title']), 'article'); // last editor if ($article['edit_date']) { // find a name, if any if ($article['edit_name']) { // label the action if (isset($article['edit_action'])) { $action = Anchors::get_action_label($article['edit_action']); } else { $action = i18n::s('edited'); } // name of last editor $user = sprintf(i18n::s('%s by %s'), $action, Users::get_link($article['edit_name'], $article['edit_address'], $article['edit_id'])); } $last_post .= $flag . BR . '<span class="tiny">' . $user . ' ' . Skin::build_date($article['edit_date']) . '</span>'; } } // this is another row of the output $text .= Skin::table_row(array($prefix . $title . $suffix . $details, 'center=' . $count, $last_post)); } // end of processing SQL::free($result); $text .= Skin::table_suffix(); return $text; }
/** * render a compact list of voted pages * * @param string the anchor (e.g. 'section:123') * @param string layout to use * @return string the rendered text **/ public static function render_voted($anchor = '', $layout = 'simple') { global $context; // we return some text; $text = ''; // number of items to display $count = COMPACT_LIST_SIZE; if (($position = strpos($anchor, ',')) !== FALSE) { $count = (int) trim(substr($anchor, $position + 1)); if (!$count) { $count = COMPACT_LIST_SIZE; } $anchor = trim(substr($anchor, 0, $position)); } // scope is limited to current surfer if ($anchor == 'self' && Surfer::get_id()) { $anchor = 'user:'******'section:') === 0) { // look at this branch of the content tree $anchors = Sections::get_branch_at_anchor($anchor); // query the database and layout that stuff $text =& Articles::list_for_anchor_by('rating', $anchors, 0, $count, $layout); // scope is limited to pages of one surfer } elseif (strpos($anchor, 'user:'******'rating', substr($anchor, 5), 0, $count, $layout); } else { $text =& Articles::list_by('rating', 0, $count, $layout); } // we have an array to format if (is_array($text)) { $text =& Skin::build_list($text, $layout); } // job done return $text; }
/** * search for some keywords in sub-sections * * This function also searches in sub-sections, with up to three levels of depth. * * @see search.php * * Modification dates are taken into account to prefer freshest information. * * @link http://www.artfulcode.net/articles/full-text-searching-mysql/ * * @param int the id of the section to look in * @param string the search string * @param float maximum score to look at * @param int the number of items to display * @param mixed the layout, if any * @return NULL on error, else an ordered array of array($score, $summary) */ public static function &search_in_section($section_id, $pattern, $offset = 1.0, $count = 10, $layout = 'search') { global $context; // sanity check if (!($pattern = trim($pattern))) { $output = NULL; return $output; } // limit the scope of the request $where = Sections::get_sql_where(); // search is restricted to one section $sections_where = ''; if ($section_id) { // look within this branch of the content tree $anchors = Sections::get_branch_at_anchor('section:' . $section_id); // the full set of sections searched $where .= " AND (sections.id IN (" . str_replace('section:', '', join(", ", $anchors)) . "))"; } // only consider live sections $where .= " AND ((sections.expiry_date is NULL) " . "OR (sections.expiry_date <= '" . NULL_DATE . "') OR (sections.expiry_date > '" . $context['now'] . "'))"; // how to compute the score for sections $score = "(MATCH(title, introduction, description)" . " AGAINST('" . SQL::escape($pattern) . "' IN BOOLEAN MODE)" . "/SQRT(GREATEST(1.1, DATEDIFF(NOW(), edit_date))))"; // the list of articles $query = "SELECT sections.*," . " " . $score . " AS score" . " FROM " . SQL::table_name('sections') . " AS sections" . " WHERE (" . $score . " < " . $offset . ") AND (" . $score . " > 0)" . " AND (" . $where . ")" . " ORDER BY score DESC" . " LIMIT " . $count; $output =& Sections::list_selected(SQL::query($query), $layout); return $output; }
$layout = new Layout_articles(); } else { $layout = Layouts::new_($item['articles_layout'], 'article'); } // avoid links to this page if (is_object($layout)) { $layout->set_focus('section:' . $item['id']); } // the maximum number of articles per page if (is_object($layout)) { $items_per_page = $layout->items_per_page(); } else { $items_per_page = ARTICLES_PER_PAGE; } // sub-sections targeting the main area if ($anchors = Sections::get_branch_at_anchor('section:' . $item['id'])) { // use ordering options set for the section if (preg_match('/\\barticles_by_([a-z_]+)\\b/i', $item['options'], $matches)) { $order = $matches[1]; } else { $order = 'edition'; } $items =& Articles::list_for_anchor_by($order, $anchors, 0, $items_per_page, $layout); // actually render the html for the section $content = ''; if (is_array($items) && is_string($item['articles_layout']) && $item['articles_layout'] == 'compact') { $content .= Skin::build_list($items, 'compact'); } elseif (is_array($items)) { $content .= Skin::build_list($items, 'decorated'); } elseif (is_string($items)) { $content .= $items;
/** * search for some keywords articles anchored to one precise section * (and its subsections) or array of sections. * * This function also searches in sub-sections, with up to three levels of depth. * * @see search.php * * Modification dates are taken into account to prefer freshest information. * * @link http://www.artfulcode.net/articles/full-text-searching-mysql/ * * @param mixed the id of the section or array of sections to look in * @param string the search string * @param float maximum score to look at * @param int the number of items to display * @param mixed the layout, if any * @return NULL on error, else an ordered array of array($score, $summary) */ public static function &search_in_section($section_id, $pattern, $offset = 1.0, $count = 10, $layout = 'search') { global $context; // sanity check if (!($pattern = trim($pattern))) { $output = NULL; return $output; } // restrict the query to addressable content $where = Articles::get_sql_where(); // search is restricted to one section if (is_numeric($section_id)) { // look for children $anchors = Sections::get_branch_at_anchor('section:' . $section_id); // the full set of sections searched $where .= " AND (anchor IN ('" . join("', '", $anchors) . "'))"; } elseif (is_array($section_id)) { $where .= " AND (anchor IN ('" . join("', '", $section_id) . "'))"; } // anonymous surfers and subscribers will see only published articles if (!Surfer::is_member()) { $where .= " AND NOT ((publish_date is NULL) OR (publish_date <= '0000-00-00'))" . " AND (publish_date < '" . $context['now'] . "')"; } // only consider live articles $where .= " AND ((expiry_date is NULL) " . "OR (expiry_date <= '" . NULL_DATE . "') OR (expiry_date > '" . $context['now'] . "'))"; // how to compute the score for articles $score = "(MATCH(title, source, introduction, overlay, description)" . " AGAINST('" . SQL::escape($pattern) . "' IN BOOLEAN MODE)" . "/SQRT(GREATEST(1.1, DATEDIFF(NOW(), edit_date))))"; // the list of articles $query = "SELECT *, " . $score . " AS score FROM " . SQL::table_name('articles') . " AS articles" . " WHERE (" . $where . ") AND (" . $score . " < " . $offset . ") AND (" . $score . " > 0)" . " ORDER BY score DESC" . " LIMIT " . $count; $output =& Articles::list_selected(SQL::query($query), $layout); return $output; }
/** * list articles as slashdot do * * @param resource the SQL result * @return string the rendered text * * @see layouts/layout.php **/ function layout($result) { global $context; // we return some text $text = ''; // empty list if (!SQL::count($result)) { return $text; } // layout in a table $text = Skin::table_prefix('wide'); // 'even' is used for title rows, 'odd' for detail rows $class_title = 'odd'; $class_detail = 'even'; // build a list of sections $family = ''; include_once $context['path_to_root'] . 'articles/article.php'; include_once $context['path_to_root'] . 'comments/comments.php'; include_once $context['path_to_root'] . 'links/links.php'; while ($item = SQL::fetch($result)) { // change the family if ($item['family'] != $family) { $family = $item['family']; // show the family $text .= Skin::table_suffix() . '<h2><span>' . $family . ' </span></h2>' . "\n" . Skin::table_prefix('wide'); } // document this section $content = $prefix = $title = $suffix = $icon = ''; $menu = array(); // permalink $url = Sections::get_permalink($item); // get the anchor $anchor = Anchors::get($item['anchor']); // get the related overlay, if any $overlay = Overlay::load($item, 'section:' . $item['id']); // use the title to label the link if (is_object($overlay)) { $title = Codes::beautify_title($overlay->get_text('title', $item)); } else { $title = Codes::beautify_title($item['title']); } // signal restricted and private sections if ($item['active'] == 'N') { $prefix .= PRIVATE_FLAG; } elseif ($item['active'] == 'R') { $prefix .= RESTRICTED_FLAG; } // this is another row of the output $text .= '<tr class="' . $class_title . '"><th>' . $prefix . Skin::build_link($url, $title, 'basic', i18n::s('View the section')) . $suffix . '</th></tr>' . "\n"; // document most recent page here $content = $prefix = $title = $suffix = $icon = ''; $menu = array(); // branches of this tree $anchors = Sections::get_branch_at_anchor('section:' . $item['id']); // get last post $article =& Articles::get_newest_for_anchor($anchors, TRUE); if ($article['id']) { // permalink $url = Articles::get_permalink($article); // get the anchor $anchor = Anchors::get($article['anchor']); // get the related overlay, if any $overlay = Overlay::load($item, 'section:' . $item['id']); // use the title to label the link if (is_object($overlay)) { $title = Codes::beautify_title($overlay->get_text('title', $article)); } else { $title = Codes::beautify_title($article['title']); } // signal restricted and private articles if ($article['active'] == 'N') { $prefix .= PRIVATE_FLAG; } elseif ($article['active'] == 'R') { $prefix .= RESTRICTED_FLAG; } // the icon to put aside if ($article['thumbnail_url']) { $icon = $article['thumbnail_url']; } // the icon to put aside if (!$icon && is_callable(array($anchor, 'get_bullet_url'))) { $icon = $anchor->get_bullet_url(); } if ($icon) { $icon = '<a href="' . $context['url_to_root'] . $url . '"><img src="' . $icon . '" class="right_image" alt="" title="' . encode_field(i18n::s('View the page')) . '" /></a>'; } // the introductory text if ($article['introduction']) { $content .= Codes::beautify_introduction($article['introduction']); } elseif (!is_object($overlay)) { $handle = new Article(); $handle->load_by_content($article); $content .= $handle->get_teaser('teaser'); } // insert overlay data, if any if (is_object($overlay)) { $content .= $overlay->get_text('list', $article); } // link to description, if any if (trim($article['description'])) { $menu[] = Skin::build_link($url, i18n::s('Read more') . MORE_IMG, 'span', i18n::s('View the page')); } // info on related files if ($count = Files::count_for_anchor('article:' . $article['id'])) { $menu[] = sprintf(i18n::ns('%d file', '%d files', $count), $count); } // info on related comments if ($count = Comments::count_for_anchor('article:' . $article['id'])) { $menu[] = sprintf(i18n::ns('%d comment', '%d comments', $count), $count); } // discuss if (Comments::allow_creation($article, $anchor)) { $menu[] = Skin::build_link(Comments::get_url('article:' . $article['id'], 'comment'), i18n::s('Discuss'), 'span'); } // the main anchor link if (is_object($anchor) && (!isset($this->focus) || $article['anchor'] != $this->focus)) { $menu[] = Skin::build_link($anchor->get_url(), ucfirst($anchor->get_title()), 'span', i18n::s('View the section')); } // list up to three categories by title, if any if ($items =& Members::list_categories_by_title_for_member('article:' . $article['id'], 0, 3, 'raw')) { foreach ($items as $id => $attributes) { $menu[] = Skin::build_link(Categories::get_permalink($attributes), $attributes['title'], 'span'); } } // append a menu $content .= '<p>' . Skin::finalize_list($menu, 'menu') . '</p>'; // this is another row of the output $text .= '<tr class="' . $class_detail . '"><td>' . '<h3 class="top"><span>' . Skin::build_link($url, $prefix . $title . $suffix, 'basic', i18n::s('View the page')) . '</span></h3>' . '<div class="content">' . $icon . $content . '</div>' . '</td></tr>' . "\n"; } } // end of processing SQL::free($result); $text .= Skin::table_suffix(); return $text; }
/** * render a compact list of recent modifications * * The provided anchor can reference: * - a section 'section:123' * - a category 'category:456' * - a user 'user:789' * - 'self' * - nothing * * @param string the anchor (e.g. 'section:123') * @param string layout to use * @return string the rendered text **/ public static function render_updated($layout = 'simple', $anchor = '') { global $context; // we return some text; $text = ''; // number of items to display $count = COMPACT_LIST_SIZE; if (($position = strpos($anchor, ',')) !== FALSE) { $count = (int) trim(substr($anchor, $position + 1)); if (!$count) { $count = COMPACT_LIST_SIZE; } $anchor = trim(substr($anchor, 0, $position)); } // scope is limited to current surfer if ($anchor == 'self' && Surfer::get_id()) { $anchor = 'user:'******'section:') === 0) { // look at this branch of the content tree $anchors = Sections::get_branch_at_anchor($anchor); // query the database and layout that stuff $text = Articles::list_for_anchor_by('edition', $anchors, 0, $count, $layout); // scope is limited to one category } elseif (strpos($anchor, 'category:') === 0) { // first level of depth $anchors = array(); // get sections linked to this category if ($topics = Members::list_sections_by_title_for_anchor($anchor, 0, 50, 'raw')) { foreach ($topics as $id => $not_used) { $anchors = array_merge($anchors, array('section:' . $id)); } } // second level of depth if (count($topics) && count($anchors) < 2000) { $topics = Sections::get_children_of_anchor($anchors); $anchors = array_merge($anchors, $topics); } // third level of depth if (count($topics) && count($anchors) < 2000) { $topics = Sections::get_children_of_anchor($anchors); $anchors = array_merge($anchors, $topics); } // fourth level of depth if (count($topics) && count($anchors) < 2000) { $topics = Sections::get_children_of_anchor($anchors); $anchors = array_merge($anchors, $topics); } // fifth level of depth if (count($topics) && count($anchors) < 2000) { $topics = Sections::get_children_of_anchor($anchors); $anchors = array_merge($anchors, $topics); } // the category itself is an anchor $anchors[] = $anchor; // ensure anchors are referenced only once $anchors = array_unique($anchors); // query the database and layout that stuff $text = Members::list_articles_by_date_for_anchor($anchors, 0, $count, $layout); // scope is limited to pages of one surfer } elseif (strpos($anchor, 'user:'******'edition', substr($anchor, 5), 0, $count, $layout); } else { $text = Articles::list_by('edition', 0, $count, $layout); } // we have an array to format if (is_array($text)) { $text = Skin::build_list($text, $layout); } // job done return $text; }