lib/modelToText/transformModel.js

Summary

Maintainability
F
4 days
Test Coverage
//////////////////////////////////////////
// Requirements                         //
//////////////////////////////////////////

var moboUtil   = require('./../util/moboUtil');

//////////////////////////////////////////
// CORE FUNCTIONS                       //
//////////////////////////////////////////

/**
 * Executes the parsing of the models
 * Will generate SMW Category and Template Sites
 *
 * @param   {object}    settings
 * @param   {object}    obj
 * @param   {string}    name        key-name of the current obj
 * @param   {object}    registry
 *
 * @returns {object}    generated wikipages
 */
exports.exec = function(settings, obj, name, registry) {
    'use strict';

    //////////////////////////////////////////
    // Inner Variables                      //
    //////////////////////////////////////////

    /** Return Object, matching the data structure of the registry */
    var returnObject = {
        category: {},
        template: {}
    };


    //////////////////////////////////////////
    // Templates                            //
    //////////////////////////////////////////

    exports.categoryTemplate = moboUtil.loadTemplate(exports, 'category.wikitext', settings);
    exports.templateTemplate = moboUtil.loadTemplate(exports, 'template.wikitext', settings);


    //////////////////////////////////////////
    // Execution                            //
    //////////////////////////////////////////

    // Generate Category
    var categoryWikitext = exports.generateCategory(settings, obj, name, registry);
    if (categoryWikitext) {
        // Remove leading underscores
        while (name.charAt(0) === '_') {
            name = name.substr(1);
        }
        returnObject.category[name] = categoryWikitext;
    }

    // Generate Template
    var templateWikitext = exports.generateTemplate(settings, obj, name, registry);
    if (templateWikitext) {
        returnObject.template[name] = templateWikitext;
    }

    return returnObject;
};

/**
 * Generates Category for all models that are defined being a sf_form
 *
 * @param   {object}    settings
 * @param   {object}    obj
 * @param   {string}    name        key-name of the current obj
 * @param   {object}    registry
 *
 * @returns {string|boolean}        generated wikitext
 */
exports.generateCategory = function(settings, obj, name, registry) {

    // If smw_category is set to false, don't create a category
    if (obj.smw_category === false) {
        return false;
    }

    var title = obj.title || name;
    var form = false;
    var formCategory = false;
    var template = true;

    // If The FormEdit mode is NOT activated and there is a form with the name name as the model, display it.
    if (!settings.formEditHelper && registry.form[obj.id]) {
        form = true;
        formCategory = false;
    }

    // If FormEdit mode is active and there is a form with the same name as the model, just display a link to it.
    if (settings.formEditHelper && registry.form[obj.id]) {
        form = false;
        formCategory = true;
    }

    // If this model is abstract, create a category for it
    // No template will be generated, so don't link for one
    // Removes all leading _ if they are used for indicating an abstract model
    if (obj.$abstract) {
        while (name.charAt(0) === '_') {
            name = name.substr(1);
        }
        template = false;
        formCategory = false;
    }


    var data = {
        name: name,
        title: title,
        form: form,
        formCategory: formCategory,
        template: template,
        overview: true,
        attr: obj.properties,

        modelObj: obj,
        settingsObj: settings
    };

    if (obj.description) {
        data.description = obj.description;
    }

    if (obj.smw_prependCategory) {
        data.prepend = obj.smw_prependCategory;
    }

    if (obj.smw_appendCategory) {
        data.prepend = obj.smw_appendCategory;
    }

    if (settings.smw_semanticDrilldown) {
        data.drilldowninfo = exports.drilldownInfo(obj, registry);
    }

    /** @deprecated */
    data.prefix = data.prepend;
    /** @deprecated */
    data.postfix = data.append;

    return exports.categoryTemplate(data);

};

/**
 * Generates Template for all not abstract models
 *
 * @param   {object}    settings
 * @param   {object}    obj
 * @param   {string}    name        key-name of the current obj
 * @param   {object}    registry
 *
 * @returns {string|boolean}        generated wikitext
 */
exports.generateTemplate = function(settings, obj, name, registry) {
    'use strict';

    // If this is an abstract model, don't create a template for it
    if (obj.$abstract) {
        return false;
    }

    var data = {
        title: obj.title || name,
        id: obj.id,
        name: name, //@deprecated
        description: obj.description || false,

        category: name,
        categories: obj.smw_categories || false,
        smw_subobject: obj.smw_subobject || false,
        arraymap: false,

        modelObj: obj,
        settingsObj: settings
    };

    if (settings.generateTemplateData) {
        data.templatedata = exports.generateTemplateData(obj);
    }

    /** Adding Prefixes */
    data.prepend = moboUtil.prePostFix('smw_prepend', obj, registry);
    data.prepend += moboUtil.prePostFix('smw_prependPage', obj, registry);

    /** Adding Postfixes */
    data.append = moboUtil.prePostFix('smw_append', obj, registry);
    data.append += moboUtil.prePostFix('smw_appendPage', obj, registry);

    data.attr = obj.properties;

    // Check if property has to be implemented as arraymap
    for (var propertyName in data.attr) {
        var attr = data.attr[propertyName];
        if (registry.expandedField[propertyName] && registry.expandedField[propertyName].items) {
            attr.smw_arraymap = true;
        }

        if (attr.smw_forceSet) {
            var value = attr.smw_overwriteData || attr.smw_overwriteOutput || '{{{' + attr.id + '|}}}';
            var setProperty = ' [[' + attr.id + '::' + value + '| ]]';

            if (!data.append) {
                data.append = setProperty;
            } else {
                data.append += setProperty;
            }
        }

    }

    // In some cases no category tag should be created
    if (obj.smw_category === false || (obj.smw_subobject && (obj.smw_category !== true))) {
        data.category = false;
    }

    // Since Handlebars.js does not support comparators:
    // inject a variable that has the name of the smw_display renderer
    var smwDisplay = obj.smw_display || settings.defaultTemplateDisplay;
    data['display_' + smwDisplay] = true;

    /** @deprecated */
    data.prefix = data.prepend;
    /** @deprecated */
    data.postfix = data.append;

    return exports.templateTemplate(data);

};

/**
 * Converts JSON Schema Model to MediaWiki Template Data Object
 * http://www.mediawiki.org/wiki/Extension:TemplateData
 *
 * @param obj
 *
 * @returns {string}    JSON String describing the TemplateData tag
 */
exports.generateTemplateData = function(obj) {
    'use strict';

    var templateData = {};

    if (obj.description) {
        templateData.description = obj.description;
    }

    if (obj.properties) {

        templateData.params = {};

        for (var propertyName in obj.properties) {

            if (obj.properties.hasOwnProperty(propertyName)) {

                var property = obj.properties[propertyName];
                var id = property.id;
                var inspect = property.items || property;

                var param = {};

                param.type = 'unknown'; // Default Type
                param.suggested = true;

                if (property.title) {
                    param.label = property.title;
                }

                if (property.description) {
                    param.description = property.description;
                } else {
                    param.description = '';
                }

                if (obj.required && obj.required.indexOf(propertyName) > -1) {
                    param.required = true;
                }

                // If an * (astericks) is given, require all fields of the model
                if (obj.required && obj.required.indexOf('*') > -1) {
                    param.required = true;
                }

                // Basic Content Types
                if (inspect.type === 'string') {
                    param.type = 'line';
                } else if (inspect.type === 'number') {
                    param.type = 'number';
                }

                // Textareas
                if (property.sf_form && property.sf_form['input type'] && property.sf_form['input type'] === 'textarea') {
                    param.type = 'string';
                }

                // Links to Wiki Sites
                if (property.form || (property.format && property.format === 'Page')) {
                    param.type = 'wiki-page-name';
                }

                // Links to SubObjects
                if (property.items && property.items.title) {
                    param.type = 'content';
                    param.description += '(SMW SubObject)';
                }

                if (property.default) {
                    // BUGFIX: If the default is a number, it will crash the wiki upload
                    // Always convert it to a string to avoid this.
                    param.default = '' + property.default;
                }

                templateData.params[id] = param;
            }
        }
    }

    return JSON.stringify(templateData, false, 4);
};

/**
 * Createas a #drilldowninfo parser function that adds all fields that set "smw_drilldown": true
 * If the Model has a form with the same ID, all fields of the form will be considered
 *
 * @param obj
 * @param registry
 * @returns {*}
 */
exports.drilldownInfo = function(obj, registry) {

    var drilldowninfo = [];
    var fieldName;
    var field;

    if (registry.expandedForm[obj.id]) {

        // If the model has a form with the identical ID, use all fields available in the whole form

        if (registry.expandedForm[obj.id].properties) {
            for (var modelName in registry.expandedForm[obj.id].properties) {
                var model = registry.expandedForm[obj.id].properties[modelName];
                if (model.properties) {
                    for (fieldName in model.properties) {
                        field = model.properties[fieldName];
                        if (field.smw_drilldown) {
                            drilldowninfo.push({
                                name: field.title,
                                id: field.id.charAt(0).toUpperCase() + field.id.slice(1) // Capitalize first letter (sic!)
                            });
                        }
                    }
                }
            }
        }

    } else {

        // Else, use only those properties the model has by itself

        if (obj.properties) {
            for (fieldName in obj.properties) {
                field = obj.properties[fieldName];
                if (field.smw_drilldown) {
                    drilldowninfo.push({
                        name: field.title,
                        id: field.id.charAt(0).toUpperCase() + field.id.slice(1) // Capitalize first letter (sic!)
                    });
                }
            }
        }
    }

    // Build #drilldowninfo parser function string
    var drilldowninfoFunction = '{{#drilldowninfo:filters=';

    for (var i = 0; i < drilldowninfo.length; i++) {
        var item = drilldowninfo[i];
        var name = item.name;
        name = name.split('(').join('');
        name = name.split(')').join('');
        name = name.split('{').join('');
        name = name.split('}').join('');
        name = name.split('|').join('');
        drilldowninfoFunction += name + ' (property=' + item.id;
        if (item.category) {
            drilldowninfoFunction += ', category=' + item.category;
        }
        drilldowninfoFunction += '), ';
    }

    drilldowninfoFunction = drilldowninfoFunction.substring(0, drilldowninfoFunction.length - 2);
    drilldowninfoFunction += '}} __SHOWINDRILLDOWN__';

    if (drilldowninfo.length > 0) {
        return drilldowninfoFunction;
    } else {
        return false;
    }

};