User tests: Successful: Unsuccessful:
As I was testing 3.8.9 RC I found this issue popping up when clicking to install the sample data:
Notice the \'
in the text. I tracked this down and it happened because in the process of rendering the page we call the function onBeforeCompileHead()
. I have a plugin installed that listens to this and in the plugin at some point the setHeadData()
of HtmlDocument
class is called. This method calls the JText::script()
again. It calls it with the language key and language value but the second argument is not the value but if the text should be considered JavaScript safe. Supplying a text string as second argument tells the method that it should always treat the string as JavaScript safe. Since the language strings was originally already set to be JavaScript safe it now gets 2 backslashes. If I were to have 3 more plugins calling setHeadData()
I would end up with 4 backslashes.
I tracked the implementation of this code back to this commit 9f692f7 which shows the code has never changed since it's original implementation in May 2013. Interesting enough either this never showed up or nobody noticed :)
plugins/system/updatenotification/updatenotification.php
(assuming you have the update notification plugin enabled)public function onBeforeCompileHead(){
$doc = JFactory::getDocument();
$head = $doc->getHeadData();
$doc->setHeadData($head);
}
\'
in it.can't
as expected.The word can't
The word can\'t
None
Status | New | ⇒ | Pending |
Category | ⇒ | Libraries |
so you called
***Document->getHeadData();
to get the current (head) data
... which also includes (unfortunately ... ??)
$data['scriptText'] = \JText::getScriptStrings();
you customize / manipulate $data, and then you call ...
***Document->setHeadData($data);
but now you will be calling 2nd (or 3rd or 4th time if you call setHeadData multiple times)
JText::script on the same language strings
this is ok to do , but the problem is a little more complex ... (i think)
how do you know if the original call to JText::script($string, $jsSafe ...) was using false or was using true for $jsSafe, you don't know right ?
Also you don't know what the setting for $interpretBackSlashes was during the original calls
public static function script($string = null, $jsSafe = false, $interpretBackSlashes = true)
this is ok to do , but the problem is a little more complex ... (i think)
I realized that as well but doesn't warrant incorrect use of a function. The real solution would be to keep track of which string wants to be jsSafe. A refactoring not to be done in this PR.
how do you know if the original call to JText::script($string, $jsSafe ...) was using false or was using true for $jsSafe, you don't know right ?
Nope, you do not know.
Also you don't know what the setting for $interpretBackSlashes was during the original calls
Yep, you don't know that either. There is more weird stuff going in here because the argument claims to be a boolean but in the function we check if it is an array :|
Also i see a logic / design problem here
$data['scriptText']
is supposed to have
$key => $already_manipulate_string
why the above ? , because that is what is given by
$data['scriptText'] = \JText::getScriptStrings();
you are not supposed to add or "re-add" them using ... Text::script aka remanipulating according to $jsSafe, and $interpretBackSlashes
instead you should some how
-- merge them with existing static::strings inside the Text class
$new_strings_array = array_merge(\JText::getScriptStrings(), $data['scriptText']);
// and then call ...
Factory::getDocument()->addScriptOptions('joomla.jtext', $new_strings_array, false);
also "fixing" this bogus behavior now may be considered a B/C break ...
i think making a full / proper fix is for J4
I also believe that is the place to really refactor this.
and then loop through $data['scriptText'] and only call Text::script only on new keys ?
Not sure if this is enough because when I look at the original commit it was for cached data. Javascript translations are not available if caching is enabled.
So from this I gather that when you load a cached page the JS has no language strings, so you need to run through all of them to be made available.
right,
missed this one about caching
but we can still do the check that i suggested and not re-add the keys already added ... to the static::$strings of Text class
Just , we need to guarantee that at least 1 call to Text:script is made inside setHeadData()
So after the loop we can do
Text::script('__DUMMY__');
that way you will get Text class to call
HTMLHelper::_('behavior.core');
Factory::getDocument()->addScriptOptions('joomla.jtext', static::$strings, false);
Adding that DUMMY string doesn't sit right with me either as it feels like a workaround. Perhaps we should just focus on a better solution on Joomla 4.
i see,
i hope i contributed something here for a more complete fix in J4
Status | Pending | ⇒ | Closed |
Closed_Date | 0000-00-00 00:00:00 | ⇒ | 2019-03-10 20:21:11 |
Closed_By | ⇒ | roland-d |
I have tested this item✅ successfully on 6d69334
This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/20843.