<commit_before>#!/usr/bin/env node

const Listr = require('listr');
const execa = require('execa');
const chalk = require('chalk');
const del = require('del');
const UpdaterRenderer = require('listr-update-renderer');
const moment = require('moment');
const argv = require('minimist')(process.argv.slice(2), {
    string: ['appMode'],
    boolean: ['lint', 'i18n'],
    default: { lint: true, i18n: false, appMode: 'bundle' }
});

const { debug, success, error, about } = require('./lib/helpers/log')('proton-bundler');
const { bash, script } = require('./lib/helpers/cli');

const {
    customBundler: { tasks: customTasks, config: customConfig },
    getCustomHooks
} = require('./lib/custom');
const { pull, push, getConfig, logCommits } = require('./lib/git');

const getTasks = (branch, { isCI, flowType = 'single', forceI18n, appMode }) => {
    const { EXTERNAL_FILES = ['.htaccess'] } = customConfig;
    const { hookPreTasks, hookPostTasks, hookPostTaskClone, hookPostTaskBuild, customConfigSetup } = getCustomHooks(
        customTasks({
            branch,
            isCI,
            flowType,
            appMode,
            forceI18n
        })
    );

    const configTasks = customConfigSetup.length
        ? customConfigSetup
        : [
              {
                  title: 'Setup app config',
                  enabled: () => !isCI,
                  task() {
                      return bash('npx proton-pack', process.argv.slice(2));
                  }
              }
          ];

    const list = [
        ...hookPreTasks,
        {
            title: 'Save dependencies if we need',
            enabled: () => !isCI && /dev|beta|alpha/.test(branch),
            task() {
                return script('updatePackageLock.sh', [argv['default-branch']]);
            }
        },
        {
            title: 'Clear previous dist',
            async task() {
                await del(['dist', 'distCurrent', 'distback'], { dryRun: false });
                isCI && execa.shell('mkdir dist');
            }
        },
        {
            title: 'Lint sources',
            enabled: () => argv.lint !== false,
            task: () => execa('npm', ['run', 'lint'])
        },
        ...configTasks,
        {
            title: 'Extract git env for the bundle',
            enabled: () => !isCI,
            async task(ctx) {
                const { commit, branch, tag } = await getConfig();
                ctx.originCommit = commit;
                ctx.originBranch = branch;
                ctx.tag = tag;
            }
        },
        {
            title: `Pull dist branch ${branch}`,
            enabled: () => !isCI,
            task: () => pull(branch)
        },
        ...hookPostTaskClone,
        {
            title: 'Copy some files',
            task() {
                const rule = EXTERNAL_FILES.length > 1 ? `{${EXTERNAL_FILES.join(',')}}` : EXTERNAL_FILES.join(',');
                return bash(`cp src/${rule} dist/`);
            }
        },
        {
            title: 'Upgrade translations inside the app',
            enabled: () => forceI18n || (!isCI && /prod|beta/.test(branch)),
            task() {
                return execa('npm', ['run', 'i18n:getlatest']);
            }
        },
        {
            title: 'Build the application',
            task() {
                const args = process.argv.slice(2);
                if (appMode === 'standalone') {
                    return execa('npm', ['run', 'build:standalone', '--', ...args]);
                }

                return execa('npm', ['run', 'build', '--', ...args]);
            }
        },
        ...hookPostTaskBuild,
        {
            title: `Push dist to ${branch}`,
            enabled: () => !isCI,
            task: (ctx) => push(branch, ctx)
        },
        {
            title: 'Update crowdin with latest translations',
            enabled: () => !isCI && /prod|beta/.test(branch),
            task() {
                return execa('npm', ['run', 'i18n:upgrade']);
            }
        },
        ...hookPostTasks
    ];
    return list;
};

/**
 * Get the API dest when we deploy.
 * You can use the custom config from proton.bundler.js to get it
 * @return {Promise<String>}
 */
async function getAPIUrl() {
    if (customConfig.apiUrl) {
        return customConfig.apiUrl;
    }

    const args = process.argv.slice(2);
    const { stdout } = await bash('npx proton-pack print-config', args);
    debug(stdout);
    const [, url] = stdout.match(/apiUrl": "(.+)",/);
    return url;
}

async function main() {
    // Custom local deploy for the CI
    const isCI = process.env.NODE_ENV_DIST === 'ci';
    const branch = argv.branch;
    const flowType = argv.flow;
    const forceI18n = argv.i18n;
    const appMode = argv.appMode;

    debug({ customConfig, argv });

    if (!branch && !isCI) {
        throw new Error('You must define a branch name. --branch=XXX');
    }

    const apiUrl = await getAPIUrl();

    process.env.NODE_ENV_BRANCH = branch;
    process.env.NODE_ENV_API = apiUrl;

    about({
        ...(!isCI && { branch }),
        apiUrl,
        appMode,
        SENTRY: process.env.NODE_ENV_SENTRY
    });

    const start = moment(Date.now());
    const listTasks = getTasks(branch, { isCI, flowType, forceI18n, appMode });
    const tasks = new Listr(listTasks, {
        renderer: UpdaterRenderer,
        collapse: false
    });

    const { context } = await tasks.run();
    debug(context);

    const now = moment(Date.now());
    const total = now.diff(start, 'seconds');
    const time = total > 60 ? moment.utc(total * 1000).format('mm:ss') : `${total}s`;

    !isCI && success('App deployment done', { time });
    isCI && success(`Build CI app to the directory: ${chalk.bold('dist')}`, { time });

    if (!isCI) {
        return logCommits(branch, flowType);
    }
}

if (argv._.includes('hosts')) {
    return script('createNewDeployBranch.sh', process.argv.slice(3)).then(({ stdout }) => console.log(stdout));
}

main().catch(error);
<commit_msg>Remove useless log<commit_after>#!/usr/bin/env node

const Listr = require('listr');
const execa = require('execa');
const chalk = require('chalk');
const del = require('del');
const UpdaterRenderer = require('listr-update-renderer');
const moment = require('moment');
const argv = require('minimist')(process.argv.slice(2), {
    string: ['appMode'],
    boolean: ['lint', 'i18n'],
    default: { lint: true, i18n: false, appMode: 'bundle' }
});

const { debug, success, error, about } = require('./lib/helpers/log')('proton-bundler');
const { bash, script } = require('./lib/helpers/cli');

const {
    customBundler: { tasks: customTasks, config: customConfig },
    getCustomHooks
} = require('./lib/custom');
const { pull, push, getConfig, logCommits } = require('./lib/git');

const getTasks = (branch, { isCI, flowType = 'single', forceI18n, appMode }) => {
    const { EXTERNAL_FILES = ['.htaccess'] } = customConfig;
    const { hookPreTasks, hookPostTasks, hookPostTaskClone, hookPostTaskBuild, customConfigSetup } = getCustomHooks(
        customTasks({
            branch,
            isCI,
            flowType,
            appMode,
            forceI18n
        })
    );

    const configTasks = customConfigSetup.length
        ? customConfigSetup
        : [
              {
                  title: 'Setup app config',
                  enabled: () => !isCI,
                  task() {
                      return bash('npx proton-pack', process.argv.slice(2));
                  }
              }
          ];

    const list = [
        ...hookPreTasks,
        {
            title: 'Save dependencies if we need',
            enabled: () => !isCI && /dev|beta|alpha/.test(branch),
            task() {
                return script('updatePackageLock.sh', [argv['default-branch']]);
            }
        },
        {
            title: 'Clear previous dist',
            async task() {
                await del(['dist', 'distCurrent', 'distback'], { dryRun: false });
                isCI && execa.shell('mkdir dist');
            }
        },
        {
            title: 'Lint sources',
            enabled: () => argv.lint !== false,
            task: () => execa('npm', ['run', 'lint'])
        },
        ...configTasks,
        {
            title: 'Extract git env for the bundle',
            enabled: () => !isCI,
            async task(ctx) {
                const { commit, branch, tag } = await getConfig();
                ctx.originCommit = commit;
                ctx.originBranch = branch;
                ctx.tag = tag;
            }
        },
        {
            title: `Pull dist branch ${branch}`,
            enabled: () => !isCI,
            task: () => pull(branch)
        },
        ...hookPostTaskClone,
        {
            title: 'Copy some files',
            task() {
                const rule = EXTERNAL_FILES.length > 1 ? `{${EXTERNAL_FILES.join(',')}}` : EXTERNAL_FILES.join(',');
                return bash(`cp src/${rule} dist/`);
            }
        },
        {
            title: 'Upgrade translations inside the app',
            enabled: () => forceI18n || (!isCI && /prod|beta/.test(branch)),
            task() {
                return execa('npm', ['run', 'i18n:getlatest']);
            }
        },
        {
            title: 'Build the application',
            task() {
                const args = process.argv.slice(2);
                if (appMode === 'standalone') {
                    return execa('npm', ['run', 'build:standalone', '--', ...args]);
                }

                return execa('npm', ['run', 'build', '--', ...args]);
            }
        },
        ...hookPostTaskBuild,
        {
            title: `Push dist to ${branch}`,
            enabled: () => !isCI,
            task: (ctx) => push(branch, ctx)
        },
        {
            title: 'Update crowdin with latest translations',
            enabled: () => !isCI && /prod|beta/.test(branch),
            task() {
                return execa('npm', ['run', 'i18n:upgrade']);
            }
        },
        ...hookPostTasks
    ];
    return list;
};

/**
 * Get the API dest when we deploy.
 * You can use the custom config from proton.bundler.js to get it
 * @return {Promise<String>}
 */
async function getAPIUrl() {
    if (customConfig.apiUrl) {
        return customConfig.apiUrl;
    }

    const args = process.argv.slice(2);
    const { stdout } = await bash('npx proton-pack print-config', args);
    debug(stdout);
    const [, url] = stdout.match(/apiUrl": "(.+)",/);
    return url;
}

async function main() {
    // Custom local deploy for the CI
    const isCI = process.env.NODE_ENV_DIST === 'ci';
    const branch = argv.branch;
    const flowType = argv.flow;
    const forceI18n = argv.i18n;
    const appMode = argv.appMode;

    debug({ customConfig, argv });

    if (!branch && !isCI) {
        throw new Error('You must define a branch name. --branch=XXX');
    }

    const apiUrl = await getAPIUrl();

    process.env.NODE_ENV_BRANCH = branch;
    process.env.NODE_ENV_API = apiUrl;

    about({
        ...(!isCI && { branch }),
        apiUrl,
        appMode,
        SENTRY: process.env.NODE_ENV_SENTRY
    });

    const start = moment(Date.now());
    const listTasks = getTasks(branch, { isCI, flowType, forceI18n, appMode });
    const tasks = new Listr(listTasks, {
        renderer: UpdaterRenderer,
        collapse: false
    });

    await tasks.run();

    const now = moment(Date.now());
    const total = now.diff(start, 'seconds');
    const time = total > 60 ? moment.utc(total * 1000).format('mm:ss') : `${total}s`;

    !isCI && success('App deployment done', { time });
    isCI && success(`Build CI app to the directory: ${chalk.bold('dist')}`, { time });

    if (!isCI) {
        return logCommits(branch, flowType);
    }
}

if (argv._.includes('hosts')) {
    return script('createNewDeployBranch.sh', process.argv.slice(3)).then(({ stdout }) => console.log(stdout));
}

main().catch(error);
<|endoftext|>


<commit_before>const fs = require('fs-extra');
const url = require('url');
const session = require('cookie-session');
const crypto = require('crypto');
const path = require('path');
const config = require('../../../../server/config');
const urlUtils = require('../../../../server/lib/url-utils');
const constants = require('../../../../server/lib/constants');
const common = require('../../../../server/lib/common');
const settingsCache = require('../../../../server/services/settings/cache');
// routeKeywords.private: 'private'
const privateRoute = '/private/';

function verifySessionHash(salt, hash) {
    if (!salt || !hash) {
        return false;
    }

    let hasher = crypto.createHash('sha256');
    hasher.update(settingsCache.get('password') + salt, 'utf8');
    return hasher.digest('hex') === hash;
}

function getRedirectUrl(query) {
    const redirect = decodeURIComponent(query.r || '/');

    try {
        return url.parse(redirect).pathname;
    } catch (e) {
        return '/';
    }
}

const privateBlogging = {
    checkIsPrivate: function checkIsPrivate(req, res, next) {
        let isPrivateBlog = settingsCache.get('is_private');

        if (!isPrivateBlog) {
            res.isPrivateBlog = false;
            return next();
        }

        res.isPrivateBlog = true;

        return session({
            maxAge: constants.ONE_MONTH_MS,
            signed: false
        })(req, res, next);
    },

    filterPrivateRoutes: function filterPrivateRoutes(req, res, next) {
        if (!res.isPrivateBlog || req.url.lastIndexOf(privateRoute, 0) === 0) {
            return next();
        }

        if (req.url.lastIndexOf('/robots.txt', 0) === 0) {
            return fs.readFile(path.resolve(__dirname, '../', 'robots.txt'), function readFile(err, buf) {
                if (err) {
                    return next(err);
                }

                res.writeHead(200, {
                    'Content-Type': 'text/plain',
                    'Content-Length': buf.length,
                    'Cache-Control': 'public, max-age=' + config.get('caching:robotstxt:maxAge')
                });

                res.end(buf);
            });
        }

        // CASE: Allow private RSS feed urls.
        // Any url which contains the hash and the postfix /rss is allowed to access a private rss feed without
        // a session. As soon as a path matches, we rewrite the url. Even Express uses rewriting when using `app.use()`.
        if (req.url.indexOf(settingsCache.get('public_hash') + '/rss') !== -1) {
            req.url = req.url.replace(settingsCache.get('public_hash') + '/', '');
            return next();
        }

        // NOTE: Redirect to /private if the session does not exist.
        privateBlogging.authenticatePrivateSession(req, res, function onSessionVerified() {
            // CASE: RSS is disabled for private blogging e.g. they create overhead
            if (req.path.match(/\/rss(\/?|\/\d+\/?)$/)) {
                return next(new common.errors.NotFoundError({
                    message: common.i18n.t('errors.errors.pageNotFound')
                }));
            }

            next();
        });
    },

    authenticatePrivateSession: function authenticatePrivateSession(req, res, next) {
        let hash = req.session.token || '',
            salt = req.session.salt || '',
            isVerified = verifySessionHash(salt, hash),
            url;

        if (isVerified) {
            return next();
        } else {
            url = urlUtils.urlFor({relativeUrl: privateRoute});
            url += '?r=' + encodeURIComponent(req.url);
            return res.redirect(url);
        }
    },

    // This is here so a call to /private/ after a session is verified will redirect to home;
    isPrivateSessionAuth: function isPrivateSessionAuth(req, res, next) {
        if (!res.isPrivateBlog) {
            return res.redirect(urlUtils.urlFor('home', true));
        }

        let hash = req.session.token || '',
            salt = req.session.salt || '',
            isVerified = verifySessionHash(salt, hash);

        if (isVerified) {
            // redirect to home if user is already authenticated
            return res.redirect(urlUtils.urlFor('home', true));
        } else {
            return next();
        }
    },

    authenticateProtection: function authenticateProtection(req, res, next) {
        // if errors have been generated from the previous call
        if (res.error) {
            return next();
        }

        const bodyPass = req.body.password;
        const pass = settingsCache.get('password');
        const hasher = crypto.createHash('sha256');
        const salt = Date.now().toString();
        const forward = getRedirectUrl(req.query);

        if (pass === bodyPass) {
            hasher.update(bodyPass + salt, 'utf8');
            req.session.token = hasher.digest('hex');
            req.session.salt = salt;

            return res.redirect(urlUtils.urlFor({relativeUrl: forward}));
        } else {
            res.error = {
                message: common.i18n.t('errors.middleware.privateblogging.wrongPassword')
            };
            return next();
        }
    }
};

module.exports = privateBlogging;
<commit_msg>Handled bad redirect URLs for private sites<commit_after>const fs = require('fs-extra');
const url = require('url');
const session = require('cookie-session');
const crypto = require('crypto');
const path = require('path');
const config = require('../../../../server/config');
const urlUtils = require('../../../../server/lib/url-utils');
const constants = require('../../../../server/lib/constants');
const common = require('../../../../server/lib/common');
const settingsCache = require('../../../../server/services/settings/cache');
// routeKeywords.private: 'private'
const privateRoute = '/private/';

function verifySessionHash(salt, hash) {
    if (!salt || !hash) {
        return false;
    }

    let hasher = crypto.createHash('sha256');
    hasher.update(settingsCache.get('password') + salt, 'utf8');
    return hasher.digest('hex') === hash;
}

function getRedirectUrl(query) {
    try {
        const redirect = decodeURIComponent(query.r || '/');
        return url.parse(redirect).pathname;
    } catch (e) {
        return '/';
    }
}

const privateBlogging = {
    checkIsPrivate: function checkIsPrivate(req, res, next) {
        let isPrivateBlog = settingsCache.get('is_private');

        if (!isPrivateBlog) {
            res.isPrivateBlog = false;
            return next();
        }

        res.isPrivateBlog = true;

        return session({
            maxAge: constants.ONE_MONTH_MS,
            signed: false
        })(req, res, next);
    },

    filterPrivateRoutes: function filterPrivateRoutes(req, res, next) {
        if (!res.isPrivateBlog || req.url.lastIndexOf(privateRoute, 0) === 0) {
            return next();
        }

        if (req.url.lastIndexOf('/robots.txt', 0) === 0) {
            return fs.readFile(path.resolve(__dirname, '../', 'robots.txt'), function readFile(err, buf) {
                if (err) {
                    return next(err);
                }

                res.writeHead(200, {
                    'Content-Type': 'text/plain',
                    'Content-Length': buf.length,
                    'Cache-Control': 'public, max-age=' + config.get('caching:robotstxt:maxAge')
                });

                res.end(buf);
            });
        }

        // CASE: Allow private RSS feed urls.
        // Any url which contains the hash and the postfix /rss is allowed to access a private rss feed without
        // a session. As soon as a path matches, we rewrite the url. Even Express uses rewriting when using `app.use()`.
        if (req.url.indexOf(settingsCache.get('public_hash') + '/rss') !== -1) {
            req.url = req.url.replace(settingsCache.get('public_hash') + '/', '');
            return next();
        }

        // NOTE: Redirect to /private if the session does not exist.
        privateBlogging.authenticatePrivateSession(req, res, function onSessionVerified() {
            // CASE: RSS is disabled for private blogging e.g. they create overhead
            if (req.path.match(/\/rss(\/?|\/\d+\/?)$/)) {
                return next(new common.errors.NotFoundError({
                    message: common.i18n.t('errors.errors.pageNotFound')
                }));
            }

            next();
        });
    },

    authenticatePrivateSession: function authenticatePrivateSession(req, res, next) {
        let hash = req.session.token || '',
            salt = req.session.salt || '',
            isVerified = verifySessionHash(salt, hash),
            url;

        if (isVerified) {
            return next();
        } else {
            url = urlUtils.urlFor({relativeUrl: privateRoute});
            url += '?r=' + encodeURIComponent(req.url);
            return res.redirect(url);
        }
    },

    // This is here so a call to /private/ after a session is verified will redirect to home;
    isPrivateSessionAuth: function isPrivateSessionAuth(req, res, next) {
        if (!res.isPrivateBlog) {
            return res.redirect(urlUtils.urlFor('home', true));
        }

        let hash = req.session.token || '',
            salt = req.session.salt || '',
            isVerified = verifySessionHash(salt, hash);

        if (isVerified) {
            // redirect to home if user is already authenticated
            return res.redirect(urlUtils.urlFor('home', true));
        } else {
            return next();
        }
    },

    authenticateProtection: function authenticateProtection(req, res, next) {
        // if errors have been generated from the previous call
        if (res.error) {
            return next();
        }

        const bodyPass = req.body.password;
        const pass = settingsCache.get('password');
        const hasher = crypto.createHash('sha256');
        const salt = Date.now().toString();
        const forward = getRedirectUrl(req.query);

        if (pass === bodyPass) {
            hasher.update(bodyPass + salt, 'utf8');
            req.session.token = hasher.digest('hex');
            req.session.salt = salt;

            return res.redirect(urlUtils.urlFor({relativeUrl: forward}));
        } else {
            res.error = {
                message: common.i18n.t('errors.middleware.privateblogging.wrongPassword')
            };
            return next();
        }
    }
};

module.exports = privateBlogging;
<|endoftext|>


<commit_before>var listOfStudents = 'listOfStudents';

function getStudentListData()
  {
	  var edorgIndex = $("#edOrgSelect").val();
      var schoolIndex = $("#schoolSelect").val();
      var courseIndex = $("#courseSelect").val();
      var selectionIndex = $("#sectionSelect").val();

      location.href = contextRootPath + "/service/layout/listOfStudentsPage/" + instHierarchy[edorgIndex].schools[schoolIndex].courses[courseIndex].sections[selectionIndex].id;
  }

  function populateView(panelConfig)
  {
    var select = "<select id='viewSelect' onChange='clearStudentList();printStudentList()'>";
    var index=0;
    if(panelConfig.items.length == 0) {
	    select += "<option value='-1'></option>";
    }
    else {
	    for(index=0;index<panelConfig.items.length;index++) {
	        select += "<option value='"+index+"'>"+panelConfig.items[index].name+"</option>";
	    }
    }
    select += "</selection>";
    document.getElementById("viewDiv").innerHTML = select;
  }

  function printStudentList()
  {
      var tableId = getTableId();
      var panelConfig = DashboardProxy.getConfig(listOfStudents);
      var viewSelect=document.getElementById("viewSelect");
      var viewIndex=viewSelect.options[viewSelect.selectedIndex].value;
      var options={};
      if(viewIndex != -1) {
	      jQuery.extend(options, panelConfig, {items:panelConfig.items[viewIndex].items});
	      DashboardUtil.makeGrid(tableId, options, DashboardProxy.getData(listOfStudents), {});
      }
    }

    function clearStudentList()
    {
        $('#'+getTableId()).jqGrid("GridUnload");
    }

    function filterStudentList(filterBy)
    {
      var panelConfig = DashboardProxy.getConfig(listOfStudents);
      var options={};
      var viewSelect=document.getElementById("viewSelect");
      var viewIndex=viewSelect.options[viewSelect.selectedIndex].value;
      if(viewIndex != -1) {
	      jQuery.extend(options, panelConfig, {items:panelConfig.items[viewIndex].items});

	      if (filterBy == undefined) {
	        DashboardUtil.makeGrid(getTableId(), options, DashboardProxy.getData(listOfStudents), {});
	      }else {

	          var filteredData = jQuery.extend({}, DashboardProxy.getData(listOfStudents));
	          filteredStudents = filteredData.students;
	          fieldName = filterBy['condition']['field'];
	          fieldValues = filterBy['condition']['value'];
	          filteredStudents = jQuery.grep(filteredStudents, function(n, i){
	            filterValue = n[fieldName];
	            var y = jQuery.inArray(filterValue, fieldValues);
	            return y != -1;
	          });

	          filteredData.students = filteredStudents;
	          DashboardUtil.makeGrid(getTableId(), options, filteredData, {});
	      }
      }
    }
function populateInstHierarchy(){
    var y = "<select id='edOrgSelect' onChange='clearStudentList();populateSchoolMenu()'>";
    y += "<option value='-1'></option>";
    var i = 0;
    for(i = 0;i<instHierarchy.length;i++){
	y += "<option value='" +i +"'>"+ instHierarchy[i].name + "</option>";
    }
    y += "</select>";
    document.getElementById("edorgDiv").innerHTML = y;

    if(instHierarchy.length == 1) {
    	$("#edOrgSelect").val(0);
    	populateSchoolMenu();
    }
}

function populateSchoolMenu(){
    var edorgSelect = document.getElementById("edOrgSelect");
    var edorgIndex = edorgSelect.options[edorgSelect.selectedIndex].value;
    var y = '';
    document.getElementById("courseDiv").innerHTML = '';
    document.getElementById("sectionDiv").innerHTML = '';
    if( edorgIndex > -1 ) {
        var temp = instHierarchy[edorgIndex].schools;

        y = "<select id='schoolSelect' onChange='clearStudentList();populateCourseMenu()'>";
        y += "<option value='-1'></option>"   ;
        var i = 0;
        for(i = 0;i<temp.length;i++) {
        	y += "<option value='" +i +"'>"+ temp[i].nameOfInstitution + "</option>";
        }
        y += "</select>";
    }
    document.getElementById("schoolDiv").innerHTML = y;

    if (instHierarchy[edorgIndex].schools.length == 1) {
    	$("#schoolSelect").val(0);
    	populateCourseMenu();
    }
}

function populateCourseMenu(){
    var edorgSelect = document.getElementById("edOrgSelect");
    var edorgIndex = edorgSelect.options[edorgSelect.selectedIndex].value;
    var schoolSelect = document.getElementById("schoolSelect");
    var schoolIndex = schoolSelect.options[schoolSelect.selectedIndex].value;
    var y = '';

    document.getElementById("sectionDiv").innerHTML = '';
    if( schoolIndex > -1) {
        var temp = instHierarchy[edorgIndex].schools[schoolIndex].courses;

        y = "<select id='courseSelect' onChange='clearStudentList();populateSectionMenu()'>";
        y += "<option value='-1'></option>";
        var j = 0;
        if(temp === undefined || temp === null) {
            y = "<select id='courseSelect'>";
            y += "<option value='0'>" + "There are no courses available for you.  Please contact your IT administrator." + "</option>";
        } else {
            for(j = 0;j < temp.length;j++){
        	y += "<option value='" +j +"'>"+ temp[j].courseTitle + "</option>";
            }
        }
    }
    document.getElementById("courseDiv").innerHTML = y;

    if (instHierarchy[edorgIndex].schools[schoolIndex].courses.length == 1) {
    	$("#courseSelect").val(0);
    	populateSectionMenu();
    }
}

function populateSectionMenu(){
    var edorgSelect = document.getElementById("edOrgSelect");
    var schoolSelect = document.getElementById("schoolSelect");
    var courseSelect = document.getElementById("courseSelect");
    var edorgIndex = edorgSelect.options[edorgSelect.selectedIndex].value;
    var schoolIndex = schoolSelect.options[schoolSelect.selectedIndex].value;
    var courseIndex = courseSelect.options[courseSelect.selectedIndex].value;
    var y = '';

    if( courseIndex > -1) {
        var temp = instHierarchy[edorgIndex].schools[schoolIndex].courses[courseIndex].sections;

        y = "<select id='sectionSelect' onChange='clearStudentList();getStudentListData()'>";
        y += "<option value='-1'></option>";
        var i = 0;
        for(;i < temp.length;i++){
        	y += "<option value='" +i +"'>"+ temp[i].sectionName + "</option>";
        }
        y += "</select>";
    }
    document.getElementById("sectionDiv").innerHTML = y;

    /* Commenting out as there is no go button hence, no auto selection for section
    if (instHierarchy[edorgIndex].schools[schoolIndex].courses[courseIndex].sections.length == 1) {
    	$("#sectionSelect").val(0);
    	getStudentListData();
    }*/
}

function populateFilter() {

    var select = "<select id='filterSelect' onChange='clearStudentList();filterStudents()'>";
    var index=0;
    select += "<option value='-1'>No Filter</option>";
    var lozengeConfig = DashboardProxy.widgetConfig.lozenge;
    for(index=0;index<lozengeConfig.items.length; index++) {
        select += "<option value='"+index+"'>"+lozengeConfig.items[index].description+"</option>";
    }
    select += "</select>";
    document.getElementById("filterDiv").innerHTML = select;

}

function filterStudents() {
    var filterSelect = document.getElementById("filterSelect");
    filterStudentList(DashboardProxy.widgetConfig.lozenge.items[filterSelect.selectedIndex-1]);
}
<commit_msg>Why won't my commits show up<commit_after>var listOfStudents = 'listOfStudents';

function getStudentListData()
  {
	  var edorgIndex = $("#edOrgSelect").val();
      var schoolIndex = $("#schoolSelect").val();
      var courseIndex = $("#courseSelect").val();
      var selectionIndex = $("#sectionSelect").val();

      location.href = contextRootPath + "/service/layout/listOfStudentsPage/" + instHierarchy[edorgIndex].schools[schoolIndex].courses[courseIndex].sections[selectionIndex].id;
  }

  function populateView(panelConfig)
  {
    var select = "<select id='viewSelect' onChange='clearStudentList();printStudentList()'>";
    var index=0;
    if(panelConfig.items.length == 0) {
	    select += "<option value='-1'></option>";
    }
    else {
	    for(index=0;index<panelConfig.items.length;index++) {
	        select += "<option value='"+index+"'>"+panelConfig.items[index].name+"</option>";
	    }
    }
    select += "</selection>";
    document.getElementById("viewDiv").innerHTML = select;
  }

  function printStudentList()
  {
      var tableId = getTableId();
      var panelConfig = DashboardProxy.getConfig(listOfStudents);
      var viewSelect=document.getElementById("viewSelect");
      var viewIndex=viewSelect.options[viewSelect.selectedIndex].value;
      var options={};
      if(viewIndex != -1) {
	      jQuery.extend(options, panelConfig, {items:panelConfig.items[viewIndex].items});
	      DashboardUtil.makeGrid(tableId, options, DashboardProxy.getData(listOfStudents), {});
      }
    }

    function clearStudentList()
    {
        $('#'+getTableId()).jqGrid("GridUnload");
    }

    function filterStudentList(filterBy)
    {
      var panelConfig = DashboardProxy.getConfig(listOfStudents);
      var options={};
      var viewSelect=document.getElementById("viewSelect");
      var viewIndex=viewSelect.options[viewSelect.selectedIndex].value;
      if(viewIndex != -1) {
	      jQuery.extend(options, panelConfig, {items:panelConfig.items[viewIndex].items});

	      if (filterBy == undefined) {
	        DashboardUtil.makeGrid(getTableId(), options, DashboardProxy.getData(listOfStudents), {});
	      }else {

	          var filteredData = jQuery.extend({}, DashboardProxy.getData(listOfStudents));
	          filteredStudents = filteredData.students;
	          fieldName = filterBy['condition']['field'];
	          fieldValues = filterBy['condition']['value'];
	          filteredStudents = jQuery.grep(filteredStudents, function(n, i){
	            filterValue = n[fieldName];
	            var y = jQuery.inArray(filterValue, fieldValues);
	            return y != -1;
	          });

	          filteredData.students = filteredStudents;
	          DashboardUtil.makeGrid(getTableId(), options, filteredData, {});
	      }
      }
    }
function populateInstHierarchy(){
    var y = "<select id='edOrgSelect' onChange='clearStudentList();populateSchoolMenu()'>";
    y += "<option value='-1'></option>";
    var i = 0;
    for(i = 0;i<instHierarchy.length;i++){
	y += "<option value='" +i +"'>"+ instHierarchy[i].name + "</option>";
    }
    y += "</select>";
    document.getElementById("edorgDiv").innerHTML = y;

    if(instHierarchy.length == 1) {
    	$("#edOrgSelect").val(0);
    	populateSchoolMenu();
    }
}

function populateSchoolMenu(){
    var edorgSelect = document.getElementById("edOrgSelect");
    var edorgIndex = edorgSelect.options[edorgSelect.selectedIndex].value;
    var y = '';
    document.getElementById("courseDiv").innerHTML = '';
    document.getElementById("sectionDiv").innerHTML = '';
    if( edorgIndex > -1 ) {
        var temp = instHierarchy[edorgIndex].schools;

        y = "<select id='schoolSelect' onChange='clearStudentList();populateCourseMenu()'>";
        y += "<option value='-1'></option>"   ;
        var i = 0;
        for(i = 0;i<temp.length;i++) {
        	y += "<option value='" +i +"'>"+ temp[i].nameOfInstitution + "</option>";
        }
        y += "</select>";
    }
    document.getElementById("schoolDiv").innerHTML = y;

    if (instHierarchy[edorgIndex].schools.length == 1) {
    	$("#schoolSelect").val(0);
    	populateCourseMenu();
    }
}

function populateCourseMenu(){
    var edorgSelect = document.getElementById("edOrgSelect");
    var edorgIndex = edorgSelect.options[edorgSelect.selectedIndex].value;
    var schoolSelect = document.getElementById("schoolSelect");
    var schoolIndex = schoolSelect.options[schoolSelect.selectedIndex].value;
    var y = '';

    document.getElementById("sectionDiv").innerHTML = '';
    if( schoolIndex > -1) {
        var temp = instHierarchy[edorgIndex].schools[schoolIndex].courses;

        y = "<select id='courseSelect' onChange='clearStudentList();populateSectionMenu()'>";
        y += "<option value='-1'></option>";
        var j = 0;

        if(temp === undefined || temp === null) {
            y = "<select id='courseSelect'>";
            y += "<option value='0'>" + "There are no courses available for you.  Please contact your IT administrator." + "</option>";
        } else {
            for(j = 0;j < temp.length;j++){
        	y += "<option value='" +j +"'>"+ temp[j].courseTitle + "</option>";
            }
        }
    }
    document.getElementById("courseDiv").innerHTML = y;

    if (instHierarchy[edorgIndex].schools[schoolIndex].courses.length == 1) {
    	$("#courseSelect").val(0);
    	populateSectionMenu();
    }
}

function populateSectionMenu(){
    var edorgSelect = document.getElementById("edOrgSelect");
    var schoolSelect = document.getElementById("schoolSelect");
    var courseSelect = document.getElementById("courseSelect");
    var edorgIndex = edorgSelect.options[edorgSelect.selectedIndex].value;
    var schoolIndex = schoolSelect.options[schoolSelect.selectedIndex].value;
    var courseIndex = courseSelect.options[courseSelect.selectedIndex].value;
    var y = '';

    if( courseIndex > -1) {
        var temp = instHierarchy[edorgIndex].schools[schoolIndex].courses[courseIndex].sections;

        y = "<select id='sectionSelect' onChange='clearStudentList();getStudentListData()'>";
        y += "<option value='-1'></option>";
        var i = 0;
        for(;i < temp.length;i++){
        	y += "<option value='" +i +"'>"+ temp[i].sectionName + "</option>";
        }
        y += "</select>";
    }
    document.getElementById("sectionDiv").innerHTML = y;

    /* Commenting out as there is no go button hence, no auto selection for section
    if (instHierarchy[edorgIndex].schools[schoolIndex].courses[courseIndex].sections.length == 1) {
    	$("#sectionSelect").val(0);
    	getStudentListData();
    }*/
}

function populateFilter() {

    var select = "<select id='filterSelect' onChange='clearStudentList();filterStudents()'>";
    var index=0;
    select += "<option value='-1'>No Filter</option>";
    var lozengeConfig = DashboardProxy.widgetConfig.lozenge;
    for(index=0;index<lozengeConfig.items.length; index++) {
        select += "<option value='"+index+"'>"+lozengeConfig.items[index].description+"</option>";
    }
    select += "</select>";
    document.getElementById("filterDiv").innerHTML = select;

}

function filterStudents() {
    var filterSelect = document.getElementById("filterSelect");
    filterStudentList(DashboardProxy.widgetConfig.lozenge.items[filterSelect.selectedIndex-1]);
}
<|endoftext|>


<commit_before>export { Embedding_FiltersArray_One as FiltersArray_One };

import * as Pool from "../../util/Pool.js";
import * as Recyclable from "../../util/Recyclable.js";
//import * as ActivationEscaping from "../ActivationEscaping.js";
//import * as BoundsArraySet from "../BoundsArraySet.js";
import { FiltersArray_Base } from "./Embedding_FiltersArray_One.js";

/**
 * A large table which is composed of all vocabulary table of every input channel. It is
 * mainly used by Embedding.AddGatherReshape.
 *
 *
 *
 * @member {Racyclable.Array} filtersArray
 *   The embedding vocabulary look-up table. It is composed by merging all input channels'
 * vocabulary.
 *
 * @see Embedding.FiltersArray_Base
 *
 */
class Embedding_FiltersArray_One extends FiltersArray_Base {

  /**
   * Used as default Embedding.FiltersArray_One provider for conforming to Recyclable interface.
   */
  static Pool = new Pool.Root( "Embedding.FiltersArray_One.Pool",
    Embedding_FiltersArray_One, Embedding_FiltersArray_One.setAsConstructor );

  /**
   *
   */
   constructor(
    input_height, input_width, input_channelCount,
    channelMultiplier, vocabularyCountPerInputChannel, bEmbedVocabularyId
  ) {
    super(
      input_height, input_width, input_channelCount,
      channelMultiplier, vocabularyCountPerInputChannel, bEmbedVocabularyId
    );
    Embedding_FiltersArray_Base.setAsConstructor_self.call( this );
  }

  /** @override */
  static setAsConstructor(
    input_channelCount,
    channelMultiplier, vocabularyCountPerInputChannel, bEmbedVocabularyId
  ) {
    super.setAsConstructor(
      input_height, input_width, input_channelCount,
      channelMultiplier, vocabularyCountPerInputChannel, bEmbedVocabularyId
    );
    Embedding_FiltersArray_Base.setAsConstructor_self.call( this );
    return this;
  }

  /** @override */
  static setAsConstructor_self() {
  }

  /** @override */
  disposeResources() {
    if ( this.filtersArray ) {
      this.filtersArray.disposeResources_and_recycleToPool();
      this.filtersArray = null;
    }

    super.disposeResources();
  }

  /**
   * Generator for initializing this object.
   *
   * @param {ActivationEscaping.ScaleBoundsArray} inputScaleBoundsArray
   *   The element value bounds (per channel) of input. Usually, it is The .output of the previous convolution-bias-activation value bounds
   * set of this pointwise convolution. It will be kept (not cloned) directly. So caller should not modify them.
   *
   * @return {boolean}
   *   Return true, if successfully. Return false, if failed.
   *
   */
  init( inputWeightArray, weightElementOffsetBegin, inputScaleBoundsArray ) {

    // 1. Calcualte weights extracting beginning and ending position.
    if ( !super.init( inputWeightArray, weightElementOffsetBegin, this.tensorWeightCountExtracted ) ) {
      return false;  // e.g. input array does not have enough data.
    }

//!!! ...unfinished... (2022/07/27) BoundsArray ?

    // 2. filtersArray
    let outChannelSubBegin;
    if ( this.bEmbedVocabularyId )
      outChannelSubBegin = 1;
    else
      outChannelSubBegin = 0;

    this.filtersArray = Recyclable.Array.Pool.get_or_create_by( this.tensorWeightCountTotal );

    let sourceIndex = weightElementOffsetBegin;
    let filterIndex = 0;

    let outChannel = 0;
    for ( let inChannel = 0; inChannel < this.input_channelCount; ++inChannel ) {
      for ( let vocabularyId = 0; vocabularyId < this.vocabularyCountPerInputChannel; ++vocabularyId ) {

        if ( this.bEmbedVocabularyId ) {
          this.filtersArray[ filterIndex ] = vocabularyId; // Embed the vocabulary's id.
          ++filterIndex;

//!!! ...unfinished... (2022/07/27) BoundsArray ?

          ++outChannel;
        }

        for ( let outChannelSub = outChannelSubBegin; outChannelSub < this.channelMultiplier; ++outChannelSub ) {
          this.filtersArray[ filterIndex ] = inputWeightArray[ sourceIndex ];
          ++filterIndex;
          ++sourceIndex;

          ++outChannel;

//!!! ...unfinished... (2022/07/27) BoundsArray ?

        }
      }
    }

    return true;
  }

}
<commit_msg>clamp_one_byLowerUpper<commit_after>export { Embedding_FiltersArray_One as FiltersArray_One };

import * as Pool from "../../util/Pool.js";
import * as Recyclable from "../../util/Recyclable.js";
//import * as ActivationEscaping from "../ActivationEscaping.js";
//import * as BoundsArraySet from "../BoundsArraySet.js";
import { FiltersArray_Base } from "./Embedding_FiltersArray_One.js";

/**
 * A large table which is composed of all vocabulary table of every input channel. It is
 * mainly used by Embedding.AddGatherReshape.
 *
 *
 *
 * @member {Racyclable.Array} filtersArray
 *   The embedding vocabulary look-up table. It is composed by merging all input channels'
 * vocabulary.
 *
 * @see Embedding.FiltersArray_Base
 *
 */
class Embedding_FiltersArray_One extends FiltersArray_Base {

  /**
   * Used as default Embedding.FiltersArray_One provider for conforming to Recyclable interface.
   */
  static Pool = new Pool.Root( "Embedding.FiltersArray_One.Pool",
    Embedding_FiltersArray_One, Embedding_FiltersArray_One.setAsConstructor );

  /**
   *
   */
   constructor(
    input_height, input_width, input_channelCount,
    channelMultiplier, vocabularyCountPerInputChannel, bEmbedVocabularyId
  ) {
    super(
      input_height, input_width, input_channelCount,
      channelMultiplier, vocabularyCountPerInputChannel, bEmbedVocabularyId
    );
    Embedding_FiltersArray_Base.setAsConstructor_self.call( this );
  }

  /** @override */
  static setAsConstructor(
    input_channelCount,
    channelMultiplier, vocabularyCountPerInputChannel, bEmbedVocabularyId
  ) {
    super.setAsConstructor(
      input_height, input_width, input_channelCount,
      channelMultiplier, vocabularyCountPerInputChannel, bEmbedVocabularyId
    );
    Embedding_FiltersArray_Base.setAsConstructor_self.call( this );
    return this;
  }

  /** @override */
  static setAsConstructor_self() {
  }

  /** @override */
  disposeResources() {
    if ( this.filtersArray ) {
      this.filtersArray.disposeResources_and_recycleToPool();
      this.filtersArray = null;
    }

    super.disposeResources();
  }

  /**
   * Generator for initializing this object.
   *
   * @param {ActivationEscaping.ScaleBoundsArray} inputScaleBoundsArray
   *   The element value bounds (per channel) of input. Usually, it is The .output of the previous convolution-bias-activation value bounds
   * set of this pointwise convolution. It will be kept (not cloned) directly. So caller should not modify them.
   *
   * @return {boolean}
   *   Return true, if successfully. Return false, if failed.
   *
   */
  init( inputWeightArray, weightElementOffsetBegin, inputScaleBoundsArray ) {

    // 1. Calcualte weights extracting beginning and ending position.
    if ( !super.init( inputWeightArray, weightElementOffsetBegin, this.tensorWeightCountExtracted ) ) {
      return false;  // e.g. input array does not have enough data.
    }

//!!! ...unfinished... (2022/07/27) BoundsArray ?

    // 2. filtersArray
    let outChannelSubBegin;
    if ( this.bEmbedVocabularyId )
      outChannelSubBegin = 1;
    else
      outChannelSubBegin = 0;

    this.filtersArray = Recyclable.Array.Pool.get_or_create_by( this.tensorWeightCountTotal );
    this.boundsArraySet.output0.set_all_byLowerUpper( +Infinity, -Infinity );

    let sourceIndex = weightElementOffsetBegin;
    let filterIndex = 0;

    let outChannel = 0;
    let outBoundsArray = this.boundsArraySet.output0.boundsArray;
    for ( let inChannel = 0; inChannel < this.input_channelCount; ++inChannel ) {
      for ( let vocabularyId = 0; vocabularyId < this.vocabularyCountPerInputChannel; ++vocabularyId ) {

        if ( this.bEmbedVocabularyId ) {
          this.filtersArray[ filterIndex ] = vocabularyId; // Embed the vocabulary's id.
          ++filterIndex;

//!!! ...unfinished... (2022/07/27) BoundsArray ?
          outBoundsArray.clamp_one_byLowerUpper( outChannel, ???aLower, ???aUpper );

          ++outChannel;
        }

        for ( let outChannelSub = outChannelSubBegin; outChannelSub < this.channelMultiplier; ++outChannelSub ) {
          this.filtersArray[ filterIndex ] = inputWeightArray[ sourceIndex ];
          ++filterIndex;
          ++sourceIndex;

//!!! ...unfinished... (2022/07/27) BoundsArray ?
          outBoundsArray.clamp_one_byLowerUpper( outChannel, ???aLower, ???aUpper );

          ++outChannel;
        }
      }
    }

    return true;
  }

}
<|endoftext|>


<commit_before>module.exports = require('appjs-' + process.platform);

<commit_msg>Fix node and gyp disagreeing on Windows OS name 'win32' and 'win'<commit_after>var platforms = {
	win32: 'win',
	mac: 'mac',
	linux: 'linux'
};

module.exports = require('appjs-' + platforms[process.platform]);
<|endoftext|>


<commit_before>// jquery tablebars plugin
// version 0.3
// usage: $('table').tablebars()
// to turn on bars for a column, add the 'data-tablebars=1' class to the corresponding
// header. By default, the bars have no style. An example css declartion is:
//
//      .ui-tablebar { color: #333; background: #DACD99; }
//
// limitations: table must have a thead, data must be simple
jQuery.fn.tablebars = function(){
  this.each(function(i, table){
    var $table = $(table);

    // decide which columns get tablebars
    function pickColumns($table){
      var columns = [];
      $table.find('thead > tr:eq(0)').children().each(function(i, cell){
        if ($(cell).attr('data-tablebars')) columns.push(i);
      });
      return columns;
    }

    function processColumn(set){
      var data = [],
          rawdata = [],
          max = 0,
          width = set.eq(0).width();
      set.each(function(i, cell){
        var rawvalue = rawdata[i] = $(cell).html();
        var value = data[i] = Math.max(0, parseFloat(rawvalue.replace(/[^0-9.\-]+/g, '')));
        if (rawvalue[rawvalue.length - 1] == "%") {
          // TODO this percent logic is O(N) when it only needs to be O(1)
          max = 100;
          return;
        }
        if (!isNaN(value) && value > max){
          max = value;
        }
      });
      if (!max) max = 1;
      set.each(function(i, cell){
        var $cell = $(cell),
            $bar = $cell.find('span.ui-tablebar');
        if (!$bar.length) {
          $bar = $('');
          $cell.css('position', 'relative').prepend($bar);
        }
        $bar.width(width * data[i] / max).html(rawdata[i]);
      });
    }

    function collectCells(columns){
      columns.forEach(function(index){
        var set = $table.find('tbody > tr > td:nth-child(' + (index + 1) + ')');
        processColumn(set);
      });
    }

    collectCells(pickColumns($table));
  });
  return this;
};
<commit_msg>upgrade tablebars<commit_after>// jquery tablebars plugin
// version 0.3
// usage: $('table').tablebars()
// to turn on bars for a column, add the 'data-tablebars=1' class to the corresponding
// header. By default, the bars have no style. An example css declartion is:
//
//      .ui-tablebar { color: #333; background: #DACD99; }
//
// limitations: table must have a thead, data must be simple
jQuery.fn.tablebars = function(){
  this.each(function(i, table){
    var $table = $(table);

    // decide which columns get tablebars
    function pickColumns($table){
      var columns = [];
      $table.find('thead > tr:eq(0)').children().each(function(i, cell){
        if ($(cell).attr('data-tablebars')) columns.push(i);
      });
      return columns;
    }

    function processColumn(set){
      var data = [],
          rawdata = [],
          max = 0,
          width = set.eq(0).width();

      // wrap cells in set with a container div
      if (set.children('div.ui-tablebar-outer').length === 0) {
        set.wrapInner('
');
      }
      set = set.children();

      set.each(function(i, cell){
        var rawvalue = rawdata[i] = $(cell).html();
        var value = data[i] = Math.max(0, parseFloat(rawvalue.replace(/[^0-9.\-]+/g, '')));
        if (rawvalue[rawvalue.length - 1] == "%") {
          // TODO this percent logic is O(N) when it only needs to be O(1)
          max = 100;
          return;
        }
        if (!isNaN(value) && value > max){
          max = value;
        }
      });
      if (!max) max = 1;
      set.each(function(i, cell){
        var $cell = $(cell),
            $bar = $cell.find('span.ui-tablebar');
        if (!$bar.length) {
          $bar = $('');
          $cell.prepend($bar);
        }
        $bar.width(width * data[i] / max).html(rawdata[i]);
      });
    }

    function collectCells(columns){
      columns.forEach(function(index){
        var set = $table.find('tbody > tr > td:nth-child(' + (index + 1) + ')');
        processColumn(set);
      });
    }

    collectCells(pickColumns($table));
  });
  return this;
};
<|endoftext|>


<commit_before>(function ($) {

    /**
     * This object provides helper functions for parsing a pasted smart snippet's code and auto populating the variable
     * fields needed by that smart snippet.
     * @type {Object}
     */
    var LayoutParser = {

        /**
         * Clear all added variables from a container
         * @param jQuery container
         */
        emptyContainer:function (container) {
            container.children('.inline-related ').each(function (i, item) {
                if (!$(item).hasClass('empty-form'))
                    $(item).remove();
            });
        },

        /**
         * Gets the standard variables container or the drop down one
         * @param String variablesHolderType
         * @return {*\jQuery}
         */
        getContainer:function (variablesHolderType) {
            var cx = null;
            $('.inline-group').each(function (i, item) {
                if (variablesHolderType == 'standard') {

                    var header = $(item).children('h2').get(0);
                    if ($(header).text().toLowerCase() == 'standard variables') {
                        cx = $(item);
                        return;
                    }

                } else if (variablesHolderType == 'select') {

                    var header = $(item).children('h2').get(0);

                    if ($(header).text().toLowerCase() == 'drop down variables') {
                        cx = $(item);
                        return;
                    }
                }
            });

            return cx;
        },

        getExistingStandardVariables:function (container) {
            var fieldRows = container.children('.dynamic-variables');
            var existingVars = new Array();

            fieldRows.each(function (i, row) {
                var textField = $(row).find('.vTextField');
                var typeField = $(row).find('select');
                var name = textField.val();
                var type = typeField.val();

                var typeDocId = typeField.attr('id');
                var obj = {name:name, type:type, typeDocId:typeDocId};
                existingVars.push(obj);
            });

            return existingVars;
        },

        getExistingSelectVariables:function (container) {
            var fieldRows = container.children('.dynamic-variables-2');
            var existingVars = new Array();

            fieldRows.each(function (i, row) {
                var name = $(row).find('.field-name').find('.vTextField').val();
                var nameDocId = $(row).find('.field-name').find('.vTextField').attr('id');

                var values = $(row).find('.field-choices').find('.vTextField').val();
                var valuesDocId = $(row).find('.field-choices').find('.vTextField').attr('id');

                var obj = {name:name, values:values, valuesDocId:valuesDocId};

                existingVars.push(obj);
            });

            return existingVars;
        },

        groupExistingVars:function (existingVars, newVars, variablesType) {
            var similarVars = [];
            var updateVars = [];
            var toBeDeletedVars = [];

            var similarFieldToCheck = (variablesType && variablesType.toLowerCase() == 'select' ? 'values' : 'type');

            for (var i = 0; i < existingVars.length; i++) {
                var toBeUpdated = false;
                var updatedFieldValue = undefined;
                var isSimilar = false;
                for (var j = 0; j < newVars.length; j++) {
                    if (existingVars[i].name == newVars[j].varname && existingVars[i][similarFieldToCheck] == newVars[j][similarFieldToCheck]) {
                        isSimilar = true;
                        break;
                    } else if (existingVars[i].name == newVars[j].varname && existingVars[i][similarFieldToCheck] != newVars[j][similarFieldToCheck]) {
                        toBeUpdated = true;
                        updatedFieldValue = newVars[j][similarFieldToCheck];
                        break;
                    }
                }

                if (toBeUpdated) {
                    existingVars[i].updateWithValue = updatedFieldValue;
                    updateVars.push(existingVars[i]);
                } else if (isSimilar) {
                    similarVars.push(existingVars[i]);
                } else if (!toBeUpdated && !isSimilar) {
                    toBeDeletedVars.push(existingVars[i]);
                }
            }

            return {
                similarVars:similarVars,
                toUpdateVars:updateVars,
                deleteVars:toBeDeletedVars
            };
        },

        findByVarName:function (arr, vName) {
            var found = false;
            $.each(arr, function (i, item) {
                if (item.name == vName) {
                    found = item;
                    return;
                }
            });

            return found;
        },

        markForDeletion:function (container, deletedVars) {
            var rows = container.children('.inline-related');

            var self = this;
            $.each(rows, function (i, row) {
                var varName = $(row).find('.field-name').find('.vTextField').val();
                var isFoundVar = self.findByVarName(deletedVars, varName);

                if (isFoundVar) {
                    var deleteCheckbox = $(row).find('.delete').find('input[type=checkbox]');
                    deleteCheckbox.attr('checked', 'checked');
                }
            });
        },

        updateVars:function (container, updatedVars, varsType) {
            var rows = container.children('.inline-related');

            var objFieldToUpdate = (varsType.toLowerCase() == 'select' ? 'valuesDocId' : 'typeDocId');

            var self = this;
            $.each(rows, function (i, row) {
                var varName = $(row).find('.field-name').find('.vTextField').val();
                var isFoundVar = self.findByVarName(updatedVars, varName);

                if (isFoundVar) {
                    $('#'+ isFoundVar[objFieldToUpdate]).val(isFoundVar.updateWithValue)
                }
            });
        },

        /**
         * Find the "Add another Standard Variable" button and trigger a click event on it. Returns the div container
         * holding form fields
         * @param container
         * @return {*|jQuery}
         */
        clickAddNewFieldStd:function (container) {

            //count the number of already inserted vars here
            //subtract 1 for the empty one present by default
            var presentFieldsCount = container.children('.inline-related').length - 1;

            var addNewFieldBtn = $(container).children('div.add-row').find('a');
            addNewFieldBtn.trigger('click');

            var addedField = $(container).children('.inline-related').last().prev();

            addedField.attr('id', 'variables-' + presentFieldsCount);

            var textField = addedField.find('input.vTextField');
            $(textField).attr('id', 'id_variables-' + presentFieldsCount + '-name');
            $(textField).attr('name', 'variables-' + presentFieldsCount + '-name');

            var textLabel = addedField.find('div.field-name').find('label');
            $(textLabel).attr('for', 'id_variables-' + presentFieldsCount + '-name');

            var select = addedField.find('div.field-widget').find('select');
            $(select).attr('id', 'id_variables-' + presentFieldsCount + '-widget');
            $(select).attr('name', 'variables-' + presentFieldsCount + '-widget');

            var selectLabel = addedField.find('div.field-widget').find('label');
            $(selectLabel).attr('for', 'id_variables-' + presentFieldsCount + '-widget')

            return addedField;
        },

        /**
         * Find the "Add another Drop Down Variable" button and trigger a click event on it. Returns the div container
         * holding form fields. There is really no difference at the moment between this and the clickAddNewFieldStd.
         * The only reason for them to be separate is for expressiveness and future extensions.
         * @param container
         * @return {*|jQuery}
         */
        clickAddNewFieldSelect:function (container) {
            var addNewFieldBtn = $(container).children('div.add-row').find('a');
            addNewFieldBtn.trigger('click');

            var addedField = $(container).children('.inline-related').last().prev();
            var inputFields = addedField.children('.vTextField');

            var presentFieldsCount = container.children('.inline-related').length;

            $(inputFields[0]).attr('id', 'id_variables-2-' + presentFieldsCount + '-name');
            $(inputFields[0]).attr('name', 'variables-2-' + presentFieldsCount + '-name');

            $(inputFields[1]).attr('id', 'id_variables-2-' + presentFieldsCount + '-choices');
            $(inputFields[1]).attr('name', 'variables-2-' + presentFieldsCount + '-choices');

            return addedField;
        },

        /**
         * Add a new standard variable in the container
         * varNameObj = {varname: 'name', type: 'type'}
         * @param varNameObj
         * @param container
         */
        addStdVar:function (varNameObj, container) {
            var fieldCx = this.clickAddNewFieldStd(container);
            $(fieldCx).find('input.vTextField').val(varNameObj.varname);
            $(fieldCx).find('select').val(varNameObj.type);
        },

        /**
         * Add a new drop down variable in the container
         * varNameObj = {varname: 'name', type: 'type', values: 'value1,value2,value3'}
         * @param varNameObj
         * @param container
         */

        addSelectVar:function (varNameObj, container) {
            var fieldCx = this.clickAddNewFieldSelect(container);
            $(fieldCx).find('div.field-name').find('input.vTextField').val(varNameObj.varname);
            $(fieldCx).find('div.field-choices').find('input.vTextField').val(varNameObj.values);
        },

        /**
         * The following code will try to match everything that's within an html comment tag. It should look like this
         *
         * <!-- SmartSnippets Variables
         * varname=type
         * -->
         *
         * Where type could be anything from TextField, TextAreaField, MerlinField or ImageField
         * Each variable is declared on a new line.
         */
        extractVarnames:function (text) {
            var regex = /<!-- SmartSnippets Variables([^>]*)-->/gi;
            var variablesSnippet = regex.exec(text);
            var varNames = []; //hold the var names here

            if (variablesSnippet) {
                var lines = variablesSnippet[1].split('\n'); //split the input in multiple lines

                $.each(lines, function (index, line) {
                    if ($.trim(line).length > 0) {
                        var vObj = {};
                        var vDeclarationArr = line.split('=');
                        vObj.varname = $.trim(vDeclarationArr[0]);

                        var type = $.trim(vDeclarationArr[1]);
                        if (type.toLowerCase().indexOf('select') != -1) {
                            var tmp = type.split('|');
                            vObj.type = $.trim(tmp[0]);
                            vObj.values = vDeclarationArr[2] ? $.trim(vDeclarationArr[2]) : '';
                        } else {
                            vObj.type = $.trim(vDeclarationArr[1]);
                        }

                        varNames.push(vObj);
                    }
                });
            }
            return varNames;
        },

        groupNewVars:function (varsArr) {
            var returnObj = {};
            returnObj.standard = new Array();
            returnObj.select = new Array();

            $.each(varsArr, function (i, variable) {
                if (variable.type.toLowerCase() == 'select') {
                    returnObj.select.push(variable);
                } else {
                    returnObj.standard.push(variable);
                }
            });

            return returnObj;
        },

        getOnlyToAddVars: function(groupedVars, newVars) {
            var onlyToAdd = new Array();
            for (var i = 0; i < newVars.length; i++) {
                var notInUpdates = true;
                var notInSimilar = true;

                for(var j = 0; j < groupedVars.similarVars.length; j++) {
                    if(newVars[i].varname == groupedVars.similarVars[j].name) {
                        notInSimilar = false;
                    }
                }

                for(var k = 0; k < groupedVars.toUpdateVars.length; k++) {
                    if(newVars[i].varname == groupedVars.toUpdateVars[k].name) {
                        notInUpdates = false;
                    }
                }

                if(notInSimilar && notInUpdates) {
                    onlyToAdd.push(newVars[i]);
                }
            }

            return onlyToAdd;
        },
        /**
         * Given an array of objects with the following structure {varname: 'name', type: 'type', values: 'value1,
         * value2,value3'} or varNameObj = {varname: 'name', type: 'type'} this function fill parse the array.
         *
         * @param varNamesArr
         */
        populate:function (varNamesArr) {
            var self = this;
            if (varNamesArr.length > 0) { //don't do any mumbo jumbo if we have no varnames

                var groupedNewVars = self.groupNewVars(varNamesArr);

                var stdContainer = self.getContainer('standard');
                var selectContainer = self.getContainer('select');

                var existingStdVars = self.getExistingStandardVariables(stdContainer);
                var existingSelectVars = self.getExistingSelectVariables(selectContainer);

                var groupedExistingStdVars = self.groupExistingVars(existingStdVars, groupedNewVars.standard, 'standard');

                if (existingStdVars.length > 0) {
                    self.markForDeletion(stdContainer, groupedExistingStdVars.deleteVars);
                    self.updateVars(stdContainer, groupedExistingStdVars.toUpdateVars, 'standard');
                }

                var groupedExistingSelectVars = self.groupExistingVars(existingSelectVars, groupedNewVars.select, 'select');
                if(existingSelectVars.length > 0) {

                    self.markForDeletion(selectContainer, groupedExistingSelectVars.deleteVars);
                    self.updateVars(selectContainer, groupedExistingSelectVars.toUpdateVars, 'select');
                }

                var onlyToAddStdVars = self.getOnlyToAddVars(groupedExistingStdVars, groupedNewVars.standard);
                var onlyToAddSelectVars = self.getOnlyToAddVars(groupedExistingSelectVars, groupedNewVars.select);

                $.each(onlyToAddStdVars, function(i, vObj) {
                    self.addStdVar(vObj, stdContainer);
                });

                $.each(onlyToAddSelectVars, function(i, vObj) {
                    self.addSelectVar(vObj, selectContainer);
                });
            }
        }
    };

    $(document).ready(function () {
        var textArea = $('#id_template_code');

        textArea.bind('paste', function (e) {
            var el = $(this);

            if ($.trim($(el).val()).length == 0) {//only when the area is empty
                //use a setTimeout to capture pasted text
                setTimeout(function () {
                    var text = $(el).val();
                    var varNames = LayoutParser.extractVarnames(text);
                    LayoutParser.populate(varNames);
                }, 100);
            }
        });
    });

})(django.jQuery);
<commit_msg>Fix for some edge cases when user pastes multiple times<commit_after>(function ($) {

    /**
     * This object provides helper functions for parsing a pasted smart snippet's code and auto populating the variable
     * fields needed by that smart snippet.
     * @type {Object}
     */
    var LayoutParser = {

        /**
         * Clear all added variables from a container
         * @param jQuery container
         */
        emptyContainer:function (container) {
            container.children('.inline-related ').each(function (i, item) {
                if (!$(item).hasClass('empty-form'))
                    $(item).remove();
            });
        },

        /**
         * Gets the standard variables container or the drop down one
         * @param String variablesHolderType
         * @return {*\jQuery}
         */
        getContainer:function (variablesHolderType) {
            var cx = null;
            $('.inline-group').each(function (i, item) {
                if (variablesHolderType == 'standard') {

                    var header = $(item).children('h2').get(0);
                    if ($(header).text().toLowerCase() == 'standard variables') {
                        cx = $(item);
                        return;
                    }

                } else if (variablesHolderType == 'select') {

                    var header = $(item).children('h2').get(0);

                    if ($(header).text().toLowerCase() == 'drop down variables') {
                        cx = $(item);
                        return;
                    }
                }
            });

            return cx;
        },

        getExistingStandardVariables:function (container) {
            var fieldRows = container.children('.dynamic-variables');
            var existingVars = new Array();

            fieldRows.each(function (i, row) {
                var textField = $(row).find('.vTextField');
                var typeField = $(row).find('select');
                var name = textField.val();
                var type = typeField.val();

                var typeDocId = typeField.attr('id');
                var obj = {name:name, type:type, typeDocId:typeDocId};
                existingVars.push(obj);
            });

            return existingVars;
        },

        getExistingSelectVariables:function (container) {
            var fieldRows = container.children('.dynamic-variables-2');
            var existingVars = new Array();

            fieldRows.each(function (i, row) {
                var name = $(row).find('.field-name').find('.vTextField').val();
                var nameDocId = $(row).find('.field-name').find('.vTextField').attr('id');

                var values = $(row).find('.field-choices').find('.vTextField').val();
                var valuesDocId = $(row).find('.field-choices').find('.vTextField').attr('id');

                var obj = {name:name, values:values, valuesDocId:valuesDocId};

                existingVars.push(obj);
            });

            return existingVars;
        },

        groupExistingVars:function (existingVars, newVars, variablesType) {
            var similarVars = [];
            var updateVars = [];
            var toBeDeletedVars = [];

            var similarFieldToCheck = (variablesType && variablesType.toLowerCase() == 'select' ? 'values' : 'type');

            for (var i = 0; i < existingVars.length; i++) {
                var toBeUpdated = false;
                var updatedFieldValue = undefined;
                var isSimilar = false;
                for (var j = 0; j < newVars.length; j++) {
                    if (existingVars[i].name == newVars[j].varname && existingVars[i][similarFieldToCheck] == newVars[j][similarFieldToCheck]) {
                        isSimilar = true;
                        break;
                    } else if (existingVars[i].name == newVars[j].varname && existingVars[i][similarFieldToCheck] != newVars[j][similarFieldToCheck]) {
                        toBeUpdated = true;
                        updatedFieldValue = newVars[j][similarFieldToCheck];
                        break;
                    }
                }

                if (toBeUpdated) {
                    existingVars[i].updateWithValue = updatedFieldValue;
                    updateVars.push(existingVars[i]);
                } else if (isSimilar) {
                    similarVars.push(existingVars[i]);
                } else if (!toBeUpdated && !isSimilar) {
                    toBeDeletedVars.push(existingVars[i]);
                }
            }

            return {
                similarVars:similarVars,
                toUpdateVars:updateVars,
                deleteVars:toBeDeletedVars
            };
        },

        findByVarName:function (arr, vName) {
            var found = false;
            $.each(arr, function (i, item) {
                if (item.name == vName) {
                    found = item;
                    return;
                }
            });

            return found;
        },

        markForDeletion:function (container, deletedVars) {
            var rows = container.children('.inline-related');

            var self = this;
            $.each(rows, function (i, row) {
                var varName = $(row).find('.field-name').find('.vTextField').val();
                var isFoundVar = self.findByVarName(deletedVars, varName);

                if (isFoundVar) {
                    var deleteBtn = $(row).find('a.inline-deletelink');
                    if(deleteBtn.get(0)) {
                        //most likely variable was added from a previous paste or by the user so trigger the deletion here
                        deleteBtn.trigger('click');
                    } else {
                        var deleteCheckbox = $(row).find('.delete').find('input[type=checkbox]');
                        deleteCheckbox.attr('checked', 'checked');
                    }
                }
            });
        },

        updateVars:function (container, updatedVars, varsType) {
            var rows = container.children('.inline-related');

            var objFieldToUpdate = (varsType.toLowerCase() == 'select' ? 'valuesDocId' : 'typeDocId');

            var self = this;
            $.each(rows, function (i, row) {
                var varName = $(row).find('.field-name').find('.vTextField').val();
                var isFoundVar = self.findByVarName(updatedVars, varName);

                if (isFoundVar) {
                    $('#'+ isFoundVar[objFieldToUpdate]).val(isFoundVar.updateWithValue)
                }
            });
        },

        /**
         * Find the "Add another Standard Variable" button and trigger a click event on it. Returns the div container
         * holding form fields
         * @param container
         * @return {*|jQuery}
         */
        clickAddNewFieldStd:function (container) {

            //count the number of already inserted vars here
            //subtract 1 for the empty one present by default
            var presentFieldsCount = container.children('.inline-related').length - 1;

            var addNewFieldBtn = $(container).children('div.add-row').find('a');
            addNewFieldBtn.trigger('click');

            var addedField = $(container).children('.inline-related').last().prev();

            addedField.attr('id', 'variables-' + presentFieldsCount);

            var textField = addedField.find('input.vTextField');
            $(textField).attr('id', 'id_variables-' + presentFieldsCount + '-name');
            $(textField).attr('name', 'variables-' + presentFieldsCount + '-name');

            var textLabel = addedField.find('div.field-name').find('label');
            $(textLabel).attr('for', 'id_variables-' + presentFieldsCount + '-name');

            var select = addedField.find('div.field-widget').find('select');
            $(select).attr('id', 'id_variables-' + presentFieldsCount + '-widget');
            $(select).attr('name', 'variables-' + presentFieldsCount + '-widget');

            var selectLabel = addedField.find('div.field-widget').find('label');
            $(selectLabel).attr('for', 'id_variables-' + presentFieldsCount + '-widget')

            return addedField;
        },

        /**
         * Find the "Add another Drop Down Variable" button and trigger a click event on it. Returns the div container
         * holding form fields. There is really no difference at the moment between this and the clickAddNewFieldStd.
         * The only reason for them to be separate is for expressiveness and future extensions.
         * @param container
         * @return {*|jQuery}
         */
        clickAddNewFieldSelect:function (container) {
            var addNewFieldBtn = $(container).children('div.add-row').find('a');
            addNewFieldBtn.trigger('click');

            var addedField = $(container).children('.inline-related').last().prev();
            var inputFields = addedField.children('.vTextField');

            var presentFieldsCount = container.children('.inline-related').length;

            $(inputFields[0]).attr('id', 'id_variables-2-' + presentFieldsCount + '-name');
            $(inputFields[0]).attr('name', 'variables-2-' + presentFieldsCount + '-name');

            $(inputFields[1]).attr('id', 'id_variables-2-' + presentFieldsCount + '-choices');
            $(inputFields[1]).attr('name', 'variables-2-' + presentFieldsCount + '-choices');

            return addedField;
        },

        /**
         * Add a new standard variable in the container
         * varNameObj = {varname: 'name', type: 'type'}
         * @param varNameObj
         * @param container
         */
        addStdVar:function (varNameObj, container) {
            var fieldCx = this.clickAddNewFieldStd(container);
            $(fieldCx).find('input.vTextField').val(varNameObj.varname);
            $(fieldCx).find('select').val(varNameObj.type);
        },

        /**
         * Add a new drop down variable in the container
         * varNameObj = {varname: 'name', type: 'type', values: 'value1,value2,value3'}
         * @param varNameObj
         * @param container
         */

        addSelectVar:function (varNameObj, container) {
            var fieldCx = this.clickAddNewFieldSelect(container);
            $(fieldCx).find('div.field-name').find('input.vTextField').val(varNameObj.varname);
            $(fieldCx).find('div.field-choices').find('input.vTextField').val(varNameObj.values);
        },

        /**
         * The following code will try to match everything that's within an html comment tag. It should look like this
         *
         * <!-- SmartSnippets Variables
         * varname=type
         * -->
         *
         * Where type could be anything from TextField, TextAreaField, MerlinField or ImageField
         * Each variable is declared on a new line.
         */
        extractVarnames:function (text) {
            var regex = /<!-- SmartSnippets Variables([^>]*)-->/gi;
            var variablesSnippet = regex.exec(text);
            var varNames = []; //hold the var names here

            if (variablesSnippet) {
                var lines = variablesSnippet[1].split('\n'); //split the input in multiple lines

                $.each(lines, function (index, line) {
                    if ($.trim(line).length > 0) {
                        var vObj = {};
                        var vDeclarationArr = line.split('=');
                        vObj.varname = $.trim(vDeclarationArr[0]);

                        var type = $.trim(vDeclarationArr[1]);
                        if (type.toLowerCase().indexOf('select') != -1) {
                            var tmp = type.split('|');
                            vObj.type = $.trim(tmp[0]);
                            vObj.values = vDeclarationArr[2] ? $.trim(vDeclarationArr[2]) : '';
                        } else {
                            vObj.type = $.trim(vDeclarationArr[1]);
                        }

                        varNames.push(vObj);
                    }
                });
            }
            return varNames;
        },

        groupNewVars:function (varsArr) {
            var returnObj = {};
            returnObj.standard = new Array();
            returnObj.select = new Array();

            $.each(varsArr, function (i, variable) {
                if (variable.type.toLowerCase() == 'select') {
                    returnObj.select.push(variable);
                } else {
                    returnObj.standard.push(variable);
                }
            });

            return returnObj;
        },

        getOnlyToAddVars: function(groupedVars, newVars) {
            var onlyToAdd = new Array();
            for (var i = 0; i < newVars.length; i++) {
                var notInUpdates = true;
                var notInSimilar = true;

                for(var j = 0; j < groupedVars.similarVars.length; j++) {
                    if(newVars[i].varname == groupedVars.similarVars[j].name) {
                        notInSimilar = false;
                    }
                }

                for(var k = 0; k < groupedVars.toUpdateVars.length; k++) {
                    if(newVars[i].varname == groupedVars.toUpdateVars[k].name) {
                        notInUpdates = false;
                    }
                }

                if(notInSimilar && notInUpdates) {
                    onlyToAdd.push(newVars[i]);
                }
            }

            return onlyToAdd;
        },
        /**
         * Given an array of objects with the following structure {varname: 'name', type: 'type', values: 'value1,
         * value2,value3'} or varNameObj = {varname: 'name', type: 'type'} this function fill parse the array.
         *
         * @param varNamesArr
         */
        populate:function (varNamesArr) {
            var self = this;
            if (varNamesArr.length > 0) { //don't do any mumbo jumbo if we have no varnames

                var groupedNewVars = self.groupNewVars(varNamesArr);

                var stdContainer = self.getContainer('standard');
                var selectContainer = self.getContainer('select');

                var existingStdVars = self.getExistingStandardVariables(stdContainer);
                var existingSelectVars = self.getExistingSelectVariables(selectContainer);

                var groupedExistingStdVars = self.groupExistingVars(existingStdVars, groupedNewVars.standard, 'standard');

                if (existingStdVars.length > 0) {
                    self.markForDeletion(stdContainer, groupedExistingStdVars.deleteVars);
                    self.updateVars(stdContainer, groupedExistingStdVars.toUpdateVars, 'standard');
                }

                var groupedExistingSelectVars = self.groupExistingVars(existingSelectVars, groupedNewVars.select, 'select');
                if(existingSelectVars.length > 0) {

                    self.markForDeletion(selectContainer, groupedExistingSelectVars.deleteVars);
                    self.updateVars(selectContainer, groupedExistingSelectVars.toUpdateVars, 'select');
                }

                var onlyToAddStdVars = self.getOnlyToAddVars(groupedExistingStdVars, groupedNewVars.standard);
                var onlyToAddSelectVars = self.getOnlyToAddVars(groupedExistingSelectVars, groupedNewVars.select);

                $.each(onlyToAddStdVars, function(i, vObj) {
                    self.addStdVar(vObj, stdContainer);
                });

                $.each(onlyToAddSelectVars, function(i, vObj) {
                    self.addSelectVar(vObj, selectContainer);
                });
            }
        }
    };

    $(document).ready(function () {
        var textArea = $('#id_template_code');

        textArea.bind('paste', function (e) {
            var el = $(this);

            if ($.trim($(el).val()).length == 0) {//only when the area is empty
                //use a setTimeout to capture pasted text
                setTimeout(function () {

                    var checkboxes = $('input[type=checkbox]');
                    $.each(checkboxes, function(i, box) {
                        $(this).attr('checked', false);
                    });

                    var text = $(el).val();
                    var varNames = LayoutParser.extractVarnames(text);
                    LayoutParser.populate(varNames);
                }, 100);
            }
        });
    });

})(django.jQuery);
<|endoftext|>


<commit_before>(function ($) {

    /**
     * This object provides helper functions for parsing a pasted smart snippet's code and auto populating the variable
     * fields needed by that smart snippet.
     * @type {Object}
     */
    var LayoutParser = {

        /**
         * Clear all added variables from a container
         * @param jQuery container
         */
        emptyContainer:function (container) {
            container.children('.inline-related ').each(function (i, item) {
                if (!$(item).hasClass('empty-form'))
                    $(item).remove();
            });
        },

        /**
         * Gets the standard variables container or the drop down one
         * @param String variablesHolderType
         * @return {*\jQuery}
         */
        getContainer:function (variablesHolderType) {
            var cx = null;
            $('.inline-group').each(function (i, item) {
                if (variablesHolderType == 'standard') {
                    if ($(item).children('h2')[0].innerText.toLowerCase() == 'standard variables') {
                        cx = $(item);
                        return;
                    }

                } else if (variablesHolderType == 'select') {
                    if ($(item).children('h2')[0].innerText.toLowerCase() == 'drop down variables') {
                        cx = $(item);
                        return;
                    }
                }
            });

            return cx;
        },

        /**
         * Find the "Add another Standard Variable" button and trigger a click event on it. Returns the div container
         * holding form fields
         * @param container
         * @return {*|jQuery}
         */
        clickAddNewFieldStd:function (container) {
            var addNewFieldBtn = $(container).children('div.add-row').find('a');
            addNewFieldBtn.trigger('click');

            var addedField = $(container).children('.inline-related').last().prev();

            return addedField;
        },

        /**
         * Find the "Add another Drop Down Variable" button and trigger a click event on it. Returns the div container
         * holding form fields. There is really no difference at the moment between this and the clickAddNewFieldStd.
         * The only reason for them to be separate is for expressiveness and future extensions.
         * @param container
         * @return {*|jQuery}
         */
        clickAddNewFieldSelect:function (container) {
            var addNewFieldBtn = $(container).children('div.add-row').find('a');
            addNewFieldBtn.trigger('click');

            var addedField = $(container).children('.inline-related').last().prev();

            return addedField;
        },

        /**
         * Add a new standard variable in the container
         * varNameObj = {varname: 'name', type: 'type'}
         * @param varNameObj
         * @param container
         */
        addStdVar:function (varNameObj, container) {
            var fieldCx = this.clickAddNewFieldStd(container);
            $(fieldCx).find('input.vTextField')[0].value = varNameObj.varname;
            $(fieldCx).find('select')[0].value = varNameObj.type;
        },

        /**
         * Add a new drop down variable in the container
         * varNameObj = {varname: 'name', type: 'type', values: 'value1,value2,value3'}
         * @param varNameObj
         * @param container
         */

        addSelectVar:function (varNameObj, container) {
            var fieldCx = this.clickAddNewFieldSelect(container);
            $(fieldCx).find('div.field-name').find('input.vTextField')[0].value = varNameObj.varname;
            $(fieldCx).find('div.field-choices').find('input.vTextField')[0].value = varNameObj.values;
        },

        /**
         * The following code will try to match everything that's within an html comment tag. It should look like this
         *
         * <!-- SmartSnippets Variables
         * varname=type
         * -->
         *
         * Where type could be anything from TextField, TextAreaField, MerlinField or ImageField
         * Each variable is declared on a new line.
         */
        extractVarnames:function (text) {
            var regex = /<!-- SmartSnippets Variables([^>]*)-->/gi;
            var variablesSnippet = regex.exec(text);
            var varNames = []; //hold the var names here

            if (variablesSnippet) {
                var lines = variablesSnippet[1].split('\n'); //split the input in multiple lines

                $.each(lines, function (index, line) {
                    if ($.trim(line).length > 0) {
                        var vObj = {};
                        var vDeclarationArr = line.split('=');
                        vObj.varname = $.trim(vDeclarationArr[0]);

                        var type = $.trim(vDeclarationArr[1]);
                        if (type.toLowerCase().indexOf('select') != -1) {
                            var tmp = type.split('|');
                            vObj.type = $.trim(tmp[0]);
                            vObj.values = vDeclarationArr[2] ? $.trim(vDeclarationArr[2]) : '';
                        } else {
                            vObj.type = $.trim(vDeclarationArr[1]);
                        }

                        varNames.push(vObj);
                    }
                });
            }
            return varNames;
        },

        /**
         * Given an array of objects with the following structure {varname: 'name', type: 'type', values: 'value1,
         * value2,value3'} or varNameObj = {varname: 'name', type: 'type'} this function fill parse the array.
         *
         * @param varNamesArr
         */
        populate: function(varNamesArr) {
            var self = this;
            if (varNamesArr.length > 0) { //don't do any mumbo jumbo if we have no varnames

                var stdContainer = self.getContainer('standard');
                var selectContainer = self.getContainer('select');

                self.emptyContainer(stdContainer);
                self.emptyContainer(selectContainer);

                $.each(varNamesArr, function (i, vObj) {

                    if (vObj.type.toLowerCase() != 'select') {
                        self.addStdVar(vObj, stdContainer);
                    } else {
                        self.addSelectVar(vObj, selectContainer);
                    }
                });
            }
        }
    };

    $(document).ready(function () {

        $('#id_template_code').bind('paste', function (e) {
            var el = $(this);
            //use a setTimeout to capture the paste event otherwise it will not trigger in the browser
            setTimeout(function () {
                var text = $(el).val();
                var varNames = LayoutParser.extractVarnames(text);
                LayoutParser.populate(varNames);
            }, 100);
        });
    });

})(django.jQuery);
<commit_msg>Fixed bug when submitting the form that didn't pass validation and fields were duplicated.<commit_after>(function ($) {

    /**
     * This object provides helper functions for parsing a pasted smart snippet's code and auto populating the variable
     * fields needed by that smart snippet.
     * @type {Object}
     */
    var LayoutParser = {

        /**
         * Clear all added variables from a container
         * @param jQuery container
         */
        emptyContainer:function (container) {
            container.children('.inline-related ').each(function (i, item) {
                if (!$(item).hasClass('empty-form'))
                    $(item).remove();
            });
        },

        /**
         * Gets the standard variables container or the drop down one
         * @param String variablesHolderType
         * @return {*\jQuery}
         */
        getContainer:function (variablesHolderType) {
            var cx = null;
            $('.inline-group').each(function (i, item) {
                if (variablesHolderType == 'standard') {

                    var header = $(item).children('h2').get(0);
                    if ($(header).text().toLowerCase() == 'standard variables') {
                        cx = $(item);
                        return;
                    }

                } else if (variablesHolderType == 'select') {

                    var header = $(item).children('h2').get(0);

                    if ($(header).text().toLowerCase() == 'drop down variables') {
                        cx = $(item);
                        return;
                    }
                }
            });

            return cx;
        },

        /**
         * Find the "Add another Standard Variable" button and trigger a click event on it. Returns the div container
         * holding form fields
         * @param container
         * @return {*|jQuery}
         */
        clickAddNewFieldStd:function (container) {

            //count the number of already inserted vars here
            //subtract 1 for the empty one present by default
            var presentFieldsCount = container.children('.inline-related').length - 1;

            var addNewFieldBtn = $(container).children('div.add-row').find('a');
            addNewFieldBtn.trigger('click');

            var addedField = $(container).children('.inline-related').last().prev();

            var textField = addedField.find('input.vTextField');
            $(textField).attr('id', 'id_variables-' + presentFieldsCount + '-name');
            $(textField).attr('name', 'variables-' + presentFieldsCount +'-name');

            var select = addedField.find('div.field-widget').find('select');
            $(select).attr('id', 'id_variables-' + presentFieldsCount + '-widget');
            $(select).attr('name', 'variables-' + presentFieldsCount + '-widget');

            return addedField;
        },

        /**
         * Find the "Add another Drop Down Variable" button and trigger a click event on it. Returns the div container
         * holding form fields. There is really no difference at the moment between this and the clickAddNewFieldStd.
         * The only reason for them to be separate is for expressiveness and future extensions.
         * @param container
         * @return {*|jQuery}
         */
        clickAddNewFieldSelect:function (container) {
            var addNewFieldBtn = $(container).children('div.add-row').find('a');
            addNewFieldBtn.trigger('click');

            var addedField = $(container).children('.inline-related').last().prev();
            var inputFields = addedField.children('.vTextField');

            var presentFieldsCount = container.children('.inline-related').length;

            $(inputFields[0]).attr('id', 'id_variables-2-' + presentFieldsCount +'-name');
            $(inputFields[0]).attr('name', 'variables-2-' + presentFieldsCount + '-name');

            $(inputFields[1]).attr('id', 'id_variables-2-' + presentFieldsCount + '-choices');
            $(inputFields[1]).attr('name', 'variables-2-' + presentFieldsCount + '-choices');

            return addedField;
        },

        /**
         * Add a new standard variable in the container
         * varNameObj = {varname: 'name', type: 'type'}
         * @param varNameObj
         * @param container
         */
        addStdVar:function (varNameObj, container) {
            var fieldCx = this.clickAddNewFieldStd(container);
            $(fieldCx).find('input.vTextField')[0].value = varNameObj.varname;
            $(fieldCx).find('select')[0].value = varNameObj.type;
        },

        /**
         * Add a new drop down variable in the container
         * varNameObj = {varname: 'name', type: 'type', values: 'value1,value2,value3'}
         * @param varNameObj
         * @param container
         */

        addSelectVar:function (varNameObj, container) {
            var fieldCx = this.clickAddNewFieldSelect(container);
            $(fieldCx).find('div.field-name').find('input.vTextField')[0].value = varNameObj.varname;
            $(fieldCx).find('div.field-choices').find('input.vTextField')[0].value = varNameObj.values;
        },

        /**
         * The following code will try to match everything that's within an html comment tag. It should look like this
         *
         * <!-- SmartSnippets Variables
         * varname=type
         * -->
         *
         * Where type could be anything from TextField, TextAreaField, MerlinField or ImageField
         * Each variable is declared on a new line.
         */
        extractVarnames:function (text) {
            var regex = /<!-- SmartSnippets Variables([^>]*)-->/gi;
            var variablesSnippet = regex.exec(text);
            var varNames = []; //hold the var names here

            if (variablesSnippet) {
                var lines = variablesSnippet[1].split('\n'); //split the input in multiple lines

                $.each(lines, function (index, line) {
                    if ($.trim(line).length > 0) {
                        var vObj = {};
                        var vDeclarationArr = line.split('=');
                        vObj.varname = $.trim(vDeclarationArr[0]);

                        var type = $.trim(vDeclarationArr[1]);
                        if (type.toLowerCase().indexOf('select') != -1) {
                            var tmp = type.split('|');
                            vObj.type = $.trim(tmp[0]);
                            vObj.values = vDeclarationArr[2] ? $.trim(vDeclarationArr[2]) : '';
                        } else {
                            vObj.type = $.trim(vDeclarationArr[1]);
                        }

                        varNames.push(vObj);
                    }
                });
            }
            return varNames;
        },

        /**
         * Given an array of objects with the following structure {varname: 'name', type: 'type', values: 'value1,
         * value2,value3'} or varNameObj = {varname: 'name', type: 'type'} this function fill parse the array.
         *
         * @param varNamesArr
         */
        populate:function (varNamesArr) {
            var self = this;
            if (varNamesArr.length > 0) { //don't do any mumbo jumbo if we have no varnames

                var stdContainer = self.getContainer('standard');
                var selectContainer = self.getContainer('select');

                self.emptyContainer(stdContainer);
                self.emptyContainer(selectContainer);

                $.each(varNamesArr, function (i, vObj) {

                    if (vObj.type.toLowerCase() != 'select') {
                        self.addStdVar(vObj, stdContainer);
                    } else {
                        self.addSelectVar(vObj, selectContainer);
                    }
                });
            }
        }
    };

    $(document).ready(function () {
        var textArea = $('#id_template_code');

        textArea.bind('paste', function (e) {
            var el = $(this);

            if ($.trim($(el).val()).length == 0) {//only when the area is empty
                //use a setTimeout to capture pasted text
                setTimeout(function () {
                    var text = $(el).val();
                    var varNames = LayoutParser.extractVarnames(text);
                    LayoutParser.populate(varNames);
                }, 100);
            }
        });
    });

})(django.jQuery);
<|endoftext|>