📜 ⬆️ ⬇️

Presentation of multi-line data in javascript and user scripts

It will be about the problem of cross-browser representation of multi-line data in javascript. This could not be a problem if Firefox could work with functions in the same way as other browsers. A single cross-browser view was never found, despite the 2-day effort. If he was, he probably already began to be used on the site userscripts.org. So far there is a separate presentation method: one for Firefox userscripts, the other for all others. Also, for Scriptish there is the possibility of reading the format of metadata (directives), which does not cover an arbitrary format, but solves the problem most often found in user scripts. We do not consider a solution with 2 requests to the server, with access to external HTML, XML and duplication of data, because we want to receive data and a script in one request, in one file, and this file is of type “text / javascript”.

Multi-line presentation of data in all browsers except Firefox


The solution for any scripts, user- and normal, but not for Firefox.
s = function(){/*   ,    */}.toString() 

Further, having cleared the text from the functional brackets with a regular expression, we get pure multi-line data. Neglecting the fact that the end of the comment '* /' characters should not appear in the data. With this in mind, the input text requires minimal verification and replacement with safe strings, which then need to be recoded back after receiving the string s.

But for some reason, this method is not accepted in Firefox - translating a function into a string representation (.toString (), .toSource ()) bites through all comments of any kind. The syntactically correct text outside the comments remains valid, which, of course, severely limits the freedom of data. In particular, the text can be wrapped into a string or into a nonstandard multi-line string with escape characters ("\") before line breaks (at the end of lines) and simply leave it as an insignificant but syntactically correct expression. Despite the non-standard way with beksleshem, such multi-line strings are supported by all browsers.

The lack of a suitable function created the need to invent a substitute for users of GreaseMonkey in user scripts, because they contain comment lines (metadata directives), to which it is sometimes useful to have access from user script and not duplicate them. Metadata syntax ("@ key value") does not allow wrapping quotes or bekslesh at the end of the line. The metadata contains a lot of useful information - the version of the script, the description and data of additional directives. But in general, for arbitrary multi-line data, their representation would be very useful. After all, it is much more convenient to collect scripts by including several lines of non-script information than to convert each line to a special type.
')
If there was a certain function .toStringWithComments () especially for Firefox, we would have a way out by combining both methods programmatically. But this (as far as can be judged) is not. To address this issue, GreaseMonkey created a special data type and syntax: the XML format of multi-line data. Instead of an expression in the script code, a literal is written beginning with "<". For simple Javascript, as expected, this syntax causes the same error as for other browsers. It is the incompatibility of syntaxes that causes such problems, which are discussed in this article - it does not look for ways of combining one and the other syntaxes (via eval () is, but only for single-line data, for which there are already quotes).

Possible solution at addon level


By the way, at the GreaseMonkey add-on level, creating a .toStringWithComments () function is as simple as creating other special functions. Perhaps, GM / Scriptish authors have already proposed this. The most that can be achieved with the existing XML type expression mechanism is to reduce the differences to one or two characters, but this is as little benefit as the original incompatibility. You need an external code generator (PHP script, nodeJS or hands and the user's head) that chooses the syntax depending on the browser.
 s = <![CDATA[   ,   CDATA ]]>.toString(); 

- for Firefox + GreaseMonkey (Fx + GM) or Scriptish - or the above code for other browsers. The principle here is that GreaseMonkey allows for multi-line free text (including comments) in the script code, and all other browsers do not, except for the mentioned trick with the function. Combine the two does not work.

For Fx + GM, the following syntax is also allowed:
 s = <>   ,    </>.toString(); 

or
 s = <anyName>   ,    </anyName>.toString(); 

The text inside may contain CDATA. This XML format (if you look at (typeof s), we get 'xml') also does not help the solution.

Note that there is still no solution for pure Firefox. And this is rather strange - years of development, the most powerful support for developers on your site, and functions like .toStringWithComments () are not. Perhaps the solution is hidden in the bowels of the MDN (Mozilla Development Network) and someone knows about it?

Solutions with damage (conversion) characters of each line


If we can specially prepare the data - wrap in quotes or put a backslash at the end, at the same time protecting all the text in the sense of JS syntax (put back slashes before quotes and back slashes), then there is also no problem presenting multi-line (decorated) data. But this decision is not always acceptable. For userscripts where directives do not allow character distortion, this is not appropriate.

Solution with a difference of 2 characters (only for userscripts)


It is useful for a regular script (in which the Fx-version will not produce the result, so it will have to generate data differently) or manual / server editing of 2 versions of user scripts in order for the external script to require minimal intervention for compatibility. It is based on the “clever” character customization so that they become similar to the correct syntax for all browsers.

The simpler the adjustment, the better, because then the extra characters will have to bite.
 //    s  Fx+GM; var isFxGM = typeof GM_getResourceText !='undefined'; //  "="   ,      Fx+GM var f = function(CDATA, s){s //var f = function(CDATA, s){s= //    Fx+GM  Scriptish <![CDATA[0]]/*   ,     CDATA *///]]> return s}; var currMeta = isFxGM ? f([]).toString() : f.toString(); var win = (typeof unsafeWindow !='undefined')? unsafeWindow: window; win.console.log(currMeta); //   ,   win.console.log('--------------'); win.console.log(currMeta.replace(/(^[\s\S]*?\/\*\r?\n?|\*\/[\s\S]*$)/gm,'')); //       

Here the trick is that the expression before the data is a simple insignificant expression s <! [CDATA [0]], which does not need to be set parameters, if only CDATA was an array variable. Therefore, in other browsers, the construction is ignored, and for Fx + GM, the expression s = <! [CDATA [0]] ...]]>; Is a multi-line XML document.

This solution is mutually exclusive. One code works only in Fx + GM, and in others it gives an error, the other - in the others it works, in Fx + GM it gives an error. This is bad for publishing scripts to userscripts.org, for which a script that works everywhere is desirable for those who do not read the notes. For non-reading notes, a variant of the second script is appropriate, with the need to remove 2 comment characters so that the script can fully work in Fx + GM. Here is the code:
 var win = (typeof unsafeWindow !='undefined')? unsafeWindow: window; var isFxGM = typeof GM_getResourceText !='undefined'; //  "/*"  "<!",      Fx+GM var f = function(s){return(s= /*<![CDATA[*//*   ,     CDATA */s//]]> )}; var currMeta = isFxGM ? f(' "/*"  "<!"   ').toString() : f.toString(); win.console.log(currMeta); //   ,   win.console.log('--------------'); win.console.log(currMeta.replace(/(^[\s\S]*?\/\/\*\r?\n?|\*\/s[\s\S]*$)/gm,'')); //       

Here, a special line reminds the user in a way that needs to be done with the script in order for it to work correctly in Firefox. Depending on the application, the line 'delete "/ *" before "<!" in the script's code, it can have other content, and the task of the script is to determine that it works incompletely and tell the user how to fix it (when he gets to the necessary functionality).

The opposite task - to make a working script in Fx + GM and give a message to other browsers - unfortunately, is not solved, because the XML format in place of the JS expression creates an unsolvable task for the proper operation of regular Javascript. It can be solved with the use of eval (), but only for single-line arbitrary text (which is not a problem at all for other solutions, for example, put the data in the JS line). You can try to create an addon plugin for GreaseMonkey and Scriptish with the addition of new functionality (GM_toStringWithComments ()), about this - at the end of the article. But here you need to know GM from the inside, so you should try to redirect the problem to developers (GreaseMonkey or Scriptish). This would also solve the problem of full script compatibility.

Development Example


In user scripts, directive commands are used in the format of comments before the script. They remain workable (in all browsers) if they write some necessary scripts in front of them. This is usually used to wrap comments with XML tags in Fx + GM, using a special syntax embedded in GreaseMonkey. The problem is that then the script ceases to be compatible with other browsers. Only the shell over the shell - the TamperMonkey add-on for Chrome could handle this. And now copes, but complicates work with scripts, transferring them to a separate list of their own from the point of view of the user. In addition, this is not a cross-browser solution.

For example, in the new version of the HabrAjax script, a picture (logo) is inserted in the file header, which is accepted by the Firefox shell and shows the logo before the extension on the about: addons page, and is ignored in other browsers. In order not to write more than 500 bytes of code twice, we read the header with directives as described above and take data from there. This is necessary not only for private tasks, but also for a higher-quality service for auto-updating the script. From the header we read the version of the script, the description, the change history (if it is written in the special homemade directive "@update"), we compare it with the changes on the server via * .meta.js and in a convenient form, we suggest updating at a convenient time. We can limit minor updates of the version in the display rights, i.e. to create conveniences that are far from being built into the browser by auto-updating scripts that are supported by Scriptish, starting with version 4 of Firefox and GreaseMonkey, starting with 0.9.13 (November 3, 2011, 8th version of Firefox).

Example of solution for user scripts


Suppose GM / Scriptish would make a GM_toStringWithComments function. Then cross-browser multi-line data retrieval in userscript would be fine;
 var f = function(){/*   ,    */}; if(typeof GM_toStringWithComments =='undefined') GM_toStringWithComments = function(f){return f.toString();}; var s = GM_toStringWithComments(f).replace(/(^function(){\/\*|\*\/$)/gm,''); 

Now this code also works, but for Fx + GM (and for just Fx) an empty string is issued.

And here, especially for userscripts, Scriptish has good news ...


Recently, this addon has a function that allows you to read metadata - the very thing that was planned for toStringWithComments (), but in a more limited application. Since GreaseMonkey does not have it, users who do not read the instructions will have to define this function with degradation - with the very sign for Fx + GM, which will let the user know what to do next.

Note that the directive does not replace the lower-level desired function toStringWithComments (), because it collects well-formed descriptions in the form of key-value pairs.

Meet the API Scriptish function GM_getMetadata () !

It issues metadata - directives, decorated as comments, to read the data that the user script transmits to Scriptish about itself. In addition to the data necessary for the operation (scope), information about the name, version, license of the script and about all other directives to which data could be used for the script, for example, the same description of changes in the script compared to with the previous version and the script number on the server.

We make up the long-awaited cross-browser user script for Firefox + Scriptish (with GreaseMonkey it will inform the user about the need for manual adjustment). A real working example can be seen in the HabrAjax script version 0.81+. At the beginning of the script file is a metadata wrapper. For Fx + GM, a reminder of inconvenience appears only when using functions that require metadata retrieval. The user is asked to change 2 bytes in the script (he will have to do this after each update!) Or simply change the addon to Scriptish.

Result


As you can see, a common cross-browser solution was not found. Perhaps it is missing, but by the amount of inconvenience, it had to be solved somewhere or at least a problem was noted. For regular scripts there is no solution at all in Firefox. For userscats, there is a non-cross-browser solution in the form of an XML syntax of an expression in Fx + GM and specially wrapped comments for other browsers. There is a cross-browser solution for Firefox + Scriptish and other browsers only for receiving metadata.

If someone knows by experience a special function like toStringWithComments () in Greasemonkey, Scriptish or Javascript - please inform. If someone can formulate a problem for the developers of GM or Scriptish or knows where it has already been described, please also inform us and us about it.

Now we need to maintain a separate version for Firefox + GM or a reminder for the user (but not for Scriptish!), If you want to read the directives (no more) of user scripts. As a solution that goes beyond the task - there is no problem to store arbitrary data in another file and read by AJAX.

Source: https://habr.com/ru/post/139746/


All Articles