Adaptation Instructions - Text Filter

Text-based content filtering operates on text prior to potential parsing into an object model. It has to be enabled in conf/config.xml:

<config>
  <ress>
    <text-filter />
  </ress>
</config>

Text-based content filtering uses C-style or SGML-style comment syntax. A single non-whitespace non-word character (e.g. ! or [) followed by optional whitespace is permitted between the comment-start token and the ai-… keyword to prevent minifiers from removing the comments.

The ai-if or ai-elseif keywords are followed by = and an XPath expression in single or double quotes. The XPath expressions are evaluated in the context of the root element of the Delivery Context document. Any regular or FIT specific XPath functions may be used.

Simple filtering

Content between the ai-if, ai-endif comment pair is retained depending on the XPath expression.

Using C-style comments:

/*! ai-if="client/os/name = 'Android OS'" */
Android detected.
/*! ai-endif */

Filtering with two alternatives

ai-else is used to start a default alternative.

Using SGML-style comments:

<!--[ ai-if="client/os/name = 'Android OS' and starts-with(client/os/version, '4.')" ]-->
Android 4.
<!--[ ai-else ]-->
Other.
<!--[ ai-endif ]-->

Filtering with three or more alternatives

ai-elseif is used to start another conditional alternative.

Using SGML-style comments:

<!--!ai-if="client/os/name = 'Android OS'" -->
Android!
<!--!ai-elseif="client/os/name = 'iOS'" -->
iOS!
<!--!ai-else -->
Other OS.
<!--!ai-endif -->

Text-based insertions and replacements

The text-based insertions and replacements use the same syntax as the filters.

The ai-insert or ai-replace keywords are followed by = and an XPath expression in single or double quotes.

The ai-insert comment will be replaced by the string value of the XPath expression. Any pair of ai-replace and ai-end comments will be replaced by the string value of the XPath expression specified inside the ai-replace comment.

Example 1: number, string and boolean replacements

The comment syntax can be used to modify a document with FIT without actually changing the JavaScript code in your editor. Imagine you have the following script:

var width = 320;

If you add ai-replace comments to get the actual viewport width, without FIT the code will do the exact same as before, but with FIT processing the actual viewport width of the client will replace the 320:

var width = /*!ai-replace="viewport/width" */ 320 /*!ai-end */;

This is very easy for numbers, but can be at times confusing with strings and booleans. While in filtering an XPath expression client/data-uri will evaluate to true, the same expression in the ai-replace or ai-insert XPath will not give the desired result:

input:

var hasDataUri = /*!ai-replace="client/data-uri"*/undefined/*!ai-end*/;

output:

var hasDataUri = ;

To use ai-replace and ai-insert with booleans, you should always use the boolean() XPath function:

input:

var hasDataUri = /*!ai-replace="boolean(client/data-uri)"*/undefined/*!ai-end*/;

output:

var hasDataUri = true;

Writing strings can be easy, if you do not need unpolluted string literals without FIT. You can just set quotes around the ai-insert or ai-replace. Note that the adaptation instruction in this example is not a comment, but part of the string:

var browser = "/*!ai-insert="client/name"*/";

Output with FIT:

var browser = "Google Chrome";

Output without FIT:

var browser = "/*!ai-insert="client/name"*/";

If you need those unpolluted string literals you cannot use ai-insert. Instead you have to use ai-replace with the concat() XPath function:

var browser = /*!ai-replace="concat('\"', client/name, '\"')"*/"Unknown"/*!ai-end*/;

Example 2: client dependant jQuery version

Decide on the server what jQuery version to load with RequireJS using ai-insert and ai-if:

var jqv = /*!ai-if="not(contains(client/name,'Internet Explorer') and number(client/version) < 9)" */
                /*!ai-insert="concat('"', 'lib/jquery-2.1.1.min', '"')"*/
          /*!ai-else*/
                "lib/jquery-1.11.1.min"
          /*!ai-endif*/;

require.config({
    baseUrl: "/js"
  , paths: {
      jquery: jqv
    , jquery_cookie: "lib/jquery.cookie.min"
  }
});

So if we do not use IE < 9, the output will be:

var jqv = "lib/jquery-2.1.1.min";
require.config({ baseUrl: "/js" , paths: { jquery: jqv , jquery_cookie: "lib/jquery.cookie.min" } });

If we do use IE < 9 the output will be:

var jqv = "lib/jquery-1.11.1.min";
require.config({ baseUrl: "/js" , paths: { jquery: jqv , jquery_cookie: "lib/jquery.cookie.min" } });

Text-based URL rewriting

ai-rewriteurl is a special replacement instruction rewriting a given URL.

The syntax is basically the same as the ai-replace syntax. The comments surround the URL to be rewritten and the ai-rewriteurl comment itself can carry the parameters used in the rewriting process.

See URL Rewriting for more information about available rewrite options.

var indexUrl = '/*!ai-rewriteurl ai-mark-foo="bar" ai-url-https="true" */index.html/*!ai-end*/';

Text-based image rewriting

ai-rewriteimage is a special replacement instruction to rewrite an image URL.

The syntax is the same as the ai-rewriteurl syntax. The comments surround the URL for the image to be rewritten and the ai-rewriteimage comment itself can carry image scaling options.

Warning: Using ai-rewriteimage for image URLs in CSS is not feasible. To rewrite these URLs, you should instead use the CSS Image Scaling instructions.

var imageURL = '/*!ai-rewriteimage ai-scaling-width="50%" ai-quality="50" */foobar.jpg/*!ai-end*/';

Note: Images in JavaScript can also be rewritten dynamically using the JavaScript Image URL API.