setting class with userProperty()

Workarounds and usability notes.

setting class with userProperty()

Postby John Robin Dove » Sat Jul 27, 2019 1:38 pm

Hi Clifton,

I am having trouble using the userProperty function to set and unset the CSS style of certain fields. This seems to have occured since I have taken a lot of my code out of the tbk and put it in an XML file but I'm not sure.

I use it like this: tbfunction_userProperty([object name], "className", {class name], "set"); Often it just fails with no warning. The rest of the code is executed but the fields, which are white and transparent, stay the same. I have found that if I put an alert in the code just after the line that's not executed, the field style then appears. Reasoning that the system needs more time, I put in timeouts to break up the execution as you showed me.
Code: Select all
var fct = function () {...} setTimeout (fct, 500)

This generally works but not always! It works better with longer values like 800 but even then it fails randomly.

I have also noticed that according to your notes it should be possible to reverse the class change by resetting it to "" This definitely does not work for me. I don't know whether this has anything to do with my other problems or not. I have put a test app here https://www.mediacours.com/tb_examples/testClass.zip the myGraphics folder should be added to the export tree. If you have no problems with it then it means my Toolbook 9.01 is the culprit.

Thanks for your time.
John

UPDATE my site is down for unknown reasons. I'll send you the zip via e-mail.
John Robin Dove
 
Posts: 486
Joined: Thu Jan 23, 2014 4:35 am

Re: setting class with userProperty()

Postby Clifton » Sat Jul 27, 2019 3:19 pm

Hi John,
There should be no reason to use any delays to accomplish what you are trying to do.
PowerPac's userProperty() is a rather complex function that accomplishes a lot of things. However, when it is manipulating classNames, it has to distinguish exactly what you want to do. Consider these details:
  1. If all you want to do is set a className to your field, then:
    userProperty( "a1", "className", "pause1", "set");
  2. Now suppose that after setting the className to "pause1", you want to change it to "pause2".
    Then this execution would appear to fail to accomplish the task:
    userProperty( "a1", "className", "pause2", "set");

    The above fails because what it really does is APPEND the class to the previous one. So in the DOM, your object would look like this:
    <span id="myID" class="pause1 pause2"> ... </span>

    To fix this problem, you would need to tell the function NOT TO APPEND the classes to what is already there.
    Therefore, this would give the correct result:
    userProperty( "a1", "className", "pause2", "set", false, false);
  3. So what about your scenario, where you want to clear the className AFTER setting it to "pause1"?
    There are two ways to do this.
    The FIRST way is to use the "toggle" value instead of "set". As the Parameter Help API indicates this will remove a className IF it is present or ADD it if it is not present on the object. In your scenario this may be all that is needed:
    userProperty( "a1", "className", "pause1", "toggle");

    The SECOND way to remove a className is to set the val parameter to an emtpy string, but tell the function NOT TO APPEND classes. In this case, the usage would look like this, but gives the same result as above.
    userProperty( "a1", "className", "", "set", false, false);
The ability to append multiple classes onto a single object using userProperty() was added a long time ago. The Parameter Help API is a little ambiguous in that is says you can clear a property with an empty string. While that is true, it does not work when manipulating classes because the function needs to know what to do with any classes that are already assigned to the object. Basically, this ability enables using classes to add styling to objects that have already been assigned styling that should never be removed. For example, if you assign a className that sets an object's font family to a web font loaded with a CSS file, you likely never want userProperty() to remove that className when assigning additional styling to the object. So the ability the preserve styles while assigning new ones is among the more powerful features of userProperty().

I tried all of the above scenarios on your submitted example and they work as designed (using TB v9.01). Another parameter to keep in the mind is the parseGroup parameter. When set to true and the function is set to target a group (tbName = [group name]), then each object in the group will have its className set to the class you define. This is a useful feature when setting the styling of lots of objects all at once.
 
Clifton
Site Admin
 
Posts: 732
Joined: Tue Jan 14, 2014 1:04 am

Re: setting class with userProperty()

Postby John Robin Dove » Sun Jul 28, 2019 8:50 am

Thanks for your detailed reply. I still haven't solved the problem but at least I know where it's coming from. I have a series of 60 fields named "a1" to "a60" in a group named "AMarkers" which is on the background. When these are required they are repositioned and their appearance is changed using userProperty to set the appropriate class. The user can also decide to cancel the action they represent. In this case their position is changed back, the class is removed and they become invisible again. Something in my system stops them being used more than once. Fortunately I have been able to reproduce the problem in a test app that I will send to you. I have simply copied eveything from the original project. There may be something obvious that I am doing wrong but so far I have failed to find it. No doubt you will.
John Robin Dove
 
Posts: 486
Joined: Thu Jan 23, 2014 4:35 am

Re: setting class with userProperty()

Postby Clifton » Sun Jul 28, 2019 4:20 pm

Well you are really close on this.
Just remove the line that sets inline styles using pgStyleObject() and it will work:
Image 2.png
Image 2.png (7.23 KiB) Viewed 1542 times

WHY?
  • When using stylesheets with class definitions, please note that the styles in these files are overridden by styles that are "inline" or set by the style property of the object. Consider this example:
    • Look at the DOM object below:
      <span style="color: red;">This is some red text.</span>
    • If I assign a class to this element that changes the color to blue, nothing will happen as shown in the example below.
      <span class="myColor" style="color: red;">This is some red text.</span>

      In the above case the inline style for color: red; will override the color set in the stylesheet for the class "myColor".
    • So now let's apply this to your example. You are trying to set the background graphic of an object using a class called "pause1". Then when you remove the class, you are setting the background to transparent. This overrides any future assignment of the class "pause1" to change the background to a graphic as long as the inline style "background: transparent;" is present.
  • There are other ways to fix your actions. You could change your stylesheet class definition:
    .pause1 {
    background-image: url(pause1.gif);
    }
    /* Change it to this instead */
    .pause1 {
    background: url(pause1.gif) !important;
    }

    Now your stylesheet will take precedence over inline styles because we added the !important flag.
  • Another approach would be to remove the inline style by running pgStyleObject() before setting the className, like this:
    pgStyleObject( "a1", "background", "-");
    userProperty( "a1", "className", "pause1", "set", false, false);
So you have a number of options to fix your actions and the choice is yours. I would either remove the pgStyleObject() line OR add the !important flag.

BTW: You are using multiple pgTBObjSet() executions to set "left" and "top" properties for this object. You can force the position in your stylesheet instead, but you would have to use the !important flag to override the inline styles set by ToolBook. If you don't want to do that, you can also execute pgTBObjSet() once and use the "position" property:
pgTBObjSet( "a1", "position", "400, 87");

OR you could use snapObjectToCenter() and align the object "a1" to a position relative to something else on the page.
 
Clifton
Site Admin
 
Posts: 732
Joined: Tue Jan 14, 2014 1:04 am

Re: setting class with userProperty()

Postby John Robin Dove » Mon Jul 29, 2019 4:48 am

Hi Clifton,
Thanks for the explanations. I don't think I would have been able to solve this problem on my own. I have just corrected the test app and now I shall try to apply the solutions to my main project. This is a bit more complicated because the code is now in 3 different places, the TBK, an extra JS file and an XML file. If I were starting again I would use the XML file only and use user properties instead of global variables but it's taken me years to get this far so I think I'll just plod on.

I intend to use the pgStyleObject( "a1", "background", "-"); solution as I need to set the cursor as well so the line will become pgStyleObject( "a1", "background, cursor", "-, pointer");. I don't think adding a position to the class is relevant because each field has a different left position when used. I also need to reset the background color to white, transparent when the fields are no longer in use because some of the objects are colored and sized differently according to their purpose. I would show you a picture but my site is still inaccessible at the moment.

John
John Robin Dove
 
Posts: 486
Joined: Thu Jan 23, 2014 4:35 am

Re: setting class with userProperty()

Postby Clifton » Mon Jul 29, 2019 6:53 am

All of what you are doing is fine as long as you recognize the style priorities of CSS stylesheets versus inline. Just a thought, but you might want to use the !important flag instead of having to remember whether the background style is set for each situation. That way you can just manipulate the className and not worry about the background with pgStyleObject().
 
Clifton
Site Admin
 
Posts: 732
Joined: Tue Jan 14, 2014 1:04 am

Re: setting class with userProperty()

Postby John Robin Dove » Mon Jul 29, 2019 8:31 am

OK, thanks again. I have just modifified the CSS file as you suggested and ... so far, so good! :D

My site is back to it's normal state. The SSL? (maybe it's not SSL in English) certificate had expired causing dire warnings to appear when I attempted to access the site on https in the browser. Not great publicity if anyone else decided to revisit my site! But every cloud has a silver lining I suppose because my site is now hosted on a new server. On this server my programs function correctly without the aid of Cloudflare. Neverthe less I have reactivated Cloudflare to be on the safe side.
John Robin Dove
 
Posts: 486
Joined: Thu Jan 23, 2014 4:35 am


Return to General Discussion

Who is online

Users browsing this forum: No registered users and 3 guests

cron