News:

SMF 2.1.4 has been released! Take it for a spin! Read more.

Main Menu

Using the smc_toggle object with pure links?

Started by bloc, March 10, 2010, 04:22:21 PM

Previous topic - Next topic

bloc

Today I ran across a mystery: in SMF 2 RC2/RC3 you can use the new toggle object for upshrinking panels. Now, i want to use it to save an option on-the-spot for  a theme width setting and I noticed you can define links instead of images in the source.

But what parameters can links have? Change the text on clicking perhaps? And could they run certain javascript code, like using DOM and setting a instant width on an area..?

Anybody have some info on this? 

Arantor

#1
Yay, another part of SMF that isn't documented :S

First up, if you haven't already, check out its code - Themes/default/scripts/script.js, line 799 onwards.

I don't use it myself, never had a need to, but glancing over its code, the object you supply to it to provide its options (yes, you supply an object, typically an inline one specified with { }) seems to support the following elements:

bToggleEnabled = true/false, whether it's even toggleable
bCurrentlyCollapsed = true/false, whether currently collapsed or not
aSwappableContainers = array of container tags that will be affected on shrink/unshrink, seems to relate to parent elements only
oCookieOptions = object for handling via a cookie:
  bUseCookie - true/false, whether to use cookies or not for this upshrink
  sCookieName - name of cookie (string)
oThemeOptions - object for handling if not using cookies:
  bUseThemeSettings - true/false, whether to store the setting in smf_themes for this user
  sOptionName - string, what value to use for the option in smf_themes
  sSessionVar and sSessionId - relating to the session key (directly to JavaScriptEscape($context['session_var']) and JavaScriptEscape($context['session_id'])) to session validate
aSwapImages = array of objects that relates to images you'll be swapping on collapse/uncollapse of this item (e.g. if you have two buttons to shrink/unshrink, you list them both here)  Each object contains:
  sId - string, id of the clickable element itself
  srcExpanded: string, URL of the image for collapsible button - uncollapsed, ideally using smf_images_url to be the theme path
  altExpanded: string, alt tag for the button when expanded, generally calling back to JavaScriptEscape of $txt[...] in PHP
  srcCollapsed: string, URL of the image for button when collapsed, much as srcExpanded
  altCollapsed: string, alt tag for the button when collapsed
aSwapLinks = array of objects that relates to text links you'll be swapping on collapse/uncollapse
  sId - string, id of the clickable element itself
  msgExpanded: string to use as the text for when expanded (like aSwapImages[].altExpanded)
  msgCollapsed: string to use when collapsed
funcOnBeforeCollapse - function to call before collapsing; pass the function as an object i.e. for function myfunction(), pass funcOnBeforeCollapse = myfunction
funcOnBeforeExpand - function to call before expanding

Note that you can have multiple of each, you could have a text link and an image that both monitor the state of a toggle, just add an array item to each.


So, you can use text links, and change the text on linking, and you can run arbitrary code too.

Anything else please let me know :)

feline

and ... this can not load to the header ($context['html_headers']), must defined in the template file.

Fel

Arantor

If you invoke it correctly I see no reason why it couldn't be called from html_headers, actually. html_headers is called after script.js is included, so the smc_toggle object would be declared by then.

bloc

Yes, it is.

And thanks, Arantor, I figured it out. :)

The "msgExpanded/msgCollapsed" is very handy, just swaps the text on toggling. But I am now stuck on "funcOnBeforeCollapse:" and "funcOnBeforeExpand", becasue I added 2 simple function names, which set the width of an object plain and simple - but for some reason i just get an JS error that my function names aren't valid functions(?). Which they are..and even defined before the smc_toggle object is called.

I am thinking it might be that these functions must actually be part of the smc_toggle object or something - but how do you define that?

Arantor

Oh, in that case...

You have:

function somefunction
{

}

You will then set funcOnBeforeCollapse = somefunction - you can actually assign functions to variables, since every function is implicitly a JS object. I assumed it was a string looking at how it was done, since I'm more PHP than JS, but it makes sense to do it that way.

feline

This I use .. and I have test it in the header .. don't work

var leftblock2 = new smc_Toggle({
bToggleEnabled: true,
bCurrentlyCollapsed: false,
aSwappableContainers: [
'upshrinkBlock2'
],
aSwapImages: [
{
sId: 'upshrinkImg2',
srcCollapsed: 'http://portamx.com/Themes/PMx/images/expand.gif',
altCollapsed: 'Expand the User block',
srcExpanded: 'http://portamx.com/Themes/PMx/images/collapse.gif',
altExpanded: 'Collapse the User block'
}
],
oThemeOptions: {
bUseThemeSettings: true,
sOptionName: 'collapse2',
sSessionVar: 'e440394a798b',
sSessionId: 'f011bcfc3bb7700048ca59df3ffc50e8'
},
oCookieOptions: {
bUseCookie: false,
sCookieName: 'upshrink2'
}
});


Fel

Arantor

* Arantor gets cross, muttering something about people who are programmers should be the best at trying to provide debugging information.

So... let's try the obvious things.

JS errors?

Is there actually an element on the page, of type img, with id upshrinkImg2?

Is there a container with id upshrinkBlock2?

Trying this as a guest (which won't EVER work)?

bloc

Quote from: Arantor on March 10, 2010, 06:25:33 PM
Oh, in that case...

You have:

function somefunction
{

}

You will then set funcOnBeforeCollapse = somefunction - you can actually assign functions to variables, since every function is implicitly a JS object. I assumed it was a string looking at how it was done, since I'm more PHP than JS, but it makes sense to do it that way.

I tried that. :)

Better to show..this is how Its laid out:

in HEAD:

<script type="text/javascript">
function tpsetnarrow()
{
document.getElementById(\'fullframe\').style.width= \'960px\';
}
function tpsetwidely()
{
document.getElementById(\'fullframe\').style.width= \'98%\';
}
</script>


And then in the body, after the links(so the toggle can find the id):
<script type="text/javascript"><!-- // --><![CDATA[
var oWideToggle = new smc_Toggle({
bToggleEnabled: true,
bCurrentlyCollapsed: ', empty($options['tpsetwide']) ? 'false' : 'true', ',
funcOnBeforeCollapse:  \'tpsetnarrow\',
funcOnBeforeExpand:  \'tpsetwidely\',
aSwapLinks: [
{
sId: \'setwide\',
msgCollapsed: \' | 960px\',
msgExpanded: \' | Wide\',
}
],
aSwappableContainers: [
],
aSwapImages: [
],
oThemeOptions: {
bUseThemeSettings: ', $context['user']['is_guest'] ? 'false' : 'true', ',
sOptionName: \'tpsetwide\',
sSessionVar: ', JavaScriptEscape($context['session_var']), ',
sSessionId: ', JavaScriptEscape($context['session_id']), '
},
oCookieOptions: {
bUseCookie: ', $context['user']['is_guest'] ? 'true' : 'false', ',
sCookieName: \'tpsetwide\'
}
});

// ]]></script>


When running this, i only get the errors I mentioned("this tmp.Method is not an function") in the js console. It seems it can't recognise the functions as real js functions...but as afaik they are lol. If I remove the custom hook calling, it works fine, save the choice and all, but of course needs reloading of the page to see the change take place.

I am thinking theres something small I am overlooking here, but from what I've read on js objects and adding methods to them, the smc_toggle does exactly what it should: defines it within itself using supplied function names and runs it. Its just that it won't accept MY function names lmao. ;D

Arantor

funcOnBeforeCollapse:  tpsetnarrow,

As I later suggested - don't pass function names, pass the function itself.

bloc

ah.. *smacks head* of course, I wasn't paying enough attention.

Thanks, Arantor, that did the trick lol. :)

Arantor

Awesome. I'll update my big post to make note of it.

feline

Quote from: Arantor on March 10, 2010, 06:31:16 PM
JS errors?
No
Quote
Is there actually an element on the page, of type img, with id upshrinkImg2?
yes
Quote
Is there a container with id upshrinkBlock2?
yes

I have it loaded to the header ($context) before the template is created, so the id's etc. are not pysicaly exist on load to header. But .. javascript is run on the client, so this normally works ..

Fel

Arantor


feline

because smc_toggle is a object, the template that have the definitions MUST completed and send to the client.
In other hand the javascript code xxx = new object is executed BEFORE the template is loaded.
That is the point why the script must be in the template and not in the header ...

Fel

Arantor

Argh, yes I'd forgotten that in some browsers it acted like that.

Good thing I suggested http://www.simplemachines.org/community/index.php?topic=370092.0 then... ;)

feline

yea .. very good point .. but not implemented in RC3 I think.
So this need modifications to the templates, we dont use this.
A better place is the function ob_sessrewrite($buffer) in the QueryString.php (i think).
Take a preg_replace to </body></html> and add the footer before ...

Fel

Arantor

Yes, that's for now, but that's why I posted it as a feature request so it can be implemented later ;)

feline

Thanks for this great idee ... I'v added that to the function ob_sessrewrite($buffer) ...

$footer= substr($buffer, strlen($buffer) - 50);
$buffer = str_replace($footer, str_replace('</body>', $context['PortaMx']['html_footer'] .'</body>', $footer), $buffer);

Works perfect  :)

Fel

bloc

I am not using the smc_toggle object for panel/block upshrinking - if thats what Feline tries to do? - so I am not sure if it would work, but placing the object call within body tag should be straighforward in theory. I am not sure its really useful for LOTS of upshrink items though, thats why I opted for my own js/cookie-based solution, where all blocks can be read in at once from a cookie, instead of one-by-one values from the themes table.

Maybe its doable still with some js juggling of the smc_toggle object, but to me it seems that was constructed rather to do a lot of things at once on different objects. Multiple panels to upshrink, calling custom functions...its an untapped resource and I will be exploring it more in themes now I've grasped how it works. ;D

feline

Yes, we using smc_toggle() for all collapse/expand functions (blocks, panels and other) and because each block is a oop class, we have always a unique id. And with the above change we can all insert just before the </body> tag.
That works perfect and save a lot of code in the templates  ;)

One word to the funcOnBeforeCollapse, funcOnBeforeExpand ..
Because the attached function run in the object context, you can access any member value in your function like if(this.opt.bToggleEnabled) {doing is the toggle enabled}

Fel

bloc

Ah, I didn't know that, thanks for the tip. :)

But one question..if you save upshrink value for every block, wouldn't that be a enormous amount of data saved in the {db_prefix}themes table..? Let say you got 5000 members, and about 20 blocks, that alone would mean theoretically 100k of entries..

I am sure it will never be that much, stats show only a slight percentage of members really use it in full, but nevertheless. I arrived at the conclusion that saving all {20} blocks in a cookie takes no space at all(on server), can be different on different machines for each user, and do not add to the db queries. The only drawback is that it won't remember if you remove the cookie or move to another machine - but then again upshrinking the blocks aren't vital for the UI experience. Nor animating the upshrinking itself lol, which some seem to think it is. ;)

Arantor

Yeah, it's really geared to handling multiple panels to be closed in a single press and/or multiple link items to update for the upshrink panels, meaning you can have a hide/show at the top and bottom of the page for example.

bloc

With the right concept I imaging it could actually transform a page totally, without the need for reloading the page. For example, press a login link, and the big(ish) login quick-login appear.

It can't handle multiple states I guess?

Arantor

No, it is literally a switch of states, but it probably wouldn't be *that* hard to butcher into supporting multiple states. Add something to deal with needing the extra data, and extending the method (changeState) to instead of toggle bCurrentlyCollapsed, have it track in this.opts.iCurrentState (integer, not boolean) and cycle through the states there.

feline

Quote from: Bloc on March 11, 2010, 07:34:11 AM
But one question..if you save upshrink value for every block, wouldn't that be a enormous amount of data saved in the {db_prefix}themes table..? Let say you got 5000 members, and about 20 blocks, that alone would mean theoretically 100k of entries..
Yes .. thats is heavy .. I think, we would move that to cookies ...

Fel

Arantor

And that's exactly why you have the power to pick which it is you set up.

feline

#27
we have moved all toggles to cookies .. works perfect, is quicker and save many hundreds records in the table (we remove all collapse entrys)  :D

Fel

feline

#28
One problem with the cookies for smc_toggle ..
The cookies are path dependent .. that's not good and I have changed that.
Can the developer that fix for next release please?


See my next post

Fel

bloc

Quote from: feline on March 12, 2010, 10:42:46 AM
One problem with the cookies for smc_toggle ..
The cookies are path dependent .. that's not good and I have changed that.
Can the developer that fix for next release please?

Fel

I don't think the SMF devs gonna notice this topic that much lol, try writing the suggestion in the Bugs board perhaps?

feline

you are right .. but I verified that more and see that's not a smf bug .. it's produced be SimpleSEF, so I have to call the author about that ..  ;)

Fel

Arantor


Advertisement: