<commit_before>import { R } from 'meteor/ramda:ramda';
import checkNpmPackage from './check-npm-package';
import { createReplacer } from './text-replacer';
import sha1 from './sha1';

import appModulePath from 'app-module-path';
appModulePath.addPath(ImportPathHelpers.basePath + '/node_modules/');

const path = Npm.require('path');
const fs = Npm.require('fs');
const cjson = Npm.require('cjson');
const optionsFilePath = path.resolve(process.cwd(), 'package.json');

const pluginOptions = {};
loadOptions();
export { loadOptions as reloadOptions };
export default pluginOptions;

function getDefaultOptions() {
	return {
		cssClassNamingConvention: {
			replacements: []
		},
		enableProfiling: false,
		enableSassCompilation: ['scss', 'sass'],
		enableStylusCompilation: ['styl', 'm.styl'],
		explicitIncludes: [],
		extensions: ['css', 'm.css', 'mss'],
		filenames: [],
		globalVariablesText: '',
		ignorePaths: [],
		jsClassNamingConvention: {
			camelCase: false
		},
		outputJsFilePath: '{dirname}/{basename}{extname}',
		outputCssFilePath: '{dirname}/{basename}{extname}',
		passthroughPaths: [],
		specificArchitecture: 'web',
		hash: null
	};
}

export function getHash() {
	return pluginOptions.hash;
}

function loadOptions() {
	let options = null;
	if (fs.existsSync(optionsFilePath)) {
		options = cjson.load(optionsFilePath).cssModules;
	}
	options = options || {};
	options.hash = sha1(JSON.stringify(options));
	if (options.hash === pluginOptions.hash)
		return pluginOptions.options;

	options.hash = JSON.stringify(options);
	options = processGlobalVariables(options);
	options = R.merge(getDefaultOptions(), options || {});

	processCssClassNamingConventionReplacements(options);
	processPassthroughPathExpressions(options);
	checkSassCompilation(options);
	checkStylusCompilation(options);

	return pluginOptions.options = options;
}

function processPassthroughPathExpressions(options) {
	const createPatternRegExp = pattern => typeof pattern === 'string' ? new RegExp(pattern) : new RegExp(pattern[0], pattern[1]);
	options.passthroughPaths = options.passthroughPaths.map(createPatternRegExp);
}

function processCssClassNamingConventionReplacements(options) {
	if (!options.cssClassNamingConvention || !options.cssClassNamingConvention.replacements)
		return;

	const replacements = options.cssClassNamingConvention.replacements;
	options.cssClassNamingConvention.replacements = replacements.map(createReplacer);
}

function checkSassCompilation(options) {
	if (!options.enableSassCompilation)
		return;

	if (options.enableSassCompilation === true
		|| (Array.isArray(options.enableSassCompilation) && R.intersection(options.enableSassCompilation, options.extensions).length)) {
		const result = checkNpmPackage('node-sass@3.x');
		if (result === true)
			return;
	}
	options.enableSassCompilation = false;
}

function checkStylusCompilation(options) {
	if (!options.enableStylusCompilation)
		return;

	if (options.enableStylusCompilation === true
		|| (Array.isArray(options.enableStylusCompilation) && R.intersection(options.enableStylusCompilation, options.extensions).length)) {
		const result = checkNpmPackage('stylus@0.x');
		if (result === true)
			return;
	}

	options.enableStylusCompilation = false;
}

function processGlobalVariables(options) {
	if (!options.globalVariables)
		return options;

	const globalVariablesText = [];
	const globalVariablesJs = [];
	options.globalVariables.forEach(entry=> {
		switch (R.type(entry)) {
			case 'Object':
				globalVariablesJs.push(entry);
				globalVariablesText.push(convertJsonVariablesToScssVariables(entry));
				break;
			case 'String':
				const fileContents = fs.readFileSync(entry, 'utf-8');
				if (path.extname(entry) === '.json') {
					const jsonVariables = cjson.parse(fileContents);
					globalVariablesJs.push(jsonVariables);
					globalVariablesText.push(convertJsonVariablesToScssVariables(jsonVariables));
				} else {
					globalVariablesJs.push(convertScssVariablesToJsonVariables(fileContents));
					globalVariablesText.push(fileContents);
				}
				break;
		}
	});
	options.globalVariablesJs = R.mergeAll(globalVariablesJs);
	options.globalVariablesText = R.join('\n', globalVariablesText);
	options.globalVariablesTextLineCount = options.globalVariablesText.split(/\r\n|\r|\n/).length;

	return options;

	function convertJsonVariablesToScssVariables(variables) {
		const convertObjectToKeyValueArray = R.toPairs;
		const convertVariablesToScss = R.reduce((variables, pair) => variables + `$${pair[0]}: ${pair[1]};\n`, '');
		const processVariables = R.pipe(convertObjectToKeyValueArray, convertVariablesToScss);
		return processVariables(variables);
	}

	function convertScssVariablesToJsonVariables(text) {
		const extractVariables = R.match(/^\$.*/gm);
		const convertVariableToJson = R.pipe(R.replace(/"/g, '\\"'), R.replace(/\$(.*):\s*(.*);/g, '"$1":"$2"'));
		const surroundWithBraces = (str) => `{${str}}`;

		const processText = R.pipe(extractVariables, R.map(convertVariableToJson), R.join(',\n'), surroundWithBraces, cjson.parse);
		return processText(text);
	}
}
<commit_msg>the plugin options hash should include the contents of globalVariables (#15)<commit_after>import { R } from 'meteor/ramda:ramda';
import checkNpmPackage from './check-npm-package';
import { createReplacer } from './text-replacer';
import sha1 from './sha1';

import appModulePath from 'app-module-path';
appModulePath.addPath(ImportPathHelpers.basePath + '/node_modules/');

const path = Npm.require('path');
const fs = Npm.require('fs');
const cjson = Npm.require('cjson');
const optionsFilePath = path.resolve(process.cwd(), 'package.json');

const pluginOptions = {};
loadOptions();
export { loadOptions as reloadOptions };
export default pluginOptions;

function getDefaultOptions() {
	return {
		cssClassNamingConvention: {
			replacements: []
		},
		enableProfiling: false,
		enableSassCompilation: ['scss', 'sass'],
		enableStylusCompilation: ['styl', 'm.styl'],
		explicitIncludes: [],
		extensions: ['css', 'm.css', 'mss'],
		filenames: [],
		globalVariablesText: '',
		ignorePaths: [],
		jsClassNamingConvention: {
			camelCase: false
		},
		outputJsFilePath: '{dirname}/{basename}{extname}',
		outputCssFilePath: '{dirname}/{basename}{extname}',
		passthroughPaths: [],
		specificArchitecture: 'web',
		hash: null
	};
}

export function getHash() {
	return pluginOptions.hash;
}

function loadOptions() {
	let options = null;
	if (fs.existsSync(optionsFilePath)) {
		options = cjson.load(optionsFilePath).cssModules;
	}
	options = options || {};
	options.hash = sha1(JSON.stringify(options));
	if (options.hash === pluginOptions.hash)
		return pluginOptions.options;

	options = processGlobalVariables(options);
	options.hash = JSON.stringify(options);
	options = R.merge(getDefaultOptions(), options || {});

	processCssClassNamingConventionReplacements(options);
	processPassthroughPathExpressions(options);
	checkSassCompilation(options);
	checkStylusCompilation(options);

	return pluginOptions.options = options;
}

function processPassthroughPathExpressions(options) {
	const createPatternRegExp = pattern => typeof pattern === 'string' ? new RegExp(pattern) : new RegExp(pattern[0], pattern[1]);
	options.passthroughPaths = options.passthroughPaths.map(createPatternRegExp);
}

function processCssClassNamingConventionReplacements(options) {
	if (!options.cssClassNamingConvention || !options.cssClassNamingConvention.replacements)
		return;

	const replacements = options.cssClassNamingConvention.replacements;
	options.cssClassNamingConvention.replacements = replacements.map(createReplacer);
}

function checkSassCompilation(options) {
	if (!options.enableSassCompilation)
		return;

	if (options.enableSassCompilation === true
		|| (Array.isArray(options.enableSassCompilation) && R.intersection(options.enableSassCompilation, options.extensions).length)) {
		const result = checkNpmPackage('node-sass@3.x');
		if (result === true)
			return;
	}
	options.enableSassCompilation = false;
}

function checkStylusCompilation(options) {
	if (!options.enableStylusCompilation)
		return;

	if (options.enableStylusCompilation === true
		|| (Array.isArray(options.enableStylusCompilation) && R.intersection(options.enableStylusCompilation, options.extensions).length)) {
		const result = checkNpmPackage('stylus@0.x');
		if (result === true)
			return;
	}

	options.enableStylusCompilation = false;
}

function processGlobalVariables(options) {
	if (!options.globalVariables)
		return options;

	const globalVariablesText = [];
	const globalVariablesJs = [];
	options.globalVariables.forEach(entry=> {
		switch (R.type(entry)) {
			case 'Object':
				globalVariablesJs.push(entry);
				globalVariablesText.push(convertJsonVariablesToScssVariables(entry));
				break;
			case 'String':
				const fileContents = fs.readFileSync(entry, 'utf-8');
				if (path.extname(entry) === '.json') {
					const jsonVariables = cjson.parse(fileContents);
					globalVariablesJs.push(jsonVariables);
					globalVariablesText.push(convertJsonVariablesToScssVariables(jsonVariables));
				} else {
					globalVariablesJs.push(convertScssVariablesToJsonVariables(fileContents));
					globalVariablesText.push(fileContents);
				}
				break;
		}
	});
	options.globalVariablesJs = R.mergeAll(globalVariablesJs);
	options.globalVariablesText = R.join('\n', globalVariablesText);
	options.globalVariablesTextLineCount = options.globalVariablesText.split(/\r\n|\r|\n/).length;

	return options;

	function convertJsonVariablesToScssVariables(variables) {
		const convertObjectToKeyValueArray = R.toPairs;
		const convertVariablesToScss = R.reduce((variables, pair) => variables + `$${pair[0]}: ${pair[1]};\n`, '');
		const processVariables = R.pipe(convertObjectToKeyValueArray, convertVariablesToScss);
		return processVariables(variables);
	}

	function convertScssVariablesToJsonVariables(text) {
		const extractVariables = R.match(/^\$.*/gm);
		const convertVariableToJson = R.pipe(R.replace(/"/g, '\\"'), R.replace(/\$(.*):\s*(.*);/g, '"$1":"$2"'));
		const surroundWithBraces = (str) => `{${str}}`;

		const processText = R.pipe(extractVariables, R.map(convertVariableToJson), R.join(',\n'), surroundWithBraces, cjson.parse);
		return processText(text);
	}
}
<|endoftext|>


<commit_before>var currentTable;
var tempSelection;
var editform = $('#cea-column-editor-form');

// Add onclick function to tabs
$("[id$=-tab]").each(function () {
    $(this).click(function(){
        var oldtable = $('.tab.active').data('name') || 'zone';
        $('.tab').removeClass("active");
        $(this).addClass("active");

        // Remember scroll position
        var scroll = $('.tabulator-tableHolder').scrollTop();

        // Store previously selected buildings before creating new table
        if (inputstore.getData(oldtable).length) {
            if (inputstore.getSelected()) {
                tempSelection = [...inputstore.getSelected()];
            }
        }

        var name = $(this).data('name');
        $('#property-table').empty();
        createTable("property-table",`${name}`,
            inputstore.getData(name),
            inputstore.getColumns(name),
            inputstore.getColumnTypes(name)
        );

        // Restore previous selected
        inputstore.setSelected(tempSelection);
        if (inputstore.getSelected()) {
            currentTable.selectRow(inputstore.getSelected());
        }
        filterSelection(inputstore.getSelected());

        currentTable.redraw();
        $('.tabulator-tableHolder').scrollTop(scroll);

    });
});

function createTable(parent, name, values, columns, types) {
    var placeholder = '';
    var tool = '';
    if (!inputstore.getData(name).length) {
        placeholder = '
File cannot be found.
';
        if (name === 'zone') {
            tool = 'zone-helper';
        } else if (name === 'district') {
            tool = 'district-helper';
        } else {
            tool = 'data-helper';
        }

        placeholder += `<div>You can create the file using the <a href="/tools/${tool}">${tool}</a> tool.</div>`;
    } else {
        placeholder = '
No matching records found.
';
    }

    $(`#${parent}`).append(`<div id="${name}-table"></div>`);
    currentTable = new Tabulator(`#${name}-table`, {
        index: 'Name',
        data: values,
        columns: defineColumns(columns, types),
        placeholder: placeholder,

        layout: (['occupancy','architecture'].includes(name)) ? 'fitDataFill' : 'fitColumns',
        height: '300px',
        cellClick: selectRow,
        cellEdited: updateData,
        rowSelectionChanged: addToSelection,
    });

    createTooltip();

    $('#select-all-button').prop('disabled', !values.length);
    $('#filter-button').prop('disabled', !values.length);
}

function defineColumns(columns, column_types) {
    var out = [];
    var editor = '';
    $.each(columns, function (index, column) {
        if (column === 'Name' || column === 'REFERENCE') {
            out.push({title: column, field: column});
        } else {
            if (column_types[column] === 'str') {
                editor = "input";
            } else  {
                editor = "number";
            }
            out.push({title: column, field: column, editor: editor});
        }
    });
    return out
}

function updateData(data) {
    var name = data.getData()['Name'];
    var column = data.getField();
    var value = data.getValue();

    // Find the layer of the property
    var table = $('.tab.active').data('name');

    // TODO: Move updates to InputStore class
    // FIXME: Not very efficient. Too many loops to find index of data
    // Update table data
    var row = currentTable.getRow(name).getData();
    row[column] = value;
    if (row['REFERENCE']) {
        row['REFERENCE'] = 'User - assumption';
        $('.tab.active').trigger('click');
    }

    // Update geometries
    if (table === 'zone' || table === 'district') {
        var properties = inputstore.getGeojson(table)['features'][inputstore.getGeojsonID(table, name)]['properties'];
        properties[column] = value;
        if (properties['REFERENCE']) {
            properties['REFERENCE'] = 'User - assumption';
        }
        if (column === 'height_ag') {
            inputstore.createNewGeojson(table);
           redrawBuildings();
        }
    }

    inputstore.addChange('update', table, data.getData()['Name'], data.getField(), data.getValue());

}

function selectRow(e, cell) {
    var value = cell.getValue();
    if(cell.getField() === 'Name') {
        if (cell.getRow().isSelected()) {
            currentTable.deselectRow(value);
        } else {
            currentTable.selectRow(value);
        }
    }
}

function addToSelection(data, row) {
    var buttons = [$('#clear-button'),$('#delete-button'),$('#edit-button')];
    $.each(buttons, function (_, button) {
        if (data.length) {
            button.show();
        } else {
            button.hide();
        }
    });

    var out = [];
    $.each(data, function (_, building) {
        out.push(building['Name']);
    });

    inputstore.setSelected(out);
    if (currentTable) {
        var scroll = $('.tabulator-tableHolder').scrollTop();
        filterSelection(out);
        $('.tabulator-tableHolder').scrollTop(scroll);
    }

   redrawBuildings();
}

function filterSelection(selection) {
    if ($('#filter-button').hasClass('btn-success')){
        currentTable.setFilter("Name", "in", selection);
    } else {
        currentTable.clearFilter();
    }
}

function createTooltip() {
    var table = $('.tab.active').data('name');

    $.each(inputstore.getColumns(table), function (_, column) {
        var glossary = inputstore.glossary[column];
        if (glossary) {
            $(`.tabulator-col-title:contains("${column}")`)
                .attr('data-toggle', 'tooltip')
                .attr('data-placement', 'top')
                .attr('data-container', 'body')
                .attr('data-html', true)
                .prop('title', `DESCRIPTION: ${glossary['DESCRIPTION']}<br>UNIT: ${glossary['UNIT']}`)
                .tooltip();
        }
    });
}

$(window).load(function () {
    $('#cea-inputs').show();

    $('#zone-tab').trigger('click');

    $('#select-all-button').click(function () {
        currentTable.selectRow();
    }).show();

    $('#filter-button').click(function () {
        $(this).toggleClass('btn-success');
        filterSelection(inputstore.getSelected());
    });

    $('#edit-button').click(function () {
        var table = $('.tab.active').data('name');
        var columns = inputstore.getColumns(table);

        $('#cea-column-editor .modal-title').text(`Editing ${table} table`);

        // TODO: Add input validation
        editform.empty();
        $.each(columns, function (_, column) {
            var type = (inputstore.getColumnTypes(table)[column] === 'str') ? 'text':'number';
            if (column !== 'Name' && column !== 'REFERENCE') {
                var input =
                    `<div class="form-group">` +
                      `<label class="control-label col-md-3 col-sm-3 col-xs-12" for="cea-input-${ column }">${ column }</label>` +
                      `<div class="col-md-6 col-sm-6 col-xs-12">` +
                        `<input type="${ type }" id="cea-input-${ column }" name="${ column }" placeholder="unchanged"
                               class="form-control col-md-7 col-xs-12">` +
                      `</div>` +
                    `</div>`;
                editform.append(input);
                if (type === 'text') {
                    $(`#cea-input-${ column }`).prop('pattern', '[T][0-9]+')
                        .prop('title', 'T[number]');
                } else if (type === 'number') {
                    $(`#cea-input-${ column }`).prop('step', 'any')
                        .prop('min', '0');
                }
            }
        });

        $('#cea-column-editor').on('shown.bs.modal', function () {
            new Tabulator("#selected-buildings", {
                data: currentTable.getSelectedData(),
                columns: currentTable.getColumnDefinitions(),
                layout:"fitColumns",
                height: 200
            });
        }).modal({'show': true, 'backdrop': 'static'});
    });

    $('#delete-button').click(function () {
        var selected = inputstore.getSelected();
        var layer = ($('.tab.active').data('name') !== 'district') ? 'zone':'district';
        var out = '\n';
        $.each(selected, function (_, building) {
            out += `${building}\n`
        });
        if (confirm("This will delete the following buildings from every table:" + out)) {
            inputstore.deleteBuildings(layer, selected);
            $('.tab.active').trigger('click');
        }
    });

    $('#clear-button').click(function () {
        currentTable.deselectRow();
        filterSelection(inputstore.getSelected());
    });

    $('#discard-button').click(function () {
        var changes = inputstore.changes;
        if (!Object.keys(changes['update']).length && !Object.keys(changes['delete']).length) {
            alert('No changes detected');
        } else {
            if (confirm("This will discard all unsaved changes.\n" + inputstore.changesToString())) {
                inputstore.resetChanges();
                $('.tab.active').trigger('click');
            }
        }
    });

    $('#save-button').click(function () {
        var changes = inputstore.changes;
        if (!Object.keys(changes['update']).length && !Object.keys(changes['delete']).length) {
            alert('No changes detected');
        } else {
            var deletemsg = Object.keys(changes['delete']).length ? "WARNING: Any buildings deleted this way cannot be recovered once saved!\n":"";
            if (confirm("Save these changes?\n"+ deletemsg +inputstore.changesToString())) {
                $('#saving-text').text('Saving Changes...');
                $('#saving-popup').modal({'show': true, 'backdrop': 'static'});

                $.ajax({
                    type: 'POST',
                    url: '/inputs/building-properties',
                    data: JSON.stringify({
                        changes: changes,
                        geojson: inputstore.geojsondata,
                        tables: inputstore.data,
                        crs: inputstore.crs
                    }),
                    contentType: 'application/json'
                }).done(function (data) {
                    // TODO: Either refresh page or do applyChanges()
                    inputstore.applyChanges(data);
                   redrawBuildings();

                    $('#saving-text').text('✔ Changes Saved!');
                    setTimeout(function(){
                        $('#saving-popup').modal('hide');
                    }, 1500);
                }).fail(function () {
                    var header =
                        '<button type="button" class="close cea-modal-close" data-dismiss="modal">' +
                        'Back' +
                        '</button>';
                    $('#saving-text').text('Something went wrong')
                        .append(header);
                });
            }
        }
    });

    editform.submit(function (e) {
        e.preventDefault();
        var table = $('.tab.active').data('name');
        var props = {};
        var form = editform.serialize().split('&');
        $.each(form, function (_, prop) {
            var temp = prop.split('=');
            if (temp[1] !== '') {
                var value = temp[1];
                if (inputstore.getColumnTypes(table)[temp[0]] !== 'str'){
                    value = Number(value);
                }
                props[temp[0]] = value;
            }
        });

        var data = [];
        $.each(inputstore.getSelected(), function (_, building) {
            // Add to changes
            $.each(props, function (key, value) {
                inputstore.addChange('update', table, building, key, value);
            });

            // Update table data
            var out = {Name: building, ...props};
            var row = currentTable.getRow(building).getData();
            if (row['REFERENCE']) {
                out['REFERENCE'] = 'User - assumption';
            }
            data.push(out);

            // Update geojsons
            // FIXME: Copied from updateData()
            if (table === 'zone' || table === 'district') {
                Object.assign(inputstore.getGeojson(table)['features'][inputstore.getGeojsonID(table, building)]['properties'], out);
            }
        });

        if (props['height_ag']) {
            inputstore.createNewGeojson(table);
           redrawBuildings();
        }

        currentTable.updateData(data);

        $('#cea-column-editor').modal('hide');
    });
});

window.addEventListener("beforeunload", function (e) {
    var confirmationMessage = 'There are still some unsaved changes.' +
        'Any unsaved changes will be discarded';

    if (Object.keys(inputstore.changes['update']).length || Object.keys(inputstore.changes['delete']).length) {
        e.returnValue = confirmationMessage;
        return  confirmationMessage;
    }
});<commit_msg>Add alert when user changes occupancy<commit_after>var currentTable;
var tempSelection;
var editform = $('#cea-column-editor-form');
const OCCUPANCY_ALERT = 'Remember to run data-helper after editing occupancy to reflect the changes to other building properties.';
let executedAlert = false;

// Add onclick function to tabs
$("[id$=-tab]").each(function () {
    $(this).click(function(){
        var oldtable = $('.tab.active').data('name') || 'zone';
        $('.tab').removeClass("active");
        $(this).addClass("active");

        // Remember scroll position
        var scroll = $('.tabulator-tableHolder').scrollTop();

        // Store previously selected buildings before creating new table
        if (inputstore.getData(oldtable).length) {
            if (inputstore.getSelected()) {
                tempSelection = [...inputstore.getSelected()];
            }
        }

        var name = $(this).data('name');
        $('#property-table').empty();
        createTable("property-table",`${name}`,
            inputstore.getData(name),
            inputstore.getColumns(name),
            inputstore.getColumnTypes(name)
        );

        // Restore previous selected
        inputstore.setSelected(tempSelection);
        if (inputstore.getSelected()) {
            currentTable.selectRow(inputstore.getSelected());
        }
        filterSelection(inputstore.getSelected());

        currentTable.redraw();
        $('.tabulator-tableHolder').scrollTop(scroll);

    });
});

function createTable(parent, name, values, columns, types) {
    var placeholder = '';
    var tool = '';
    if (!inputstore.getData(name).length) {
        placeholder = '
File cannot be found.
';
        if (name === 'zone') {
            tool = 'zone-helper';
        } else if (name === 'district') {
            tool = 'district-helper';
        } else {
            tool = 'data-helper';
        }

        placeholder += `<div>You can create the file using the <a href="/tools/${tool}">${tool}</a> tool.</div>`;
    } else {
        placeholder = '
No matching records found.
';
    }

    let editCallback = {};
    if (name === 'occupancy') {
        editCallback.dataEdited = showOccupancyAlert;
    }

    $(`#${parent}`).append(`<div id="${name}-table"></div>`);
    currentTable = new Tabulator(`#${name}-table`, {
        index: 'Name',
        data: values,
        columns: defineColumns(columns, types),
        placeholder: placeholder,

        layout: (['occupancy','architecture'].includes(name)) ? 'fitDataFill' : 'fitColumns',
        height: '300px',
        cellClick: selectRow,
        cellEdited: updateData,
        rowSelectionChanged: addToSelection,

        ...editCallback
    });

    createTooltip();

    $('#select-all-button').prop('disabled', !values.length);
    $('#filter-button').prop('disabled', !values.length);
}

function defineColumns(columns, column_types) {
    var out = [];
    var editor = '';
    $.each(columns, function (index, column) {
        if (column === 'Name' || column === 'REFERENCE') {
            out.push({title: column, field: column});
        } else {
            if (column_types[column] === 'str') {
                editor = "input";
            } else  {
                editor = "number";
            }
            out.push({title: column, field: column, editor: editor});
        }
    });
    return out
}

function updateData(data) {
    var name = data.getData()['Name'];
    var column = data.getField();
    var value = data.getValue();

    // Find the layer of the property
    var table = $('.tab.active').data('name');

    // TODO: Move updates to InputStore class
    // FIXME: Not very efficient. Too many loops to find index of data
    // Update table data
    var row = currentTable.getRow(name).getData();
    row[column] = value;
    if (row['REFERENCE']) {
        row['REFERENCE'] = 'User - assumption';
        $('.tab.active').trigger('click');
    }

    // Update geometries
    if (table === 'zone' || table === 'district') {
        var properties = inputstore.getGeojson(table)['features'][inputstore.getGeojsonID(table, name)]['properties'];
        properties[column] = value;
        if (properties['REFERENCE']) {
            properties['REFERENCE'] = 'User - assumption';
        }
        if (column === 'height_ag') {
            inputstore.createNewGeojson(table);
           redrawBuildings();
        }
    }

    inputstore.addChange('update', table, data.getData()['Name'], data.getField(), data.getValue());

}

function selectRow(e, cell) {
    var value = cell.getValue();
    if(cell.getField() === 'Name') {
        if (cell.getRow().isSelected()) {
            currentTable.deselectRow(value);
        } else {
            currentTable.selectRow(value);
        }
    }
}

function addToSelection(data, row) {
    var buttons = [$('#clear-button'),$('#delete-button'),$('#edit-button')];
    $.each(buttons, function (_, button) {
        if (data.length) {
            button.show();
        } else {
            button.hide();
        }
    });

    var out = [];
    $.each(data, function (_, building) {
        out.push(building['Name']);
    });

    inputstore.setSelected(out);
    if (currentTable) {
        var scroll = $('.tabulator-tableHolder').scrollTop();
        filterSelection(out);
        $('.tabulator-tableHolder').scrollTop(scroll);
    }

   redrawBuildings();
}

function filterSelection(selection) {
    if ($('#filter-button').hasClass('btn-success')){
        currentTable.setFilter("Name", "in", selection);
    } else {
        currentTable.clearFilter();
    }
}

function createTooltip() {
    var table = $('.tab.active').data('name');

    $.each(inputstore.getColumns(table), function (_, column) {
        var glossary = inputstore.glossary[column];
        if (glossary) {
            $(`.tabulator-col-title:contains("${column}")`)
                .attr('data-toggle', 'tooltip')
                .attr('data-placement', 'top')
                .attr('data-container', 'body')
                .attr('data-html', true)
                .prop('title', `DESCRIPTION: ${glossary['DESCRIPTION']}<br>UNIT: ${glossary['UNIT']}`)
                .tooltip();
        }
    });
}

function showOccupancyAlert() {
    if (!executedAlert) {
        executedAlert = true;
        alert(OCCUPANCY_ALERT);
    }
}

$(window).load(function () {
    $('#cea-inputs').show();

    $('#zone-tab').trigger('click');

    $('#select-all-button').click(function () {
        currentTable.selectRow();
    }).show();

    $('#filter-button').click(function () {
        $(this).toggleClass('btn-success');
        filterSelection(inputstore.getSelected());
    });

    $('#edit-button').click(function () {
        var table = $('.tab.active').data('name');
        var columns = inputstore.getColumns(table);

        $('#cea-column-editor .modal-title').text(`Editing ${table} table`);

        if (table === 'occupancy') {
            $('#cea-column-editor-form').on('submit', showOccupancyAlert);
        }

        // TODO: Add input validation
        editform.empty();
        $.each(columns, function (_, column) {
            var type = (inputstore.getColumnTypes(table)[column] === 'str') ? 'text':'number';
            if (column !== 'Name' && column !== 'REFERENCE') {
                var input =
                    `<div class="form-group">` +
                      `<label class="control-label col-md-3 col-sm-3 col-xs-12" for="cea-input-${ column }">${ column }</label>` +
                      `<div class="col-md-6 col-sm-6 col-xs-12">` +
                        `<input type="${ type }" id="cea-input-${ column }" name="${ column }" placeholder="unchanged"
                               class="form-control col-md-7 col-xs-12">` +
                      `</div>` +
                    `</div>`;
                editform.append(input);
                if (type === 'text') {
                    $(`#cea-input-${ column }`).prop('pattern', '[T][0-9]+')
                        .prop('title', 'T[number]');
                } else if (type === 'number') {
                    $(`#cea-input-${ column }`).prop('step', 'any')
                        .prop('min', '0');
                }
            }
        });

        $('#cea-column-editor').on('shown.bs.modal', function () {
            new Tabulator("#selected-buildings", {
                data: currentTable.getSelectedData(),
                columns: currentTable.getColumnDefinitions(),
                layout:"fitColumns",
                height: 200
            });
        }).modal({'show': true, 'backdrop': 'static'});
    });

    $('#delete-button').click(function () {
        var selected = inputstore.getSelected();
        var layer = ($('.tab.active').data('name') !== 'district') ? 'zone':'district';
        var out = '\n';
        $.each(selected, function (_, building) {
            out += `${building}\n`
        });
        if (confirm("This will delete the following buildings from every table:" + out)) {
            inputstore.deleteBuildings(layer, selected);
            $('.tab.active').trigger('click');
        }
    });

    $('#clear-button').click(function () {
        currentTable.deselectRow();
        filterSelection(inputstore.getSelected());
    });

    $('#discard-button').click(function () {
        var changes = inputstore.changes;
        if (!Object.keys(changes['update']).length && !Object.keys(changes['delete']).length) {
            alert('No changes detected');
        } else {
            if (confirm("This will discard all unsaved changes.\n" + inputstore.changesToString())) {
                inputstore.resetChanges();
                $('.tab.active').trigger('click');
            }
        }
    });

    $('#save-button').click(function () {
        var changes = inputstore.changes;
        if (!Object.keys(changes['update']).length && !Object.keys(changes['delete']).length) {
            alert('No changes detected');
        } else {
            var deletemsg = Object.keys(changes['delete']).length ? "WARNING: Any buildings deleted this way cannot be recovered once saved!\n":"";
            if (confirm("Save these changes?\n"+ deletemsg +inputstore.changesToString())) {
                $('#saving-text').text('Saving Changes...');
                $('#saving-popup').modal({'show': true, 'backdrop': 'static'});

                $.ajax({
                    type: 'POST',
                    url: '/inputs/building-properties',
                    data: JSON.stringify({
                        changes: changes,
                        geojson: inputstore.geojsondata,
                        tables: inputstore.data,
                        crs: inputstore.crs
                    }),
                    contentType: 'application/json'
                }).done(function (data) {
                    // TODO: Either refresh page or do applyChanges()
                    inputstore.applyChanges(data);
                   redrawBuildings();

                    $('#saving-text').text('✔ Changes Saved!');
                    setTimeout(function(){
                        $('#saving-popup').modal('hide');
                    }, 1500);
                }).fail(function () {
                    var header =
                        '<button type="button" class="close cea-modal-close" data-dismiss="modal">' +
                        'Back' +
                        '</button>';
                    $('#saving-text').text('Something went wrong')
                        .append(header);
                });
            }
        }
    });

    editform.submit(function (e) {
        e.preventDefault();
        var table = $('.tab.active').data('name');
        var props = {};
        var form = editform.serialize().split('&');
        $.each(form, function (_, prop) {
            var temp = prop.split('=');
            if (temp[1] !== '') {
                var value = temp[1];
                if (inputstore.getColumnTypes(table)[temp[0]] !== 'str'){
                    value = Number(value);
                }
                props[temp[0]] = value;
            }
        });

        var data = [];
        $.each(inputstore.getSelected(), function (_, building) {
            // Add to changes
            $.each(props, function (key, value) {
                inputstore.addChange('update', table, building, key, value);
            });

            // Update table data
            var out = {Name: building, ...props};
            var row = currentTable.getRow(building).getData();
            if (row['REFERENCE']) {
                out['REFERENCE'] = 'User - assumption';
            }
            data.push(out);

            // Update geojsons
            // FIXME: Copied from updateData()
            if (table === 'zone' || table === 'district') {
                Object.assign(inputstore.getGeojson(table)['features'][inputstore.getGeojsonID(table, building)]['properties'], out);
            }
        });

        if (props['height_ag']) {
            inputstore.createNewGeojson(table);
           redrawBuildings();
        }

        currentTable.updateData(data);

        $('#cea-column-editor').modal('hide');
    });
});

window.addEventListener("beforeunload", function (e) {
    var confirmationMessage = 'There are still some unsaved changes.' +
        'Any unsaved changes will be discarded';

    if (Object.keys(inputstore.changes['update']).length || Object.keys(inputstore.changes['delete']).length) {
        e.returnValue = confirmationMessage;
        return  confirmationMessage;
    }
});<|endoftext|>


<commit_before>import multipleChoice   from './multiple_choice_serializer';
import genusTypes       from '../../../constants/genus_types';

export default function factory(type) {
  switch (type) {
    case 'multipleChoice':
      return multipleChoice;

    default:
      throw `invalid type: ${type}`;
  }
}<commit_msg>new line<commit_after>import multipleChoice   from './multiple_choice_serializer';
import genusTypes       from '../../../constants/genus_types';

export default function factory(type) {
  switch (type) {
    case 'multipleChoice':
      return multipleChoice;

    default:
      throw `invalid type: ${type}`;
  }
}
<|endoftext|>


<commit_before>require('./../utils/jquery-slidefade');

var $ = require('jquery');
var t = require('../utils/translate');

require('jquery-ui/ui/core');
require('jquery-ui/ui/widget');
require('jquery-ui/ui/mouse');
require('jquery-ui/ui/draggable');
require('jquery-ui/ui/droppable');
require('jquery-ui/ui/sortable');
require('jquery-ui/ui/resizable');
require('jquery-ui/ui/button');
require('jquery-ui/ui/dialog');

var Dashboard = function($dashboard) {
    this.$dashboard = $dashboard;
};

Dashboard.prototype = {
    initTools: function($dashboard) {
        $dashboard.find('.dashboard-tools-toggle').on('click', function (e) {
            e.preventDefault();
            $dashboard.find('.dashboard-tools').toggleClass('visible');
        });

        var $form = $dashboard.find('#add-dashboard-module-form');

        $form.find('.add-dashboard-link').on('click', function (e) {
            var $typeInput = $form.find('[name="type"]');
            var type = $form.find('[name="module"] option:selected').data('type');

            if (type) {
                $typeInput.val(type);

                $.ajax({
                    url: $form.attr('action'),
                    method: $form.attr('method'),
                    dataType: 'json',
                    data: $form.serialize(),
                    success: function (result) {
                        if (result.error) {
                            return;
                        }

                        document.location = result.success_url;
                    }
                });
            }

            e.preventDefault();
        });

        $dashboard.find('.reset-dashboard-link').on('click', function(e) {
            var buttons = {};
            var resetDashboard = function () {
                var $form = $dashboard.find('#reset-dashboard-form');

                $.ajax({
                    url: $form.attr('action'),
                    method: $form.attr('method'),
                    dataType: 'json',
                    data: $form.serialize(),
                    success: function (result) {
                        if (result.error) {
                            return;
                        }

                        location.reload();
                    }
                });
            };

            buttons[t('Yes')] = function() {
                resetDashboard();
                $(this).dialog('close');
            };

            buttons[t('Cancel')] = function() {
                $(this).dialog('close');
            };

            $dashboard.find('#reset-dashboard-dialog').dialog({
                resizable: false,
                modal: true,
                buttons: buttons
            });

            e.preventDefault();
        });
    },
    updateDashboardModules: function($dashboard) {
        var $form = $dashboard.find('#update-dashboard-modules-form');
        var modules = [];

        $dashboard.find('.dashboard-column').each(function () {
            var $column = $(this);
            var column = $column.closest('.dashboard-column-wrapper').index();

            $column.find('.dashboard-item').each(function () {
                var $item = $(this);
                var order = $item.index();
                var id = $item.data('module-id');

                modules.push({
                    id: id,
                    column: column,
                    order: order
                });
            });
        });

        $form.find('[name="modules"]').val(JSON.stringify(modules));

        $.ajax({
            url: $form.attr('action'),
            method: $form.attr('method'),
            dataType: 'json',
            data: $form.serialize()
        });
    },
    initModulesDragAndDrop: function($dashboard) {
        var self = this;

        $dashboard.find('.dashboard-column').droppable({
            activeClass: 'active',
            hoverClass: 'hovered',
            tolerance: 'pointer',
            accept: '.dashboard-item'
        }).sortable({
            items: '.dashboard-item',
            handle: '.dashboard-item-header',
            tolerance: 'pointer',
            connectWith: '.dashboard-column',
            cursor: 'move',
            placeholder: 'dashboard-item placeholder',
            forcePlaceholderSize: true,
            update: function (event, ui) {
                self.updateDashboardModules($dashboard);
            }
        });
    },
    initCollapsibleModules: function($dashboard) {
        var $form = $dashboard.find('#update-dashboard-module-collapse-form');

        $dashboard.find('.dashboard-item.collapsible').each(function () {
            var $item = $(this);
            var $link = $item.find('.dashboard-item-collapse');
            var $collapsible = $item.find('.dashboard-item-content');
            var moduleId = $item.data('module-id');

            $link.on('click', function (e) {
                e.preventDefault();

                $collapsible.slideFadeToggle(200, 'swing', function () {
                    var collapsed = $collapsible.is(':visible') == false;

                    if (collapsed) {
                        $item.addClass('collapsed')
                    } else {
                        $item.removeClass('collapsed')
                    }

                    $form.find('[name="id"]').val(moduleId);
                    $form.find('[name="collapsed"]').val(collapsed ? 'true' : 'false');

                    $.ajax({
                        url: $form.attr('action'),
                        method: $form.attr('method'),
                        dataType: 'json',
                        data: $form.serialize()
                    });
                });
            });
        });
    },
    initDeletableModules: function($dashboard) {
        var $form = $dashboard.find('#remove-dashboard-module-form');

        $dashboard.find('.dashboard-item.deletable').each(function () {
            var $item = $(this);
            var $link = $item.find('.dashboard-item-remove');
            var moduleId = $item.data('module-id');

            $link.on('click', function (e) {
                e.preventDefault();

                var buttons = {};

                var deleteModule = function () {
                    $item.fadeOut(200, 'swing', function () {
                        $form.find('[name="id"]').val(moduleId);

                        $.ajax({
                            url: $form.attr('action'),
                            method: $form.attr('method'),
                            dataType: 'json',
                            data: $form.serialize()
                        });
                    });
                };

                buttons[t('Delete')] = function () {
                    deleteModule();
                    $(this).dialog('close');
                };

                buttons[t('Cancel')] = function () {
                    $(this).dialog('close');
                };

                $dashboard.find('#module-remove-dialog').dialog({
                    resizable: false,
                    modal: true,
                    buttons: buttons
                });
            });
        });
    },
    initAjaxModules: function($dashboard) {
        $dashboard.find('.dashboard-item.ajax').each(function () {
            var $item = $(this);
            var $content = $item.find('.dashboard-item-content');
            var url = $item.data('ajax-url');

            $.ajax({
                url: url,
                dataType: 'json',
                success: function (result) {
                    if (result.error) {
                        $content.empty();
                        return;
                    }

                    var oldHeight = $content.height();
                    $content.html(result.html);
                    var newHeight = $content.height();

                    $content.height(oldHeight);
                    $content.animate({
                        height: newHeight
                    }, 250);
                },
                error: function () {
                    $content.empty();
                }
            });
        });
    },
    updateModuleChildrenFormsetLabels: function($inline) {
        $inline.find('.inline-related').each(function(i) {
            $(this).find('.inline_label').text('#' + (i + 1));
        });
    },
    updateModuleChildrenFormsetFormIndex: function($form, index) {
        var prefix = "children";
        var id_regex = new RegExp("(" + prefix + "-(\\d+|__prefix__))");
        var replacement = prefix + "-" + index;

        $form.find("fieldset.module *").each(function() {
            var $el = $(this);

            $.each(['for', 'id', 'name'], function() {
                var attr = this;

                if ($el.attr(attr)) {
                    $el.attr(attr, $el.attr(attr).replace(id_regex, replacement));
                }
            });
        });
    },
    updateModuleChildrenFormsetFormsIndexes: function($inline) {
        var self = this;
        var from = parseInt($inline.find('.inline-related.has_original').length);

        $inline.find('.inline-related.last-related').each(function(i) {
            self.updateModuleChildrenFormsetFormIndex($(this), from + i);
        });
    },
    updateModuleChildrenFormsetTotalForms: function($inline) {
        var $totalFormsInput = $inline.find('[name="children-TOTAL_FORMS"]');
        var totalForms = parseInt($inline.find('.inline-related').length);

        $totalFormsInput.val(totalForms);
    },
    initModuleChildrenFormsetUpdate: function($dashboard) {
        if (!$dashboard.hasClass('change-form')) {
            return;
        }

        var self = this;
        var $inline = $dashboard.find('.inline-group');

        $inline.find('.add-row a').on('click', function(e) {
            e.preventDefault();

            var $empty = $inline.find('.inline-related.empty-form');
            var $clone = $empty
                .clone(true)
                .removeClass('empty-form')
                .insertBefore($empty);

            self.updateModuleChildrenFormsetLabels($inline);
            self.updateModuleChildrenFormsetFormIndex($empty, parseInt($inline.find('.inline-related').length) - 1);
            self.updateModuleChildrenFormsetFormIndex($clone, parseInt($inline.find('.inline-related').length) - 2);
            self.updateModuleChildrenFormsetTotalForms($inline);
        });

        $inline.find('.inline-deletelink').on('click', function(e) {
            e.preventDefault();

            $(this).closest('.inline-related').remove();

            self.updateModuleChildrenFormsetFormsIndexes($inline);
            self.updateModuleChildrenFormsetLabels($inline);
            self.updateModuleChildrenFormsetTotalForms($inline);
        });
    },
    run: function() {
        var $dashboard = this.$dashboard;

        try {
            this.initTools($dashboard);
            this.initModulesDragAndDrop($dashboard);
            this.initCollapsibleModules($dashboard);
            this.initDeletableModules($dashboard);
            this.initAjaxModules($dashboard);
            this.initModuleChildrenFormsetUpdate($dashboard);
        } catch (e) {
            console.error(e, e.stack);
        }

        $dashboard.addClass('initialized');
    }
};

$(document).ready(function() {
    $('.dashboard.jet').each(function() {
        new Dashboard($(this)).run();
    });
});
<commit_msg>Fix dashboard module height wrong after height animation<commit_after>require('./../utils/jquery-slidefade');

var $ = require('jquery');
var t = require('../utils/translate');

require('jquery-ui/ui/core');
require('jquery-ui/ui/widget');
require('jquery-ui/ui/mouse');
require('jquery-ui/ui/draggable');
require('jquery-ui/ui/droppable');
require('jquery-ui/ui/sortable');
require('jquery-ui/ui/resizable');
require('jquery-ui/ui/button');
require('jquery-ui/ui/dialog');

var Dashboard = function($dashboard) {
    this.$dashboard = $dashboard;
};

Dashboard.prototype = {
    initTools: function($dashboard) {
        $dashboard.find('.dashboard-tools-toggle').on('click', function (e) {
            e.preventDefault();
            $dashboard.find('.dashboard-tools').toggleClass('visible');
        });

        var $form = $dashboard.find('#add-dashboard-module-form');

        $form.find('.add-dashboard-link').on('click', function (e) {
            var $typeInput = $form.find('[name="type"]');
            var type = $form.find('[name="module"] option:selected').data('type');

            if (type) {
                $typeInput.val(type);

                $.ajax({
                    url: $form.attr('action'),
                    method: $form.attr('method'),
                    dataType: 'json',
                    data: $form.serialize(),
                    success: function (result) {
                        if (result.error) {
                            return;
                        }

                        document.location = result.success_url;
                    }
                });
            }

            e.preventDefault();
        });

        $dashboard.find('.reset-dashboard-link').on('click', function(e) {
            var buttons = {};
            var resetDashboard = function () {
                var $form = $dashboard.find('#reset-dashboard-form');

                $.ajax({
                    url: $form.attr('action'),
                    method: $form.attr('method'),
                    dataType: 'json',
                    data: $form.serialize(),
                    success: function (result) {
                        if (result.error) {
                            return;
                        }

                        location.reload();
                    }
                });
            };

            buttons[t('Yes')] = function() {
                resetDashboard();
                $(this).dialog('close');
            };

            buttons[t('Cancel')] = function() {
                $(this).dialog('close');
            };

            $dashboard.find('#reset-dashboard-dialog').dialog({
                resizable: false,
                modal: true,
                buttons: buttons
            });

            e.preventDefault();
        });
    },
    updateDashboardModules: function($dashboard) {
        var $form = $dashboard.find('#update-dashboard-modules-form');
        var modules = [];

        $dashboard.find('.dashboard-column').each(function () {
            var $column = $(this);
            var column = $column.closest('.dashboard-column-wrapper').index();

            $column.find('.dashboard-item').each(function () {
                var $item = $(this);
                var order = $item.index();
                var id = $item.data('module-id');

                modules.push({
                    id: id,
                    column: column,
                    order: order
                });
            });
        });

        $form.find('[name="modules"]').val(JSON.stringify(modules));

        $.ajax({
            url: $form.attr('action'),
            method: $form.attr('method'),
            dataType: 'json',
            data: $form.serialize()
        });
    },
    initModulesDragAndDrop: function($dashboard) {
        var self = this;

        $dashboard.find('.dashboard-column').droppable({
            activeClass: 'active',
            hoverClass: 'hovered',
            tolerance: 'pointer',
            accept: '.dashboard-item'
        }).sortable({
            items: '.dashboard-item',
            handle: '.dashboard-item-header',
            tolerance: 'pointer',
            connectWith: '.dashboard-column',
            cursor: 'move',
            placeholder: 'dashboard-item placeholder',
            forcePlaceholderSize: true,
            update: function (event, ui) {
                self.updateDashboardModules($dashboard);
            }
        });
    },
    initCollapsibleModules: function($dashboard) {
        var $form = $dashboard.find('#update-dashboard-module-collapse-form');

        $dashboard.find('.dashboard-item.collapsible').each(function () {
            var $item = $(this);
            var $link = $item.find('.dashboard-item-collapse');
            var $collapsible = $item.find('.dashboard-item-content');
            var moduleId = $item.data('module-id');

            $link.on('click', function (e) {
                e.preventDefault();

                $collapsible.slideFadeToggle(200, 'swing', function () {
                    var collapsed = $collapsible.is(':visible') == false;

                    if (collapsed) {
                        $item.addClass('collapsed')
                    } else {
                        $item.removeClass('collapsed')
                    }

                    $form.find('[name="id"]').val(moduleId);
                    $form.find('[name="collapsed"]').val(collapsed ? 'true' : 'false');

                    $.ajax({
                        url: $form.attr('action'),
                        method: $form.attr('method'),
                        dataType: 'json',
                        data: $form.serialize()
                    });
                });
            });
        });
    },
    initDeletableModules: function($dashboard) {
        var $form = $dashboard.find('#remove-dashboard-module-form');

        $dashboard.find('.dashboard-item.deletable').each(function () {
            var $item = $(this);
            var $link = $item.find('.dashboard-item-remove');
            var moduleId = $item.data('module-id');

            $link.on('click', function (e) {
                e.preventDefault();

                var buttons = {};

                var deleteModule = function () {
                    $item.fadeOut(200, 'swing', function () {
                        $form.find('[name="id"]').val(moduleId);

                        $.ajax({
                            url: $form.attr('action'),
                            method: $form.attr('method'),
                            dataType: 'json',
                            data: $form.serialize()
                        });
                    });
                };

                buttons[t('Delete')] = function () {
                    deleteModule();
                    $(this).dialog('close');
                };

                buttons[t('Cancel')] = function () {
                    $(this).dialog('close');
                };

                $dashboard.find('#module-remove-dialog').dialog({
                    resizable: false,
                    modal: true,
                    buttons: buttons
                });
            });
        });
    },
    initAjaxModules: function($dashboard) {
        $dashboard.find('.dashboard-item.ajax').each(function () {
            var $item = $(this);
            var $content = $item.find('.dashboard-item-content');
            var url = $item.data('ajax-url');

            $.ajax({
                url: url,
                dataType: 'json',
                success: function (result) {
                    if (result.error) {
                        $content.empty();
                        return;
                    }

                    var oldHeight = $content.height();
                    $content.html(result.html);
                    var newHeight = $content.height();

                    $content.height(oldHeight);
                    $content.animate({
                        height: newHeight
                    }, 250, 'swing', function() {
                        $content.height('auto');
                    });
                },
                error: function () {
                    $content.empty();
                }
            });
        });
    },
    updateModuleChildrenFormsetLabels: function($inline) {
        $inline.find('.inline-related').each(function(i) {
            $(this).find('.inline_label').text('#' + (i + 1));
        });
    },
    updateModuleChildrenFormsetFormIndex: function($form, index) {
        var prefix = "children";
        var id_regex = new RegExp("(" + prefix + "-(\\d+|__prefix__))");
        var replacement = prefix + "-" + index;

        $form.find("fieldset.module *").each(function() {
            var $el = $(this);

            $.each(['for', 'id', 'name'], function() {
                var attr = this;

                if ($el.attr(attr)) {
                    $el.attr(attr, $el.attr(attr).replace(id_regex, replacement));
                }
            });
        });
    },
    updateModuleChildrenFormsetFormsIndexes: function($inline) {
        var self = this;
        var from = parseInt($inline.find('.inline-related.has_original').length);

        $inline.find('.inline-related.last-related').each(function(i) {
            self.updateModuleChildrenFormsetFormIndex($(this), from + i);
        });
    },
    updateModuleChildrenFormsetTotalForms: function($inline) {
        var $totalFormsInput = $inline.find('[name="children-TOTAL_FORMS"]');
        var totalForms = parseInt($inline.find('.inline-related').length);

        $totalFormsInput.val(totalForms);
    },
    initModuleChildrenFormsetUpdate: function($dashboard) {
        if (!$dashboard.hasClass('change-form')) {
            return;
        }

        var self = this;
        var $inline = $dashboard.find('.inline-group');

        $inline.find('.add-row a').on('click', function(e) {
            e.preventDefault();

            var $empty = $inline.find('.inline-related.empty-form');
            var $clone = $empty
                .clone(true)
                .removeClass('empty-form')
                .insertBefore($empty);

            self.updateModuleChildrenFormsetLabels($inline);
            self.updateModuleChildrenFormsetFormIndex($empty, parseInt($inline.find('.inline-related').length) - 1);
            self.updateModuleChildrenFormsetFormIndex($clone, parseInt($inline.find('.inline-related').length) - 2);
            self.updateModuleChildrenFormsetTotalForms($inline);
        });

        $inline.find('.inline-deletelink').on('click', function(e) {
            e.preventDefault();

            $(this).closest('.inline-related').remove();

            self.updateModuleChildrenFormsetFormsIndexes($inline);
            self.updateModuleChildrenFormsetLabels($inline);
            self.updateModuleChildrenFormsetTotalForms($inline);
        });
    },
    run: function() {
        var $dashboard = this.$dashboard;

        try {
            this.initTools($dashboard);
            this.initModulesDragAndDrop($dashboard);
            this.initCollapsibleModules($dashboard);
            this.initDeletableModules($dashboard);
            this.initAjaxModules($dashboard);
            this.initModuleChildrenFormsetUpdate($dashboard);
        } catch (e) {
            console.error(e, e.stack);
        }

        $dashboard.addClass('initialized');
    }
};

$(document).ready(function() {
    $('.dashboard.jet').each(function() {
        new Dashboard($(this)).run();
    });
});
<|endoftext|>


<commit_before>/* global document, setTimeout, WSE */
/*
    Copyright (c) 2012, 2013 The WebStory Engine Contributors
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.

    * Neither the name WebStory Engine nor the names of its contributors
      may be used to endorse or promote products derived from this software
      without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function (out)
{
    "use strict";

    out.assets.mixins.displayable.flicker = function (command, args)
    {
        var self, duration, bus, stage, times, step, element, fx = out.fx;
        var isAnimation, fn, iteration, maxOpacity, val1, val2, dur1, dur2;

        args = args || {};
        self = this;
        duration = command.getAttribute("duration") || 500;
        times = command.getAttribute("times") || 10;
        maxOpacity = command.getAttribute("opacity") || 1;
        element = args.element || document.getElementById(this.cssid);
        step = duration / times;
        iteration = 0;

        if (!element)
        {
            this.bus.trigger(
                "wse.interpreter.warning",
                {
                    element: command,
                    message: "DOM Element for asset is missing!"
                }
            );

            return;
        }

        if (!(parseInt(element.style.opacity, 10)))
        {
            val1 = 0;
            val2 = maxOpacity;
            dur1 = step / 3;
            dur2 = dur1 * 2;
        }
        else
        {
            val2 = 0;
            val1 = maxOpacity;
            dur2 = step / 3;
            dur1 = dur2 * 2;
        }

        //         console.log("CSS ID: " + this.cssid, element);

        bus = args.bus || this.bus;
        stage = args.stage || this.stage;
        isAnimation = args.animation === true ? true : false;

        if (!isAnimation)
        {
            self.interpreter.waitCounter += 1;
        }

        fn = function ()
        {
            iteration += 1;
            fx.transform(
                function (v)
                {
                    element.style.opacity = v;
                },
                val1,
                val2,
                {
                    duration: dur1,
                    onFinish: function ()
                    {
                        fx.transform(
                            function (v)
                            {
                                element.style.opacity = v;
                            },
                            val2,
                            val1,
                            {
                                duration: dur2,
                                onFinish: function ()
                                {
                                    if (iteration <= times)
                                    {
                                        setTimeout(fn, 0);
                                        return;
                                    }
                                    if (!isAnimation)
                                    {
                                        self.interpreter.waitCounter -= 1;
                                    }
                                },
                                easing: fx.easing.easeInQuad
                            }
                        );
                    },
                    easing: fx.easing.easeInQuad
                }
            );
        };
        fn();

        bus.trigger("wse.assets.mixins.flicker", this);

        return {
            doNext: true
        };
    };
}(WSE));<commit_msg>Removed debug comment from flicker asset.<commit_after>/* global document, setTimeout, WSE */
/*
    Copyright (c) 2012, 2013 The WebStory Engine Contributors
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.

    * Neither the name WebStory Engine nor the names of its contributors
      may be used to endorse or promote products derived from this software
      without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
(function (out)
{
    "use strict";

    out.assets.mixins.displayable.flicker = function (command, args)
    {
        var self, duration, bus, stage, times, step, element, fx = out.fx;
        var isAnimation, fn, iteration, maxOpacity, val1, val2, dur1, dur2;

        args = args || {};
        self = this;
        duration = command.getAttribute("duration") || 500;
        times = command.getAttribute("times") || 10;
        maxOpacity = command.getAttribute("opacity") || 1;
        element = args.element || document.getElementById(this.cssid);
        step = duration / times;
        iteration = 0;

        if (!element)
        {
            this.bus.trigger(
                "wse.interpreter.warning",
                {
                    element: command,
                    message: "DOM Element for asset is missing!"
                }
            );

            return;
        }

        if (!(parseInt(element.style.opacity, 10)))
        {
            val1 = 0;
            val2 = maxOpacity;
            dur1 = step / 3;
            dur2 = dur1 * 2;
        }
        else
        {
            val2 = 0;
            val1 = maxOpacity;
            dur2 = step / 3;
            dur1 = dur2 * 2;
        }

        bus = args.bus || this.bus;
        stage = args.stage || this.stage;
        isAnimation = args.animation === true ? true : false;

        if (!isAnimation)
        {
            self.interpreter.waitCounter += 1;
        }

        fn = function ()
        {
            iteration += 1;
            fx.transform(
                function (v)
                {
                    element.style.opacity = v;
                },
                val1,
                val2,
                {
                    duration: dur1,
                    onFinish: function ()
                    {
                        fx.transform(
                            function (v)
                            {
                                element.style.opacity = v;
                            },
                            val2,
                            val1,
                            {
                                duration: dur2,
                                onFinish: function ()
                                {
                                    if (iteration <= times)
                                    {
                                        setTimeout(fn, 0);
                                        return;
                                    }
                                    if (!isAnimation)
                                    {
                                        self.interpreter.waitCounter -= 1;
                                    }
                                },
                                easing: fx.easing.easeInQuad
                            }
                        );
                    },
                    easing: fx.easing.easeInQuad
                }
            );
        };
        fn();

        bus.trigger("wse.assets.mixins.flicker", this);

        return {
            doNext: true
        };
    };
}(WSE));<|endoftext|>


<commit_before>import sqlFormatter from "./../src/sqlFormatter";
import behavesLikeSqlFormatter from "./behavesLikeSqlFormatter";

describe("StandardSqlFormatter", function() {
    behavesLikeSqlFormatter();

    it("formats INSERT without INTO", function() {
        const result = sqlFormatter.format(
            "INSERT Customers (ID, MoneyBalance, Address, City) VALUES (12,-123.4, 'Skagen 2111','Stv');"
        );
        expect(result).toBe(
            "INSERT\n" +
            "  Customers (ID, MoneyBalance, Address, City)\n" +
            "VALUES\n" +
            "  (12, -123.4, 'Skagen 2111', 'Stv');"
        );
    });

    it("formats ALTER TABLE ... MODIFY query", function() {
        const result = sqlFormatter.format(
            "ALTER TABLE supplier MODIFY supplier_name char(100) NOT NULL;"
        );
        expect(result).toBe(
            "ALTER TABLE\n" +
            "  supplier\n" +
            "MODIFY\n" +
            "  supplier_name char(100) NOT NULL;"
        );
    });

    it("formats ALTER TABLE ... ALTER COLUMN query", function() {
        const result = sqlFormatter.format(
            "ALTER TABLE supplier ALTER COLUMN supplier_name VARCHAR(100) NOT NULL;"
        );
        expect(result).toBe(
            "ALTER TABLE\n" +
            "  supplier\n" +
            "ALTER COLUMN\n" +
            "  supplier_name VARCHAR(100) NOT NULL;"
        );
    });

    it("recognizes [] strings", function() {
        expect(sqlFormatter.format("[foo JOIN bar]")).toBe("[foo JOIN bar]");
        expect(sqlFormatter.format("[foo ]] JOIN bar]")).toBe("[foo ]] JOIN bar]");
    });

    it("recognizes @variables", function() {
        const result = sqlFormatter.format(
            "SELECT @variable, @a1_2.3$, @'var name', @\"var name\", @`var name`, @[var name];"
        );
        expect(result).toBe(
            "SELECT\n" +
            "  @variable,\n" +
            "  @a1_2.3$,\n" +
            "  @'var name',\n" +
            "  @\"var name\",\n" +
            "  @`var name`,\n" +
            "  @[var name];"
        );
    });

    it("replaces @variables with param values", function() {
        const result = sqlFormatter.format(
            "SELECT @variable, @a1_2.3$, @'var name', @\"var name\", @`var name`, @[var name], @'var\\name';",
            {
                params: {
                    "variable": "\"variable value\"",
                    "a1_2.3$": "'weird value'",
                    "var name": "'var value'",
                    "var\\name": "'var\\ value'"
                }
            }
        );
        expect(result).toBe(
            "SELECT\n" +
            "  \"variable value\",\n" +
            "  'weird value',\n" +
            "  'var value',\n" +
            "  'var value',\n" +
            "  'var value',\n" +
            "  'var value',\n" +
            "  'var\\ value';"
        );
    });

    it("recognizes :variables", function() {
        const result = sqlFormatter.format(
            "SELECT :variable, :a1_2.3$, :'var name', :\"var name\", :`var name`, :[var name];"
        );
        expect(result).toBe(
            "SELECT\n" +
            "  :variable,\n" +
            "  :a1_2.3$,\n" +
            "  :'var name',\n" +
            "  :\"var name\",\n" +
            "  :`var name`,\n" +
            "  :[var name];"
        );
    });

    it("replaces :variables with param values", function() {
        const result = sqlFormatter.format(
            "SELECT :variable, :a1_2.3$, :'var name', :\"var name\", :`var name`," +
            " :[var name], :'escaped \\'var\\'', :\"^*& weird \\\" var   \";",
            {
                params: {
                    "variable": "\"variable value\"",
                    "a1_2.3$": "'weird value'",
                    "var name": "'var value'",
                    "escaped 'var'": "'weirder value'",
                    "^*& weird \" var   ": "'super weird value'"
                }
            }
        );
        expect(result).toBe(
            "SELECT\n" +
            "  \"variable value\",\n" +
            "  'weird value',\n" +
            "  'var value',\n" +
            "  'var value',\n" +
            "  'var value',\n" +
            "  'var value',\n" +
            "  'weirder value',\n" +
            "  'super weird value';"
        );
    });

    it("recognizes ?[0-9]* placeholders", function() {
        const result = sqlFormatter.format("SELECT ?1, ?25, ?;");
        expect(result).toBe(
            "SELECT\n" +
            "  ?1,\n" +
            "  ?25,\n" +
            "  ?;"
        );
    });

    it("replaces ? numbered placeholders with param values", function() {
        const result = sqlFormatter.format("SELECT ?1, ?2, ?0;", {
            params: {
                0: "first",
                1: "second",
                2: "third"
            }
        });
        expect(result).toBe(
            "SELECT\n" +
            "  second,\n" +
            "  third,\n" +
            "  first;"
        );
    });

    it("replaces ? indexed placeholders with param values", function() {
        const result = sqlFormatter.format("SELECT ?, ?, ?;", {
            params: ["first", "second", "third"]
        });
        expect(result).toBe(
            "SELECT\n" +
            "  first,\n" +
            "  second,\n" +
            "  third;"
        );
    });

    it("formats query with GO batch separator", function() {
        const result = sqlFormatter.format("SELECT 1 GO SELECT 2", {
            params: ["first", "second", "third"]
        });
        expect(result).toBe(
            "SELECT\n" +
            "  1\n" +
            "GO\n" +
            "SELECT\n" +
            "  2"
        );
    });

    it("formats SELECT query with CROSS JOIN", function() {
        const result = sqlFormatter.format("SELECT a, b FROM t CROSS JOIN t2 on t.id = t2.id_t", {
            params: ["first", "second", "third"]
        });
        expect(result).toBe(
            "SELECT\n" +
            "  a,\n" +
            "  b\n" +
            "FROM\n" +
            "  t\n" +
            "  CROSS JOIN t2 on t.id = t2.id_t"
        );
    });

    it("formats SELECT query with CROSS APPLY", function() {
        const result = sqlFormatter.format("SELECT a, b FROM t CROSS APPLY fn(t.id)", {
            params: ["first", "second", "third"]
        });
        expect(result).toBe(
            "SELECT\n" +
            "  a,\n" +
            "  b\n" +
            "FROM\n" +
            "  t\n" +
            "  CROSS APPLY fn(t.id)"
        );
    });

    it("formats simple SELECT", function() {
        const result = sqlFormatter.format("SELECT N, M FROM t");
        expect(result).toBe(
            "SELECT\n" +
            "  N,\n" +
            "  M\n" +
            "FROM\n" +
            "  t"
        );
    });

    it("formats simple SELECT with national characters (MSSQL)", function() {
        const result = sqlFormatter.format("SELECT N'value'");
        expect(result).toBe(
            "SELECT\n" +
            "  N'value'"
        );
    });

    it("formats SELECT query with OUTER APPLY", function() {
        const result = sqlFormatter.format("SELECT a, b FROM t OUTER APPLY fn(t.id)", {
            params: ["first", "second", "third"]
        });
        expect(result).toBe(
            "SELECT\n" +
            "  a,\n" +
            "  b\n" +
            "FROM\n" +
            "  t\n" +
            "  OUTER APPLY fn(t.id)"
        );
    });

    it("formats FETCH FIRST like LIMIT", function() {
        const result = sqlFormatter.format(
            "SELECT * FETCH FIRST 2 ROWS ONLY;"
        );
        expect(result).toBe(
            "SELECT\n" +
            "  *\n" +
            "FETCH FIRST\n" +
            "  2 ROWS ONLY;"
        );
    });

    it("formats tricky line comments", function() {
        expect(sqlFormatter.format("SELECT a#comment, here\nFROM b--comment")).toBe(
            "SELECT\n" +
            "  a #comment, here\n" +
            "FROM\n" +
            "  b --comment"
        );
    });
});
<commit_msg>Additional tests for CREATE TABLE<commit_after>import sqlFormatter from "./../src/sqlFormatter";
import behavesLikeSqlFormatter from "./behavesLikeSqlFormatter";

describe("StandardSqlFormatter", function() {
    behavesLikeSqlFormatter();

    it("formats short CREATE TABLE", function() {
        expect(sqlFormatter.format(
            "CREATE TABLE items (a INT PRIMARY KEY, b TEXT);"
        )).toBe(
            "CREATE TABLE items (a INT PRIMARY KEY, b TEXT);"
        );
    });

    it("formats long CREATE TABLE", function() {
        expect(sqlFormatter.format(
            "CREATE TABLE items (a INT PRIMARY KEY, b TEXT, c INT NOT NULL, d INT NOT NULL);"
        )).toBe(
            "CREATE TABLE items (\n" +
            "  a INT PRIMARY KEY,\n" +
            "  b TEXT,\n" +
            "  c INT NOT NULL,\n" +
            "  d INT NOT NULL\n" +
            ");"
        );
    });

    it("formats INSERT without INTO", function() {
        const result = sqlFormatter.format(
            "INSERT Customers (ID, MoneyBalance, Address, City) VALUES (12,-123.4, 'Skagen 2111','Stv');"
        );
        expect(result).toBe(
            "INSERT\n" +
            "  Customers (ID, MoneyBalance, Address, City)\n" +
            "VALUES\n" +
            "  (12, -123.4, 'Skagen 2111', 'Stv');"
        );
    });

    it("formats ALTER TABLE ... MODIFY query", function() {
        const result = sqlFormatter.format(
            "ALTER TABLE supplier MODIFY supplier_name char(100) NOT NULL;"
        );
        expect(result).toBe(
            "ALTER TABLE\n" +
            "  supplier\n" +
            "MODIFY\n" +
            "  supplier_name char(100) NOT NULL;"
        );
    });

    it("formats ALTER TABLE ... ALTER COLUMN query", function() {
        const result = sqlFormatter.format(
            "ALTER TABLE supplier ALTER COLUMN supplier_name VARCHAR(100) NOT NULL;"
        );
        expect(result).toBe(
            "ALTER TABLE\n" +
            "  supplier\n" +
            "ALTER COLUMN\n" +
            "  supplier_name VARCHAR(100) NOT NULL;"
        );
    });

    it("recognizes [] strings", function() {
        expect(sqlFormatter.format("[foo JOIN bar]")).toBe("[foo JOIN bar]");
        expect(sqlFormatter.format("[foo ]] JOIN bar]")).toBe("[foo ]] JOIN bar]");
    });

    it("recognizes @variables", function() {
        const result = sqlFormatter.format(
            "SELECT @variable, @a1_2.3$, @'var name', @\"var name\", @`var name`, @[var name];"
        );
        expect(result).toBe(
            "SELECT\n" +
            "  @variable,\n" +
            "  @a1_2.3$,\n" +
            "  @'var name',\n" +
            "  @\"var name\",\n" +
            "  @`var name`,\n" +
            "  @[var name];"
        );
    });

    it("replaces @variables with param values", function() {
        const result = sqlFormatter.format(
            "SELECT @variable, @a1_2.3$, @'var name', @\"var name\", @`var name`, @[var name], @'var\\name';",
            {
                params: {
                    "variable": "\"variable value\"",
                    "a1_2.3$": "'weird value'",
                    "var name": "'var value'",
                    "var\\name": "'var\\ value'"
                }
            }
        );
        expect(result).toBe(
            "SELECT\n" +
            "  \"variable value\",\n" +
            "  'weird value',\n" +
            "  'var value',\n" +
            "  'var value',\n" +
            "  'var value',\n" +
            "  'var value',\n" +
            "  'var\\ value';"
        );
    });

    it("recognizes :variables", function() {
        const result = sqlFormatter.format(
            "SELECT :variable, :a1_2.3$, :'var name', :\"var name\", :`var name`, :[var name];"
        );
        expect(result).toBe(
            "SELECT\n" +
            "  :variable,\n" +
            "  :a1_2.3$,\n" +
            "  :'var name',\n" +
            "  :\"var name\",\n" +
            "  :`var name`,\n" +
            "  :[var name];"
        );
    });

    it("replaces :variables with param values", function() {
        const result = sqlFormatter.format(
            "SELECT :variable, :a1_2.3$, :'var name', :\"var name\", :`var name`," +
            " :[var name], :'escaped \\'var\\'', :\"^*& weird \\\" var   \";",
            {
                params: {
                    "variable": "\"variable value\"",
                    "a1_2.3$": "'weird value'",
                    "var name": "'var value'",
                    "escaped 'var'": "'weirder value'",
                    "^*& weird \" var   ": "'super weird value'"
                }
            }
        );
        expect(result).toBe(
            "SELECT\n" +
            "  \"variable value\",\n" +
            "  'weird value',\n" +
            "  'var value',\n" +
            "  'var value',\n" +
            "  'var value',\n" +
            "  'var value',\n" +
            "  'weirder value',\n" +
            "  'super weird value';"
        );
    });

    it("recognizes ?[0-9]* placeholders", function() {
        const result = sqlFormatter.format("SELECT ?1, ?25, ?;");
        expect(result).toBe(
            "SELECT\n" +
            "  ?1,\n" +
            "  ?25,\n" +
            "  ?;"
        );
    });

    it("replaces ? numbered placeholders with param values", function() {
        const result = sqlFormatter.format("SELECT ?1, ?2, ?0;", {
            params: {
                0: "first",
                1: "second",
                2: "third"
            }
        });
        expect(result).toBe(
            "SELECT\n" +
            "  second,\n" +
            "  third,\n" +
            "  first;"
        );
    });

    it("replaces ? indexed placeholders with param values", function() {
        const result = sqlFormatter.format("SELECT ?, ?, ?;", {
            params: ["first", "second", "third"]
        });
        expect(result).toBe(
            "SELECT\n" +
            "  first,\n" +
            "  second,\n" +
            "  third;"
        );
    });

    it("formats query with GO batch separator", function() {
        const result = sqlFormatter.format("SELECT 1 GO SELECT 2", {
            params: ["first", "second", "third"]
        });
        expect(result).toBe(
            "SELECT\n" +
            "  1\n" +
            "GO\n" +
            "SELECT\n" +
            "  2"
        );
    });

    it("formats SELECT query with CROSS JOIN", function() {
        const result = sqlFormatter.format("SELECT a, b FROM t CROSS JOIN t2 on t.id = t2.id_t", {
            params: ["first", "second", "third"]
        });
        expect(result).toBe(
            "SELECT\n" +
            "  a,\n" +
            "  b\n" +
            "FROM\n" +
            "  t\n" +
            "  CROSS JOIN t2 on t.id = t2.id_t"
        );
    });

    it("formats SELECT query with CROSS APPLY", function() {
        const result = sqlFormatter.format("SELECT a, b FROM t CROSS APPLY fn(t.id)", {
            params: ["first", "second", "third"]
        });
        expect(result).toBe(
            "SELECT\n" +
            "  a,\n" +
            "  b\n" +
            "FROM\n" +
            "  t\n" +
            "  CROSS APPLY fn(t.id)"
        );
    });

    it("formats simple SELECT", function() {
        const result = sqlFormatter.format("SELECT N, M FROM t");
        expect(result).toBe(
            "SELECT\n" +
            "  N,\n" +
            "  M\n" +
            "FROM\n" +
            "  t"
        );
    });

    it("formats simple SELECT with national characters (MSSQL)", function() {
        const result = sqlFormatter.format("SELECT N'value'");
        expect(result).toBe(
            "SELECT\n" +
            "  N'value'"
        );
    });

    it("formats SELECT query with OUTER APPLY", function() {
        const result = sqlFormatter.format("SELECT a, b FROM t OUTER APPLY fn(t.id)", {
            params: ["first", "second", "third"]
        });
        expect(result).toBe(
            "SELECT\n" +
            "  a,\n" +
            "  b\n" +
            "FROM\n" +
            "  t\n" +
            "  OUTER APPLY fn(t.id)"
        );
    });

    it("formats FETCH FIRST like LIMIT", function() {
        const result = sqlFormatter.format(
            "SELECT * FETCH FIRST 2 ROWS ONLY;"
        );
        expect(result).toBe(
            "SELECT\n" +
            "  *\n" +
            "FETCH FIRST\n" +
            "  2 ROWS ONLY;"
        );
    });

    it("formats tricky line comments", function() {
        expect(sqlFormatter.format("SELECT a#comment, here\nFROM b--comment")).toBe(
            "SELECT\n" +
            "  a #comment, here\n" +
            "FROM\n" +
            "  b --comment"
        );
    });
});
<|endoftext|>


<commit_before>//
// REQUEST ANIMATION FRAME POLYFILL --------------------------------------------------
//
// Request Animation Frame for smarter/better/smoother animation
//
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
// http://creativejs.com/resources/requestanimationframe/
//

(function()
{
	var lastTime = 0,
		vendors  = ['ms', 'moz', 'webkit', 'o'];

	for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x)
	{
		window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
		window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
	}

	if(!window.requestAnimationFrame)
	{
		window.requestAnimationFrame = function(callback)
		{
			var currTime = new Date().getTime(), timeToCall = Math.max(0, 16 - (currTime - lastTime));
			var id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall);
			lastTime = currTime + timeToCall;

			return id;
		};
	}

	if(!window.cancelAnimationFrame)
	{
		window.cancelAnimationFrame = function(id)
		{
			clearTimeout(id);
		};
	}

}());<commit_msg>Added requestAnimationFrame Polyfill<commit_after>//
// REQUEST ANIMATION FRAME POLYFILL --------------------------------------------------
//
// Request Animation Frame for smarter/better/smoother animation
//
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
// http://creativejs.com/resources/requestanimationframe/
//

(function()
{
	var lastTime = 0,
	    vendors  = ['ms', 'moz', 'webkit', 'o'];

	for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x)
	{
		window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
		window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
	}

	if(!window.requestAnimationFrame)
	{
		window.requestAnimationFrame = function(callback)
		{
			var currTime = new Date().getTime(), timeToCall = Math.max(0, 16 - (currTime - lastTime));
			var id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall);
			lastTime = currTime + timeToCall;

			return id;
		};
	}

	if(!window.cancelAnimationFrame)
	{
		window.cancelAnimationFrame = function(id)
		{
			clearTimeout(id);
		};
	}

}());<|endoftext|>