News:

Bored?  Looking to kill some time?  Want to chat with other SMF users?  Join us in IRC chat or Discord

Main Menu

Customising function constructPageIndex (nasty evil stuffz)

Started by Antechinus, July 03, 2014, 09:56:07 PM

Previous topic - Next topic

Antechinus

Ok all you back end geniuses, I am needing a bit of guidance here. :D

What I want to do is a better implementation of "Previous page" and "Next page" buttons for function constructPageIndex, as well as adding some decent styling hooks to the same, and turning the whole shebang into a proper list (which it really ought to be).

The way I want to do this is by assigning an extra class to the existing class="navPages" where I want it. This is better than just chucking in extra spans all over the place (ye olde 2.1 method) for two reasons. First it's cleaner markup. Second, it will make for cleaner and more versatile CSS, because you will be able to style all elements with one basic class, and change specific anchors rather than having to play with spans inside them. You know you want it (you can even steal it for 2.1 ;)).

At the moment the 2.0.x base link is generated as this:

$base_link = '<a class="navPages" href="' . ($flexible_start ? $base_url : strtr($base_url, array('%' => '%%')) . ';start=%d') . '">%s</a> ';


I can sort out turning it into a list, simply by changing the base link generation to this:

$base_link = '<li><a class="navPages" href="' . ($flexible_start ? $base_url : strtr($base_url, array('%' => '%%')) . ';start=%d') . '">%s</a></li>';


With template calling it as this:

<div class="pagesection">
<ul class="pagelinks"><li class="stupid_bloat_for_teh_extra_uglies">', $txt['pages'], '</li>', $context['page_index'], '</li>
</div>


Which will enable me to easily hide the redundant text that tells me something I already knew: that these are "Pages:". :P


The tricky bit (for me) is assigning an extra class to the base link anchor. This would have to be handled in a couple of places, and is going to require some conditionals. The basic way of doing it is to use this for the "Previous page" button:

// Show 'Prev'
if ($start >= $num_per_page)
$pageindex .= sprintf($base_link, $start - $num_per_page, ' <span class="previous_page">'. $txt['previous page']. '</span>');



I want to change that to this:

[code]// Show 'Prev'
if ($start >= $num_per_page)
$pageindex .= sprintf($base_link, $start - $num_per_page, $txt['previous page']);



And have the base link sorted out so that it will generate this:

$base_link = '<a class="navPages previous_page" href="' . ($flexible_start ? $base_url : strtr($base_url, array('%' => '%%')) . ';start=%d') . '">%s</a> ';


Obviously the base link also has to generate this for the "Next page" link:

$base_link = '<a class="navPages next_page" href="' . ($flexible_start ? $base_url : strtr($base_url, array('%' => '%%')) . ';start=%d') . '">%s</a> ';


Short version: I need an extra variable in the base link markup, like this:

$base_link = '<a class="navPages %stuffz" href="' . ($flexible_start ? $base_url : strtr($base_url, array('%' => '%%')) . ';start=%d') . '">%s</a> ';

And some way of getting the right class assigned to %stuffz.

Any takers? :D

Antechinus

Bumpity. :P Come on guys, someone here must know how to do this. :D

Antechinus

Bleh. So I RTFPHPM a bit, did a lot of breaking stuff and swearing, and got it working.

No, you can't have the code. My code. Get yer own. :P

* Antechinus goes to write mod now...............

kat


Antechinus

You should try it sometime. Plenty of entertainment to be had.


Antechinus

Yay! I have bugz!

Quite apart from my personal collection of arthropods and prokaryote fauna, there is also a bug in the effing page index stuff. This is the one relevant to this thread.

So, it mostly works perfectly, except when splitting topics. That causes an undefined error:

   http://127.0.0.1/SMF_20x/index.php?action=splittopics;sa=selectTopics;subname=Split+test+1;topic=1.0;start2=0;move=reset;msg=0;xml
8: Undefined index: next_page
File: K:/VertrigoServ/www/SMF_20x/Sources/Subs.php
Line: 721


The line in Subs is the last one here:

// Show 'Next'.
$display_page = ($start + $num_per_page) > $max_value ? $max_value : ($start + $num_per_page);
if (($display_page <= $tmpMaxPages)&&($tmpMaxPages > 1))
$pageindex .= sprintf($base_link, $display_page, $txt['next_page'], ' next_page');


There is also a "previous page" link in the modified page index, but that never causes an undefined error. It's only the "next page" link that is acting up. Note that it doesn't give an undefined anywhere else. It only happens when you are actually splitting a topic via SplitTopics.template.php. That's apparently down to how the javascript in that template calls the updated page index when you shunt posts from the not-selected to selected areas.

function onDocReceived(XMLDoc)
{
var i, j, pageIndex;
for (i = 0; i < 2; i++)
{
pageIndex = XMLDoc.getElementsByTagName("pageIndex")[i];
setInnerHTML(document.getElementById("pageindex_" + pageIndex.getAttribute("section")), pageIndex.firstChild.nodeValue);
start[i] = pageIndex.getAttribute("startFrom");
}


The js is default SMF. I haven't touched it (yet). Anyone got any ideas on how to tweak it to make it behave?

Complete code for the modified page index function goes like this:

function constructPageIndex($base_url, &$start, $max_value, $num_per_page, $flexible_start = false)
{
global $modSettings, $txt;

// Save whether $start was less than 0 or not.
$start = (int) $start;
$start_invalid = $start < 0;

// Make sure $start is a proper variable - not less than 0.
if ($start_invalid)
$start = 0;
// Not greater than the upper bound.
elseif ($start >= $max_value)
$start = max(0, (int) $max_value - (((int) $max_value % (int) $num_per_page) == 0 ? $num_per_page : ((int) $max_value % (int) $num_per_page)));
// And it has to be a multiple of $num_per_page!
else
$start = max(0, (int) $start - ((int) $start % (int) $num_per_page));

// Wireless will need the protocol on the URL somewhere.
if (WIRELESS)
$base_url .= ';' . WIRELESS_PROTOCOL;

$base_link = '<li><a class="navPages%3$s" href="' . ($flexible_start ? $base_url : strtr($base_url, array('%' => '%%')) . ';start=%1$d') . '">%2$s</a></li>';

// Compact pages is off or on?
if (empty($modSettings['compactTopicPagesEnable']))
{
// Show the left arrow.
$pageindex = $start == 0 ? ' ' : sprintf($base_link, $start - $num_per_page, '&#171;', ' previous_page');

// Show all the pages.
$display_page = 1;
for ($counter = 0; $counter < $max_value; $counter += $num_per_page)
$pageindex .= $start == $counter && !$start_invalid ? '<li><a class="navPages current_page">' . $display_page++ . '</a></li>' : sprintf($base_link, $counter, $display_page++, '');

// Show the right arrow.
$display_page = ($start + $num_per_page) > $max_value ? $max_value : ($start + $num_per_page);
if ($start != $counter - $max_value && !$start_invalid)
$pageindex .= $display_page > $counter - $num_per_page ? ' ' : sprintf($base_link, $display_page, '&#187;', ' next_page');
}
else
{
// If they didn't enter an odd value, pretend they did.
$PageContiguous = (int) ($modSettings['compactTopicPagesContiguous'] - ($modSettings['compactTopicPagesContiguous'] % 2)) / 2;
$pageindex = '<li><span class="navPages pages_text">' .$txt['pages']. '</span></li>';

// Show 'Prev'
if ($start > ($num_per_page - 1))
$pageindex = sprintf($base_link, $start - $num_per_page, $txt['previous_page'], ' previous_page');

// Show the first page. (>1< ... 6 7 [8] 9 10 ... 15)
if ($start > $num_per_page * $PageContiguous)
$pageindex .= sprintf($base_link, 0, '1', '');

// Show the ... after the first page.  (1 >...< 6 7 [8] 9 10 ... 15)
if ($start > $num_per_page * ($PageContiguous + 1))
$pageindex .= '<li><span class="navPages page_dots" style="cursor: pointer;" onclick="' . htmlspecialchars('expandPages(this, ' . JavaScriptEscape(($flexible_start ? $base_url : strtr($base_url, array('%' => '%%')) . ';start=%1$d')) . ', ' . $num_per_page . ', ' . ($start - $num_per_page * $PageContiguous) . ', ' . $num_per_page . ');') . '">...</span></li>';

// Show the pages before the current one. (1 ... >6 7< [8] 9 10 ... 15)
for ($nCont = $PageContiguous; $nCont >= 1; $nCont--)
if ($start >= $num_per_page * $nCont)
{
$tmpStart = $start - $num_per_page * $nCont;
$pageindex .= sprintf($base_link, $tmpStart, $tmpStart / $num_per_page + 1,'');
}

// Show the current page. (1 ... 6 7 >[8]< 9 10 ... 15)
if (!$start_invalid)
$pageindex .= '<li><a class="navPages current_page">' . ($start / $num_per_page + 1) . '</a></li>';
else
$pageindex .= sprintf($base_link, $start, $start / $num_per_page + 1, '');

// Show the pages after the current one... (1 ... 6 7 [8] >9 10< ... 15)
$tmpMaxPages = (int) (($max_value - 1) / $num_per_page) * $num_per_page;
for ($nCont = 1; $nCont <= $PageContiguous; $nCont++)
if ($start + $num_per_page * $nCont <= $tmpMaxPages)
{
$tmpStart = $start + $num_per_page * $nCont;
$pageindex .= sprintf($base_link, $tmpStart, $tmpStart / $num_per_page + 1,'');
}

// Show the '...' part near the end. (1 ... 6 7 [8] 9 10 >...< 15)
if ($start + $num_per_page * ($PageContiguous + 1) < $tmpMaxPages)
$pageindex .= '<li><span class="navPages page_dots" style="cursor: pointer;" onclick="expandPages(this, \'' . ($flexible_start ? strtr($base_url, array('\'' => '\\\'')) : strtr($base_url, array('%' => '%%', '\'' => '\\\'')) . ';start=%1$d') . '\', ' . ($start + $num_per_page * ($PageContiguous + 1)) . ', ' . $tmpMaxPages . ', ' . $num_per_page . ');">...</span></li>';

// Show the last number in the list. (1 ... 6 7 [8] 9 10 ... >15<)
if ($start + $num_per_page * $PageContiguous < $tmpMaxPages)
$pageindex .= sprintf($base_link, $tmpMaxPages, $tmpMaxPages / $num_per_page + 1, '');

// Show 'Next'.
$display_page = ($start + $num_per_page) > $max_value ? $max_value : ($start + $num_per_page);
if (($display_page <= $tmpMaxPages)&&($tmpMaxPages > 1))
$pageindex .= sprintf($base_link, $display_page, $txt['next_page'], ' next_page');
}

return $pageindex;
}


With the template just calling the output like this:

<ul class="pagelinks" id="pageindex_selected">', $context['selected']['page_index'], '</ul>

Antechinus

Meh. Turns out the problem is probably coming from Sources/SplitTopic.php. Specifically, this bit:

// Fix an oversized starting page (to make sure both pageindexes are properly set).
if ($context['selected']['start'] >= $context['selected']['num_messages'])
$context['selected']['start'] = $context['selected']['num_messages'] <= $context['messages_per_page'] ? 0 : ($context['selected']['num_messages'] - (($context['selected']['num_messages'] % $context['messages_per_page']) == 0 ? $context['messages_per_page'] : ($context['selected']['num_messages'] % $context['messages_per_page'])));

// Build a page list of the not-selected topics...
$context['not_selected']['page_index'] = constructPageIndex($scripturl . '?action=splittopics;sa=selectTopics;subname=' . strtr(urlencode($_REQUEST['subname']), array('%' => '%%')) . ';topic=' . $topic . '.%1$d;start2=' . $context['selected']['start'], $context['not_selected']['start'], $context['not_selected']['num_messages'], $context['messages_per_page'], true);
// ...and one of the selected topics.
$context['selected']['page_index'] = constructPageIndex($scripturl . '?action=splittopics;sa=selectTopics;subname=' . strtr(urlencode($_REQUEST['subname']), array('%' => '%%')) . ';topic=' . $topic . '.' . $context['not_selected']['start'] . ';start2=%1$d', $context['selected']['start'], $context['selected']['num_messages'], $context['messages_per_page'], true);


Obviously this means nobody will have a clue how it works. Go on, prove me wrong.

Arantor

So where is $txt['next_page'] defined?

Also, why use a language string instead of something like &raquo; ?

Antechinus

To answer the second question first, because for various reasons I hate &raquo;. ;)

The $txt is defined in ThemeStrings.english.php, and in Subs.php.

// Custom strings for previous/next pages.
$txt['previous_page'] = 'previous';
$txt['next_page'] = 'next';


And Subs:

function constructPageIndex($base_url, &$start, $max_value, $num_per_page, $flexible_start = false)
{
global $modSettings, $txt;

// Save whether $start was less than 0 or not.
$start = (int) $start;
$start_invalid = $start < 0;

// Make sure $start is a proper variable - not less than 0.
if ($start_invalid)
$start = 0;
// Not greater than the upper bound.
elseif ($start >= $max_value)
$start = max(0, (int) $max_value - (((int) $max_value % (int) $num_per_page) == 0 ? $num_per_page : ((int) $max_value % (int) $num_per_page)));
// And it has to be a multiple of $num_per_page!
else
$start = max(0, (int) $start - ((int) $start % (int) $num_per_page));

// Wireless will need the protocol on the URL somewhere.
if (WIRELESS)
$base_url .= ';' . WIRELESS_PROTOCOL;

$base_link = '<li><a class="navPages%3$s" href="' . ($flexible_start ? $base_url : strtr($base_url, array('%' => '%%')) . ';start=%1$d') . '">%2$s</a></li>';

// Compact pages is off or on?
if (empty($modSettings['compactTopicPagesEnable']))
{
// Show the left arrow.
$pageindex = $start == 0 ? ' ' : sprintf($base_link, $start - $num_per_page, '&#171;', ' previous_page');

// Show all the pages.
$display_page = 1;
for ($counter = 0; $counter < $max_value; $counter += $num_per_page)
$pageindex .= $start == $counter && !$start_invalid ? '<li><a class="navPages current_page">' . $display_page++ . '</a></li>' : sprintf($base_link, $counter, $display_page++, '');

// Show the right arrow.
$display_page = ($start + $num_per_page) > $max_value ? $max_value : ($start + $num_per_page);
if ($start != $counter - $max_value && !$start_invalid)
$pageindex .= $display_page > $counter - $num_per_page ? ' ' : sprintf($base_link, $display_page, '&#187;', ' next_page');
}
else
{
// If they didn't enter an odd value, pretend they did.
$PageContiguous = (int) ($modSettings['compactTopicPagesContiguous'] - ($modSettings['compactTopicPagesContiguous'] % 2)) / 2;
$pageindex = '<li><span class="navPages pages_text">' .$txt['pages']. '</span></li>';

// Show 'Prev'
if ($start > ($num_per_page - 1))
$pageindex = sprintf($base_link, $start - $num_per_page, $txt['previous_page'], ' previous_page');

// Show the first page. (>1< ... 6 7 [8] 9 10 ... 15)
if ($start > $num_per_page * $PageContiguous)
$pageindex .= sprintf($base_link, 0, '1', '');

// Show the ... after the first page.  (1 >...< 6 7 [8] 9 10 ... 15)
if ($start > $num_per_page * ($PageContiguous + 1))
$pageindex .= '<li><span class="navPages page_dots" style="cursor: pointer;" onclick="' . htmlspecialchars('expandPages(this, ' . JavaScriptEscape(($flexible_start ? $base_url : strtr($base_url, array('%' => '%%')) . ';start=%1$d')) . ', ' . $num_per_page . ', ' . ($start - $num_per_page * $PageContiguous) . ', ' . $num_per_page . ');') . '">...</span></li>';

// Show the pages before the current one. (1 ... >6 7< [8] 9 10 ... 15)
for ($nCont = $PageContiguous; $nCont >= 1; $nCont--)
if ($start >= $num_per_page * $nCont)
{
$tmpStart = $start - $num_per_page * $nCont;
$pageindex .= sprintf($base_link, $tmpStart, $tmpStart / $num_per_page + 1,'');
}

// Show the current page. (1 ... 6 7 >[8]< 9 10 ... 15)
if (!$start_invalid)
$pageindex .= '<li><a class="navPages current_page">' . ($start / $num_per_page + 1) . '</a></li>';
else
$pageindex .= sprintf($base_link, $start, $start / $num_per_page + 1, '');

// Show the pages after the current one... (1 ... 6 7 [8] >9 10< ... 15)
$tmpMaxPages = (int) (($max_value - 1) / $num_per_page) * $num_per_page;
for ($nCont = 1; $nCont <= $PageContiguous; $nCont++)
if ($start + $num_per_page * $nCont <= $tmpMaxPages)
{
$tmpStart = $start + $num_per_page * $nCont;
$pageindex .= sprintf($base_link, $tmpStart, $tmpStart / $num_per_page + 1,'');
}

// Show the '...' part near the end. (1 ... 6 7 [8] 9 10 >...< 15)
if ($start + $num_per_page * ($PageContiguous + 1) < $tmpMaxPages)
$pageindex .= '<li><span class="navPages page_dots" style="cursor: pointer;" onclick="expandPages(this, \'' . ($flexible_start ? strtr($base_url, array('\'' => '\\\'')) : strtr($base_url, array('%' => '%%', '\'' => '\\\'')) . ';start=%1$d') . '\', ' . ($start + $num_per_page * ($PageContiguous + 1)) . ', ' . $tmpMaxPages . ', ' . $num_per_page . ');">...</span></li>';

// Show the last number in the list. (1 ... 6 7 [8] 9 10 ... >15<)
if ($start + $num_per_page * $PageContiguous < $tmpMaxPages)
$pageindex .= sprintf($base_link, $tmpMaxPages, $tmpMaxPages / $num_per_page + 1, '');

// Show 'Next'.
$display_page = ($start + $num_per_page) > $max_value ? $max_value : ($start + $num_per_page);
if (($display_page <= $tmpMaxPages)&&($tmpMaxPages > 1))
$pageindex .= sprintf($base_link, $display_page, $txt['next_page'], ' next_page');
}

return $pageindex;
}

Arantor

ThemeStrings isn't loaded in XML mode and it's running in XML mode as per the ;xml URL you provided.

Either modify Subs.php to declare them if not otherwise declared or move the definition to index.language.php.

Antechinus

Ok, but the funny thing is that when I disabled that js by commenting it out, the problem still occurred. That's what led me to now think it's likely to be a Sources problem rather than a js problem.

I don't want to stick the strings in index.english.php since that's not doable for a mod (want to package the thing). So, how would you suggest modifying Subs?

Arantor

Well, the URL *clearly* says it's calling a ;xml URL and in that circumstance it won't be loaded because the theme doesn't get fully loaded. Whatever JS you commented out is almost certainly not the JS calling for segments of a topic via XML...

The simplest way of doing this in Subs.php is to have this after the global declaration:

if (!isset($txt['previous_page']))
    $txt['previous_page'] = 'previous';
if (!isset($txt['next_page']))
   $txt['next_page'] = 'next';

Antechinus

Ok, but that will be untranslatable. Is there a way of doing it that will allow various languages to use the right translation? What about Modifications.english.php? Does that get loaded in XML mode?

Arantor

Yes, Modifications is loaded in literally every scenario. It's the only thing that is.

The different possibilities:
* Wireless - loads index, Wireless and Modifications
* XML - loads index and Modifications
* no action specified or on the list of simple actions (which don't require much theme stuff, e.g. print page) - loads index and Modifications
* everything else, load Modifications and whatever the theme says it wants to load in $settings['theme_templates'], if not specified, use index. (So on a stock install, index is used anyway)

Antechinus

Ok cool. I'll give it a bash with the strings in that one then.

Antechinus

Yup, that works. Sorted. :D

(Actually they'd have to go in that file for a packaged version anyway. I just hadn't thought of trying it on the test theme, which has strings for Africa).

Arantor

And that's what you get for daring people to prove you wrong :P

Antechinus

Yeah well, the last time I asked for a bit of help in this thread no bugger answered, so I figured give them a bit of a dare and they'll want to prove me wrong. Bloody worked a treat. :D

Antechinus

Ay up. Was just going over this again and had a brainwave, which I should have thought of before. Pseudos. Ditch all the txt strings and just use pseudos. Easy to style, unlimited choice of content, and no translation issues. D'oh.

* Antechinus is using pseudos now, just in case you were wondering.

Biology Forums

Quote from: Antechinus on January 09, 2015, 08:02:47 PM
Ay up. Was just going over this again and had a brainwave, which I should have thought of before. Pseudos. Ditch all the txt strings and just use pseudos. Easy to style, unlimited choice of content, and no translation issues. D'oh.

* Antechinus is using pseudos now, just in case you were wondering.

Could you provide us examples of the fruit of your labour?

Antechinus

#21
Ok. Desktop and mobile, with dots and expanded.

The shiny indicators for the next/previous buttons are done with CSS borders on :before pseudo elements. The actual HTML coming from Subs.php is just a basic non-breaking space. The default text that says "Pages:" before the list is still there, but now has a defined class so it can be hidden by display: none; if you don't want it (I obviously don't).

This also applies to the tiny <<  >> things on the message index. Basically, all ugly stuff in Sources is replaced with non-breaking spaces, and all visible content can be styled up with your choice of CSS. Everything has the ruling class of .navPages, with everything apart from the basic page links also having an auxiliary class for easy targeting.

None of this requires template edits now either. I dropped the idea of using an unordered list (too much PITA for not enough benefit) so all of this will just drop straight into default templates markup via $context['page_index']. I'm defo going to package this soon. Just need to do a bit more through checking for odd bits I may have missed. :)

ETA: By the way, with these buttons in action I think it's best to set admin to show only one contiguous page. That way it all fits on a phone, and with the ... buttons, plus the first and last page always displaying anyway, there's not really any need to display any more than one contiguous page. It's just a waste of space and will only annoy mobile users.

Antechinus

Oh yeah, code. Sources goes like this. You can see the space character that gets sprintf'd in with the rest.

// Show 'Prev'
if ($start > ($num_per_page - 1))
$pageindex = sprintf($base_link, $start - $num_per_page, '&nbsp;', ' previous_page');



And the CSS goes like this:

.previous_page, .next_page {
text-indent: 100%;
overflow: hidden;
padding: 2px 0 4px 0;
width: 33px;
}
.previous_page:before, .next_page:before {
content: "";
position: relative;
display: inline-block;
left: -26px;
vertical-align: middle;
height: 0;
margin: -1px 4px 1px 4px;
border-right: 12px solid #444;
border-top: 6px solid transparent;
border-bottom: 6px solid transparent;
}
.next_page:before {
border-right: none;
border-left: 12px solid #444;
}
.previous_page:hover:before {
border-right: 12px solid #b47a0b;
}
.next_page:hover:before {
border-left: 12px solid #b47a0b;
}


That can actually be simplified slightly as I was using some of the fancy positioning to hide the text strings, just before I thought of using a space character instead. The final version will knock a few lines off that. The space character is useful for the pseudos though, since it allows them to be vertically aligned without any bother.

Antechinus

Hey I have a general feedback/discussion question. This may be better in the Customization Development board now but I'm not fussed.

I have the code sorted so it's bug-free on all pages, but what I'm wondering is about the old default text that says "Pages: " in front of the list of numbers. I've never liked this text and usually remove it. I regard it as a waste of space since I expect everyone knows what the list of numbers is for (standard web practice for years and all that).

With the mod package, to make this text optional/stylable I have to do a find/replace on 35 hits in 12 files, which is ok. They can all be set to skip on error since they're not critical. The question is what to replace the default code with. At the moment I have stripped Subs.php so it doesn't generate content for the "Pages: " stuff (because I don't want it).

With the actual mod there are then two options:

1/ I can set the mod to replace it in the template with <span class="navPages page_text"> etc, if the consensus is that it would be better to keep the old default blurb while making it targetable via CSS, or

2/ I can just set the mod to remove the old stuff without bothering to replace it. This will obviously simplify the CSS for some people, if they don't want it displayed, and will also simplify the markup.

I think 2/ makes more sense, but am open to doing 1/ if there's enough call for it. :)

Arantor

No, there are more than 2 options.

3. Change the value of $txt['pages'] from inside constructPageIndex. The language string will have been loaded by then and can safely be changed by constructPageIndex in any circumstance I can think of.

4. Use the buffer hook to add a buffer and do a replacement on $txt['pages'] from after it has been displayed. Several mods now exist demonstrating this concept.

Antechinus

Ah, but you're forgetting a very nasty little piece of 2.0.x markup evil. The actual text is called from languages, but the colon and the space after it are not. They, for some obscure reason, are hard coded into the templates. Therefore, if you do not wish to have "Pages: " displayed, you will be left with a colon and a space in front of your page index if you try to jigger it via languages/hooks. The colon and space are also impossible to target via CSS, since they are not elements and cannot be assigned to a class.

IOW, template hacks FTW.

Arantor

So that rules 3 out. That most certainly does not rule 4 out. You just target $txt['pages'] plus the colon and space.


Arantor

Sure you want to learn how hooks work? Because this is where it starts to get crazy evil voodoo. Consider, essentially, that what I'm about to show you is 'the *entire* page HTML is going to get shoved into a PHP variable that you can abuse with str_replace for fun and profit.

Antechinus

Ok. Well TBH, that sounds like it can go do evil things with syphilitic goats for all I care. I'm thinking that if there's not an overwhelming desire for people to keep that frigging text, they'd be better off with clean markup. These are very minor template edits that, in practice, will not cause any problem. If someone has already edited their template there, which is not going to be very common, the mod will just skip.

Arantor

Then for your maintenance purposes you're probably best doing that. I'm just pointing out that there are alternatives that do not require vast edits - and if it were me, I would be quite comfortable adding a buffer and doing it that way. But I realise this is a specialised approach and not suited to everyone.

Antechinus

Yes but they're not vast edits. They're only tiny ones. It just so happens that there are 35 of them, but the vast majority of those are in templates that nobody apart from me is ever nuts enough to edit.

And FWIW, it'll still play nicely with your page dropdown mod. I've checked. Chalky would spew if it didn't. :D

Arantor


Antechinus

I didn't even know about it until today, but making it look smooth with what I'm planning is a piece of cake anyway. It's not a bad idea, although I'd never thought of it, and am not sure I'd ever want it once I have next/previous buttons running, but there's certainly no harm in it.

Antechinus

Ok, after sleeping on it I've decided to go with the clean solution: I'll just exterminate the "Pages: " BS. If anyone then throws a tizzy about its absence, I'll explain exactly how they can write their own mod to add it back in, while still keeping full styling flexibility and integrating with my mod, and tell them to go for it. :)

onepiece

If it's for a theme, I would suggest the following change to index.template.php file of your theme:

Code (Find) Select
$settings['require_theme_strings'] = false;
}


Code (Replace) Select
$settings['require_theme_strings'] = false;

$settings['output_buffers'] = 'strip_pages_label';
}

function strip_pages_label($buffer)
{
global $txt;

$buffer = str_replace($txt['pages'] . ': ', '', $buffer);

return $buffer;
}


The code to find is basically the end of 'template_init' function. You just define the function to use to modify the output using the $settings['output_buffers'] option. The function could be improved to use regular expressions not to strip unwanted matches too.

Antechinus

Yeah I want it as a mod though, because I want to rewrite the Subs.php output anyway. So I'm just going to hit the templates with edits. Like I said earlier, doesn't matter if some of them skip, but chances are nobody will have edited them anyway. It's very minor and obscure stuff.

Arantor

I don't understand why $txt['pages'] plus the extra markup wasn't part of constructPageIndex in the first place, when it never gets used without it as far as I remember.

onepiece

You could just do this in Subs.php then:

Code (Find) Select
return $pageindex;
}


Code (Replace) Select
add_integration_function('integrate_buffer', 'strip_pages_label', false);

return $pageindex;
}

function strip_pages_label($buffer)
{
global $txt;

$buffer = str_replace($txt['pages'] . ': ', '', $buffer);

return $buffer;
}


Sorry, it sounds painful to make a package for all those edits, so I couldn't resist. You could probably even avoid making changes to source files at all by making changes to the output using regular expressions.

Antechinus

Because they were bonkers in them days. Still are. :D

Anyway it'll get used without the bastard by the time I'm done with it. ;)

And no, it's not painful at all. I'm a themer. I make template edits all over the place, including complete markup and PHP rebuilds, just for fun. This is nothing.

Arantor

That last part is what I was getting at with the buffer hook business.

Hmm, I do wonder if I should consider adding some of the ideas from here into my  gallery mod because that replaces constructPageIndex with its own version.

Antechinus

Do you want the final code for what I'm running? IMO having a page index without next/previous buttons is just bonkers.

Arantor

Well, mine is vastly different in terms of logic, since I do things no one else does.

For example, if on page 2, I don't have a different link back to page 1, I have the canonical link, e.g. domain.com/index.php?media/item/my-item.1/ vs domain.com/index.php?media/item/my-item.1/page-2/ which also doesn't play nice with cPI hence I rolled my own. Am curious about markup since I emulated the visual style of SMF's standard, even down to the click to expand which also needed reworking.

But I am interested in thoughts on first/prev/next/last vs prev/next buttons.

Antechinus

#43
Ok well my markup is this, chosen so any element can easily be styled. This works flawlessly on any default template, with the next/previous only showing up on pages where they should (ie: not inside topics on message index).

My 2c about first/last buttons is that they are a waste of space. If doing things with mobile in mind you want compact. First/last buttons are just extra bloat, since SMF always displays the links to the first and last pages anyway FFS, and if you leave those two extra buttons out, and set the admin setting to 1 contiguous page, the whole page index while fit nicely on one line even with next/previous buttons.

This is good, since phones are relevant these days. Having more than one contiguous page displayed is pointless, since it's basically an hangover from the stupid old days when SMF did not have the things it really needs: previous page and next page buttons. So, if you're fixing that problem anyway, no worries.

Anyway, markup.

function constructPageIndex($base_url, &$start, $max_value, $num_per_page, $flexible_start = false)
{
global $modSettings, $txt;

// Save whether $start was less than 0 or not.
$start = (int) $start;
$start_invalid = $start < 0;

// Make sure $start is a proper variable - not less than 0.
if ($start_invalid)
$start = 0;
// Not greater than the upper bound.
elseif ($start >= $max_value)
$start = max(0, (int) $max_value - (((int) $max_value % (int) $num_per_page) == 0 ? $num_per_page : ((int) $max_value % (int) $num_per_page)));
// And it has to be a multiple of $num_per_page!
else
$start = max(0, (int) $start - ((int) $start % (int) $num_per_page));

// Wireless will need the protocol on the URL somewhere.
if (WIRELESS)
$base_url .= ';' . WIRELESS_PROTOCOL;

$base_link = '<a class="navPages%3$s" href="' . ($flexible_start ? $base_url : strtr($base_url, array('%' => '%%')) . ';start=%1$d') . '">%2$s</a>';

// Compact pages is off or on?
if (empty($modSettings['compactTopicPagesEnable']))
{
// Show the left arrow.
$pageindex = $start == 0 ? ' ' : sprintf($base_link, $start - $num_per_page, '&nbsp;', ' previous_page');

// Show all the pages.
$display_page = 1;
for ($counter = 0; $counter < $max_value; $counter += $num_per_page)
$pageindex .= $start == $counter && !$start_invalid ? '<a class="navPages current_page">' . $display_page++ . '</a>' : sprintf($base_link, $counter, $display_page++, '');

// Show the right arrow.
$display_page = ($start + $num_per_page) > $max_value ? $max_value : ($start + $num_per_page);
if ($start != $counter - $max_value && !$start_invalid)
$pageindex .= $display_page > $counter - $num_per_page ? ' ' : sprintf($base_link, $display_page, '&nbsp;', ' next_page');
}
else
{
// If they didn't enter an odd value, pretend they did.
$PageContiguous = (int) ($modSettings['compactTopicPagesContiguous'] - ($modSettings['compactTopicPagesContiguous'] % 2)) / 2;
$pageindex = '';

if (!$start_invalid)
{
// Show 'Prev'
if ($start > ($num_per_page - 1))
$pageindex = sprintf($base_link, $start - $num_per_page, '&nbsp;', ' previous_page');
}

// Show the first page. (>1< ... 6 7 [8] 9 10 ... 15)
if ($start > $num_per_page * $PageContiguous)
$pageindex .= sprintf($base_link, 0, '1', '');

// Show the ... after the first page.  (1 >...< 6 7 [8] 9 10 ... 15)
if ($start > $num_per_page * ($PageContiguous + 1))
$pageindex .= '<span class="navPages page_dots" style="cursor: pointer;" onclick="' . htmlspecialchars('expandPages(this, ' . JavaScriptEscape(($flexible_start ? $base_url : strtr($base_url, array('%' => '%%')) . ';start=%1$d')) . ', ' . $num_per_page . ', ' . ($start - $num_per_page * $PageContiguous) . ', ' . $num_per_page . ');') . '">...</span>';

// Show the pages before the current one. (1 ... >6 7< [8] 9 10 ... 15)
for ($nCont = $PageContiguous; $nCont >= 1; $nCont--)
if ($start >= $num_per_page * $nCont)
{
$tmpStart = $start - $num_per_page * $nCont;
$pageindex .= sprintf($base_link, $tmpStart, $tmpStart / $num_per_page + 1,'');
}

// Show the current page. (1 ... 6 7 >[8]< 9 10 ... 15)
if (!$start_invalid)
$pageindex .= '<span class="navPages current_page">' . ($start / $num_per_page + 1) . '</span>';
else
$pageindex .= sprintf($base_link, $start, $start / $num_per_page + 1, '');

// Show the pages after the current one... (1 ... 6 7 [8] >9 10< ... 15)
$tmpMaxPages = (int) (($max_value - 1) / $num_per_page) * $num_per_page;
for ($nCont = 1; $nCont <= $PageContiguous; $nCont++)
if ($start + $num_per_page * $nCont <= $tmpMaxPages)
{
$tmpStart = $start + $num_per_page * $nCont;
$pageindex .= sprintf($base_link, $tmpStart, $tmpStart / $num_per_page + 1,'');
}

// Show the '...' part near the end. (1 ... 6 7 [8] 9 10 >...< 15)
if ($start + $num_per_page * ($PageContiguous + 1) < $tmpMaxPages)
$pageindex .= '<span class="navPages page_dots" style="cursor: pointer;" onclick="expandPages(this, \'' . ($flexible_start ? strtr($base_url, array('\'' => '\\\'')) : strtr($base_url, array('%' => '%%', '\'' => '\\\'')) . ';start=%1$d') . '\', ' . ($start + $num_per_page * ($PageContiguous + 1)) . ', ' . $tmpMaxPages . ', ' . $num_per_page . ');">...</span>';

// Show the last number in the list. (1 ... 6 7 [8] 9 10 ... >15<)
if ($start + $num_per_page * $PageContiguous < $tmpMaxPages)
$pageindex .= sprintf($base_link, $tmpMaxPages, $tmpMaxPages / $num_per_page + 1, '');

if (!$start_invalid)
{
// Show 'Next'.
$display_page = ($start + $num_per_page) > $max_value ? $max_value : ($start + $num_per_page);
if (($display_page <= $tmpMaxPages)&&($tmpMaxPages > 1))
$pageindex .= sprintf($base_link, $display_page, '&nbsp;', ' next_page');
}
}

return $pageindex;
}


Like I mentioned earlier, just having the non-breaking space generated in markup is handy when it comes to styling up the pseudo elements which do the visible indicators in the CSS, because it allows you to get things aligned nicely by just using vertical-align: middle; on the pseudos. They need a bit of "text" in the parent anchor for this to work.

Antechinus

Oh by the way Ranty one: that old dropdown mod that you'd almost forgotten about seems, on further reflection, to be probably the ideal way of handling page index presentation on phones, if it is used in combination with next/previous page buttons (just for greater convenience). Selects can be made to look quite decent these days, even on dark themes on iOS and even without js hacks to mutate the default styling.

Obviously it would still be possible to have an expanded page index presentation on desktop, if anyone actually wanted it, but a select makes a lot of sense on phones. So I'd be marking it up to put the select right in the middle, and the next/previous buttons at each end. I might look into this.

Arantor


Antechinus

Yeah I was just mentioning it to Chalky on her site. She liked the idea for phones too, and she uses them a lot so would know. Seems like a winner.

Arantor

Yup. It'd be a pain for me to implement because I do weird stuff in my copy of the function but that's what I get for showing off with pretty URLs :P

Advertisement: