/** * Sets a section as the default. */ function section_set_default() { extract(psa(array('default_section'))); $exists = safe_row('name', 'txp_section', "name = '" . doSlash($default_section) . "'"); if ($exists && set_pref('default_section', $default_section, 'section', PREF_HIDDEN)) { send_script_response(announce(gTxt('default_section_updated'))); return; } send_script_response(announce(gTxt('section_save_failed'), E_ERROR)); }
/** * Renders a page navigation form. * * @param string $event Event * @param int $page Current page number * @param int $numPages Total pages * @param string $sort Sort criterion * @param string $dir Sort direction, either "asc" or "desc" * @param string $crit Search criterion * @param string $search_method Search method * @param int $total Total search term hit count [0] * @param int $limit First visible search term hit number [0] * @param string $step Step * @param int $list Number of displayed page links discounting jump links, previous and next * @return string HTML */ function nav_form($event, $page, $numPages, $sort = '', $dir = '', $crit = '', $search_method = '', $total = 0, $limit = 0, $step = 'list', $list = 5) { $out = array(); if ($crit != '' && $total > 1) { $out[] = announce(gTxt('showing_search_results', array('{from}' => ($page - 1) * $limit + 1, '{to}' => min($total, $page * $limit), '{total}' => $total)), TEXTPATTERN_ANNOUNCE_REGULAR); } if ($numPages > 1) { $nav = array(); $list--; $page = max(min($page, $numPages), 1); $start = max(1, min($numPages - $list, $page - floor($list / 2))); $end = min($numPages, $start + $list); $parameters = array('event' => $event, 'step' => $step, 'dir' => $dir, 'crit' => $crit, 'search_method' => $search_method); // Previous page. if ($page > 1) { $nav[] = PrevNextLink($event, $page - 1, gTxt('prev'), 'prev', $sort, $dir, $crit, $search_method, $step); } else { $nav[] = span(gTxt('prev'), array('class' => 'navlink-disabled', 'aria-disabled' => 'true')); } // Jump to the first page. if ($start > 1) { $nav[] = href(1, $parameters + array('page' => 1), array('class' => 'navlink')); } // Jump to mid. if ($start > 2) { $between = ceil($start / 2); $nav[] = href('…', $parameters + array('page' => $between), array('class' => 'navlink', 'title' => $between)); } // Page links. for ($i = $start; $i <= $end; $i++) { if ($i == $page) { $class = 'navlink-active'; } else { $class = 'navlink'; } $nav[] = href($i, $parameters + array('page' => $i), array('class' => $class)); } // Jump to mid. if ($end < $numPages - 1) { $between = $end + floor(($numPages - $end) / 2); $nav[] = href('…', $parameters + array('page' => $between), array('class' => 'navlink', 'title' => $between)); } // Jump to the last page. if ($end < $numPages) { $nav[] = href($numPages, $parameters + array('page' => $numPages), array('class' => 'navlink')); } // Next page. if ($page < $numPages) { $nav[] = PrevNextLink($event, $page + 1, gTxt('next'), 'next', $sort, $dir, $crit, $search_method, $step); } else { $nav[] = span(gTxt('next'), array('class' => 'navlink-disabled', 'aria-disabled' => 'true')); } $out[] = n . tag(tag(join(tag_end('li') . tag_start('li'), $nav), 'li'), 'ul', array('class' => 'nav-tertiary prev-next')); } return join('', $out); }
/** * Renders article editor form. * * @param string|array $message The activity message * @param bool $concurrent Treat as a concurrent save * @param bool $refresh_partials Whether refresh partial contents */ function article_edit($message = '', $concurrent = false, $refresh_partials = false) { global $vars, $txp_user, $prefs, $event, $view; extract($prefs); /* $partials is an array of: $key => array ( 'mode' => {PARTIAL_STATIC | PARTIAL_VOLATILE | PARTIAL_VOLATILE_VALUE}, 'selector' => $DOM_selector, 'cb' => $callback_function, 'html' => $return_value_of_callback_function (need not be intialised here) ) */ $partials = array('html_title' => array('mode' => PARTIAL_VOLATILE, 'selector' => 'title', 'cb' => 'article_partial_html_title'), 'sLastMod' => array('mode' => PARTIAL_VOLATILE_VALUE, 'selector' => '[name=sLastMod]', 'cb' => 'article_partial_value'), 'sPosted' => array('mode' => PARTIAL_VOLATILE_VALUE, 'selector' => '[name=sPosted]', 'cb' => 'article_partial_value'), 'sidehelp' => array('mode' => PARTIAL_VOLATILE, 'selector' => '#textfilter_group', 'cb' => 'article_partial_sidehelp'), 'url_title' => array('mode' => PARTIAL_STATIC, 'selector' => 'p.url-title', 'cb' => 'article_partial_url_title'), 'url_title_value' => array('mode' => PARTIAL_VOLATILE_VALUE, 'selector' => '#url-title', 'cb' => 'article_partial_url_title_value'), 'description' => array('mode' => PARTIAL_STATIC, 'selector' => 'p.description', 'cb' => 'article_partial_description'), 'description_value' => array('mode' => PARTIAL_VOLATILE_VALUE, 'selector' => '#description', 'cb' => 'article_partial_description_value'), 'keywords' => array('mode' => PARTIAL_STATIC, 'selector' => 'p.keywords', 'cb' => 'article_partial_keywords'), 'keywords_value' => array('mode' => PARTIAL_VOLATILE_VALUE, 'selector' => '#keywords', 'cb' => 'article_partial_keywords_value'), 'image' => array('mode' => PARTIAL_STATIC, 'selector' => '#image_group', 'cb' => 'article_partial_image'), 'custom_fields' => array('mode' => PARTIAL_STATIC, 'selector' => '#custom_field_group', 'cb' => 'article_partial_custom_fields'), 'recent_articles' => array('mode' => PARTIAL_VOLATILE, 'selector' => '#recent_group .recent', 'cb' => 'article_partial_recent_articles'), 'title' => array('mode' => PARTIAL_STATIC, 'selector' => 'p.title', 'cb' => 'article_partial_title'), 'title_value' => array('mode' => PARTIAL_VOLATILE_VALUE, 'selector' => '#title', 'cb' => 'article_partial_title_value'), 'article_clone' => array('mode' => PARTIAL_VOLATILE, 'selector' => '#article_partial_article_clone', 'cb' => 'article_partial_article_clone'), 'article_view' => array('mode' => PARTIAL_VOLATILE, 'selector' => '#article_partial_article_view', 'cb' => 'article_partial_article_view'), 'body' => array('mode' => PARTIAL_STATIC, 'selector' => 'p.body', 'cb' => 'article_partial_body'), 'excerpt' => array('mode' => PARTIAL_STATIC, 'selector' => 'p.excerpt', 'cb' => 'article_partial_excerpt'), 'author' => array('mode' => PARTIAL_VOLATILE, 'selector' => 'p.author', 'cb' => 'article_partial_author'), 'view_modes' => array('mode' => PARTIAL_VOLATILE, 'selector' => '#view_modes', 'cb' => 'article_partial_view_modes'), 'article_nav' => array('mode' => PARTIAL_VOLATILE, 'selector' => 'p.nav-tertiary', 'cb' => 'article_partial_article_nav'), 'status' => array('mode' => PARTIAL_VOLATILE, 'selector' => '#write-status', 'cb' => 'article_partial_status'), 'categories' => array('mode' => PARTIAL_STATIC, 'selector' => '#categories_group', 'cb' => 'article_partial_categories'), 'section' => array('mode' => PARTIAL_STATIC, 'selector' => 'p.section', 'cb' => 'article_partial_section'), 'comments' => array('mode' => PARTIAL_VOLATILE, 'selector' => '#write-comments', 'cb' => 'article_partial_comments'), 'posted' => array('mode' => PARTIAL_VOLATILE, 'selector' => '#write-timestamp', 'cb' => 'article_partial_posted'), 'expires' => array('mode' => PARTIAL_VOLATILE, 'selector' => '#write-expires', 'cb' => 'article_partial_expires')); // Add partials for custom fields (and their values which is redundant by // design, for plugins). global $cfs; foreach ($cfs as $k => $v) { $partials["custom_field_{$k}"] = array('mode' => PARTIAL_STATIC, 'selector' => "p.custom-field.custom-{$k}", 'cb' => 'article_partial_custom_field'); $partials["custom_{$k}"] = array('mode' => PARTIAL_STATIC, 'selector' => "#custom-{$k}", 'cb' => 'article_partial_value'); } extract(gpsa(array('view', 'from_view', 'step'))); // Newly-saved article. if (!empty($GLOBALS['ID'])) { $ID = $GLOBALS['ID']; $step = 'edit'; } else { $ID = gps('ID'); } // Switch to 'text' view upon page load and after article post. if (!$view || gps('save') || gps('publish')) { $view = 'text'; } if (!$step) { $step = "create"; } if ($step == "edit" && $view == "text" && !empty($ID) && $from_view != 'preview' && $from_view != 'html' && !$concurrent) { $pull = true; // It's an existing article - off we go to the database. $ID = assert_int($ID); $rs = safe_row("*, UNIX_TIMESTAMP(Posted) AS sPosted,\n UNIX_TIMESTAMP(Expires) AS sExpires,\n UNIX_TIMESTAMP(LastMod) AS sLastMod", 'textpattern', "ID = {$ID}"); if (empty($rs)) { return; } $rs['reset_time'] = $rs['publish_now'] = false; } else { $pull = false; // Assume they came from post. if ($from_view == 'preview' or $from_view == 'html') { $store_out = array(); $store = unserialize(base64_decode(ps('store'))); foreach ($vars as $var) { if (isset($store[$var])) { $store_out[$var] = $store[$var]; } } } else { $store_out = gpsa($vars); if ($concurrent) { $store_out['sLastMod'] = safe_field("UNIX_TIMESTAMP(LastMod) AS sLastMod", 'textpattern', "ID = {$ID}"); } if (!has_privs('article.set_markup') && !empty($ID)) { $oldArticle = safe_row("textile_body, textile_excerpt", 'textpattern', "ID = {$ID}"); if (!empty($oldArticle)) { $store_out['textile_body'] = $oldArticle['textile_body']; $store_out['textile_excerpt'] = $oldArticle['textile_excerpt']; } } } // Use preferred Textfilter as default and fallback. $hasfilter = new \Textpattern\Textfilter\Constraint(null); $validator = new Validator(); foreach (array('textile_body', 'textile_excerpt') as $k) { $hasfilter->setValue($store_out[$k]); $validator->setConstraints($hasfilter); if (!$validator->validate()) { $store_out[$k] = $use_textile; } } $rs = textile_main_fields($store_out); if (!empty($rs['exp_year'])) { if (empty($rs['exp_month'])) { $rs['exp_month'] = 1; } if (empty($rs['exp_day'])) { $rs['exp_day'] = 1; } if (empty($rs['exp_hour'])) { $rs['exp_hour'] = 0; } if (empty($rs['exp_minute'])) { $rs['exp_minute'] = 0; } if (empty($rs['exp_second'])) { $rs['exp_second'] = 0; } $rs['sExpires'] = safe_strtotime($rs['exp_year'] . '-' . $rs['exp_month'] . '-' . $rs['exp_day'] . ' ' . $rs['exp_hour'] . ':' . $rs['exp_minute'] . ':' . $rs['exp_second']); } if (!empty($rs['year'])) { $rs['sPosted'] = safe_strtotime($rs['year'] . '-' . $rs['month'] . '-' . $rs['day'] . ' ' . $rs['hour'] . ':' . $rs['minute'] . ':' . $rs['second']); } } $validator = new Validator(new SectionConstraint($rs['Section'])); if (!$validator->validate()) { $rs['Section'] = getDefaultSection(); } extract($rs); $GLOBALS['step'] = $step; if ($step != 'create' && isset($sPosted)) { // Previous record? $rs['prev_id'] = checkIfNeighbour('prev', $sPosted); // Next record? $rs['next_id'] = checkIfNeighbour('next', $sPosted); } else { $rs['prev_id'] = $rs['next_id'] = 0; } // Let plugins chime in on partials meta data. callback_event_ref('article_ui', 'partials_meta', 0, $rs, $partials); $rs['partials_meta'] =& $partials; // Get content for volatile partials. foreach ($partials as $k => $p) { if ($p['mode'] == PARTIAL_VOLATILE || $p['mode'] == PARTIAL_VOLATILE_VALUE) { $cb = $p['cb']; $partials[$k]['html'] = is_array($cb) ? call_user_func($cb, $rs, $k) : $cb($rs, $k); } } if ($refresh_partials) { $response[] = announce($message); $response[] = '$("#article_form [type=submit]").val(textpattern.gTxt("save"))'; if ($Status < STATUS_LIVE) { $response[] = '$("#article_form").addClass("saved").removeClass("published")'; } else { $response[] = '$("#article_form").addClass("published").removeClass("saved")'; } // Update the volatile partials. foreach ($partials as $k => $p) { // Volatile partials need a target DOM selector. if (empty($p['selector']) && $p['mode'] != PARTIAL_STATIC) { trigger_error("Empty selector for partial '{$k}'", E_USER_ERROR); } else { // Build response script. if ($p['mode'] == PARTIAL_VOLATILE) { // Volatile partials replace *all* of the existing HTML // fragment for their selector. $response[] = '$("' . $p['selector'] . '").replaceWith("' . escape_js($p['html']) . '")'; } elseif ($p['mode'] == PARTIAL_VOLATILE_VALUE) { // Volatile partial values replace the *value* of elements // matching their selector. $response[] = '$("' . $p['selector'] . '").val("' . escape_js($p['html']) . '")'; } } } send_script_response(join(";\n", $response)); // Bail out. return; } foreach ($partials as $k => $p) { if ($p['mode'] == PARTIAL_STATIC) { $cb = $p['cb']; $partials[$k]['html'] = is_array($cb) ? call_user_func($cb, $rs, $k) : $cb($rs, $k); } } $page_title = $ID ? $Title : gTxt('write'); pagetop($page_title, $message); $class = array(); if ($Status >= STATUS_LIVE) { $class[] = 'published'; } elseif ($ID) { $class[] = 'saved'; } if ($step !== 'create') { $class[] = 'async'; } echo n . tag_start('form', array('class' => $class, 'id' => 'article_form', 'name' => 'article_form', 'method' => 'post', 'action' => 'index.php')); if (!empty($store_out)) { echo hInput('store', base64_encode(serialize($store_out))); } echo hInput('ID', $ID) . eInput('article') . sInput($step) . hInput('sPosted', $sPosted) . hInput('sLastMod', $sLastMod) . hInput('AuthorID', $AuthorID) . hInput('LastModID', $LastModID) . n . '<input type="hidden" name="view" />'; echo n . '<div class="txp-layout-4col-cell-1-2-3">' . hed(gTxt('tab_write'), 1, array('class' => 'txp-heading')); echo n . '<div role="region" id="main_content">'; // View mode tabs. echo $partials['view_modes']['html']; // Title input. if ($view == 'preview') { echo n . '<div class="preview">' . graf(gTxt('title'), array('class' => 'alert-block information')) . hed($Title, 1, ' class="title"'); } elseif ($view == 'html') { echo n . '<div class="html">' . graf(gTxt('title'), array('class' => 'alert-block information')) . hed($Title, 1, ' class="title"'); } elseif ($view == 'text') { echo n . '<div class="text">' . $partials['title']['html']; } // Body. if ($view == 'preview') { echo n . '<div class="body">' . n . graf(gTxt('body'), array('class' => 'alert-block information')) . $Body_html . '</div>'; } elseif ($view == 'html') { echo graf(gTxt('body'), array('class' => 'alert-block information')) . n . tag(str_replace(array(n, t), array(br, sp . sp . sp . sp), txpspecialchars($Body_html)), 'pre', ' class="body"'); } else { echo $partials['body']['html']; } // Excerpt. if ($articles_use_excerpts) { if ($view == 'preview') { echo n . '<div class="excerpt">' . graf(gTxt('excerpt'), array('class' => 'alert-block information')) . $Excerpt_html . '</div>'; } elseif ($view == 'html') { echo graf(gTxt('excerpt'), array('class' => 'alert-block information')) . n . tag(str_replace(array(n, t), array(br, sp . sp . sp . sp), txpspecialchars($Excerpt_html)), 'pre', array('class' => 'excerpt')); } else { echo $partials['excerpt']['html']; } } echo hInput('from_view', $view), n . '</div>'; // Author. if ($view == "text" && $step != "create") { echo $partials['author']['html']; } echo n . '</div>' . n . '</div>'; // End of .txp-layout-4col-cell-1-2-3. // Sidebar column (only shown if in text editing view). if ($view == 'text') { echo n . '<div class="txp-layout-4col-cell-4alt">'; // 'Publish/Save' button. if ($step == 'create' and empty($GLOBALS['ID'])) { if (has_privs('article.publish')) { $push_button = fInput('submit', 'publish', gTxt('publish'), 'publish'); } else { $push_button = fInput('submit', 'publish', gTxt('save'), 'publish'); } echo graf($push_button, array('class' => 'txp-save')); } elseif ($Status >= STATUS_LIVE && has_privs('article.edit.published') || $Status >= STATUS_LIVE && $AuthorID === $txp_user && has_privs('article.edit.own.published') || $Status < STATUS_LIVE && has_privs('article.edit') || $Status < STATUS_LIVE && $AuthorID === $txp_user && has_privs('article.edit.own')) { echo graf(fInput('submit', 'save', gTxt('save'), 'publish'), array('class' => 'txp-save')); } // View/Duplicate/Create new article links. $an_cb = href('<span class="ui-icon ui-extra-icon-new-document"></span> ' . gTxt('create_new'), 'index.php?event=article', array('class' => 'txp-new')); $ac_cb = $rs['partials_meta']['article_clone']['cb']; $av_cb = $rs['partials_meta']['article_view']['cb']; echo $step != 'create' ? graf($an_cb . $ac_cb($rs) . $av_cb($rs), array('class' => 'txp-actions')) : ''; // Prev/next article links. if ($step != 'create' and ($rs['prev_id'] or $rs['next_id'])) { echo $partials['article_nav']['html']; } echo n . '<div role="region" id="supporting_content">'; // 'Sort and display' section. echo pluggable_ui('article_ui', 'sort_display', wrapRegion('txp-write-sort-group', $partials['status']['html'] . $partials['section']['html'] . $partials['categories']['html'], '', gTxt('sort_display')), $rs); // 'Date and time' collapsible section. if ($step == "create" and empty($GLOBALS['ID'])) { // Timestamp. // Avoiding modified date to disappear. if (!empty($store_out['year'])) { $persist_timestamp = safe_strtotime($store_out['year'] . '-' . $store_out['month'] . '-' . $store_out['day'] . ' ' . $store_out['hour'] . ':' . $store_out['minute'] . ':' . $store_out['second']); } else { $persist_timestamp = time(); } $posted_block = pluggable_ui('article_ui', 'timestamp', inputLabel('year', tsi('year', '%Y', $persist_timestamp, '', 'year') . ' <span role="separator">/</span> ' . tsi('month', '%m', $persist_timestamp, '', 'month') . ' <span role="separator">/</span> ' . tsi('day', '%d', $persist_timestamp, '', 'day'), 'publish_date', array('timestamp', 'instructions_publish_date'), array('class' => 'txp-form-field date posted')) . inputLabel('hour', tsi('hour', '%H', $persist_timestamp, '', 'hour') . ' <span role="separator">:</span> ' . tsi('minute', '%M', $persist_timestamp, '', 'minute') . ' <span role="separator">:</span> ' . tsi('second', '%S', $persist_timestamp, '', 'second'), 'publish_time', array('', 'instructions_publish_time'), array('class' => 'txp-form-field time posted')) . n . tag(checkbox('publish_now', '1', $publish_now, '', 'publish_now') . n . tag(gTxt('set_to_now'), 'label', array('for' => 'publish_now')), 'div', array('class' => 'posted-now')), array('sPosted' => $persist_timestamp) + $rs); // Expires. if (!empty($store_out['exp_year'])) { $persist_timestamp = safe_strtotime($store_out['exp_year'] . '-' . $store_out['exp_month'] . '-' . $store_out['exp_day'] . ' ' . $store_out['exp_hour'] . ':' . $store_out['exp_minute'] . ':' . $store_out['second']); } else { $persist_timestamp = 0; } $expires_block = pluggable_ui('article_ui', 'expires', inputLabel('exp_year', tsi('exp_year', '%Y', $persist_timestamp, '', 'exp_year') . ' <span role="separator">/</span> ' . tsi('exp_month', '%m', $persist_timestamp, '', 'exp_month') . ' <span role="separator">/</span> ' . tsi('exp_day', '%d', $persist_timestamp, '', 'exp_day'), 'expire_date', array('expires', 'instructions_expire_date'), array('class' => 'txp-form-field date expires')) . inputLabel('exp_hour', tsi('exp_hour', '%H', $persist_timestamp, '', 'exp_hour') . ' <span role="separator">:</span> ' . tsi('exp_minute', '%M', $persist_timestamp, '', 'exp_minute') . ' <span role="separator">:</span> ' . tsi('exp_second', '%S', $persist_timestamp, '', 'exp_second'), 'expire_time', array('', 'instructions_expire_time'), array('class' => 'txp-form-field time expires')), $rs); } else { // Timestamp. $posted_block = $partials['posted']['html']; // Expires. $expires_block = $partials['expires']['html']; } echo wrapRegion('txp-dates-group', $posted_block . $expires_block, 'txp-dates-group-content', 'date_settings', 'article_dates'); // 'Meta' collapsible section. // 'URL-only title' field. $html_url_title = $partials['url_title']['html']; // 'Description' field. $html_description = $partials['description']['html']; // 'Keywords' field. $html_keywords = $partials['keywords']['html']; echo wrapRegion('txp-meta-group', $html_url_title . $html_description . $html_keywords, 'txp-meta-group-content', 'meta', 'article_meta'); // 'Comment options' collapsible section. echo wrapRegion('txp-comments-group', $partials['comments']['html'], 'txp-comments-group-content', 'comment_settings', 'article_comments', $use_comments == 1 ? '' : 'empty'); // 'Article image' collapsible section. echo $partials['image']['html']; // 'Custom fields' collapsible section. echo $partials['custom_fields']['html']; // 'Advanced options' collapsible section. // 'Article markup'/'Excerpt markup' selection. if (has_privs('article.set_markup')) { $html_markup = inputLabel('markup-body', pref_text('textile_body', $textile_body, 'markup-body'), 'article_markup', array('', 'instructions_textile_body'), array('class' => 'txp-form-field markup markup-body')) . inputLabel('markup-excerpt', pref_text('textile_excerpt', $textile_excerpt, 'markup-excerpt'), 'excerpt_markup', array('', 'instructions_textile_excerpt'), array('class' => 'txp-form-field markup markup-excerpt')); } else { $html_markup = ''; } $html_markup = pluggable_ui('article_ui', 'markup', $html_markup, $rs); // 'Override form' selection. $form_pop = $allow_form_override ? form_pop($override_form, 'override-form') : ''; $html_override = $form_pop ? pluggable_ui('article_ui', 'override', inputLabel('override-form', $form_pop, 'override_default_form', array('override_form', 'instructions_override_form'), array('class' => 'txp-form-field override-form')), $rs) : ''; echo wrapRegion('txp-advanced-group', $html_markup . $html_override, 'txp-advanced-group-content', 'advanced_options', 'article_advanced'); // Custom menu entries. echo pluggable_ui('article_ui', 'extend_col_1', '', $rs); // 'Text formatting help' collapsible section. echo $partials['sidehelp']['html']; // 'Recent articles' collapsible section. echo wrapRegion('txp-recent-group', $partials['recent_articles']['html'], 'txp-recent-group-content', 'recent_articles', 'article_recent'); echo n . '</div>'; // End of #supporting_content. echo n . '</div>'; // End of .txp-layout-4col-cell-4alt. } echo tInput() . n . '</form>'; }
/** * Renders a page navigation form. * * @param string $event Event * @param int $page Current page number * @param int $numPages Total pages * @param string $sort Sort criterion * @param string $dir Sort direction, either "asc" or "desc" * @param string $crit Search criterion * @param string $search_method Search method * @param int $total Total search term hit count [0] * @param int $limit First visible search term hit number [0] * @param string $step Step * @param int $list Number of displayed page links discounting jump links, previous and next * @return string HTML */ function nav_form($event, $page, $numPages, $sort = '', $dir = '', $crit = '', $search_method = '', $total = 0, $limit = 0, $step = 'list', $list = 5) { $out = array(); if ($crit != '' && $total > 1) { $out[] = announce(gTxt('showing_search_results', array('{from}' => ($page - 1) * $limit + 1, '{to}' => min($total, $page * $limit), '{total}' => $total)), TEXTPATTERN_ANNOUNCE_REGULAR); } if ($numPages > 1) { $nav = array(); $list--; $page = max(min($page, $numPages), 1); $start = max(1, min($numPages - $list, $page - floor($list / 2))); $end = min($numPages, $start + $list); $parameters = array('event' => $event, 'step' => $step, 'dir' => $dir, 'crit' => $crit, 'search_method' => $search_method); // Previous page. if ($page > 1) { $nav[] = n . PrevNextLink($event, $page - 1, gTxt('prev'), 'prev', $sort, $dir, $crit, $search_method, $step); } else { $nav[] = n . span(span(gTxt('prev'), array('class' => 'ui-icon ui-icon-arrowthick-1-w')), array('class' => 'disabled', 'aria-disabled' => 'true', 'aria-label' => gTxt('prev'))); } $nav[] = form(n . tag(gTxt('page'), 'label', array('for' => 'current-page')) . n . tag_void('input', array('class' => 'current-page', 'id' => 'current-page', 'name' => 'page', 'type' => 'text', 'size' => INPUT_XSMALL, 'inputmode' => 'numeric', 'pattern' => '[0-9]+', 'value' => $page)) . n . gTxt('of') . n . span($numPages, array('class' => 'total-pages')) . eInput($event) . hInput('sort', $sort) . hInput('dir', $dir) . hInput('crit', $crit) . hInput('search_method', $search_method), '', '', 'get'); // Next page. if ($page < $numPages) { $nav[] = n . PrevNextLink($event, $page + 1, gTxt('next'), 'next', $sort, $dir, $crit, $search_method, $step); } else { $nav[] = n . span(span(gTxt('next'), array('class' => 'ui-icon ui-icon-arrowthick-1-e')), array('class' => 'disabled', 'aria-disabled' => 'true', 'aria-label' => gTxt('next'))); } $out[] = n . tag(join($nav) . n, 'nav', array('class' => 'prev-next')); } return join('', $out); }