Marfeel uses PhantomJS to extract a publisher's items for the section mosaic. As it does this, Marfeel detects metadata and stores this information in the DOM inside a script. 

To avoid reparsing the DOM, Marfeel doesn't make direct calls to the script tag and defines another way of getting metadata from the DOM.

Specifically, when Marfeel loads a customer's page, PhantomJS identifies and extracts all the articles first. Then the metadata is scanned to detect any active metadata.

In Marfeel Touch, the definition.json includes the metadataProviders flag that contains all the active metadata providers in an array. The file must have the same name as the metadataProvider in order to be detected and replicated with the same logic:

Gutenberg/MarfeelAlibaba/src/main/resources/metadataProviders/<PROVIDER_NAME.js
CODE

If a file has a different name to what is indicated in the metadataProviders in definition.json, this is detailed in the error code 12 of the PhantomJS exit codes. That is, a metadataProvider error is produced because something unsupported was identified. 

Marfeel matches all the detected metadata from a publisher's section mosaic to the ones in Marfeel Touch in an array. 

The following example indicates metadata being matched from a RegExp:

document.marfeel.metadataProviders = document.marfeel.metadataProviders || {};
document.marfeel.metadataProviders.regexpExample = {
    className: "mrf-regexpExample",
    type: "test",
    matcher: new RegExp("meta(data[\S\s]+?)string")
};
CODE

Marfeel searches all the scripts in a website to detect and match metadata after the article details have been identified and extracted. The scripts are loaded not for performance, but for the specific function of having their information inspected. Once the information is scanned, this information is sent to the sections mosaic. 

Examples

Detecting and extracting metadata from the window object

document.marfeel.metadataProviders = document.marfeel.metadataProviders || {};
document.marfeel.metadataProviders.amplitudeMetricsDetector = (function() {
    function merge(obj1, obj2) {
        for (var key in obj2) {
            if (obj2.hasOwnProperty(key)) {
                obj1[key] = obj2[key];
            }
        }
        return obj1;
    }

    function toString() {
        return '{"@context":"http://schema.org","@type":"AmplitudeMetrics","customMetrics": ' + JSON.stringify(merge(window.amProp, window.pageViewProperties)) + "}";
    }

    return {
        className: "mrf-amplitudeMetrics",
        type: "AmplitudeMetrics",
        toString: toString
    };
}());
CODE

More complex usage with custom matcher function and toString

document.marfeel.metadataProviders = document.marfeel.metadataProviders || {};
document.marfeel.metadataProviders.defaultDfpSlotDetector = (function () {
    var SLOT_DETECTOR = /defineSlot\(([\s\S]+?)\)/g;
    var matches = [];

    function matcher(content) {
        var defineSlotMatcher = SLOT_DETECTOR.exec(content)

        while (defineSlotMatcher !== null) {
          matcher.push('{"slot": ' + defineSlotMatcher[1] + '}');
          defineSlotMatcher = SLOT_DETECTOR.exec(content)
        }

        return matches;
    }

    function toString(matches) {
        var result = { "@context": "http://schema.org", "@type": "AdTargetings" };

        if (matches.length === 0) {
            return "";
        }

        result[JSON_PROPERTY] = matches;
        return JSON.stringify(result);
    }

    return {
        className: "mrf-adTargetings",
        type: "AdTargetings",
        matcher: matcher,
        toString: toString
    };
} ());
CODE

Properties

PropertiesDescription
String classNameClass name for metadata tag
String typeType of metadata
Function | RegExp matcherMatcher for the metadata. Will execute for each script tag.
Function toStringConverts data to JSON stringm
Boolean detailsOnlyDefault false, if true ignore this provider