<commit_before>"use strict";

exports.activate = context => {

    const encoding = "utf8";
    const Utf8BOM = "\ufeff";
    const stringEmpty = "";
    const commonDirectorySeparator = "/";
    const defaultSmartQuotes = '""' + "''";
    const markdownId = "markdown";
    const extensionManifiestFileName = "package.json";
    const typographerExtensionsRule = "extended_replacements";

    const vscode = require("vscode");
    const util = require("util");
    const fs = require("fs");
    const path = require("path");
    const childProcess = require("child_process");
    const semantic = require("./semantic");
    const idToc = require("./id.toc");
    const attribution = require("./attribution");
    const replacements = require("./replacements");
    const importContext = { vscode: vscode, util: util, fs: fs, path: path, markdownId: markdownId };

    const lazy = { lastOutputChannel: null, markdownIt: undefined, settings: undefined, decorationTypeSet: [] };

    const htmlTemplateSet = semantic.getHtmlTemplateSet(path, fs, encoding);

    const transcodeText = (text, fileName, css, embedCss, rootPath) => {
        text = semantic.replaceIncludes(importContext, text, fileName, lazy.settings);
        let result = lazy.markdownIt.render(text);
        let style = "";
        for (let index = 0; index < css.length; ++index) {
            if (embedCss) {
                const absolute = path.join(rootPath, css[index]);
                let cssCode = util.format(htmlTemplateSet.notFoundCss, absolute);
                if (fs.existsSync(absolute))
                    cssCode = fs.readFileSync(absolute, encoding);
                style += util.format(htmlTemplateSet.embeddedStyle, cssCode);
            } else {
                const relativePath = path.relative(path.dirname(fileName), rootPath);
                const relative =  path.join(relativePath, css[index])
                    .replace(/\\/g, commonDirectorySeparator);
                style += util.format(htmlTemplateSet.style, relative);
            } //if
            if (index < css.length - 1) style += "\n";
        } //loop
        return util.format(htmlTemplateSet.html,
            semantic.documentTitle ? semantic.documentTitle : `Converted from: ${path.basename(fileName)}`,
            style,
            result);
    }; //transcodeText

    const convertText = (text, fileName, css, embedCss, outputPath, rootPath) => {
        let result = transcodeText(text, fileName, css, embedCss, rootPath);
        const effectiveOutputPath = outputPath ?
            path.join(rootPath, outputPath) : path.dirname(fileName);
        if (!fs.existsSync(effectiveOutputPath))
            vscode.window.showErrorMessage(util.format("Path not found: %s", effectiveOutputPath));
        const output = path.join(
            effectiveOutputPath,
            path.basename(fileName,
                path.extname(fileName))) + ".html";
        result = Utf8BOM + result;
        fs.writeFileSync(output, result);
        return output;
    }; //convertText

    const successAction = (inputs, outputs, settings) => {
        const count = inputs.length;
        if (!settings.reportSuccess) {
            if (settings.showHtmlInBrowser)
                for (let index = 0; index < count; ++index)
                    childProcess.exec(outputs[index]);
            return;
        } //if
        if (lazy.lastOutputChannel)
            lazy.lastOutputChannel.clear();
        else
            lazy.lastOutputChannel = vscode.window.createOutputChannel("Converted to HTML");
        for (let index = 0; index < count; ++index) {
            lazy.lastOutputChannel.appendLine("Markdown file");
            lazy.lastOutputChannel.appendLine(`${inputs[index]}`);
            lazy.lastOutputChannel.appendLine("is converted to");
            lazy.lastOutputChannel.appendLine(`${outputs[index]}`);
            lazy.lastOutputChannel.appendLine(stringEmpty);
            if (settings.showHtmlInBrowser)
                childProcess.exec(outputs[index]);
        } //loop
        if (count > 1)
            lazy.lastOutputChannel.appendLine(`${count} Markdown files files converted to HTML`);
        lazy.lastOutputChannel.show(true);
    }; //successAction

    const command = action => {
        try {
            if (!vscode.workspace.workspaceFolders) {
                vscode.window.showWarningMessage("No workspace. Use File -> Open Folder...");
                return;
            } //if
            return action(lazy.settings);
        } catch (ex) {
            console.log(ex);
            vscode.window.showErrorMessage(ex.toString() + " Markdown conversion failed.");
        } //exception
    }; //command

    const convertOne = settings => {
        const editor = vscode.window.activeTextEditor;
        if (!editor) {
            vscode.window.showErrorMessage("Open Markdown file (.md)");
            return;
        } //if no editor
        if (editor.document.languageId != markdownId) return;
        const text = editor.document.getText();
        const rootPath = vscode.workspace.getWorkspaceFolder(editor.document.uri).uri.fsPath;
        const outputFileName =
            convertText(
                text,
                editor.document.fileName,
                settings.css,
                settings.embedCss,
                settings.outputPath,
                rootPath);
        successAction([editor.document.fileName], [outputFileName], settings);
    } //convertOne

    const convertSet = settings => {
        vscode.workspace.findFiles("**/*.md").then(function (files) {
            if (!files || files.length < 1)
                return  vscode.window.showWarningMessage("No Markdown files found");
            const inputs = [];
            const outputs = [];
            for (let index = 0; index < files.length; ++index) {
                const fileName = files[index].fsPath;
                const text = fs.readFileSync(fileName, encoding);
                inputs.push(fileName);
                const rootPath = vscode.workspace.getWorkspaceFolder(files[index]).uri.fsPath;
                outputs.push(convertText(
                    text,
                    fileName,
                    settings.css,
                    settings.embedCss,
                    settings.outputPath,
                    rootPath));
            } //loop
            if (settings.reportSuccess)
                if (inputs.length < 1)
                    vscode.window.showWarningMessage("No .md files found in the workspace");
                else
                    successAction(inputs, outputs, settings);
        });
    } //convertSet

    const updateDecorators = () => {
        if (!vscode.window.activeTextEditor) return;
        const document = vscode.window.activeTextEditor.document;
        if (document.languageId != markdownId) return;
        if (!lazy.settings)
            lazy.settings = semantic.getSettings(importContext);
        const text = vscode.window.activeTextEditor.document.getText();
        // clean:
        for (let index in lazy.decorationTypeSet)
            vscode.window.activeTextEditor.setDecorations(lazy.decorationTypeSet[index], []);
        lazy.decorationTypeSet = [];
        // populate:
        if (lazy.settings.pluginSyntaxDecorators) {
            for (let index in lazy.settings.pluginSyntaxDecorators) {
                const plugin = lazy.settings.pluginSyntaxDecorators[index];
                if (!plugin) continue;
                let decoratorSet = [];
                const document = vscode.window.activeTextEditor.document;
                const text = document.getText();
                semantic.thenableRegex(plugin.regexString, text, !plugin.relativeToWholeText).then(
                    function (start, length, groups) {
                        let title = plugin.tooltipFormat;
                        if (groups[1] && title.includes("%s"))
                            title = util.format(title, groups[1].toString());
                        decoratorSet.push({
                            range: semantic.getVSCodeRange(vscode, document, start, groups[0]),
                            hoverMessage: title
                        });
                    }); //looped occurrences and groups
                vscode.window.activeTextEditor.setDecorations(
                    plugin.decorationType, decoratorSet);
                lazy.decorationTypeSet.push(plugin.decorationType);
            } //loop plugins
        } //loop additional plug-ins
    }; //updateDecorators
    updateDecorators();

    vscode.workspace.onDidOpenTextDocument(textDocument => {
        if (textDocument.languageId == markdownId)
            updateDecorators();
    });
    vscode.window.onDidChangeActiveTextEditor(e=> {
        if (e.document && e.document.languageId == markdownId)
            updateDecorators();
    }, null, context.subscriptions);
    vscode.workspace.onDidChangeTextDocument(e => {
        if (e.document && e.document.languageId == markdownId)
            updateDecorators();
    }); //vscode.workspace.onDidChangeTextDocument
    vscode.workspace.onDidChangeConfiguration(e => {
        if (lazy.markdownIt)
            setupMarkdown(lazy.markdownIt, true);
        updateDecorators(); // it checks up active text editor and its document anyway
    }); //vscode.workspace.onDidChangeConfiguration

    const setupMarkdown = (baseImplementation, updateSettings) => {
        if (updateSettings)
            lazy.markdownIt = new baseImplementation.constructor();
        else
            lazy.markdownIt = baseImplementation;
        if (!lazy.settings || updateSettings)
            lazy.settings = semantic.getSettings(importContext);
        const optionSet = (() => {
            // result.xhtmlOut: it closes all tags, like in <br />, non-default, but it would be a crime not to close tags:
            let result = { xhtmlOut: true, highlight: null, langPrefix: null };
            result.html = lazy.settings.allowHTML;
            result.typographer = lazy.settings.typographer;
            if (lazy.settings.typographer) {
                if (!lazy.settings.smartQuotes)
                    result.quotes = defaultSmartQuotes;
                else if (!lazy.settings.smartQuotes.length)
                    result.quotes = defaultSmartQuotes;
                else if (lazy.settings.smartQuotes.length < defaultSmartQuotes.length)
                    result.quotes = defaultSmartQuotes;
                else
                    result.quotes = lazy.settings.smartQuotes;
            } //if settings.typographer
            return result;
        })(); //optionSet
        const additionalPlugins = (() => {
            let result = [];
            if (!lazy.settings.additionalPlugins) return result;
            if (!lazy.settings.additionalPlugins.plugins) return result;
            if (!lazy.settings.additionalPlugins.plugins.length) return result;
            if (lazy.settings.additionalPlugins.plugins.length < 1) return result;
            let effectiveParentPath = lazy.settings.additionalPlugins.absolutePath;
            if (!effectiveParentPath) {
                let relativePath = lazy.settings.additionalPlugins.relativePath;
                if (!relativePath) return result;
                relativePath = relativePath.toString();
                const rootPath = vscode.workspace.getWorkspaceFolder(vscode.window.activeTextEditor.document.uri).uri.fsPath;
                effectiveParentPath = path.join(rootPath, relativePath);
            } //if
            if (!effectiveParentPath) return result;
            if (!fs.existsSync(effectiveParentPath.toString())) return result;
            for (let pluginDataProperty in lazy.settings.additionalPlugins.plugins) {
                const pluginData = lazy.settings.additionalPlugins.plugins[pluginDataProperty];
                if (!pluginData.name) continue;
                const effectivePath =
                    path.join(effectiveParentPath.toString(), pluginData.name.toString());
                if (!fs.existsSync(effectivePath)) continue;
                if (!pluginData.enable) continue;
                result.push({ name: effectivePath, options: pluginData.options });
            } // loop settings.additionalPlugins.plugins
            return result;
        })(); //additionalPlugins
        const setupUsage = (md => {
            if (!md) return;
            const idTopOptions = {
                excludeFromTocRegex: lazy.settings.excludeFromTocRegex,
                tocItemIndentInEm: lazy.settings.tocItemIndentInEm,
                enableHeadingId: lazy.settings.headingId, // false => no id in headings => no TOC
                headingIdPrefix: lazy.settings.headingIdPrefix,
                tocRegex: lazy.settings.tocRegex,
                includeLevel: lazy.settings.tocIncludeLevels,
                tocContainerClass: lazy.settings.tocContainerClass,
                autoNumberingRegex: lazy.settings.autoNumberingRegex,
            };
            md.use(idToc, idTopOptions);
            md.use(attribution, {
                titleLocatorRegex: lazy.settings.titleLocatorRegex,
                abbreviationRegex: lazy.settings.abbreviationRegex,
                attributeRegex: lazy.settings.attributeRegex,
                cssClassRegex: lazy.settings.cssClassRegex,
                titleClassName: lazy.settings.titleClassName,
            });
            md.use(replacements, { });
            if (!lazy.settings.typographerExtensions)
                md.disable(typographerExtensionsRule);
            for (let pluginData in additionalPlugins) {
                let plugin;
                try {
                    plugin = require(additionalPlugins[pluginData].name);
                } catch (requireException) {
                    continue;
                } //exception
                md = md.use(plugin, additionalPlugins[pluginData].options);
            } // using additionalPlugins
        })(lazy.markdownIt);
        return baseImplementation;
    }; //setupMarkdown

    context.subscriptions.push(
        vscode.commands.registerCommand("extensible.markdown.convertToHtml", () => {
            command(convertOne);
        }));
    context.subscriptions.push(
        vscode.commands.registerCommand("extensible.markdown.convertToHtml.all", () => {
            command(convertSet);
        }));

    return {
        extendMarkdownIt: baseImplementation => {
            try {
                return setupMarkdown(baseImplementation);
            } catch (ex) {
                const getManifest = () => {
                    const pathName = path.join(context.extensionPath, extensionManifiestFileName);
                    const content = fs.readFileSync(pathName).toString();
                    return JSON.parse(content);
                } //getManifest
                vscode.window.showErrorMessage(`${getManifest().displayName}: activation failed`);
            } //exception
        }
    };

}; //exports.activate

exports.deactivate = () => { };
<commit_msg>Markdown-it option: restored lost optionSet use<commit_after>"use strict";

exports.activate = context => {

    const encoding = "utf8";
    const Utf8BOM = "\ufeff";
    const stringEmpty = "";
    const commonDirectorySeparator = "/";
    const defaultSmartQuotes = '""' + "''";
    const markdownId = "markdown";
    const extensionManifiestFileName = "package.json";
    const typographerExtensionsRule = "extended_replacements";

    const vscode = require("vscode");
    const util = require("util");
    const fs = require("fs");
    const path = require("path");
    const childProcess = require("child_process");
    const semantic = require("./semantic");
    const idToc = require("./id.toc");
    const attribution = require("./attribution");
    const replacements = require("./replacements");
    const importContext = { vscode: vscode, util: util, fs: fs, path: path, markdownId: markdownId };

    const lazy = { lastOutputChannel: null, markdownIt: undefined, settings: undefined, decorationTypeSet: [] };

    const htmlTemplateSet = semantic.getHtmlTemplateSet(path, fs, encoding);

    const transcodeText = (text, fileName, css, embedCss, rootPath) => {
        text = semantic.replaceIncludes(importContext, text, fileName, lazy.settings);
        let result = lazy.markdownIt.render(text);
        let style = "";
        for (let index = 0; index < css.length; ++index) {
            if (embedCss) {
                const absolute = path.join(rootPath, css[index]);
                let cssCode = util.format(htmlTemplateSet.notFoundCss, absolute);
                if (fs.existsSync(absolute))
                    cssCode = fs.readFileSync(absolute, encoding);
                style += util.format(htmlTemplateSet.embeddedStyle, cssCode);
            } else {
                const relativePath = path.relative(path.dirname(fileName), rootPath);
                const relative =  path.join(relativePath, css[index])
                    .replace(/\\/g, commonDirectorySeparator);
                style += util.format(htmlTemplateSet.style, relative);
            } //if
            if (index < css.length - 1) style += "\n";
        } //loop
        return util.format(htmlTemplateSet.html,
            semantic.documentTitle ? semantic.documentTitle : `Converted from: ${path.basename(fileName)}`,
            style,
            result);
    }; //transcodeText

    const convertText = (text, fileName, css, embedCss, outputPath, rootPath) => {
        let result = transcodeText(text, fileName, css, embedCss, rootPath);
        const effectiveOutputPath = outputPath ?
            path.join(rootPath, outputPath) : path.dirname(fileName);
        if (!fs.existsSync(effectiveOutputPath))
            vscode.window.showErrorMessage(util.format("Path not found: %s", effectiveOutputPath));
        const output = path.join(
            effectiveOutputPath,
            path.basename(fileName,
                path.extname(fileName))) + ".html";
        result = Utf8BOM + result;
        fs.writeFileSync(output, result);
        return output;
    }; //convertText

    const successAction = (inputs, outputs, settings) => {
        const count = inputs.length;
        if (!settings.reportSuccess) {
            if (settings.showHtmlInBrowser)
                for (let index = 0; index < count; ++index)
                    childProcess.exec(outputs[index]);
            return;
        } //if
        if (lazy.lastOutputChannel)
            lazy.lastOutputChannel.clear();
        else
            lazy.lastOutputChannel = vscode.window.createOutputChannel("Converted to HTML");
        for (let index = 0; index < count; ++index) {
            lazy.lastOutputChannel.appendLine("Markdown file");
            lazy.lastOutputChannel.appendLine(`${inputs[index]}`);
            lazy.lastOutputChannel.appendLine("is converted to");
            lazy.lastOutputChannel.appendLine(`${outputs[index]}`);
            lazy.lastOutputChannel.appendLine(stringEmpty);
            if (settings.showHtmlInBrowser)
                childProcess.exec(outputs[index]);
        } //loop
        if (count > 1)
            lazy.lastOutputChannel.appendLine(`${count} Markdown files files converted to HTML`);
        lazy.lastOutputChannel.show(true);
    }; //successAction

    const command = action => {
        try {
            if (!vscode.workspace.workspaceFolders) {
                vscode.window.showWarningMessage("No workspace. Use File -> Open Folder...");
                return;
            } //if
            return action(lazy.settings);
        } catch (ex) {
            console.log(ex);
            vscode.window.showErrorMessage(ex.toString() + " Markdown conversion failed.");
        } //exception
    }; //command

    const convertOne = settings => {
        const editor = vscode.window.activeTextEditor;
        if (!editor) {
            vscode.window.showErrorMessage("Open Markdown file (.md)");
            return;
        } //if no editor
        if (editor.document.languageId != markdownId) return;
        const text = editor.document.getText();
        const rootPath = vscode.workspace.getWorkspaceFolder(editor.document.uri).uri.fsPath;
        const outputFileName =
            convertText(
                text,
                editor.document.fileName,
                settings.css,
                settings.embedCss,
                settings.outputPath,
                rootPath);
        successAction([editor.document.fileName], [outputFileName], settings);
    } //convertOne

    const convertSet = settings => {
        vscode.workspace.findFiles("**/*.md").then(function (files) {
            if (!files || files.length < 1)
                return  vscode.window.showWarningMessage("No Markdown files found");
            const inputs = [];
            const outputs = [];
            for (let index = 0; index < files.length; ++index) {
                const fileName = files[index].fsPath;
                const text = fs.readFileSync(fileName, encoding);
                inputs.push(fileName);
                const rootPath = vscode.workspace.getWorkspaceFolder(files[index]).uri.fsPath;
                outputs.push(convertText(
                    text,
                    fileName,
                    settings.css,
                    settings.embedCss,
                    settings.outputPath,
                    rootPath));
            } //loop
            if (settings.reportSuccess)
                if (inputs.length < 1)
                    vscode.window.showWarningMessage("No .md files found in the workspace");
                else
                    successAction(inputs, outputs, settings);
        });
    } //convertSet

    const updateDecorators = () => {
        if (!vscode.window.activeTextEditor) return;
        const document = vscode.window.activeTextEditor.document;
        if (document.languageId != markdownId) return;
        if (!lazy.settings)
            lazy.settings = semantic.getSettings(importContext);
        const text = vscode.window.activeTextEditor.document.getText();
        // clean:
        for (let index in lazy.decorationTypeSet)
            vscode.window.activeTextEditor.setDecorations(lazy.decorationTypeSet[index], []);
        lazy.decorationTypeSet = [];
        // populate:
        if (lazy.settings.pluginSyntaxDecorators) {
            for (let index in lazy.settings.pluginSyntaxDecorators) {
                const plugin = lazy.settings.pluginSyntaxDecorators[index];
                if (!plugin) continue;
                let decoratorSet = [];
                const document = vscode.window.activeTextEditor.document;
                const text = document.getText();
                semantic.thenableRegex(plugin.regexString, text, !plugin.relativeToWholeText).then(
                    function (start, length, groups) {
                        let title = plugin.tooltipFormat;
                        if (groups[1] && title.includes("%s"))
                            title = util.format(title, groups[1].toString());
                        decoratorSet.push({
                            range: semantic.getVSCodeRange(vscode, document, start, groups[0]),
                            hoverMessage: title
                        });
                    }); //looped occurrences and groups
                vscode.window.activeTextEditor.setDecorations(
                    plugin.decorationType, decoratorSet);
                lazy.decorationTypeSet.push(plugin.decorationType);
            } //loop plugins
        } //loop additional plug-ins
    }; //updateDecorators
    updateDecorators();

    vscode.workspace.onDidOpenTextDocument(textDocument => {
        if (textDocument.languageId == markdownId)
            updateDecorators();
    });
    vscode.window.onDidChangeActiveTextEditor(e=> {
        if (e.document && e.document.languageId == markdownId)
            updateDecorators();
    }, null, context.subscriptions);
    vscode.workspace.onDidChangeTextDocument(e => {
        if (e.document && e.document.languageId == markdownId)
            updateDecorators();
    }); //vscode.workspace.onDidChangeTextDocument
    vscode.workspace.onDidChangeConfiguration(e => {
        if (lazy.markdownIt)
            setupMarkdown(lazy.markdownIt, true);
        updateDecorators(); // it checks up active text editor and its document anyway
    }); //vscode.workspace.onDidChangeConfiguration

    const setupMarkdown = (baseImplementation, updateSettings) => {
        if (updateSettings)
            lazy.markdownIt = new baseImplementation.constructor();
        else
            lazy.markdownIt = baseImplementation;
        if (!lazy.settings || updateSettings)
            lazy.settings = semantic.getSettings(importContext);
        const optionSet = (() => {
            // result.xhtmlOut: it closes all tags, like in <br />, non-default, but it would be a crime not to close tags:
            let result = { xhtmlOut: true, highlight: null, langPrefix: null };
            result.html = lazy.settings.allowHTML;
            result.typographer = lazy.settings.typographer;
            if (lazy.settings.typographer) {
                if (!lazy.settings.smartQuotes)
                    result.quotes = defaultSmartQuotes;
                else if (!lazy.settings.smartQuotes.length)
                    result.quotes = defaultSmartQuotes;
                else if (lazy.settings.smartQuotes.length < defaultSmartQuotes.length)
                    result.quotes = defaultSmartQuotes;
                else
                    result.quotes = lazy.settings.smartQuotes;
            } //if settings.typographer
            return result;
        })(); //optionSet
        const additionalPlugins = (() => {
            let result = [];
            if (!lazy.settings.additionalPlugins) return result;
            if (!lazy.settings.additionalPlugins.plugins) return result;
            if (!lazy.settings.additionalPlugins.plugins.length) return result;
            if (lazy.settings.additionalPlugins.plugins.length < 1) return result;
            let effectiveParentPath = lazy.settings.additionalPlugins.absolutePath;
            if (!effectiveParentPath) {
                let relativePath = lazy.settings.additionalPlugins.relativePath;
                if (!relativePath) return result;
                relativePath = relativePath.toString();
                const rootPath = vscode.workspace.getWorkspaceFolder(vscode.window.activeTextEditor.document.uri).uri.fsPath;
                effectiveParentPath = path.join(rootPath, relativePath);
            } //if
            if (!effectiveParentPath) return result;
            if (!fs.existsSync(effectiveParentPath.toString())) return result;
            for (let pluginDataProperty in lazy.settings.additionalPlugins.plugins) {
                const pluginData = lazy.settings.additionalPlugins.plugins[pluginDataProperty];
                if (!pluginData.name) continue;
                const effectivePath =
                    path.join(effectiveParentPath.toString(), pluginData.name.toString());
                if (!fs.existsSync(effectivePath)) continue;
                if (!pluginData.enable) continue;
                result.push({ name: effectivePath, options: pluginData.options });
            } // loop settings.additionalPlugins.plugins
            return result;
        })(); //additionalPlugins
        const setupUsage = (md => {
            if (!md) return;
            md.set(optionSet);
            const idTopOptions = {
                excludeFromTocRegex: lazy.settings.excludeFromTocRegex,
                tocItemIndentInEm: lazy.settings.tocItemIndentInEm,
                enableHeadingId: lazy.settings.headingId, // false => no id in headings => no TOC
                headingIdPrefix: lazy.settings.headingIdPrefix,
                tocRegex: lazy.settings.tocRegex,
                includeLevel: lazy.settings.tocIncludeLevels,
                tocContainerClass: lazy.settings.tocContainerClass,
                autoNumberingRegex: lazy.settings.autoNumberingRegex,
            };
            md.use(idToc, idTopOptions);
            md.use(attribution, {
                titleLocatorRegex: lazy.settings.titleLocatorRegex,
                abbreviationRegex: lazy.settings.abbreviationRegex,
                attributeRegex: lazy.settings.attributeRegex,
                cssClassRegex: lazy.settings.cssClassRegex,
                titleClassName: lazy.settings.titleClassName,
            });
            md.use(replacements, { });
            if (!lazy.settings.typographerExtensions)
                md.disable(typographerExtensionsRule);
            for (let pluginData in additionalPlugins) {
                let plugin;
                try {
                    plugin = require(additionalPlugins[pluginData].name);
                } catch (requireException) {
                    continue;
                } //exception
                md = md.use(plugin, additionalPlugins[pluginData].options);
            } // using additionalPlugins
        })(lazy.markdownIt);
        return baseImplementation;
    }; //setupMarkdown

    context.subscriptions.push(
        vscode.commands.registerCommand("extensible.markdown.convertToHtml", () => {
            command(convertOne);
        }));
    context.subscriptions.push(
        vscode.commands.registerCommand("extensible.markdown.convertToHtml.all", () => {
            command(convertSet);
        }));

    return {
        extendMarkdownIt: baseImplementation => {
            try {
                return setupMarkdown(baseImplementation);
            } catch (ex) {
                const getManifest = () => {
                    const pathName = path.join(context.extensionPath, extensionManifiestFileName);
                    const content = fs.readFileSync(pathName).toString();
                    return JSON.parse(content);
                } //getManifest
                vscode.window.showErrorMessage(`${getManifest().displayName}: activation failed`);
            } //exception
        }
    };

}; //exports.activate

exports.deactivate = () => { };
<|endoftext|>


<commit_before>if (! window.XOSLIB_LOADED ) {
    window.XOSLIB_LOADED=true;

    SLIVER_API = "/plstackapi/slivers/";
    SLICE_API = "/plstackapi/slices/";
    SLICEROLE_API = "/plstackapi/slice_roles/";
    NODE_API = "/plstackapi/nodes/";
    SITE_API = "/plstackapi/sites/";
    USER_API = "/plstackapi/users/";
    USERDEPLOYMENT_API = "/plstackapi/user_deployments/";
    DEPLOYMENT_API = "/plstackapi/deployments/";
    IMAGE_API = "/plstackapi/images/";
    NETWORKTEMPLATE_API = "/plstackapi/networktemplates/";
    NETWORK_API = "/plstackapi/networks/";
    NETWORKSLIVER_API = "/plstackapi/networkslivers/";
    SERVICE_API = "/plstackapi/services/";
    SLICEPRIVILEGE_API = "/plstackapi/slice_privileges/";
    NETWORKDEPLOYMENT_API = "/plstackapi/networkdeployments/";

    /* changed as a side effect of the big rename
    SLICEDEPLOYMENT_API = "/plstackapi/slice_deployments/";
    USERDEPLOYMENT_API = "/plstackapi/user_deployments/";
    */

    SLICEDEPLOYMENT_API = "/plstackapi/slicedeployments/";
    USERDEPLOYMENT_API = "/plstackapi/userdeployments/";

    SLICEPLUS_API = "/xoslib/slicesplus/";

    XOSModel = Backbone.Model.extend({
        /* from backbone-tastypie.js */
        //idAttribute: 'resource_uri',

        /* from backbone-tastypie.js */
        url: function() {
                    var url = this.attributes.resource_uri;

                    if (!url) {
                        if (this.id) {
                            url = this.urlRoot + this.id;
                        } else {
                            // this happens when creating a new model.
                            url = this.urlRoot;
                        }
                    }

                    if (!url) {
                        // XXX I'm not sure this does anything useful
                        url = ( _.isFunction( this.collection.url ) ? this.collection.url() : this.collection.url );
                        url = url || this.urlRoot;
                    }

                    // remove any existing query parameters
                    url && ( url.indexOf("?") > -1 ) && ( url = url.split("?")[0] );

                    url && ( url += ( url.length > 0 && url.charAt( url.length - 1 ) === '/' ) ? '' : '/' );

                    url && ( url += "?no_hyperlinks=1" );

                    return url;
            },

            listMethods: function() {
                var res = [];
                for(var m in this) {
                    if(typeof this[m] == "function") {
                        res.push(m)
                    }
                }
                return res;
            },

            /* If a 'validate' method is supplied, then it will be called
               automatically on save. Unfortunately, save calls neither the
               'error' nor the 'success' callback if the validator fails.

               For now, we're calling our validator 'xosValidate' so this
               autoamtic validation doesn't occur.
            */

            xosValidate: function(attrs, options) {
                errors = {};
                foundErrors = false;
                _.each(this.validators, function(validatorList, fieldName) {
                    _.each(validatorList, function(validator) {
                        if (fieldName in attrs) {
                            validatorResult = validateField(validator, attrs[fieldName], this)
                            if (validatorResult != true) {
                                errors[fieldName] = validatorResult;
                                foundErrors = true;
                            }
                        }
                    });
                });
                if (foundErrors) {
                    return errors;
                }
                // backbone.js semantics -- on successful validate, return nothing
            },

            /* uncommenting this would make validate() call xosValidate()
            validate: function(attrs, options) {
                r = this.xosValidate(attrs, options);
                console.log("validate");
                console.log(r);
                return r;
            }, */
    });

    XOSCollection = Backbone.Collection.extend({
        objects: function() {
                    return this.models.map(function(element) { return element.attributes; });
                 },

        initialize: function(){
          this.isLoaded = false;
          this.failedLoad = false;
          this.startedLoad = false;
          this.sortVar = 'name';
          this.sortOrder = 'asc';
          this.on( "sort", this.sorted );
        },

        relatedCollections: [],
        foreignCollections: [],

        sorted: function() {
            //console.log("sorted " + this.modelName);
        },

        simpleComparator: function( model ){
          parts=this.sortVar.split(".");
          result = model.get(parts[0]);
          for (index=1; index<parts.length; ++index) {
              result=result[parts[index]];
          }
          return result;
        },

        comparator: function (left, right) {
            var l = this.simpleComparator(left);
            var r = this.simpleComparator(right);

            if (l === void 0) return -1;
            if (r === void 0) return 1;

            if (this.sortOrder=="desc") {
                return l < r ? 1 : l > r ? -1 : 0;
            } else {
                return l < r ? -1 : l > r ? 1 : 0;
            }
        },

        fetchSuccess: function(collection, response, options) {
            //console.log("fetch succeeded " + collection.modelName);
            this.failedLoad = false;
            this.fetching = false;
            if (!this.isLoaded) {
                this.isLoaded = true;
                Backbone.trigger("xoslib:collectionLoadChange", this);
            }
            this.trigger("fetchStateChange");
            if (options["orig_success"]) {
                options["orig_success"](collection, response, options);
            }
        },

        fetchFailure: function(collection, response, options) {
            //console.log("fetch failed " + collection.modelName);
            this.fetching = false;
            if ((!this.isLoaded) && (!this.failedLoad)) {
                this.failedLoad=true;
                Backbone.trigger("xoslib:collectionLoadChange", this);
            }
            this.trigger("fetchStateChange");
            if (options["orig_failure"]) {
                options["orig_failure"](collection, response, options);
            }
        },

        fetch: function(options) {
            var self=this;
            this.fetching=true;
            //console.log("fetch " + this.modelName);
            if (!this.startedLoad) {
                this.startedLoad=true;
                Backbone.trigger("xoslib:collectionLoadChange", this);
            }
            this.trigger("fetchStateChange");
            if (options == undefined) {
                options = {};
            }
            options["orig_success"] = options["success"];
            options["orig_failure"] = options["failure"];
            options["success"] = function(collection, response, options) { self.fetchSuccess.call(self, collection, response, options); };
            options["failure"] = this.fetchFailure;
            Backbone.Collection.prototype.fetch.call(this, options);
        },

        startPolling: function() {
            if (!this._polling) {
                var collection=this;
                setInterval(function() { collection.fetch(); }, 10000);
                this._polling=true;
                this.fetch();
            }
        },

        refresh: function(refreshRelated) {
            if (!this.fetching) {
                this.fetch();
            }
            if (refreshRelated) {
                for (related in this.relatedCollections) {
                    related = xos[related];
                    if (!related.fetching) {
                        related.fetch();
                    }
                }
            }
        },

        maybeFetch: function(options){
                // Helper function to fetch only if this collection has not been fetched before.
            if(this._fetched){
                    // If this has already been fetched, call the success, if it exists
                options.success && options.success();
                console.log("alreadyFetched");
                return;
            }

                // when the original success function completes mark this collection as fetched
            var self = this,
            successWrapper = function(success){
                return function(){
                    self._fetched = true;
                    success && success.apply(this, arguments);
                };
            };
            options.success = successWrapper(options.success);
            console.log("call fetch");
            this.fetch(options);
        },

        getOrFetch: function(id, options){
                // Helper function to use this collection as a cache for models on the server
            var model = this.get(id);

            if(model){
                options.success && options.success(model);
                return;
            }

            model = new this.model({
                resource_uri: id
            });

            model.fetch(options);
        },

        filterBy: function(fieldName, value) {
             filtered = this.filter(function(obj) {
                 return obj.get(fieldName) == value;
                 });
             return new this.constructor(filtered);
        },

        /* from backbone-tastypie.js */
        url: function( models ) {
                    var url = this.urlRoot || ( models && models.length && models[0].urlRoot );
                    url && ( url += ( url.length > 0 && url.charAt( url.length - 1 ) === '/' ) ? '' : '/' );

                    // Build a url to retrieve a set of models. This assume the last part of each model's idAttribute
                    // (set to 'resource_uri') contains the model's id.
                    if ( models && models.length ) {
                            var ids = _.map( models, function( model ) {
                                            var parts = _.compact( model.id.split('/') );
                                            return parts[ parts.length - 1 ];
                                    });
                            url += 'set/' + ids.join(';') + '/';
                    }

                    url && ( url += "?no_hyperlinks=1" );

                    return url;
            },

        listMethods: function() {
                var res = [];
                for(var m in this) {
                    if(typeof this[m] == "function") {
                        res.push(m)
                    }
                }
                return res;
            },
    });

    function define_model(lib, attrs) {
        modelName = attrs.modelName;
        modelClassName = modelName;
        collectionClassName = modelName + "Collection";

        if (!attrs.collectionName) {
            attrs.collectionName = modelName + "s";
        }
        collectionName = attrs.collectionName;

        modelAttrs = {}
        collectionAttrs = {}

        for (key in attrs) {
            value = attrs[key];
            if ($.inArray(key, ["urlRoot", "modelName", "collectionName", "validate"])>=0) {
                modelAttrs[key] = value;
            }
            if ($.inArray(key, ["urlRoot", "modelName", "collectionName", "relatedCollections", "foreignCollections"])>=0) {
                collectionAttrs[key] = value;
            }
        }

        if (xosdefaults && xosdefaults[modelName]) {
            modelAttrs["defaults"] = xosdefaults[modelName];
        }

        if (xosvalidators && xosvalidators[modelName]) {
            modelAttrs["validators"] = xosvalidators[modelName];
        }

        lib[modelName] = XOSModel.extend(modelAttrs);

        collectionAttrs["model"] = lib[modelName];

        lib[collectionClassName] = XOSCollection.extend(collectionAttrs);
        lib[collectionName] = new lib[collectionClassName]();

        lib.allCollectionNames.push(collectionName);
        lib.allCollections.push(lib[collectionName]);
    };

    function xoslib() {
        this.allCollectionNames = [];
        this.allCollections = [];

        define_model(this, {urlRoot: SLIVER_API,
                            relatedCollections: {"networkSlivers": "sliver"},
                            foreignCollections: ["slices", "deployments", "images", "nodes", "users"],
                            modelName: "sliver"});

        define_model(this, {urlRoot: SLICE_API,
                           relatedCollections: {"slivers": "slice", "sliceDeployments": "slice", "slicePrivileges": "slice", "networks": "owner"},
                           foreignCollections: ["services", "sites"],
                           modelName: "slice",
                           validate: function(attrs, options) {
                               errors = XOSModel.prototype.validate(this, attrs, options);
                               // validate that slice.name starts with site.login_base
                               site = attrs.site || this.site;
                               if ((site!=undefined) && (attrs.name!=undefined)) {
                                   site = xos.sites.get(site);
                                   if (attrs.name.indexOf(site.attributes.login_base+"_") != 0) {
                                        errors = errors || {};
                                        errors["name"] = "must start with " + site.attributes.login_base + "_";
                                   }
                               }
                               return errors;
                             },
                           });

        define_model(this, {urlRoot: SLICEDEPLOYMENT_API,
                           foreignCollections: ["slices", "deployments"],
                           modelName: "sliceDeployment"});

        define_model(this, {urlRoot: SLICEPRIVILEGE_API,
                            foreignCollections: ["slices", "users", "sliceRoles"],
                            modelName: "slicePrivilege"});

        define_model(this, {urlRoot: SLICEROLE_API,
                            modelName: "sliceRole"});

        define_model(this, {urlRoot: NODE_API,
                            foreignCollections: ["sites", "deployments"],
                            modelName: "node"});

        define_model(this, {urlRoot: SITE_API,
                            relatedCollections: {"users": "site", "slices": "site", "nodes": "site"},
                            modelName: "site"});

        define_model(this, {urlRoot: USER_API,
                            relatedCollections: {"slicePrivileges": "user", "slices": "owner", "userDeployments": "user"},
                            foreignCollections: ["sites"],
                            modelName: "user"});

        define_model(this, {urlRoot: USERDEPLOYMENT_API,
                            foreignCollections: ["users","deployments"],
                            modelName: "userDeployment"});

        define_model(this, { urlRoot: DEPLOYMENT_API,
                             relatedCollections: {"nodes": "deployment", "slivers": "deploymentNetwork", "networkDeployments": "deployment", "userDeployments": "deployment"},
                             modelName: "deployment"});

        define_model(this, {urlRoot: IMAGE_API,
                            model: this.image,
                            modelName: "image"});

        define_model(this, {urlRoot: NETWORKTEMPLATE_API,
                            modelName: "networkTemplate"});

        define_model(this, {urlRoot: NETWORK_API,
                            relatedCollections: {"networkDeployments": "network", "networkSlivers": "network"},
                            foreignCollections: ["slices", "networkTemplates"],
                            modelName: "network"});

        define_model(this, {urlRoot: NETWORKSLIVER_API,
                            modelName: "networkSliver"});

        define_model(this, {urlRoot: NETWORKDEPLOYMENT_API,
                            modelName: "networkDeployment"});

        define_model(this, {urlRoot: SERVICE_API,
                            modelName: "service"});

        // enhanced REST
        define_model(this, {urlRoot: SLICEPLUS_API,
                            relatedCollections: {'slivers': "slice"},
                            modelName: "slicePlus",
                            collectionName: "slicesPlus"});

        this.listObjects = function() { return this.allCollectionNames; };

        this.getCollectionStatus = function() {
            stats = {isLoaded: 0, failedLoad: 0, startedLoad: 0};
            for (index in this.allCollections) {
                collection = this.allCollections[index];
                if (collection.isLoaded) {
                    stats["isLoaded"] = stats["isLoaded"] + 1;
                }
                if (collection.failedLoad) {
                    stats["failedLoad"] = stats["failedLoad"] + 1;
                }
                if (collection.startedLoad) {
                    stats["startedLoad"] = stats["startedLoad"] + 1;
                }
            }
            stats["completedLoad"] = stats["failedLoad"] + stats["isLoaded"];
            return stats;
        };
    };

    xos = new xoslib();

    function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }

    (function() {
      var _sync = Backbone.sync;
      Backbone.sync = function(method, model, options){
        options.beforeSend = function(xhr){
          var token = getCookie("csrftoken");
          xhr.setRequestHeader('X-CSRFToken', token);
        };
        return _sync(method, model, options);
      };
    })();
}
<commit_msg>fix validation misnamed in slice model<commit_after>if (! window.XOSLIB_LOADED ) {
    window.XOSLIB_LOADED=true;

    SLIVER_API = "/plstackapi/slivers/";
    SLICE_API = "/plstackapi/slices/";
    SLICEROLE_API = "/plstackapi/slice_roles/";
    NODE_API = "/plstackapi/nodes/";
    SITE_API = "/plstackapi/sites/";
    USER_API = "/plstackapi/users/";
    USERDEPLOYMENT_API = "/plstackapi/user_deployments/";
    DEPLOYMENT_API = "/plstackapi/deployments/";
    IMAGE_API = "/plstackapi/images/";
    NETWORKTEMPLATE_API = "/plstackapi/networktemplates/";
    NETWORK_API = "/plstackapi/networks/";
    NETWORKSLIVER_API = "/plstackapi/networkslivers/";
    SERVICE_API = "/plstackapi/services/";
    SLICEPRIVILEGE_API = "/plstackapi/slice_privileges/";
    NETWORKDEPLOYMENT_API = "/plstackapi/networkdeployments/";

    /* changed as a side effect of the big rename
    SLICEDEPLOYMENT_API = "/plstackapi/slice_deployments/";
    USERDEPLOYMENT_API = "/plstackapi/user_deployments/";
    */

    SLICEDEPLOYMENT_API = "/plstackapi/slicedeployments/";
    USERDEPLOYMENT_API = "/plstackapi/userdeployments/";

    SLICEPLUS_API = "/xoslib/slicesplus/";

    XOSModel = Backbone.Model.extend({
        /* from backbone-tastypie.js */
        //idAttribute: 'resource_uri',

        /* from backbone-tastypie.js */
        url: function() {
                    var url = this.attributes.resource_uri;

                    if (!url) {
                        if (this.id) {
                            url = this.urlRoot + this.id;
                        } else {
                            // this happens when creating a new model.
                            url = this.urlRoot;
                        }
                    }

                    if (!url) {
                        // XXX I'm not sure this does anything useful
                        url = ( _.isFunction( this.collection.url ) ? this.collection.url() : this.collection.url );
                        url = url || this.urlRoot;
                    }

                    // remove any existing query parameters
                    url && ( url.indexOf("?") > -1 ) && ( url = url.split("?")[0] );

                    url && ( url += ( url.length > 0 && url.charAt( url.length - 1 ) === '/' ) ? '' : '/' );

                    url && ( url += "?no_hyperlinks=1" );

                    return url;
            },

            listMethods: function() {
                var res = [];
                for(var m in this) {
                    if(typeof this[m] == "function") {
                        res.push(m)
                    }
                }
                return res;
            },

            /* If a 'validate' method is supplied, then it will be called
               automatically on save. Unfortunately, save calls neither the
               'error' nor the 'success' callback if the validator fails.

               For now, we're calling our validator 'xosValidate' so this
               autoamtic validation doesn't occur.
            */

            xosValidate: function(attrs, options) {
                errors = {};
                foundErrors = false;
                _.each(this.validators, function(validatorList, fieldName) {
                    _.each(validatorList, function(validator) {
                        if (fieldName in attrs) {
                            validatorResult = validateField(validator, attrs[fieldName], this)
                            if (validatorResult != true) {
                                errors[fieldName] = validatorResult;
                                foundErrors = true;
                            }
                        }
                    });
                });
                if (foundErrors) {
                    return errors;
                }
                // backbone.js semantics -- on successful validate, return nothing
            },

            /* uncommenting this would make validate() call xosValidate()
            validate: function(attrs, options) {
                r = this.xosValidate(attrs, options);
                console.log("validate");
                console.log(r);
                return r;
            }, */
    });

    XOSCollection = Backbone.Collection.extend({
        objects: function() {
                    return this.models.map(function(element) { return element.attributes; });
                 },

        initialize: function(){
          this.isLoaded = false;
          this.failedLoad = false;
          this.startedLoad = false;
          this.sortVar = 'name';
          this.sortOrder = 'asc';
          this.on( "sort", this.sorted );
        },

        relatedCollections: [],
        foreignCollections: [],

        sorted: function() {
            //console.log("sorted " + this.modelName);
        },

        simpleComparator: function( model ){
          parts=this.sortVar.split(".");
          result = model.get(parts[0]);
          for (index=1; index<parts.length; ++index) {
              result=result[parts[index]];
          }
          return result;
        },

        comparator: function (left, right) {
            var l = this.simpleComparator(left);
            var r = this.simpleComparator(right);

            if (l === void 0) return -1;
            if (r === void 0) return 1;

            if (this.sortOrder=="desc") {
                return l < r ? 1 : l > r ? -1 : 0;
            } else {
                return l < r ? -1 : l > r ? 1 : 0;
            }
        },

        fetchSuccess: function(collection, response, options) {
            //console.log("fetch succeeded " + collection.modelName);
            this.failedLoad = false;
            this.fetching = false;
            if (!this.isLoaded) {
                this.isLoaded = true;
                Backbone.trigger("xoslib:collectionLoadChange", this);
            }
            this.trigger("fetchStateChange");
            if (options["orig_success"]) {
                options["orig_success"](collection, response, options);
            }
        },

        fetchFailure: function(collection, response, options) {
            //console.log("fetch failed " + collection.modelName);
            this.fetching = false;
            if ((!this.isLoaded) && (!this.failedLoad)) {
                this.failedLoad=true;
                Backbone.trigger("xoslib:collectionLoadChange", this);
            }
            this.trigger("fetchStateChange");
            if (options["orig_failure"]) {
                options["orig_failure"](collection, response, options);
            }
        },

        fetch: function(options) {
            var self=this;
            this.fetching=true;
            //console.log("fetch " + this.modelName);
            if (!this.startedLoad) {
                this.startedLoad=true;
                Backbone.trigger("xoslib:collectionLoadChange", this);
            }
            this.trigger("fetchStateChange");
            if (options == undefined) {
                options = {};
            }
            options["orig_success"] = options["success"];
            options["orig_failure"] = options["failure"];
            options["success"] = function(collection, response, options) { self.fetchSuccess.call(self, collection, response, options); };
            options["failure"] = this.fetchFailure;
            Backbone.Collection.prototype.fetch.call(this, options);
        },

        startPolling: function() {
            if (!this._polling) {
                var collection=this;
                setInterval(function() { collection.fetch(); }, 10000);
                this._polling=true;
                this.fetch();
            }
        },

        refresh: function(refreshRelated) {
            if (!this.fetching) {
                this.fetch();
            }
            if (refreshRelated) {
                for (related in this.relatedCollections) {
                    related = xos[related];
                    if (!related.fetching) {
                        related.fetch();
                    }
                }
            }
        },

        maybeFetch: function(options){
                // Helper function to fetch only if this collection has not been fetched before.
            if(this._fetched){
                    // If this has already been fetched, call the success, if it exists
                options.success && options.success();
                console.log("alreadyFetched");
                return;
            }

                // when the original success function completes mark this collection as fetched
            var self = this,
            successWrapper = function(success){
                return function(){
                    self._fetched = true;
                    success && success.apply(this, arguments);
                };
            };
            options.success = successWrapper(options.success);
            console.log("call fetch");
            this.fetch(options);
        },

        getOrFetch: function(id, options){
                // Helper function to use this collection as a cache for models on the server
            var model = this.get(id);

            if(model){
                options.success && options.success(model);
                return;
            }

            model = new this.model({
                resource_uri: id
            });

            model.fetch(options);
        },

        filterBy: function(fieldName, value) {
             filtered = this.filter(function(obj) {
                 return obj.get(fieldName) == value;
                 });
             return new this.constructor(filtered);
        },

        /* from backbone-tastypie.js */
        url: function( models ) {
                    var url = this.urlRoot || ( models && models.length && models[0].urlRoot );
                    url && ( url += ( url.length > 0 && url.charAt( url.length - 1 ) === '/' ) ? '' : '/' );

                    // Build a url to retrieve a set of models. This assume the last part of each model's idAttribute
                    // (set to 'resource_uri') contains the model's id.
                    if ( models && models.length ) {
                            var ids = _.map( models, function( model ) {
                                            var parts = _.compact( model.id.split('/') );
                                            return parts[ parts.length - 1 ];
                                    });
                            url += 'set/' + ids.join(';') + '/';
                    }

                    url && ( url += "?no_hyperlinks=1" );

                    return url;
            },

        listMethods: function() {
                var res = [];
                for(var m in this) {
                    if(typeof this[m] == "function") {
                        res.push(m)
                    }
                }
                return res;
            },
    });

    function define_model(lib, attrs) {
        modelName = attrs.modelName;
        modelClassName = modelName;
        collectionClassName = modelName + "Collection";

        if (!attrs.collectionName) {
            attrs.collectionName = modelName + "s";
        }
        collectionName = attrs.collectionName;

        modelAttrs = {}
        collectionAttrs = {}

        for (key in attrs) {
            value = attrs[key];
            if ($.inArray(key, ["urlRoot", "modelName", "collectionName", "validate"])>=0) {
                modelAttrs[key] = value;
            }
            if ($.inArray(key, ["urlRoot", "modelName", "collectionName", "relatedCollections", "foreignCollections"])>=0) {
                collectionAttrs[key] = value;
            }
        }

        if (xosdefaults && xosdefaults[modelName]) {
            modelAttrs["defaults"] = xosdefaults[modelName];
        }

        if (xosvalidators && xosvalidators[modelName]) {
            modelAttrs["validators"] = xosvalidators[modelName];
        }

        lib[modelName] = XOSModel.extend(modelAttrs);

        collectionAttrs["model"] = lib[modelName];

        lib[collectionClassName] = XOSCollection.extend(collectionAttrs);
        lib[collectionName] = new lib[collectionClassName]();

        lib.allCollectionNames.push(collectionName);
        lib.allCollections.push(lib[collectionName]);
    };

    function xoslib() {
        this.allCollectionNames = [];
        this.allCollections = [];

        define_model(this, {urlRoot: SLIVER_API,
                            relatedCollections: {"networkSlivers": "sliver"},
                            foreignCollections: ["slices", "deployments", "images", "nodes", "users"],
                            modelName: "sliver"});

        define_model(this, {urlRoot: SLICE_API,
                           relatedCollections: {"slivers": "slice", "sliceDeployments": "slice", "slicePrivileges": "slice", "networks": "owner"},
                           foreignCollections: ["services", "sites"],
                           modelName: "slice",
                           xosValidate: function(attrs, options) {
                               errors = XOSModel.prototype.xosValidate(this, attrs, options);
                               // validate that slice.name starts with site.login_base
                               site = attrs.site || this.site;
                               if ((site!=undefined) && (attrs.name!=undefined)) {
                                   site = xos.sites.get(site);
                                   if (attrs.name.indexOf(site.attributes.login_base+"_") != 0) {
                                        errors = errors || {};
                                        errors["name"] = "must start with " + site.attributes.login_base + "_";
                                   }
                               }
                               return errors;
                             },
                           });

        define_model(this, {urlRoot: SLICEDEPLOYMENT_API,
                           foreignCollections: ["slices", "deployments"],
                           modelName: "sliceDeployment"});

        define_model(this, {urlRoot: SLICEPRIVILEGE_API,
                            foreignCollections: ["slices", "users", "sliceRoles"],
                            modelName: "slicePrivilege"});

        define_model(this, {urlRoot: SLICEROLE_API,
                            modelName: "sliceRole"});

        define_model(this, {urlRoot: NODE_API,
                            foreignCollections: ["sites", "deployments"],
                            modelName: "node"});

        define_model(this, {urlRoot: SITE_API,
                            relatedCollections: {"users": "site", "slices": "site", "nodes": "site"},
                            modelName: "site"});

        define_model(this, {urlRoot: USER_API,
                            relatedCollections: {"slicePrivileges": "user", "slices": "owner", "userDeployments": "user"},
                            foreignCollections: ["sites"],
                            modelName: "user"});

        define_model(this, {urlRoot: USERDEPLOYMENT_API,
                            foreignCollections: ["users","deployments"],
                            modelName: "userDeployment"});

        define_model(this, { urlRoot: DEPLOYMENT_API,
                             relatedCollections: {"nodes": "deployment", "slivers": "deploymentNetwork", "networkDeployments": "deployment", "userDeployments": "deployment"},
                             modelName: "deployment"});

        define_model(this, {urlRoot: IMAGE_API,
                            model: this.image,
                            modelName: "image"});

        define_model(this, {urlRoot: NETWORKTEMPLATE_API,
                            modelName: "networkTemplate"});

        define_model(this, {urlRoot: NETWORK_API,
                            relatedCollections: {"networkDeployments": "network", "networkSlivers": "network"},
                            foreignCollections: ["slices", "networkTemplates"],
                            modelName: "network"});

        define_model(this, {urlRoot: NETWORKSLIVER_API,
                            modelName: "networkSliver"});

        define_model(this, {urlRoot: NETWORKDEPLOYMENT_API,
                            modelName: "networkDeployment"});

        define_model(this, {urlRoot: SERVICE_API,
                            modelName: "service"});

        // enhanced REST
        define_model(this, {urlRoot: SLICEPLUS_API,
                            relatedCollections: {'slivers': "slice"},
                            modelName: "slicePlus",
                            collectionName: "slicesPlus"});

        this.listObjects = function() { return this.allCollectionNames; };

        this.getCollectionStatus = function() {
            stats = {isLoaded: 0, failedLoad: 0, startedLoad: 0};
            for (index in this.allCollections) {
                collection = this.allCollections[index];
                if (collection.isLoaded) {
                    stats["isLoaded"] = stats["isLoaded"] + 1;
                }
                if (collection.failedLoad) {
                    stats["failedLoad"] = stats["failedLoad"] + 1;
                }
                if (collection.startedLoad) {
                    stats["startedLoad"] = stats["startedLoad"] + 1;
                }
            }
            stats["completedLoad"] = stats["failedLoad"] + stats["isLoaded"];
            return stats;
        };
    };

    xos = new xoslib();

    function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }

    (function() {
      var _sync = Backbone.sync;
      Backbone.sync = function(method, model, options){
        options.beforeSend = function(xhr){
          var token = getCookie("csrftoken");
          xhr.setRequestHeader('X-CSRFToken', token);
        };
        return _sync(method, model, options);
      };
    })();
}
<|endoftext|>


<commit_before>import { default as React, Component } from 'react';
import { ItemCheckboxList } from './component/ItemCheckboxList.js';
import { ItemList } from './component/ItemList.js';
import classNames from 'classnames';
import { manager } from '../middleware/ChannelManager.js';
import { StaticSearch } from './component/StaticSearch.js';
var helper = require('../middleware/helper.js');

export class NativeList extends Component {
	constructor(props, context) {
		super(props);
		this.state = {
			items: [],
			storedItems: [],
			rawData: {
				hits: {
					hits: []
				}
			},
			defaultSelectAll: false
		};
		this.previousSelectedSensor = {};
		this.channelId = null;
		this.channelListener = null;
		this.defaultSelected = this.props.defaultSelected;
		this.handleSelect = this.handleSelect.bind(this);
		this.handleRemove = this.handleRemove.bind(this);
		this.filterBySearch = this.filterBySearch.bind(this);
		this.selectAll = this.selectAll.bind(this);
		this.type = this.props.multipleSelect ? 'Terms' : 'Term';
	}

	// Get the items from Appbase when component is mounted
	componentDidMount() {
		this.setQueryInfo();
		this.createChannel();
	}

	componentWillUpdate() {
		setTimeout(() => {
			if (this.defaultSelected != this.props.defaultSelected) {
				this.defaultSelected = this.props.defaultSelected;
				let items = this.state.items;

				items = items.map((item) => {
					item.key = item.key.toString();
					item.status = this.defaultSelected && this.defaultSelected.indexOf(item.key) > -1 ? true : false;
					return item;
				});

				this.setState({
					items: items,
					storedItems: items
				});
				this.handleSelect(this.defaultSelected);
			}
		}, 300);
	}

	// stop streaming request and remove listener when component will unmount
	componentWillUnmount() {
		if(this.channelId) {
			manager.stopStream(this.channelId);
		}
		if(this.channelListener) {
			this.channelListener.remove();
		}
	}

	// set the query type and input data
	setQueryInfo() {
		var obj = {
				key: this.props.sensorId,
				value: {
					queryType: this.type,
					inputData: this.props.appbaseField
				}
		};
		helper.selectedSensor.setSensorInfo(obj);
	}

	// Create a channel which passes the depends and receive results whenever depends changes
	createChannel() {
		// Set the depends - add self aggs query as well with depends
		let depends = this.props.depends ? this.props.depends : {};
		depends['aggs'] = {
			key: this.props.appbaseField,
			sort: this.props.sortBy,
			size: this.props.size
		};
		// create a channel and listen the changes
		var channelObj = manager.create(this.context.appbaseRef, this.context.type, depends);
		this.channelId = channelObj.channelId;
		this.channelListener = channelObj.emitter.addListener(this.channelId, function(res) {
			let data = res.data;
			let rawData;
			if(res.mode === 'streaming') {
				rawData = this.state.rawData;
				rawData.hits.hits.push(res.data);
			} else if(res.mode === 'historic') {
				rawData = data;
			}
			this.setState({
				rawData: rawData
			});
			this.setData(rawData);
		}.bind(this));
	}

	setData(data) {
		if(data.aggregations && data.aggregations[this.props.appbaseField] && data.aggregations[this.props.appbaseField].buckets) {
			this.addItemsToList(data.aggregations[this.props.appbaseField].buckets);
		}
	}

	addItemsToList(newItems) {
		newItems = newItems.map((item) => {
			item.key = item.key.toString();
			item.status = this.defaultSelected && this.defaultSelected.indexOf(item.key) > -1 ? true : false;
			return item
		});
		this.setState({
			items: newItems,
			storedItems: newItems
		});
	}

	// Handler function when a value is selected
	handleSelect(value) {
		this.setValue(value, true)
	}

	// Handler function when a value is deselected or removed
	handleRemove(value, isExecuteQuery=false) {
		this.setValue(value, isExecuteQuery)
	}

	// set value
	setValue(value, isExecuteQuery=false) {
		var obj = {
			key: this.props.sensorId,
			value: value
		};
		helper.selectedSensor.set(obj, isExecuteQuery);
	}

	// selectAll
	selectAll(value, defaultSelected, cb) {
		let items = this.state.items.filter((item) => {item.status = value; return item; });
		if(value) {
			this.defaultSelected = defaultSelected;
		}
		this.setState({
			items: items,
			storedItems: items,
			defaultSelectAll: value
		}, cb);
	}

	// filter
	filterBySearch(value) {
		if(value) {
			let items = this.state.storedItems.filter(function(item) {
				return item.key && item.key.toLowerCase().indexOf(value.toLowerCase()) > -1;
			});
			this.setState({
				items: items
			});
		} else {
			this.setState({
				items: this.state.storedItems
			});
		}
	}

	render() {
		// Checking if component is single select or multiple select
		let listComponent,
			searchComponent = null,
			title = null;

		if (this.props.multipleSelect) {
			listComponent = <ItemCheckboxList
				items={this.state.items}
				onSelect={this.handleSelect}
				onRemove={this.handleRemove}
				showCount={this.props.showCount}
				selectAll={this.selectAll}
				defaultSelected={this.props.defaultSelected}
				includeSelectAll={this.props.includeSelectAll}/>
		}
		else {
			listComponent = <ItemList
				items={this.state.items}
				onSelect={this.handleSelect}
				onRemove={this.handleRemove}
				showCount={this.props.showCount}
				defaultSelected={this.props.defaultSelected}/>
		}

		// set static search
		if(this.props.showSearch) {
			searchComponent = <StaticSearch
				placeholder={this.props.searchPlaceholder}
				changeCallback={this.filterBySearch}
			/>
		}

		if(this.props.title) {
			title = (
{this.props.title}
);
		}

		let cx = classNames({
			'rbc-search-active': this.props.showSearch,
			'rbc-search-inactive': !this.props.showSearch,
			'rbc-title-active': this.props.title,
			'rbc-title-inactive': !this.props.title,
			'rbc-placeholder-active': this.props.searchPlaceholder,
			'rbc-placeholder-inactive': !this.props.searchPlaceholder,
			'rbc-singlelist': !this.props.multipleSelect,
			'rbc-multilist': this.props.multipleSelect
		});

		return (
			<div className={`rbc col s12 col-xs-12 card thumbnail ${cx}`}>
				{title}
				{searchComponent}
				{listComponent}

		);
	}
}

NativeList.propTypes = {
	appbaseField: React.PropTypes.string.isRequired,
	size: React.PropTypes.number,
	showCount: React.PropTypes.bool,
	multipleSelect: React.PropTypes.bool,
	sortBy: React.PropTypes.string,
	includeSelectAll: React.PropTypes.bool
};

// Default props value
NativeList.defaultProps = {
	showCount: true,
	multipleSelect: true,
	sortBy: 'count',
	size: 100,
	showSearch: false,
	title: null,
	searchPlaceholder: 'Search',
	includeSelectAll: false
};

// context type
NativeList.contextTypes = {
	appbaseRef: React.PropTypes.any.isRequired,
	type: React.PropTypes.any.isRequired
};
<commit_msg>Fix defaultSelection issue while initializing<commit_after>import { default as React, Component } from 'react';
import { ItemCheckboxList } from './component/ItemCheckboxList.js';
import { ItemList } from './component/ItemList.js';
import classNames from 'classnames';
import { manager } from '../middleware/ChannelManager.js';
import { StaticSearch } from './component/StaticSearch.js';
var helper = require('../middleware/helper.js');

export class NativeList extends Component {
	constructor(props, context) {
		super(props);
		this.state = {
			items: [],
			storedItems: [],
			rawData: {
				hits: {
					hits: []
				}
			},
			defaultSelectAll: false
		};
		this.previousSelectedSensor = {};
		this.channelId = null;
		this.channelListener = null;
		this.defaultSelected = this.props.defaultSelected;
		this.handleSelect = this.handleSelect.bind(this);
		this.handleRemove = this.handleRemove.bind(this);
		this.filterBySearch = this.filterBySearch.bind(this);
		this.selectAll = this.selectAll.bind(this);
		this.type = this.props.multipleSelect ? 'Terms' : 'Term';
	}

	// Get the items from Appbase when component is mounted
	componentDidMount() {
		this.setQueryInfo();
		this.handleSelect('');
		this.createChannel();
	}

	componentWillUpdate() {
		setTimeout(() => {
			if (this.defaultSelected != this.props.defaultSelected) {
				this.defaultSelected = this.props.defaultSelected;
				let items = this.state.items;

				items = items.map((item) => {
					item.key = item.key.toString();
					item.status = this.defaultSelected && this.defaultSelected.indexOf(item.key) > -1 ? true : false;
					return item;
				});

				this.setState({
					items: items,
					storedItems: items
				});
				this.handleSelect(this.defaultSelected);
			}
		}, 300);
	}

	// stop streaming request and remove listener when component will unmount
	componentWillUnmount() {
		if(this.channelId) {
			manager.stopStream(this.channelId);
		}
		if(this.channelListener) {
			this.channelListener.remove();
		}
	}

	// set the query type and input data
	setQueryInfo() {
		var obj = {
				key: this.props.sensorId,
				value: {
					queryType: this.type,
					inputData: this.props.appbaseField
				}
		};
		helper.selectedSensor.setSensorInfo(obj);
	}

	// Create a channel which passes the depends and receive results whenever depends changes
	createChannel() {
		// Set the depends - add self aggs query as well with depends
		let depends = this.props.depends ? this.props.depends : {};
		depends['aggs'] = {
			key: this.props.appbaseField,
			sort: this.props.sortBy,
			size: this.props.size
		};
		// create a channel and listen the changes
		var channelObj = manager.create(this.context.appbaseRef, this.context.type, depends);
		this.channelId = channelObj.channelId;
		this.channelListener = channelObj.emitter.addListener(this.channelId, function(res) {
			let data = res.data;
			let rawData;
			if(res.mode === 'streaming') {
				rawData = this.state.rawData;
				rawData.hits.hits.push(res.data);
			} else if(res.mode === 'historic') {
				rawData = data;
			}
			this.setState({
				rawData: rawData
			});
			this.setData(rawData);
		}.bind(this));
	}

	setData(data) {
		if(data.aggregations && data.aggregations[this.props.appbaseField] && data.aggregations[this.props.appbaseField].buckets) {
			this.addItemsToList(data.aggregations[this.props.appbaseField].buckets);
		}
	}

	addItemsToList(newItems) {
		newItems = newItems.map((item) => {
			item.key = item.key.toString();
			item.status = this.defaultSelected && this.defaultSelected.indexOf(item.key) > -1 ? true : false;
			return item
		});
		this.setState({
			items: newItems,
			storedItems: newItems
		});
	}

	// Handler function when a value is selected
	handleSelect(value) {
		this.setValue(value, true)
	}

	// Handler function when a value is deselected or removed
	handleRemove(value, isExecuteQuery=false) {
		this.setValue(value, isExecuteQuery)
	}

	// set value
	setValue(value, isExecuteQuery=false) {
		var obj = {
			key: this.props.sensorId,
			value: value
		};
		helper.selectedSensor.set(obj, isExecuteQuery);
	}

	// selectAll
	selectAll(value, defaultSelected, cb) {
		let items = this.state.items.filter((item) => {item.status = value; return item; });
		if(value) {
			this.defaultSelected = defaultSelected;
		}
		this.setState({
			items: items,
			storedItems: items,
			defaultSelectAll: value
		}, cb);
	}

	// filter
	filterBySearch(value) {
		if(value) {
			let items = this.state.storedItems.filter(function(item) {
				return item.key && item.key.toLowerCase().indexOf(value.toLowerCase()) > -1;
			});
			this.setState({
				items: items
			});
		} else {
			this.setState({
				items: this.state.storedItems
			});
		}
	}

	render() {
		// Checking if component is single select or multiple select
		let listComponent,
			searchComponent = null,
			title = null;

		if (this.props.multipleSelect) {
			listComponent = <ItemCheckboxList
				items={this.state.items}
				onSelect={this.handleSelect}
				onRemove={this.handleRemove}
				showCount={this.props.showCount}
				selectAll={this.selectAll}
				defaultSelected={this.props.defaultSelected}
				includeSelectAll={this.props.includeSelectAll}/>
		}
		else {
			listComponent = <ItemList
				items={this.state.items}
				onSelect={this.handleSelect}
				onRemove={this.handleRemove}
				showCount={this.props.showCount}
				defaultSelected={this.props.defaultSelected}/>
		}

		// set static search
		if(this.props.showSearch) {
			searchComponent = <StaticSearch
				placeholder={this.props.searchPlaceholder}
				changeCallback={this.filterBySearch}
			/>
		}

		if(this.props.title) {
			title = (
{this.props.title}
);
		}

		let cx = classNames({
			'rbc-search-active': this.props.showSearch,
			'rbc-search-inactive': !this.props.showSearch,
			'rbc-title-active': this.props.title,
			'rbc-title-inactive': !this.props.title,
			'rbc-placeholder-active': this.props.searchPlaceholder,
			'rbc-placeholder-inactive': !this.props.searchPlaceholder,
			'rbc-singlelist': !this.props.multipleSelect,
			'rbc-multilist': this.props.multipleSelect
		});

		return (
			<div className={`rbc col s12 col-xs-12 card thumbnail ${cx}`}>
				{title}
				{searchComponent}
				{listComponent}

		);
	}
}

NativeList.propTypes = {
	appbaseField: React.PropTypes.string.isRequired,
	size: React.PropTypes.number,
	showCount: React.PropTypes.bool,
	multipleSelect: React.PropTypes.bool,
	sortBy: React.PropTypes.string,
	includeSelectAll: React.PropTypes.bool
};

// Default props value
NativeList.defaultProps = {
	showCount: true,
	multipleSelect: true,
	sortBy: 'count',
	size: 100,
	showSearch: false,
	title: null,
	searchPlaceholder: 'Search',
	includeSelectAll: false
};

// context type
NativeList.contextTypes = {
	appbaseRef: React.PropTypes.any.isRequired,
	type: React.PropTypes.any.isRequired
};
<|endoftext|>


<commit_before>/* app/views/partials/grid.js - Photo Grid View partials */
'use strict';

define([
    'jquery',
    'backbone',
    'underscore',
    'tpl/jst',
    //'mixfilter',
    'app/views/partials/filterviews',
    'mixitup',
    'imagesLoaded'
], function( $, Backbone, _, TPL, Filter ) {

    var GridThumb = Backbone.View.extend({
        tagName : 'div',
        className : function() {
            if ( this.model.has('type_tags') ) {
                var tags = []
                _.each( this.model.get('type_tags'), function(obj) {
                    tags.push( obj.className )
                }, this )
                return 'photo-cell ' + tags.join(' ')
            } else {
                return 'photo-cell'
            }
        },
        template : TPL.gridThumb,
        render : function() {
            var html = this.template({
                url : this.url(),
                thumb : this.model.get('thumb'),
                title : this.model.get('title'),
                summary : this.model.get('summary')
            })
            this.$el.append( html )
            this.el.dataset.name = this.model.get('title')
            this.el.dataset.date = this.model.get('date').unix()
            return this.el
        }
    })

    var Grid = Backbone.View.extend({
        tagName : 'div',
        className: 'photo-grid showcase',
        rowTmpl : TPL.gridRow,
        $row : undefined,
        initialize : function() {
            if ( this.$el.children().length ) { return this.el }

            this.collection.forEach( function(model, index){
                this.$el.append( new this.Thumb({
                    model : model
                }).render() )
            }, this )

            this.$el.append($('
')).append($('
'))

        },

        render : function() {
            return this.el
        }
    })

    var GridPage = Backbone.View.extend({
        initialize : function(){
            _.bindAll( this, 'render', 'navigate', 'filter', 'init' )
            var self = this

            this.collection.fetch({
                success : function(collection) {
                    self.grid = new self.Grid({
                        collection : collection,
                        id : self.class + '-grid'
                    })

                    self.filterbar = new Filter({
                        el : '#filter-bar',
                        model : self.model,
                        collection : collection
                    })

                    Backbone.dispatcher.trigger(self.class + ':ready', self)
                }
            })

        },

        events : {
            'click .photo-cell a' : 'navigate'
        },

        init : function(spinner) {
            var hashObj = $.deparam.fragment()

            this.delegateEvents()

            var hasTags = this.collection.some(function(m){ return m.has('type_tags') })
            this.filterbar.render({ mixitup : true, hasTags : hasTags })

            this.$el.addClass(this.class)

            if ( !this.collection.length ) {
                throw {
                    message : 'Not Loaded Yet',
                    type : 'EmptyCollection'
                }
            }

            hashObj.filter = hashObj.filter || '*'
            hashObj.sort = hashObj.sort || 'name'
            this.model.set( hashObj )

            history.replaceState({}, '', $.param.fragment('', hashObj))
            if (spinner) {spinner.detach()}
            this.render()
        },

        render : function() {
            var self = this

            this.$el.html( this.grid.render({
                scrolTo : this.lastY
            }) )

            this.lastY = null

            this.$('.page').imagesLoaded(function(){
                $( '#' + self.class + '-grid' ).mixItUp({
                    selectors : {
                        target : '.photo-cell',
                        filter : '',
                        sort : ''
                    },
                    callbacks : {},
                    controls : {
                        enable : false
                    },
                    load : {
                        filter : self.model.get('filter') || '*',
                        sort : self.model.get('sort') + ':asc'
                    }
                })
            })

            this.model.on('change', function(model) {
                var newAttr = model.changedAttributes()
                if ( newAttr.filter ) {
                    this.filter(newAttr.filter)
                } else if ( newAttr.sort ) {
                    this.sort(newAttr.sort)
                }
                Backbone.dispatcher.trigger('savehistory')
            }, this)

            $(window).on('hashchange', function() {
                var hashObj = $.deparam.fragment()
                this.model.set(hashObj)
            }.bind(this))
        },

        filter : function(filter) {
            this.grid.$el.mixItUp('filter', filter)
        },

        sort : function(sort) {
            this.grid.$el.mixItUp('sort', sort + ':asc')
        },

        onClose : function() {
            this.grid.$el.mixItUp('destroy', true)

            $('.page').removeClass(this.class)

            this.model.off('change')
            this.model.clear({ silent : true })

            $(window).off('hashchange')

            this.filterbar.close()
        },

        navigate : function(e) {
            e.preventDefault()
            this.lastY = window.pageYOffset
            Backbone.dispatcher.trigger('navigate:detail', e, this)
        }

    })

    return {
        Grid : Grid,
        Thumb : GridThumb,
        Page : GridPage
    }

})
<commit_msg>fixed scrolling on mixitup pages<commit_after>/* app/views/partials/grid.js - Photo Grid View partials */
'use strict';

define([
    'jquery',
    'backbone',
    'underscore',
    'tpl/jst',
    //'mixfilter',
    'app/views/partials/filterviews',
    'mixitup',
    'imagesLoaded'
], function( $, Backbone, _, TPL, Filter ) {

    var GridThumb = Backbone.View.extend({
        tagName : 'div',
        className : function() {
            if ( this.model.has('type_tags') ) {
                var tags = []
                _.each( this.model.get('type_tags'), function(obj) {
                    tags.push( obj.className )
                }, this )
                return 'photo-cell ' + tags.join(' ')
            } else {
                return 'photo-cell'
            }
        },
        template : TPL.gridThumb,
        render : function() {
            var html = this.template({
                url : this.url(),
                thumb : this.model.get('thumb'),
                title : this.model.get('title'),
                summary : this.model.get('summary')
            })
            this.$el.append( html )
            this.el.dataset.name = this.model.get('title')
            this.el.dataset.date = this.model.get('date').unix()
            return this.el
        }
    })

    var Grid = Backbone.View.extend({
        tagName : 'div',
        className: 'photo-grid showcase',
        rowTmpl : TPL.gridRow,
        $row : undefined,
        initialize : function() {
            if ( this.$el.children().length ) { return this.el }

            this.collection.forEach( function(model, index){
                this.$el.append( new this.Thumb({
                    model : model
                }).render() )
            }, this )

            this.$el.append($('
')).append($('
'))

        },

        render : function() {
            return this.el
        }
    })

    var GridPage = Backbone.View.extend({
        initialize : function(){
            _.bindAll( this, 'render', 'navigate', 'filter', 'init' )
            var self = this

            this.collection.fetch({
                success : function(collection) {
                    self.grid = new self.Grid({
                        collection : collection,
                        id : self.class + '-grid'
                    })

                    self.filterbar = new Filter({
                        el : '#filter-bar',
                        model : self.model,
                        collection : collection
                    })

                    Backbone.dispatcher.trigger(self.class + ':ready', self)
                }
            })

        },

        events : {
            'click .photo-cell a' : 'navigate'
        },

        init : function(spinner) {
            var hashObj = $.deparam.fragment()

            this.delegateEvents()

            var hasTags = this.collection.some(function(m){ return m.has('type_tags') })
            this.filterbar.render({ mixitup : true, hasTags : hasTags })

            this.$el.addClass(this.class)

            if ( !this.collection.length ) {
                throw {
                    message : 'Not Loaded Yet',
                    type : 'EmptyCollection'
                }
            }

            hashObj.filter = hashObj.filter || '*'
            hashObj.sort = hashObj.sort || 'name'
            this.model.set( hashObj )

            history.replaceState({}, '', $.param.fragment('', hashObj))
            if (spinner) {spinner.detach()}
            this.render()
        },

        render : function() {
            var self = this

            this.$el.html( this.grid.render() )

            this.$('.page').imagesLoaded(function(){
                $( '#' + self.class + '-grid' ).mixItUp({
                    selectors : {
                        target : '.photo-cell',
                        filter : '',
                        sort : ''
                    },
                    callbacks : {
                        onMixLoad : function(state) {
                            $('html, body').animate({ scrollTop: this.lastY }, 'fast')
                            this.lastY = null
                        }.bind(self)
                    },
                    controls : {
                        enable : false
                    },
                    load : {
                        filter : self.model.get('filter') || '*',
                        sort : self.model.get('sort') + ':asc'
                    }
                })
            })

            this.model.on('change', function(model) {
                var newAttr = model.changedAttributes()
                if ( newAttr.filter ) {
                    this.filter(newAttr.filter)
                } else if ( newAttr.sort ) {
                    this.sort(newAttr.sort)
                }
                Backbone.dispatcher.trigger('savehistory')
            }, this)

            $(window).on('hashchange', function() {
                var hashObj = $.deparam.fragment()
                this.model.set(hashObj)
            }.bind(this))
        },

        filter : function(filter) {
            this.grid.$el.mixItUp('filter', filter)
        },

        sort : function(sort) {
            this.grid.$el.mixItUp('sort', sort + ':asc')
        },

        onClose : function() {
            this.grid.$el.mixItUp('destroy', true)

            $('.page').removeClass(this.class)

            this.model.off('change')
            this.model.clear({ silent : true })

            $(window).off('hashchange')

            this.filterbar.close()
        },

        navigate : function(e) {
            e.preventDefault()
            this.lastY = window.pageYOffset
            Backbone.dispatcher.trigger('navigate:detail', e, this)
        }

    })

    return {
        Grid : Grid,
        Thumb : GridThumb,
        Page : GridPage
    }

})
<|endoftext|>


<commit_before>const webpack = require('webpack'),
  BowerWebpackPlugin = require('bower-webpack-plugin'),
  path = require('path'),
  IS_DEBUG = process.env.DEBUG && process.env.DEBUG != 'false',
  IS_WATCH = process.env.WATCH && process.env.WATCH != 'false',
  BASE = path.join(__dirname, '..', process.env.BASE)

module.exports = {
  entry: path.join(BASE, process.env.IN),
  target: 'web',
  cache: true,
  output: {
    path: BASE,
    filename: process.env.OUT,
    sourceMapFilename: `${process.env.OUT}.map`
  },
  devtool: IS_DEBUG ? '#source-map' : false,
  watch: IS_WATCH,
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules|bower/,
        loader: 'babel-loader?presets[]=es2015'
      },
      {
        test: /\.html$/,
        exclude: /node_modules|bower/,
        loader: 'html-loader?attrs=none'
      },
      {
        test: /\.json$/,
        exclude: /node_modules|bower/,
        loader: 'json-loader'
      }
    ]
  },
  resolve: {
    alias: {
    }
  },
  plugins: [
    new webpack.ProvidePlugin({
      // $: 'jquery',
      // 'window.jQuery': 'jquery',
    }),
    // minify by default
    new webpack.optimize.UglifyJsPlugin({
      sourceMap: IS_DEBUG
    }),
    // load also the bower components
    new BowerWebpackPlugin({
      excludes: /\.css$/,
      searchResolveModulesDirectories: false
    })
  ]
}

<commit_msg>added: js banner<commit_after>const webpack = require('webpack'),
  BowerWebpackPlugin = require('bower-webpack-plugin'),
  path = require('path'),
  IS_DEBUG = process.env.DEBUG && process.env.DEBUG != 'false',
  IS_WATCH = process.env.WATCH && process.env.WATCH != 'false',
  BASE = path.join(__dirname, '..', process.env.BASE)

module.exports = {
  entry: path.join(BASE, process.env.IN),
  target: 'web',
  cache: true,
  output: {
    path: BASE,
    filename: process.env.OUT,
    sourceMapFilename: `${process.env.OUT}.map`
  },
  devtool: IS_DEBUG ? '#source-map' : false,
  watch: IS_WATCH,
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules|bower/,
        loader: 'babel-loader?presets[]=es2015'
      },
      {
        test: /\.html$/,
        exclude: /node_modules|bower/,
        loader: 'html-loader?attrs=none'
      },
      {
        test: /\.json$/,
        exclude: /node_modules|bower/,
        loader: 'json-loader'
      }
    ]
  },
  resolve: {
    alias: {
    }
  },
  plugins: [
    // load also the bower components
    new BowerWebpackPlugin({
      excludes: /\.css$/,
      searchResolveModulesDirectories: false
    }),
    new webpack.ProvidePlugin({
      // $: 'jquery',
      // 'window.jQuery': 'jquery',
    }),
    // minify by default
    new webpack.optimize.UglifyJsPlugin({
      sourceMap: IS_DEBUG
    }),
    new webpack.BannerPlugin(`Gold Interactive - ${ new Date().getFullYear() }`)
  ]
}

<|endoftext|>


<commit_before>import ChatClient from 'src/server/clients/ChatClient'

export default async function initializeProjectChannel(project, players, options = {}) {
  const channelName = project.name
  const chatClient = options.chatClient || new ChatClient()

  console.log(`Initializing project channel #${channelName}`)

  const {goal} = project
  const goalIssueNum = goal.url.replace(/.*\/(\d+)$/, '$1')
  const goalLink = `[${goalIssueNum}: ${goal.title}](${goal.url})`

  await chatClient.createChannel(channelName, players.map(p => p.handle).concat('echo'), goalLink)

  // Split welcome message into 2 so that the goal link preview
  // is inserted right after the goal link.
  const projectWelcomeMessage1 = `🎊 *Welcome to the ${channelName} project channel!* 🎊

*Your goal is:* ${goalLink}
`

  const projectWelcomeMessage2 = `*Your team is:*
  ${players.map(p => `• _${p.name}_ - @${p.handle}`).join('\n  ')}

*Time to start work on your project!*

The first step is to create an appropriate project artifact.
Once you've created the artifact, connect it to your project with the \`/project set-artifact\` command.

Run \`/project set-artifact --help\` for more guidance.
`

  await chatClient.sendChannelMessage(channelName, projectWelcomeMessage1).catch(err => {
    console.error(`Project channel ${channelName} welcome message #1 failed to post:`)
    console.error(projectWelcomeMessage1)
    console.error(err)
  })
  await chatClient.sendChannelMessage(channelName, projectWelcomeMessage2).catch(err => {
    console.error(`Project channel ${channelName} welcome message #2 failed to post:`)
    console.error(projectWelcomeMessage1)
    console.error(err)
  })
}
<commit_msg>fix typo<commit_after>import ChatClient from 'src/server/clients/ChatClient'

export default async function initializeProjectChannel(project, players, options = {}) {
  const channelName = project.name
  const chatClient = options.chatClient || new ChatClient()

  console.log(`Initializing project channel #${channelName}`)

  const {goal} = project
  const goalIssueNum = goal.url.replace(/.*\/(\d+)$/, '$1')
  const goalLink = `[${goalIssueNum}: ${goal.title}](${goal.url})`

  await chatClient.createChannel(channelName, players.map(p => p.handle).concat('echo'), goalLink)

  // Split welcome message into 2 so that the goal link preview
  // is inserted right after the goal link.
  const projectWelcomeMessage1 = `🎊 *Welcome to the ${channelName} project channel!* 🎊

*Your goal is:* ${goalLink}
`

  const projectWelcomeMessage2 = `*Your team is:*
  ${players.map(p => `• _${p.name}_ - @${p.handle}`).join('\n  ')}

*Time to start work on your project!*

The first step is to create an appropriate project artifact.
Once you've created the artifact, connect it to your project with the \`/project set-artifact\` command.

Run \`/project set-artifact --help\` for more guidance.
`

  await chatClient.sendChannelMessage(channelName, projectWelcomeMessage1).catch(err => {
    console.error(`Project channel ${channelName} welcome message #1 failed to post:`)
    console.error(projectWelcomeMessage1)
    console.error(err)
  })
  await chatClient.sendChannelMessage(channelName, projectWelcomeMessage2).catch(err => {
    console.error(`Project channel ${channelName} welcome message #2 failed to post:`)
    console.error(projectWelcomeMessage2)
    console.error(err)
  })
}
<|endoftext|>