<commit_before>/* eslint-env node */
'use strict';

const EmberApp = require('ember-cli/lib/broccoli/ember-app');
const concat = require('broccoli-concat');
const mergeTrees = require('broccoli-merge-trees');
const uglify = require('broccoli-uglify-js');
const CleanCSS = require('broccoli-clean-css');
const environment = EmberApp.env();
const isProduction = environment === 'production';
let assetLocation, codemirrorAssets;

assetLocation = function (fileName) {
    if (isProduction) {
        fileName = fileName.replace('.', '.min.');
    }
    return `/assets/${fileName}`;
};

codemirrorAssets = function () {
    let codemirrorFiles = [
        // 'lib/codemirror.css',
        'theme/xq-light.css',
        'lib/codemirror.js',
        'mode/htmlmixed/htmlmixed.js',
        'mode/xml/xml.js',
        'mode/css/css.js',
        'mode/javascript/javascript.js'
    ];

    if (environment === 'test') {
        return {import: codemirrorFiles};
    }

    let config = {};

    config.public = {
        include: codemirrorFiles,
        destDir: '/',
        processTree(tree) {
            let jsTree = concat(tree, {
                outputFile: 'assets/codemirror/codemirror.js',
                headerFiles: ['lib/codemirror.js'],
                inputFiles: ['mode/**/*'],
                sourceMapConfig: {enabled: false}
            });

            let cssTree = concat(tree, {
                outputFile: 'assets/codemirror/codemirror.css',
                inputFiles: ['**/*.css']
            });

            if (isProduction) {
                jsTree = uglify(jsTree);
                cssTree = new CleanCSS(cssTree);
            }

            return mergeTrees([tree, jsTree, cssTree]);
        }
    };

    // put the files in vendor ready for importing into the test-support file
    if (environment === 'development') {
        config.vendor =  codemirrorFiles;
    }

    return config;
};

function postcssPlugins() {
    let plugins = [{
        module: require('postcss-easy-import')
    }, {
        module: require('postcss-custom-properties')
    }, {
        module: require('postcss-color-function')
    }, {
        module: require('autoprefixer'),
        options: {
            browsers: ['last 2 versions']
        }
    }];

    if (isProduction) {
        plugins.push({
            module: require('cssnano')
        });
    }

    return plugins;
}

module.exports = function (defaults) {
    let app = new EmberApp(defaults, {
        'ember-cli-babel': {
            optional: ['es6.spec.symbols'],
            includePolyfill: true
        },
        'ember-composable-helpers': {
            only: ['toggle']
        },
        outputPaths: {
            app: {
                html: isProduction ? 'index.min.html' : 'index.html',
                js: assetLocation('ghost.js'),
                css: {
                    app: assetLocation('ghost.css'),
                    // TODO: find a way to use the .min file with the lazyLoader
                    'app-dark': 'assets/ghost-dark.css'
                }
            },
            vendor: {
                js:  assetLocation('vendor.js'),
                css: assetLocation('vendor.css')
            }
        },
        postcssOptions: {
            compile: {
                enabled: true,
                plugins: postcssPlugins()
            }
        },
        fingerprint: {
            enabled: true,
            extensions: ['js', 'css', 'png', 'jpg', 'jpeg', 'gif', 'map']
        },
        nodeAssets: {
            'blueimp-md5': {
                import: ['js/md5.js']
            },
            codemirror: codemirrorAssets(),
            'jquery-deparam': {
                import: ['jquery-deparam.js']
            },
            'password-generator': {
                import: ['lib/password-generator.js']
            },
            'simplemde': {
                srcDir: 'debug',
                import: ['simplemde.js', 'simplemde.css']
            }
        },
        'ember-cli-selectize': {
            theme: false
        },
        svg: {
            paths: [
                'public/assets/icons'
            ],
            optimize: {
                plugins: [
                    {removeDimensions: true},
                    {removeTitle: true},
                    {removeXMLNS: true},
                    // Transforms on groups are necessary to work around Firefox
                    // not supporting transform-origin on line/path elements.
                    {convertPathData: {
                        applyTransforms: false
                    }},
                    {moveGroupAttrsToElems: false}
                ]
            }
        }
    });

    // 'dem Scripts
    app.import('bower_components/validator-js/validator.js');
    app.import('bower_components/rangyinputs/rangyinputs-jquery-src.js');
    app.import('bower_components/keymaster/keymaster.js');
    app.import('bower_components/devicejs/lib/device.js');

    // jquery-ui partial build
    app.import('bower_components/jquery-ui/ui/core.js');
    app.import('bower_components/jquery-ui/ui/widget.js');
    app.import('bower_components/jquery-ui/ui/mouse.js');
    app.import('bower_components/jquery-ui/ui/draggable.js');
    app.import('bower_components/jquery-ui/ui/droppable.js');
    app.import('bower_components/jquery-ui/ui/sortable.js');

    app.import('bower_components/jquery-file-upload/js/jquery.fileupload.js');
    app.import('bower_components/blueimp-load-image/js/load-image.all.min.js');
    app.import('bower_components/jquery-file-upload/js/jquery.fileupload-process.js');
    app.import('bower_components/jquery-file-upload/js/jquery.fileupload-image.js');
    app.import('bower_components/google-caja/html-css-sanitizer-bundle.js');
    app.import('bower_components/jqueryui-touch-punch/jquery.ui.touch-punch.js');

    if (app.env !== 'production') {
        app.import(`${app.bowerDirectory}/jquery.simulate.drag-sortable/jquery.simulate.drag-sortable.js`, {type: 'test'});
    }

    // pull things we rely on via lazy-loading into the test-support.js file so
    // that tests don't break when running via http://localhost:4200/tests
    if (app.env === 'development') {
        app.import('vendor/codemirror/lib/codemirror.js', {type: 'test'});
    }

    return app.toTree();
};
<commit_msg>🐛  fix sticky save notifications (#762)<commit_after>/* eslint-env node */
'use strict';

const EmberApp = require('ember-cli/lib/broccoli/ember-app');
const concat = require('broccoli-concat');
const mergeTrees = require('broccoli-merge-trees');
const uglify = require('broccoli-uglify-js');
const CleanCSS = require('broccoli-clean-css');
const environment = EmberApp.env();
const isProduction = environment === 'production';
let assetLocation, codemirrorAssets;

assetLocation = function (fileName) {
    if (isProduction) {
        fileName = fileName.replace('.', '.min.');
    }
    return `/assets/${fileName}`;
};

codemirrorAssets = function () {
    let codemirrorFiles = [
        // 'lib/codemirror.css',
        'theme/xq-light.css',
        'lib/codemirror.js',
        'mode/htmlmixed/htmlmixed.js',
        'mode/xml/xml.js',
        'mode/css/css.js',
        'mode/javascript/javascript.js'
    ];

    if (environment === 'test') {
        return {import: codemirrorFiles};
    }

    let config = {};

    config.public = {
        include: codemirrorFiles,
        destDir: '/',
        processTree(tree) {
            let jsTree = concat(tree, {
                outputFile: 'assets/codemirror/codemirror.js',
                headerFiles: ['lib/codemirror.js'],
                inputFiles: ['mode/**/*'],
                sourceMapConfig: {enabled: false}
            });

            let cssTree = concat(tree, {
                outputFile: 'assets/codemirror/codemirror.css',
                inputFiles: ['**/*.css']
            });

            if (isProduction) {
                jsTree = uglify(jsTree);
                cssTree = new CleanCSS(cssTree);
            }

            return mergeTrees([tree, jsTree, cssTree]);
        }
    };

    // put the files in vendor ready for importing into the test-support file
    if (environment === 'development') {
        config.vendor =  codemirrorFiles;
    }

    return config;
};

function postcssPlugins() {
    let plugins = [{
        module: require('postcss-easy-import')
    }, {
        module: require('postcss-custom-properties')
    }, {
        module: require('postcss-color-function')
    }, {
        module: require('autoprefixer'),
        options: {
            browsers: ['last 2 versions']
        }
    }];

    if (isProduction) {
        plugins.push({
            module: require('cssnano'),
            // cssnano minifies animations sometimes wrong, so they don't work anymore.
            // See: https://github.com/ben-eb/gulp-cssnano/issues/33#issuecomment-210518957
            options: {
                reduceIdents: {
                    keyframes: false
                },
                discardUnused: {
                    keyframes: false
                }
            }
        });
    }

    return plugins;
}

module.exports = function (defaults) {
    let app = new EmberApp(defaults, {
        'ember-cli-babel': {
            optional: ['es6.spec.symbols'],
            includePolyfill: true
        },
        'ember-composable-helpers': {
            only: ['toggle']
        },
        outputPaths: {
            app: {
                html: isProduction ? 'index.min.html' : 'index.html',
                js: assetLocation('ghost.js'),
                css: {
                    app: assetLocation('ghost.css'),
                    // TODO: find a way to use the .min file with the lazyLoader
                    'app-dark': 'assets/ghost-dark.css'
                }
            },
            vendor: {
                js:  assetLocation('vendor.js'),
                css: assetLocation('vendor.css')
            }
        },
        postcssOptions: {
            compile: {
                enabled: true,
                plugins: postcssPlugins()
            }
        },
        fingerprint: {
            enabled: true,
            extensions: ['js', 'css', 'png', 'jpg', 'jpeg', 'gif', 'map']
        },
        nodeAssets: {
            'blueimp-md5': {
                import: ['js/md5.js']
            },
            codemirror: codemirrorAssets(),
            'jquery-deparam': {
                import: ['jquery-deparam.js']
            },
            'password-generator': {
                import: ['lib/password-generator.js']
            },
            'simplemde': {
                srcDir: 'debug',
                import: ['simplemde.js', 'simplemde.css']
            }
        },
        'ember-cli-selectize': {
            theme: false
        },
        svg: {
            paths: [
                'public/assets/icons'
            ],
            optimize: {
                plugins: [
                    {removeDimensions: true},
                    {removeTitle: true},
                    {removeXMLNS: true},
                    // Transforms on groups are necessary to work around Firefox
                    // not supporting transform-origin on line/path elements.
                    {convertPathData: {
                        applyTransforms: false
                    }},
                    {moveGroupAttrsToElems: false}
                ]
            }
        }
    });

    // 'dem Scripts
    app.import('bower_components/validator-js/validator.js');
    app.import('bower_components/rangyinputs/rangyinputs-jquery-src.js');
    app.import('bower_components/keymaster/keymaster.js');
    app.import('bower_components/devicejs/lib/device.js');

    // jquery-ui partial build
    app.import('bower_components/jquery-ui/ui/core.js');
    app.import('bower_components/jquery-ui/ui/widget.js');
    app.import('bower_components/jquery-ui/ui/mouse.js');
    app.import('bower_components/jquery-ui/ui/draggable.js');
    app.import('bower_components/jquery-ui/ui/droppable.js');
    app.import('bower_components/jquery-ui/ui/sortable.js');

    app.import('bower_components/jquery-file-upload/js/jquery.fileupload.js');
    app.import('bower_components/blueimp-load-image/js/load-image.all.min.js');
    app.import('bower_components/jquery-file-upload/js/jquery.fileupload-process.js');
    app.import('bower_components/jquery-file-upload/js/jquery.fileupload-image.js');
    app.import('bower_components/google-caja/html-css-sanitizer-bundle.js');
    app.import('bower_components/jqueryui-touch-punch/jquery.ui.touch-punch.js');

    if (app.env !== 'production') {
        app.import(`${app.bowerDirectory}/jquery.simulate.drag-sortable/jquery.simulate.drag-sortable.js`, {type: 'test'});
    }

    // pull things we rely on via lazy-loading into the test-support.js file so
    // that tests don't break when running via http://localhost:4200/tests
    if (app.env === 'development') {
        app.import('vendor/codemirror/lib/codemirror.js', {type: 'test'});
    }

    return app.toTree();
};
<|endoftext|>


<commit_before>import chalk from 'chalk'
import path from 'path'
import pad from 'pad'

import * as log from '../log'
import duration from '../duration'

import createGraph from '../graph/create'
import archy from '../util/archy'

export function runCommand() {
    createGraph(path.resolve('.'), function(err, [entryNode], layers) {
        if (err) {
            end(err)
        }

        console.log('Christmas Tree:')
        console.log(archy(entryNode))

        console.log('Layers:')
        layers.forEach((layer, index) => {
            layer.forEach(node =>
                console.log(
                    pad(index * 2, ``) +
                        `${index + 1} ${chalk.yellow(node.name)}`
                )
            )
        })
        end(null)
    })
}

function end(err) {
    if (err) {
        log.failure(err)
        process.exit(1)
    } else {
        log.success(`done in ${duration()}`)
    }
}
<commit_msg>New output for the graph command<commit_after>import chalk from 'chalk'
import path from 'path'
import pad from 'pad'

import * as log from '../log'
import duration from '../duration'

import createGraph from '../graph/create'
import archy from '../util/archy'

export function runCommand() {
    createGraph(path.resolve('.'), (err, [entryNode] = [], layers) => {
        if (err) {
            end(err)
        }

        // const treeText = archy(entryNode).split('\n')
        log.info(`Christmas Tree:`)
        archy(entryNode)
            .split('\n')
            .map(line => line.trim())
            .filter(Boolean)
            .forEach(line => log.info(line, ''))

        log.info('Layers:')
        layers.forEach((layer, index) => {
            layer.forEach(node =>
                log.info(
                    pad(index * 2, ``) +
                        `${index + 1} ${chalk.yellow(node.name)}`,
                    ''
                )
            )
        })
        end(null)
    })
}

function end(err) {
    if (err) {
        log.failure(err)
        process.exit(1)
    } else {
        log.success(`done in ${duration()}`)
    }
}
<|endoftext|>


<commit_before>/* global  Materialize, Clipboard, escapeHtml, Notify*/
"use strict";

var host = window.location.hostname; // edit this if needed
var messages = [];
var addressLoaded = false;

function checkSupport() {
  var support = "MozWebSocket" in window ? 'MozWebSocket' : ("WebSocket" in window ? 'WebSocket' : null);
  if (support === null) {
    Materialize.toast('Your browser doesn\'t support Websockets! You won\'t be able to use this service...', 1000000, 'warning-toast');
    return false;
  }

  return true;
}

function checkNotify() {
  if (window.Notification && Notify.needsPermission) {
    Notify.requestPermission();
  }
}

function notifyEmail(email) {
  var myNotification = new Notify(email.from, {
    icon: '/img/ios-desktop.png',
    body: email.body,
    timeout: 4
  });

  myNotification.show();
}

function showRaw(id) {
  $('#rawArea').text(messages[id].raw);
  $('#rawModal').openModal();
}

function getAttachments(id) {
  if (messages[id].attachments.length === 0) {
    return 'No Attachments';
  } else {
    var lengthString = messages[id].attachments.length + ' attachment';
    if(messages[id].attachments.length > 1){
      lengthString += 's';
    }
    lengthString += ': ';

    var attachmentLinks = messages[id].attachments.map(function(attachment){
      var dataURI = 'data:' + attachment.type + ';' + attachment.transferEncoding + ',' + attachment.data;
      return '' + attachment.name + '';
    }).join(', ');

    var attachmentString = lengthString + attachmentLinks;

    return attachmentString;
  }
}

function processDisconnect(event) {
  Materialize.toast('Server connection lost - please refresh', 1000000, 'warning-toast');
}

function processMessage(event) {
  if (!addressLoaded) {
    // first payload is always our config data, a JSON array of [address, port, maxbytes]
    var config = JSON.parse(event.data);
    $('#serverAddress').html(host);
    $('#mailAddress').html(config[0]);
    $('#serverPort').html(config[1]);
    $('#dropSize').html(config[2] / 1000);

    $('#copyLink').attr('data-clipboard-text', config[0]);
    addressLoaded = true;
    return;
  }

  var mailObj = JSON.parse(event.data);
  messages.push(mailObj);
  var messageID = messages.length - 1;

  // do body sanity checking; SHOULD be only temporary until python packages them right
  if (mailObj.body === null) {
    mailObj.body = '[no body]';
    messages.pop();
    messages.push(mailObj);
    messageID = messages.length - 1;
  }

  var message = '
' +
    'mail' +
    '' + escapeHtml(mailObj.subject) + '' +
    '
' + escapeHtml(mailObj.from) + ' (at ' + escapeHtml(mailObj.fromIP[0]) + ')
' +
    new Date().toLocaleString() + '
' +
    getAttachments(messageID) + '
' +
    'code' +
    '
' + escapeHtml(mailObj.body).replace(/(?:\r\n|\r|\n)/g, '
') + '
' +
    '
';

  $('#noMessages').hide();
  $('#messageCollection').prepend(message);
  notifyEmail(mailObj);
}

if (checkSupport()) {
  var mailSocket = new WebSocket('ws://' + host + ':9000');
  mailSocket.onmessage = processMessage;
  mailSocket.onclose = processDisconnect;

  // fire up our copy button (has to be selected to work)
  var clipboard = new Clipboard('#copyLink');

  checkNotify();
}
<commit_msg>leave in sanity checking<commit_after>/* global  Materialize, Clipboard, escapeHtml, Notify*/
"use strict";

var host = window.location.hostname; // edit this if needed
var messages = [];
var addressLoaded = false;

function checkSupport() {
  var support = "MozWebSocket" in window ? 'MozWebSocket' : ("WebSocket" in window ? 'WebSocket' : null);
  if (support === null) {
    Materialize.toast('Your browser doesn\'t support Websockets! You won\'t be able to use this service...', 1000000, 'warning-toast');
    return false;
  }

  return true;
}

function checkNotify() {
  if (window.Notification && Notify.needsPermission) {
    Notify.requestPermission();
  }
}

function notifyEmail(email) {
  var myNotification = new Notify(email.from, {
    icon: '/img/ios-desktop.png',
    body: email.body,
    timeout: 4
  });

  myNotification.show();
}

function showRaw(id) {
  $('#rawArea').text(messages[id].raw);
  $('#rawModal').openModal();
}

function getAttachments(id) {
  if (messages[id].attachments.length === 0) {
    return 'No Attachments';
  } else {
    var lengthString = messages[id].attachments.length + ' attachment';
    if(messages[id].attachments.length > 1){
      lengthString += 's';
    }
    lengthString += ': ';

    var attachmentLinks = messages[id].attachments.map(function(attachment){
      var dataURI = 'data:' + attachment.type + ';' + attachment.transferEncoding + ',' + attachment.data;
      return '' + attachment.name + '';
    }).join(', ');

    var attachmentString = lengthString + attachmentLinks;

    return attachmentString;
  }
}

function processDisconnect(event) {
  Materialize.toast('Server connection lost - please refresh', 1000000, 'warning-toast');
}

function processMessage(event) {
  if (!addressLoaded) {
    // first payload is always our config data, a JSON array of [address, port, maxbytes]
    var config = JSON.parse(event.data);
    $('#serverAddress').html(host);
    $('#mailAddress').html(config[0]);
    $('#serverPort').html(config[1]);
    $('#dropSize').html(config[2] / 1000);

    $('#copyLink').attr('data-clipboard-text', config[0]);
    addressLoaded = true;
    return;
  }

  var mailObj = JSON.parse(event.data);
  messages.push(mailObj);
  var messageID = messages.length - 1;

  // do body sanity checking
  if (mailObj.body === null) {
    mailObj.body = '[no body]';
    messages.pop();
    messages.push(mailObj);
    messageID = messages.length - 1;
  }

  var message = '
' +
    'mail' +
    '' + escapeHtml(mailObj.subject) + '' +
    '
' + escapeHtml(mailObj.from) + ' (at ' + escapeHtml(mailObj.fromIP[0]) + ')
' +
    new Date().toLocaleString() + '
' +
    getAttachments(messageID) + '
' +
    'code' +
    '
' + escapeHtml(mailObj.body).replace(/(?:\r\n|\r|\n)/g, '
') + '
' +
    '
';

  $('#noMessages').hide();
  $('#messageCollection').prepend(message);
  notifyEmail(mailObj);
}

if (checkSupport()) {
  var mailSocket = new WebSocket('ws://' + host + ':9000');
  mailSocket.onmessage = processMessage;
  mailSocket.onclose = processDisconnect;

  // fire up our copy button (has to be selected to work)
  var clipboard = new Clipboard('#copyLink');

  checkNotify();
}
<|endoftext|>


<commit_before>/*!
 * jQuery Environment
 * Copyright 2015 Kai Feldmaier (kai.feldmaier@gmail.com)
 * Licensed under MIT (http://opensource.org/licenses/MIT)
 */

 (function($) {
	var Environment = function(element, options)
	{
		var __e = $(element);
		var __o = this;

		/**
		 * @private
		 * Settings NS
		 */
		var __s = $.extend({
						development: {
							flag: true,
							explicit: false,
							uri: 'http://dev.mydomain.com',
							links: {
								'a#mylink':'http://dev.mydomain.com/home'
							},
							hidden: null
						},
						review: {
							flag: true,
							explicit: false,
							uri: 'http://rvw.mydomain.com',
							links: {
								'a#mylink':'http://rvw.mydomain.com/home'
							},
							hidden: null
						},
						productive: {
							flag: false,
							explicit: false,
							uri: null,
							links: null,
							hidden: null
						}
					}, options || {});

		/**
		 * @private
		 * Class Variables NS
		 */
		var __c = {
			devtools: false,
			environment: null,
			prev_environment: null,
			flag: null
		};

		/*
		 * Change the current environment to match the
		 * given key
		 */
		this.setEnvironment = function(key)
		{
			if (!__s.hasOwnProperty(key) || __c.environment == key)
				return;

			__c.prev_environment = __c.environment;
			__c.environment = key;

			if (__c.prev_environment)
			{
				__updateLinks(__c.prev_environment, false);
				__updateHidden(__c.prev_environment, false);
			}

			__updateLinks(__c.environment, true);
			__updateHidden(__c.environment, true);

			__showFlag(__s[__c.environment].flag);

		}

		/*
		 *
		 */
		this.setDevtools = function (active)
		{
			if (active == __c.devtools)
				return;

			__c.devtools = active;

			if (__c.environment && __s[__c.environment])
				__showFlag(__s[__c.environment].flag);
		}

		/*
		 * Setup an explicit environment.
		 */
		this.setExplicitEnvironment = function (key)
		{
			var env = __getExplicitEnvironment();
			if (key == env)
				return;

			if (__s.hasOwnProperty(env))
				__s[env].explicit = false;

			if (__s.hasOwnProperty(key))
			{
				__s[key].explicit = true;
				__o.setEnvironment(key);
			}
		}

		/*
		 * Update selectors configured as "hidden"
		 */
		var __updateHidden = function(environment, current)
		{
			if (!environment || !__s.hasOwnProperty(environment) || !__s[environment].hidden || !$.isArray(__s[environment].hidden))
				return;

			for (var i=0; i < __s[environment].hidden.length; i++)
			{
				var e = __e.find(__s[environment].hidden[i]);
				if (e && e.length)
				{
					if (current)
					{
						e.each(function(){
							$(this).data('prev-hidden', $(this).is(':hidden'));
							$(this).hide();
						});
					} else {
						e.each(function(){
							if (!$(this).data('prev-hidden'))
								$(this).show();

							$(this).removeData('prev-hidden');
						});
					}
				}

			}
		}

		/*
		 * Update selectors configured as "links"
		 */
		var __updateLinks = function(environment, current)
		{
			if (!environment || !__s.hasOwnProperty(environment) || !__s[environment].links)
				return;

			for (var selector in __s[environment].links)
			{
				if (current)
				{
					__e.find(selector).each(function(){
						$(this).data('prev-href', $(this).attr('href'));
						$(this).attr('href', __s[environment].links[selector]);
					});

				} else {
					__e.find(selector).each(function(){
						$(this).attr('href', $(this).data('prev-href'));
						$(this).data('prev-href', null);
					});
				}
			}

		}

		/*
		 * Show/hide the status box in the upper right corner
		 */
		var __showFlag = function(show)
		{
			if (!__c.devtools)
				return;

			if (!__c.flag)
			{
				var styles = [
					''
				].join('\n');
				__e.append($(styles));
				__c.flag = $('

');
				__c.flag.appendTo(__e);
			}

			var links, env;

			__c.flag.find('.body').text(__c.environment ? __capitalizeFirstLetter(__c.environment) : '').attr('title', __c.environment ? 'Panel defined by jquery.environment Plugin' : '');

			links = [];
			for (env in __s)
			{
				if (env == __c.environment)
					continue;

				links.push(''+__capitalizeFirstLetter(env)+'');
			}

			__c.flag.find('.footer').html(links.join(' | '));

			__c.flag.find('a').on('click', function(event){
				event.preventDefault();
				if ($(this).attr('data-environment'))
					__o.setExplicitEnvironment($(this).attr('data-environment'));
			});

			if (show)
			{
				__c.flag.show();
			} else {
				__c.flag.hide();
			}
		}

		/*
		 * @private
		 */
		var __capitalizeFirstLetter = function(string)
		{
    		return string.charAt(0).toUpperCase() + string.slice(1);
		}

		/*
		 * Find the current environment by comparing window location and
		 * the uri of each environment setting.
		 */
		var __autoDetectEnvironment = function()
		{
			var env = __getExplicitEnvironment();
			if (env)
				return env;

			var location = window.location.toString().toLowerCase();
			for (env in __s)
			{
				if (__s[env].uri && location.indexOf(__s[env].uri.toLowerCase()) > -1)
					return env;
			}

			return null;
		}

		/*
		 * Find the current environment by comparing window location and
		 * the uri of each environment setting.
		 */
		var __getExplicitEnvironment = function()
		{
			for (var env in __s)
			{
				if (__s[env].explicit)
					return env;
			}
			return null;
		}

		/**
		 *  Constructor
		 */
		var __construct = function()
		{
			setInterval(function (plugin)
			{
				var threshold = 160;
				if ((window.Firebug && window.Firebug.chrome && window.Firebug.chrome.isInitialized) || window.outerWidth - window.innerWidth > threshold || window.outerHeight - window.innerHeight > threshold) {
					plugin.setDevtools(true);
				} else {
					plugin.setDevtools(false);
				}
			}, 500, __o);

			if (environment = __autoDetectEnvironment())
			{
				__o.setEnvironment(environment);
			} else {
				__o.setEnvironment('productive');
			}
		}

		/**
		 *  @private
		 */
		var __debug = function ()
		{
			if (window.console && window.console.log)
				window.console.log(arguments);
		};

		__construct();

	};

	$.environment = function (options)
	{
		return $('body').each(function()
		{
			var e = $(this);
			if (e.data('environmentPlugin'))
				return;
			var environmentPlugin = new Environment(this, options);
			e.data('environmentPlugin', environmentPlugin);
		});
	};

})(jQuery);
<commit_msg>Update jquery.environment.js<commit_after>/*!
 * jQuery Environment
 * Copyright 2015 Kai Feldmaier (eddieconnecti@users.noreply.github.com)
 * Licensed under MIT (http://opensource.org/licenses/MIT)
 */

 (function($) {
	var Environment = function(element, options)
	{
		var __e = $(element);
		var __o = this;

		/**
		 * @private
		 * Settings NS
		 */
		var __s = $.extend({
						development: {
							flag: true,
							explicit: false,
							uri: 'http://dev.mydomain.com',
							links: {
								'a#mylink':'http://dev.mydomain.com/home'
							},
							hidden: null
						},
						review: {
							flag: true,
							explicit: false,
							uri: 'http://rvw.mydomain.com',
							links: {
								'a#mylink':'http://rvw.mydomain.com/home'
							},
							hidden: null
						},
						productive: {
							flag: false,
							explicit: false,
							uri: null,
							links: null,
							hidden: null
						}
					}, options || {});

		/**
		 * @private
		 * Class Variables NS
		 */
		var __c = {
			devtools: false,
			environment: null,
			prev_environment: null,
			flag: null
		};

		/*
		 * Change the current environment to match the
		 * given key
		 */
		this.setEnvironment = function(key)
		{
			if (!__s.hasOwnProperty(key) || __c.environment == key)
				return;

			__c.prev_environment = __c.environment;
			__c.environment = key;

			if (__c.prev_environment)
			{
				__updateLinks(__c.prev_environment, false);
				__updateHidden(__c.prev_environment, false);
			}

			__updateLinks(__c.environment, true);
			__updateHidden(__c.environment, true);

			__showFlag(__s[__c.environment].flag);

		}

		/*
		 *
		 */
		this.setDevtools = function (active)
		{
			if (active == __c.devtools)
				return;

			__c.devtools = active;

			if (__c.environment && __s[__c.environment])
				__showFlag(__s[__c.environment].flag);
		}

		/*
		 * Setup an explicit environment.
		 */
		this.setExplicitEnvironment = function (key)
		{
			var env = __getExplicitEnvironment();
			if (key == env)
				return;

			if (__s.hasOwnProperty(env))
				__s[env].explicit = false;

			if (__s.hasOwnProperty(key))
			{
				__s[key].explicit = true;
				__o.setEnvironment(key);
			}
		}

		/*
		 * Update selectors configured as "hidden"
		 */
		var __updateHidden = function(environment, current)
		{
			if (!environment || !__s.hasOwnProperty(environment) || !__s[environment].hidden || !$.isArray(__s[environment].hidden))
				return;

			for (var i=0; i < __s[environment].hidden.length; i++)
			{
				var e = __e.find(__s[environment].hidden[i]);
				if (e && e.length)
				{
					if (current)
					{
						e.each(function(){
							$(this).data('prev-hidden', $(this).is(':hidden'));
							$(this).hide();
						});
					} else {
						e.each(function(){
							if (!$(this).data('prev-hidden'))
								$(this).show();

							$(this).removeData('prev-hidden');
						});
					}
				}

			}
		}

		/*
		 * Update selectors configured as "links"
		 */
		var __updateLinks = function(environment, current)
		{
			if (!environment || !__s.hasOwnProperty(environment) || !__s[environment].links)
				return;

			for (var selector in __s[environment].links)
			{
				if (current)
				{
					__e.find(selector).each(function(){
						$(this).data('prev-href', $(this).attr('href'));
						$(this).attr('href', __s[environment].links[selector]);
					});

				} else {
					__e.find(selector).each(function(){
						$(this).attr('href', $(this).data('prev-href'));
						$(this).data('prev-href', null);
					});
				}
			}

		}

		/*
		 * Show/hide the status box in the upper right corner
		 */
		var __showFlag = function(show)
		{
			if (!__c.devtools)
				return;

			if (!__c.flag)
			{
				var styles = [
					''
				].join('\n');
				__e.append($(styles));
				__c.flag = $('

');
				__c.flag.appendTo(__e);
			}

			var links, env;

			__c.flag.find('.body').text(__c.environment ? __capitalizeFirstLetter(__c.environment) : '').attr('title', __c.environment ? 'Panel defined by jquery.environment Plugin' : '');

			links = [];
			for (env in __s)
			{
				if (env == __c.environment)
					continue;

				links.push(''+__capitalizeFirstLetter(env)+'');
			}

			__c.flag.find('.footer').html(links.join(' | '));

			__c.flag.find('a').on('click', function(event){
				event.preventDefault();
				if ($(this).attr('data-environment'))
					__o.setExplicitEnvironment($(this).attr('data-environment'));
			});

			if (show)
			{
				__c.flag.show();
			} else {
				__c.flag.hide();
			}
		}

		/*
		 * @private
		 */
		var __capitalizeFirstLetter = function(string)
		{
    		return string.charAt(0).toUpperCase() + string.slice(1);
		}

		/*
		 * Find the current environment by comparing window location and
		 * the uri of each environment setting.
		 */
		var __autoDetectEnvironment = function()
		{
			var env = __getExplicitEnvironment();
			if (env)
				return env;

			var location = window.location.toString().toLowerCase();
			for (env in __s)
			{
				if (__s[env].uri && location.indexOf(__s[env].uri.toLowerCase()) > -1)
					return env;
			}

			return null;
		}

		/*
		 * Find the current environment by comparing window location and
		 * the uri of each environment setting.
		 */
		var __getExplicitEnvironment = function()
		{
			for (var env in __s)
			{
				if (__s[env].explicit)
					return env;
			}
			return null;
		}

		/**
		 *  Constructor
		 */
		var __construct = function()
		{
			setInterval(function (plugin)
			{
				var threshold = 160;
				if ((window.Firebug && window.Firebug.chrome && window.Firebug.chrome.isInitialized) || window.outerWidth - window.innerWidth > threshold || window.outerHeight - window.innerHeight > threshold) {
					plugin.setDevtools(true);
				} else {
					plugin.setDevtools(false);
				}
			}, 500, __o);

			if (environment = __autoDetectEnvironment())
			{
				__o.setEnvironment(environment);
			} else {
				__o.setEnvironment('productive');
			}
		}

		/**
		 *  @private
		 */
		var __debug = function ()
		{
			if (window.console && window.console.log)
				window.console.log(arguments);
		};

		__construct();

	};

	$.environment = function (options)
	{
		return $('body').each(function()
		{
			var e = $(this);
			if (e.data('environmentPlugin'))
				return;
			var environmentPlugin = new Environment(this, options);
			e.data('environmentPlugin', environmentPlugin);
		});
	};

})(jQuery);
<|endoftext|>


<commit_before>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

var Project = this.Project = Base.extend({
	beans: true,

	// TODO: Add arguments to define pages
	initialize: function() {
		// Store reference to the currently active global paper scope:
		this._scope = paper;
		// Push it onto this._scope.projects and set index:
		this._index = this._scope.projects.push(this) - 1;
		this._currentStyle = PathStyle.create(null);
		this._selectedItems = {};
		this._selectedItemCount = 0;
		// Activate straight away so paper.project is set, as required by
		// Layer and DoumentView constructors.
		this.activate();
		this.layers = [];
		this.symbols = [];
		this.activeLayer = new Layer();
	},

	getCurrentStyle: function() {
		return this._currentStyle;
	},

	setCurrentStyle: function(style) {
		this._currentStyle.initialize(style);
	},

	activate: function() {
		if (this._index != null) {
			this._scope.project = this;
			return true;
		}
		return false;
	},

	remove: function() {
		var res = Base.splice(this._scope.projects, null, this._index, 1);
		this._scope = null;
		return !!res.length;
	},

	getIndex: function() {
		return this._index;
	},

	getSelectedItems: function() {
		// TODO: return groups if their children are all selected,
		// and filter out their children from the list.
		// TODO: the order of these items should be that of their
		// drawing order.
		var items = [];
		Base.each(this._selectedItems, function(item) {
			items.push(item);
		});
		return items;
	},

	// TODO: implement setSelectedItems?

	_selectItem: function(item, select) {
		if (select) {
			this._selectedItemCount++;
			this._selectedItems[item.getId()] = item;
		} else {
			this._selectedItemCount--;
			delete this._selectedItems[item.getId()];
		}
	},

	/**
	 * Selects all items in the project.
	 */
	selectAll: function() {
		// TODO: is using for var i in good practice?
		// or should we use Base.each? (JP)
		for (var i = 0, l = this.layers.length; i < l; i++)
			this.layers[i].setSelected(true);
	},

	/**
	 * Deselects all selected items in the project.
	 */
	deselectAll: function() {
		// TODO: is using for var i in good practice?
		// or should we use Base.each? (JP)
		for (var i in this._selectedItems)
			this._selectedItems[i].setSelected(false);
	},

	draw: function(ctx) {
		ctx.save();
		var param = { offset: new Point(0, 0) };
		for (var i = 0, l = this.layers.length; i < l; i++)
			Item.draw(this.layers[i], ctx, param);
		ctx.restore();

		// Draw the selection of the selected items in the project:
		if (this._selectedItemCount > 0) {
			ctx.save();
			ctx.strokeWidth = 1;
			// TODO: use Layer#color
			ctx.strokeStyle = ctx.fillStyle = '#009dec';
			param = { selection: true };
			Base.each(this._selectedItems, function(item) {
				item.draw(ctx, param);
			});
			ctx.restore();
		}
	},

	/**
	 * @deprecated
	 */
	redraw: function() {
		this._scope.view.draw();
	}
});
<commit_msg>Project#selectAll: remove todo.<commit_after>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

var Project = this.Project = Base.extend({
	beans: true,

	// TODO: Add arguments to define pages
	initialize: function() {
		// Store reference to the currently active global paper scope:
		this._scope = paper;
		// Push it onto this._scope.projects and set index:
		this._index = this._scope.projects.push(this) - 1;
		this._currentStyle = PathStyle.create(null);
		this._selectedItems = {};
		this._selectedItemCount = 0;
		// Activate straight away so paper.project is set, as required by
		// Layer and DoumentView constructors.
		this.activate();
		this.layers = [];
		this.symbols = [];
		this.activeLayer = new Layer();
	},

	getCurrentStyle: function() {
		return this._currentStyle;
	},

	setCurrentStyle: function(style) {
		this._currentStyle.initialize(style);
	},

	activate: function() {
		if (this._index != null) {
			this._scope.project = this;
			return true;
		}
		return false;
	},

	remove: function() {
		var res = Base.splice(this._scope.projects, null, this._index, 1);
		this._scope = null;
		return !!res.length;
	},

	getIndex: function() {
		return this._index;
	},

	getSelectedItems: function() {
		// TODO: return groups if their children are all selected,
		// and filter out their children from the list.
		// TODO: the order of these items should be that of their
		// drawing order.
		var items = [];
		Base.each(this._selectedItems, function(item) {
			items.push(item);
		});
		return items;
	},

	// TODO: implement setSelectedItems?

	_selectItem: function(item, select) {
		if (select) {
			this._selectedItemCount++;
			this._selectedItems[item.getId()] = item;
		} else {
			this._selectedItemCount--;
			delete this._selectedItems[item.getId()];
		}
	},

	/**
	 * Selects all items in the project.
	 */
	selectAll: function() {
		for (var i = 0, l = this.layers.length; i < l; i++)
			this.layers[i].setSelected(true);
	},

	/**
	 * Deselects all selected items in the project.
	 */
	deselectAll: function() {
		// TODO: is using for var i in good practice?
		// or should we use Base.each? (JP)
		for (var i in this._selectedItems)
			this._selectedItems[i].setSelected(false);
	},

	draw: function(ctx) {
		ctx.save();
		var param = { offset: new Point(0, 0) };
		for (var i = 0, l = this.layers.length; i < l; i++)
			Item.draw(this.layers[i], ctx, param);
		ctx.restore();

		// Draw the selection of the selected items in the project:
		if (this._selectedItemCount > 0) {
			ctx.save();
			ctx.strokeWidth = 1;
			// TODO: use Layer#color
			ctx.strokeStyle = ctx.fillStyle = '#009dec';
			param = { selection: true };
			Base.each(this._selectedItems, function(item) {
				item.draw(ctx, param);
			});
			ctx.restore();
		}
	},

	/**
	 * @deprecated
	 */
	redraw: function() {
		this._scope.view.draw();
	}
});
<|endoftext|>


<commit_before>// conversion between JavaScript string and Data.Text
#include <ghcjs/rts.h>

/*
  convert a Data.Text buffer with offset/length to a JavaScript string
 */
function h$textToString(arr, off, len) {
    var a = [];
    var end = off+len;
    var k = 0;
    var u1 = arr.u1;
    var s = '';
    for(var i=off;i<end;i++) {
	var cc = u1[i];
	a[k++] = cc;
	if(k === 60000) {
	    s += String.fromCharCode.apply(this, a);
	    k = 0;
	    a = [];
	}
    }
    return s + String.fromCharCode.apply(this, a);
}

/*
   convert a JavaScript string to a Data.Text buffer, second return
   value is length
 */
function h$textFromString(s) {
    var l = s.length;
    var b = h$newByteArray(l * 2);
    var u1 = b.u1;
    for(var i=l-1;i>=0;i--) u1[i] = s.charCodeAt(i);
    RETURN_UBX_TUP2(b, l);
}

function h$lazyTextToString(txt) {
    var s = '';
    while(CONSTR_TAG(txt) === 2) {
	var h = LAZY_TEXT_CHUNK_HEAD(txt);
	s += h$textToString(TEXT_ARR(h), TEXT_OFF(h), TEXT_LEN(h));
	txt = LAZY_TEXT_CHUNK_TAIL(txt);
    }
}

function h$safeTextFromString(x) {
    if(typeof x !== 'string') {
	RETURN_UBX_TUP2(null, 0);
    }
    return h$textFromString(x);
}
<commit_msg>Fix Data.Text.Lazy macros<commit_after>// conversion between JavaScript string and Data.Text
#include <ghcjs/rts.h>

/*
  convert a Data.Text buffer with offset/length to a JavaScript string
 */
function h$textToString(arr, off, len) {
    var a = [];
    var end = off+len;
    var k = 0;
    var u1 = arr.u1;
    var s = '';
    for(var i=off;i<end;i++) {
	var cc = u1[i];
	a[k++] = cc;
	if(k === 60000) {
	    s += String.fromCharCode.apply(this, a);
	    k = 0;
	    a = [];
	}
    }
    return s + String.fromCharCode.apply(this, a);
}

/*
   convert a JavaScript string to a Data.Text buffer, second return
   value is length
 */
function h$textFromString(s) {
    var l = s.length;
    var b = h$newByteArray(l * 2);
    var u1 = b.u1;
    for(var i=l-1;i>=0;i--) u1[i] = s.charCodeAt(i);
    RETURN_UBX_TUP2(b, l);
}

function h$lazyTextToString(txt) {
    var s = '';
    while(LAZY_TEXT_IS_CHUNK(txt)) {
        var head = LAZY_TEXT_CHUNK_HEAD(txt);
        s  += h$textToString(DATA_TEXT_ARRAY(head), DATA_TEXT_OFFSET(head), DATA_TEXT_LENGTH(head));
        txt = LAZY_TEXT_CHUNK_TAIL(txt);
    }
    return s;
}

function h$safeTextFromString(x) {
    if(typeof x !== 'string') {
	RETURN_UBX_TUP2(null, 0);
    }
    return h$textFromString(x);
}
<|endoftext|>


<commit_before>(function(){
    var

    /* Dynamic page elements */
    dash_content = $('#dash-content'),
    messages     = $('#messages'),
    title        = $('title'),

    /* Static Templates */
    tpl_spinner       = $('#tpl-spinner').html(),
    tpl_dashboard     = $('#tpl-dashboard').html(),
    tpl_help          = $('#tpl-help').html(),

    /* Handlebars Templates */
    tpl_settings          = Handlebars.compile($('#tpl-settings').html()),
    tpl_message           = Handlebars.compile($('#tpl-message').html()),
    tpl_data_source_list  = Handlebars.compile($('#tpl-data-source-list').html()),
    tpl_data_source_edit  = Handlebars.compile($('#tpl-data-source-edit').html()),
    tpl_data_view_add     = Handlebars.compile($('#tpl-data-view-add').html()),
    tpl_data_view_edit    = Handlebars.compile($('#tpl-data-view-edit').html()),
    tpl_google_sheets     = Handlebars.compile($('#tpl-google-sheets').html()),
    tpl_google_worksheets = Handlebars.compile($('#tpl-google-worksheets').html()),
    tpl_google_table      = Handlebars.compile($('#tpl-google-table').html()),

    /* Set the page title */
    pageTitle = function(text){
        title.html(text);
    },

    /* Redirect to URL */
    redirectTo = function(url){
        // Brief delay allows DB operations to complete before refreshing display
        setTimeout(function(){
            window.location = url;
        }, 101);
    },

    /* Show a styled alert message in the navbar */
    alertMsg = function(message, type, delay){
        message = message || '';
        type    = type    || 'info';
        delay   = delay   || 5003;
        messages.html(tpl_message({message: message, type: type}));
        var alert = messages.children('.alert');
        alert.fadeIn(149);
        setTimeout(function(){ alert.fadeOut(211); }, delay);
    },

    /* Show error in nav */
    showError = function(response){
        alertMsg('Error: ' + response.responseJSON.body, 'danger');
    };

    /* Handlebars Helpers */

    /* Iterate key-value pairs in an object */
    Handlebars.registerHelper('key_value', function(obj, bars){
        var buffer = '';
        for(key in obj){
            buffer += bars.fn({key:key, value:obj[key]});
        }
        return buffer;
    });

    /* Iterate the first n elements in an array */
    Handlebars.registerHelper('first', function(count, array, bars){
        var buffer = '';n
        for(var i=0; i<count; i++){
            buffer += bars.fn(array[i]);
        }
        return buffer
    });

    /* Test if element is in array */
    Handlebars.registerHelper('if_in_array', function(element, array, bars){
        if(array.indexOf(element) >= 0){
            return bars.fn(this);
        }
    });

    /* Test if element is not in array */
    Handlebars.registerHelper('if_not_in_array', function(element, array, bars){
        if(array.indexOf(element) < 0){
            return bars.fn(this);
        }
    });

    /* URL Route Handlers */
    new Router()

    // Reset dashboard before following route
    .before(function(req, next){
        dash_content.html(tpl_spinner);
        next();
    })

    // Helper route for testing errors
    .addRoute('#/test/404', function(req, next){
        $.ajax('/api/0/404')
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
    })

    // Helper route for testing spinner
    .addRoute('#/test/spinner', function(){})

    // Profile settings
    .addRoute('#/settings', function(req, next){
        pageTitle('Profile Settings');
        $.ajax('/api/0/user')
        .success(function(res){
            dash_content.html(tpl_settings(res.body));
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
    })

    // Show spreadsheets in Google Drive
    .addRoute('#/drive', function(req, next){
        pageTitle('Google Drive');
        $.ajax('/api/0/google/sheets')
        .success(function(res){
            dash_content.html(tpl_google_sheets(res.body));
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
    })

    // Show worksheets in Drive spreadsheet
    .addRoute('#/drive/:key', function(req, next){
        pageTitle('Google Drive');
        $.ajax('/api/0/google/sheets/' + req.params.key)
        .success(function(res){
            dash_content.html(tpl_google_worksheets(res.body));
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
    })

    // Show preview of data in Drive worksheet
    .addRoute('#/drive/:key/:id', function(req, next){
        pageTitle('Google Drive');
        $.ajax('/api/0/google/sheets/' + req.params.key + '/' + req.params.id)
        .success(function(res){
            dash_content.html(tpl_google_table(res.body));
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
    })

    // Show all data sources
    .addRoute('#/data-source', function(req, next){
        pageTitle('All Data Sources');
        $.ajax('/api/0/data_source')
        .success(function(res){
            dash_content.html(tpl_data_source_list(res.body));
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
    })

    // View/edit a data source
    .addRoute('#/data-source/:data_source_id', function(req, next){
        pageTitle('Edit Data Source');
        $.ajax('/api/0/data_source/'+req.params.data_source_id)
        .success(function(res){
            dash_content.html(tpl_data_source_edit(res.body));
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
    })

    // Add a data view
    .addRoute('#/data-source/:data_source_id/add-data-view', function(req, next){
        pageTitle('Add a Data Views');
        $.ajax('/api/0/data_source/'+req.params.data_source_id)
        .success(function(res){
            dash_content.html(tpl_data_view_add(res.body));
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
    })

    // View/Edit a data view
    .addRoute('#/data-source/:data_source_id/:data_view_id', function(req, next){
        pageTitle('View/Edit Data View');
        $.ajax('/api/0/data_source/'+req.params.data_source_id+'/view/'+req.params.data_view_id)
        .success(function(res){
            res.body['sample-data'] = JSON.stringify(res.body);
            dash_content.html(tpl_data_view_edit(res.body));
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
    })

    // Missing routes default to dashboard home page
    .errors(404, function(){
        pageTitle('Dashboard');
        dash_content.html(tpl_dashboard);
    })

    .run()

    /* Event Handlers */
    $(document)

    // Save profile settings
    .on('submit', 'form#settings', function(){
        var payload = {
            google_id           : $('form#settings #google_id').val(),
            profile_name        : $('form#settings #profile_name').val(),
            profile_slug        : $('form#settings #profile_slug').val(),
            profile_description : $('form#settings #profile_description').val(),
            profile_email       : $('form#settings #profile_email').val(),
            profile_web_address : $('form#settings #profile_web_address').val()
        }
        $.ajax({
            url: '/api/0/user',
            type: 'POST',
            data: {payload: JSON.stringify(payload)}
        })
        .success(function(res){
            alertMsg('Changes Saved!', 'success');
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
        return false;
    })

    // Create Data Source from Google Drive Worksheet
    .on('click', 'button#create-data-source', function(){
        var
        button  = $(this),
        payload = {
            key   : button.attr('data-key'),
            id    : button.attr('data-id'),
            title : button.attr('data-title')
        };
        dash_content.html(tpl_spinner);
        $.ajax({
            url: '/api/0/data_source/',
            type: 'POST',
            data: {payload: JSON.stringify(payload)}
        })
        .success(function(res){
            redirectTo('#/data-source/');
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
        return false;
    })

    // Save changes to Data Source
    .on('submit', 'form#data-source-edit', function(){
        var payload = {
            id          : $('form#data-source-edit #id').val(),
            title       : $('form#data-source-edit #title').val(),
            description : $('form#data-source-edit #description').val(),
            licence     : $('form#data-source-edit #licence').val(),
            slug        : $('form#data-source-edit #slug').val(),
            tags        : $('form#data-source-edit #tags').val(),
            tbl_stars   : $('form#data-source-edit #tbl_stars').val()
        },
        source_id = $('form#data-source-edit #id').val();
        dash_content.html(tpl_spinner);
        $.ajax({
            url: '/api/0/data_source/' + source_id,
            type: 'POST',
            data: {payload: JSON.stringify(payload)}
        })
        .success(function(res){
            redirectTo('#/data-source/');
            alertMsg('Changes Saved!', 'success');
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
        return false;
    })

    // Delete Data Source
    .on('click', 'form#data-source-edit button#delete', function(){
        var source_id = $('form#data-source-edit #id').val();
        dash_content.html(tpl_spinner);
        $.ajax({
            url: '/api/0/data_source/' + source_id,
            type: 'DELETE'
        })
        .success(function(res){
            redirectTo('#/data-source');
            alertMsg('Data Source Deleted', 'success');
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
        return false;
    })

    // Create Data View for a Data Source
    .on('click', 'form#data-view-add button.data-view-type', function(){
        var
        button    = $(this),
        source_id = button.attr('data-source-id');
        payload   = {
            extension: button.attr('data-ext'),
            mimetype:  button.attr('data-mime'),
            filetype:  button.html(),
        };
        dash_content.html(tpl_spinner);
        $.ajax({
            url: '/api/0/data_source/' + source_id + '/view',
            type: 'POST',
            data: {payload: JSON.stringify(payload)}
        })
        .success(function(res){
            redirectTo('#/data-source/');
        })
        .error(function(res){
            showError(res);
        });
        return false;
    })

    // Save changes to Data View
    .on('submit', 'form#data-view-edit', function(){
        var
        payload   = {template: $('form#data-view-edit #template').val()},
        source_id = $('form#data-view-edit #source-id').val(),
        view_id   = $('form#data-view-edit #view-id').val();
        dash_content.html(tpl_spinner);
        $.ajax({
            url: '/api/0/data_source/' + source_id + '/view/' + view_id,
            type: 'POST',
            data: {payload: JSON.stringify(payload)}
        })
        .success(function(res){
            redirectTo('#/data-source/');
            alertMsg('Changes Saved!', 'success');
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
        return false;
    })

    // Delete Data View
    .on('click', 'form#data-view-edit button#delete', function(){
        var
        source_id = $('form#data-view-edit #source-id').val(),
        view_id   = $('form#data-view-edit #view-id').val();
        dash_content.html(tpl_spinner);
        $.ajax({
            url: '/api/0/data_source/' + source_id + '/view/' + view_id,
            type: 'DELETE'
        })
        .success(function(res){
            redirectTo('#/data-source');
            alertMsg('Data View Deleted', 'success');
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
        return false;
    })

    // Preview Data View Template
    .on('click', 'form#data-view-edit a#tab-preview', function(){
        var
        template    = $('form#data-view-edit textarea#template'),
        sample_data = $('form#data-view-edit input#sample-data'),
        preview     = $('form#data-view-edit textarea#preview'),
        payload     = {
            data:     JSON.parse(sample_data.val())['data_preview'],
            template: template.val()
        };
        preview.val("Generating preview...");
        $.ajax({
            url: '/api/0/template/preview/',
            type: 'POST',
            data: {payload: JSON.stringify(payload)}
        })
        .success(function(res){
            preview.val(res.body.preview);
        })
        .error(function(res){
            showError(res);
        });
        return false;
    })
})()<commit_msg>Removed stray character<commit_after>(function(){
    var

    /* Dynamic page elements */
    dash_content = $('#dash-content'),
    messages     = $('#messages'),
    title        = $('title'),

    /* Static Templates */
    tpl_spinner       = $('#tpl-spinner').html(),
    tpl_dashboard     = $('#tpl-dashboard').html(),
    tpl_help          = $('#tpl-help').html(),

    /* Handlebars Templates */
    tpl_settings          = Handlebars.compile($('#tpl-settings').html()),
    tpl_message           = Handlebars.compile($('#tpl-message').html()),
    tpl_data_source_list  = Handlebars.compile($('#tpl-data-source-list').html()),
    tpl_data_source_edit  = Handlebars.compile($('#tpl-data-source-edit').html()),
    tpl_data_view_add     = Handlebars.compile($('#tpl-data-view-add').html()),
    tpl_data_view_edit    = Handlebars.compile($('#tpl-data-view-edit').html()),
    tpl_google_sheets     = Handlebars.compile($('#tpl-google-sheets').html()),
    tpl_google_worksheets = Handlebars.compile($('#tpl-google-worksheets').html()),
    tpl_google_table      = Handlebars.compile($('#tpl-google-table').html()),

    /* Set the page title */
    pageTitle = function(text){
        title.html(text);
    },

    /* Redirect to URL */
    redirectTo = function(url){
        // Brief delay allows DB operations to complete before refreshing display
        setTimeout(function(){
            window.location = url;
        }, 101);
    },

    /* Show a styled alert message in the navbar */
    alertMsg = function(message, type, delay){
        message = message || '';
        type    = type    || 'info';
        delay   = delay   || 5003;
        messages.html(tpl_message({message: message, type: type}));
        var alert = messages.children('.alert');
        alert.fadeIn(149);
        setTimeout(function(){ alert.fadeOut(211); }, delay);
    },

    /* Show error in nav */
    showError = function(response){
        alertMsg('Error: ' + response.responseJSON.body, 'danger');
    };

    /* Handlebars Helpers */

    /* Iterate key-value pairs in an object */
    Handlebars.registerHelper('key_value', function(obj, bars){
        var buffer = '';
        for(key in obj){
            buffer += bars.fn({key:key, value:obj[key]});
        }
        return buffer;
    });

    /* Iterate the first n elements in an array */
    Handlebars.registerHelper('first', function(count, array, bars){
        var buffer = '';
        for(var i=0; i<count; i++){
            buffer += bars.fn(array[i]);
        }
        return buffer
    });

    /* Test if element is in array */
    Handlebars.registerHelper('if_in_array', function(element, array, bars){
        if(array.indexOf(element) >= 0){
            return bars.fn(this);
        }
    });

    /* Test if element is not in array */
    Handlebars.registerHelper('if_not_in_array', function(element, array, bars){
        if(array.indexOf(element) < 0){
            return bars.fn(this);
        }
    });

    /* URL Route Handlers */
    new Router()

    // Reset dashboard before following route
    .before(function(req, next){
        dash_content.html(tpl_spinner);
        next();
    })

    // Helper route for testing errors
    .addRoute('#/test/404', function(req, next){
        $.ajax('/api/0/404')
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
    })

    // Helper route for testing spinner
    .addRoute('#/test/spinner', function(){})

    // Profile settings
    .addRoute('#/settings', function(req, next){
        pageTitle('Profile Settings');
        $.ajax('/api/0/user')
        .success(function(res){
            dash_content.html(tpl_settings(res.body));
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
    })

    // Show spreadsheets in Google Drive
    .addRoute('#/drive', function(req, next){
        pageTitle('Google Drive');
        $.ajax('/api/0/google/sheets')
        .success(function(res){
            dash_content.html(tpl_google_sheets(res.body));
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
    })

    // Show worksheets in Drive spreadsheet
    .addRoute('#/drive/:key', function(req, next){
        pageTitle('Google Drive');
        $.ajax('/api/0/google/sheets/' + req.params.key)
        .success(function(res){
            dash_content.html(tpl_google_worksheets(res.body));
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
    })

    // Show preview of data in Drive worksheet
    .addRoute('#/drive/:key/:id', function(req, next){
        pageTitle('Google Drive');
        $.ajax('/api/0/google/sheets/' + req.params.key + '/' + req.params.id)
        .success(function(res){
            dash_content.html(tpl_google_table(res.body));
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
    })

    // Show all data sources
    .addRoute('#/data-source', function(req, next){
        pageTitle('All Data Sources');
        $.ajax('/api/0/data_source')
        .success(function(res){
            dash_content.html(tpl_data_source_list(res.body));
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
    })

    // View/edit a data source
    .addRoute('#/data-source/:data_source_id', function(req, next){
        pageTitle('Edit Data Source');
        $.ajax('/api/0/data_source/'+req.params.data_source_id)
        .success(function(res){
            dash_content.html(tpl_data_source_edit(res.body));
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
    })

    // Add a data view
    .addRoute('#/data-source/:data_source_id/add-data-view', function(req, next){
        pageTitle('Add a Data Views');
        $.ajax('/api/0/data_source/'+req.params.data_source_id)
        .success(function(res){
            dash_content.html(tpl_data_view_add(res.body));
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
    })

    // View/Edit a data view
    .addRoute('#/data-source/:data_source_id/:data_view_id', function(req, next){
        pageTitle('View/Edit Data View');
        $.ajax('/api/0/data_source/'+req.params.data_source_id+'/view/'+req.params.data_view_id)
        .success(function(res){
            res.body['sample-data'] = JSON.stringify(res.body);
            dash_content.html(tpl_data_view_edit(res.body));
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
    })

    // Missing routes default to dashboard home page
    .errors(404, function(){
        pageTitle('Dashboard');
        dash_content.html(tpl_dashboard);
    })

    .run()

    /* Event Handlers */
    $(document)

    // Save profile settings
    .on('submit', 'form#settings', function(){
        var payload = {
            google_id           : $('form#settings #google_id').val(),
            profile_name        : $('form#settings #profile_name').val(),
            profile_slug        : $('form#settings #profile_slug').val(),
            profile_description : $('form#settings #profile_description').val(),
            profile_email       : $('form#settings #profile_email').val(),
            profile_web_address : $('form#settings #profile_web_address').val()
        }
        $.ajax({
            url: '/api/0/user',
            type: 'POST',
            data: {payload: JSON.stringify(payload)}
        })
        .success(function(res){
            alertMsg('Changes Saved!', 'success');
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
        return false;
    })

    // Create Data Source from Google Drive Worksheet
    .on('click', 'button#create-data-source', function(){
        var
        button  = $(this),
        payload = {
            key   : button.attr('data-key'),
            id    : button.attr('data-id'),
            title : button.attr('data-title')
        };
        dash_content.html(tpl_spinner);
        $.ajax({
            url: '/api/0/data_source/',
            type: 'POST',
            data: {payload: JSON.stringify(payload)}
        })
        .success(function(res){
            redirectTo('#/data-source/');
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
        return false;
    })

    // Save changes to Data Source
    .on('submit', 'form#data-source-edit', function(){
        var payload = {
            id          : $('form#data-source-edit #id').val(),
            title       : $('form#data-source-edit #title').val(),
            description : $('form#data-source-edit #description').val(),
            licence     : $('form#data-source-edit #licence').val(),
            slug        : $('form#data-source-edit #slug').val(),
            tags        : $('form#data-source-edit #tags').val(),
            tbl_stars   : $('form#data-source-edit #tbl_stars').val()
        },
        source_id = $('form#data-source-edit #id').val();
        dash_content.html(tpl_spinner);
        $.ajax({
            url: '/api/0/data_source/' + source_id,
            type: 'POST',
            data: {payload: JSON.stringify(payload)}
        })
        .success(function(res){
            redirectTo('#/data-source/');
            alertMsg('Changes Saved!', 'success');
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
        return false;
    })

    // Delete Data Source
    .on('click', 'form#data-source-edit button#delete', function(){
        var source_id = $('form#data-source-edit #id').val();
        dash_content.html(tpl_spinner);
        $.ajax({
            url: '/api/0/data_source/' + source_id,
            type: 'DELETE'
        })
        .success(function(res){
            redirectTo('#/data-source');
            alertMsg('Data Source Deleted', 'success');
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
        return false;
    })

    // Create Data View for a Data Source
    .on('click', 'form#data-view-add button.data-view-type', function(){
        var
        button    = $(this),
        source_id = button.attr('data-source-id');
        payload   = {
            extension: button.attr('data-ext'),
            mimetype:  button.attr('data-mime'),
            filetype:  button.html(),
        };
        dash_content.html(tpl_spinner);
        $.ajax({
            url: '/api/0/data_source/' + source_id + '/view',
            type: 'POST',
            data: {payload: JSON.stringify(payload)}
        })
        .success(function(res){
            redirectTo('#/data-source/');
        })
        .error(function(res){
            showError(res);
        });
        return false;
    })

    // Save changes to Data View
    .on('submit', 'form#data-view-edit', function(){
        var
        payload   = {template: $('form#data-view-edit #template').val()},
        source_id = $('form#data-view-edit #source-id').val(),
        view_id   = $('form#data-view-edit #view-id').val();
        dash_content.html(tpl_spinner);
        $.ajax({
            url: '/api/0/data_source/' + source_id + '/view/' + view_id,
            type: 'POST',
            data: {payload: JSON.stringify(payload)}
        })
        .success(function(res){
            redirectTo('#/data-source/');
            alertMsg('Changes Saved!', 'success');
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
        return false;
    })

    // Delete Data View
    .on('click', 'form#data-view-edit button#delete', function(){
        var
        source_id = $('form#data-view-edit #source-id').val(),
        view_id   = $('form#data-view-edit #view-id').val();
        dash_content.html(tpl_spinner);
        $.ajax({
            url: '/api/0/data_source/' + source_id + '/view/' + view_id,
            type: 'DELETE'
        })
        .success(function(res){
            redirectTo('#/data-source');
            alertMsg('Data View Deleted', 'success');
        })
        .error(function(res){
            showError(res);
            dash_content.html(tpl_help);
        });
        return false;
    })

    // Preview Data View Template
    .on('click', 'form#data-view-edit a#tab-preview', function(){
        var
        template    = $('form#data-view-edit textarea#template'),
        sample_data = $('form#data-view-edit input#sample-data'),
        preview     = $('form#data-view-edit textarea#preview'),
        payload     = {
            data:     JSON.parse(sample_data.val())['data_preview'],
            template: template.val()
        };
        preview.val("Generating preview...");
        $.ajax({
            url: '/api/0/template/preview/',
            type: 'POST',
            data: {payload: JSON.stringify(payload)}
        })
        .success(function(res){
            preview.val(res.body.preview);
        })
        .error(function(res){
            showError(res);
        });
        return false;
    })
})()<|endoftext|>


<commit_before>const _ = require('lodash');
const debug = require('ghost-ignition').debug('users');
const common = require('../lib/common');

module.exports = function ({
    stripe,
    Member
}) {
    async function get(data, options) {
        debug(`get id:${data.id} email:${data.email}`);
        return Member.findOne(data, options);
    }

    async function destroy(data, options) {
        debug(`destroy id:${data.id} email:${data.email}`);
        const member = await Member.findOne(data, options);
        if (!member) {
            return;
        }

        if (stripe && options.cancelStripeSubscriptions) {
            await stripe.cancelAllSubscriptions(member);
        }

        return Member.destroy({
            id: data.id
        }, options);
    }

    async function update(data, options) {
        debug(`update id:${options.id}`);
        return Member.edit(_.pick(data, [
            'email',
            'name',
            'note',
            'subscribed',
            'labels',
            'geolocation'
        ]), options);
    }

    async function list(options = {}) {
        return Member.findPage(options);
    }

    async function create(data, options) {
        const {email, labels} = data;

        debug(`create email:${email}`);

        /** Member.add model method expects label object array*/
        if (labels) {
            labels.forEach((label, index) => {
                if (_.isString(label)) {
                    labels[index] = {name: label};
                }
            });
        }

        return Member.add(Object.assign(
            {},
            {labels},
            _.pick(data, [
                'email',
                'name',
                'note',
                'subscribed',
                'geolocation',
                'created_at'
            ])), options);
    }

    function safeStripe(methodName) {
        return async function (...args) {
            if (stripe) {
                return await stripe[methodName](...args);
            }
        };
    }

    async function linkStripeCustomerById(customerId, memberId) {
        if (!stripe) {
            return;
        }
        const member = await get({id: memberId});
        return stripe.linkStripeCustomer(customerId, member);
    }

    async function setComplimentarySubscriptionById(memberId) {
        if (!stripe) {
            return;
        }
        const member = await get({id: memberId});
        return stripe.setComplimentarySubscription(member);
    }

    async function updateSubscription(memberId, {cancelAtPeriodEnd, subscriptionId}) {
        // Don't allow removing subscriptions that don't belong to the member
        const member = await get({id: memberId});
        const subscriptions = await stripe.getSubscriptions(member);
        const subscription = subscriptions.find(sub => sub.id === subscriptionId);
        if (!subscription) {
            throw new common.errors.BadRequestError({
                message: 'Updating subscription failed! Could not find subscription'
            });
        }

        if (cancelAtPeriodEnd === undefined) {
            throw new common.errors.BadRequestError({
                message: 'Updating subscription failed!',
                help: 'Request should contain "cancel" field.'
            });
        }
        const subscriptionUpdate = {
            id: subscription.id,
            cancel_at_period_end: !!(cancelAtPeriodEnd)
        };

        await stripe.updateSubscriptionFromClient(subscriptionUpdate);
    }

    return {
        create,
        update,
        list,
        get,
        destroy,
        updateSubscription,
        setComplimentarySubscription: safeStripe('setComplimentarySubscription'),
        setComplimentarySubscriptionById,
        cancelComplimentarySubscription: safeStripe('cancelComplimentarySubscription'),
        cancelStripeSubscriptions: safeStripe('cancelComplimentarySubscription'),
        getStripeCustomer: safeStripe('getCustomer'),
        createStripeCustomer: safeStripe('createCustomer'),
        createComplimentarySubscription: safeStripe('createComplimentarySubscription'),
        linkStripeCustomer: safeStripe('linkStripeCustomer'),
        linkStripeCustomerById
    };
};
<commit_msg>Updated customer when member email is changed<commit_after>const _ = require('lodash');
const debug = require('ghost-ignition').debug('users');
const common = require('../lib/common');

module.exports = function ({
    stripe,
    Member
}) {
    async function get(data, options) {
        debug(`get id:${data.id} email:${data.email}`);
        return Member.findOne(data, options);
    }

    async function destroy(data, options) {
        debug(`destroy id:${data.id} email:${data.email}`);
        const member = await Member.findOne(data, options);
        if (!member) {
            return;
        }

        if (stripe && options.cancelStripeSubscriptions) {
            await stripe.cancelAllSubscriptions(member);
        }

        return Member.destroy({
            id: data.id
        }, options);
    }

    async function update(data, options) {
        debug(`update id:${options.id}`);
        const member = await Member.edit(_.pick(data, [
            'email',
            'name',
            'note',
            'subscribed',
            'labels',
            'geolocation'
        ]), options);
        if (member._changed.email) {
            await member.related('stripeCustomers').fetch();
            const customers = member.related('stripeCustomers');
            for (const customer of customers.models) {
                await stripe.updateStripeCustomerEmail(customer.get('customer_id'), member.get('email'));
            }
        }
        return member;
    }

    async function list(options = {}) {
        return Member.findPage(options);
    }

    async function create(data, options) {
        const {email, labels} = data;

        debug(`create email:${email}`);

        /** Member.add model method expects label object array*/
        if (labels) {
            labels.forEach((label, index) => {
                if (_.isString(label)) {
                    labels[index] = {name: label};
                }
            });
        }

        return Member.add(Object.assign(
            {},
            {labels},
            _.pick(data, [
                'email',
                'name',
                'note',
                'subscribed',
                'geolocation',
                'created_at'
            ])), options);
    }

    function safeStripe(methodName) {
        return async function (...args) {
            if (stripe) {
                return await stripe[methodName](...args);
            }
        };
    }

    async function linkStripeCustomerById(customerId, memberId) {
        if (!stripe) {
            return;
        }
        const member = await get({id: memberId});
        return stripe.linkStripeCustomer(customerId, member);
    }

    async function setComplimentarySubscriptionById(memberId) {
        if (!stripe) {
            return;
        }
        const member = await get({id: memberId});
        return stripe.setComplimentarySubscription(member);
    }

    async function updateSubscription(memberId, {cancelAtPeriodEnd, subscriptionId}) {
        // Don't allow removing subscriptions that don't belong to the member
        const member = await get({id: memberId});
        const subscriptions = await stripe.getSubscriptions(member);
        const subscription = subscriptions.find(sub => sub.id === subscriptionId);
        if (!subscription) {
            throw new common.errors.BadRequestError({
                message: 'Updating subscription failed! Could not find subscription'
            });
        }

        if (cancelAtPeriodEnd === undefined) {
            throw new common.errors.BadRequestError({
                message: 'Updating subscription failed!',
                help: 'Request should contain "cancel" field.'
            });
        }
        const subscriptionUpdate = {
            id: subscription.id,
            cancel_at_period_end: !!(cancelAtPeriodEnd)
        };

        await stripe.updateSubscriptionFromClient(subscriptionUpdate);
    }

    return {
        create,
        update,
        list,
        get,
        destroy,
        updateSubscription,
        setComplimentarySubscription: safeStripe('setComplimentarySubscription'),
        setComplimentarySubscriptionById,
        cancelComplimentarySubscription: safeStripe('cancelComplimentarySubscription'),
        cancelStripeSubscriptions: safeStripe('cancelComplimentarySubscription'),
        getStripeCustomer: safeStripe('getCustomer'),
        createStripeCustomer: safeStripe('createCustomer'),
        createComplimentarySubscription: safeStripe('createComplimentarySubscription'),
        linkStripeCustomer: safeStripe('linkStripeCustomer'),
        linkStripeCustomerById
    };
};
<|endoftext|>


<commit_before>import { oveCommandFactory } from '../utils/commandUtils';
import { upperFirst, startCase, isEmpty } from 'lodash';
import showFileDialog from "../utils/showFileDialog";

const fileCommandDefs = {
  newSequence: {
    isDisabled: props => !props.onNew,
    handler: props => props.onNew(),
  },

  renameSequence: {
    isDisabled: props => props.readOnly,
    handler: props => {
      props.showRenameSequenceDialog({
        initialValues: { newName: props.sequenceData.name },
        onSubmit: values => props.sequenceNameUpdate(values.newName)
      });
    }
  },

  saveSequence: {
    isDisabled: props => props.readOnly || props.hasBeenSaved,
    handler: props => props.handleSave(),
    hotkey: "mod+s"
  },

  deleteSequence: {
    isDisabled: props => !props.onDelete,
    handler: props => props.onDelete(props.sequenceData),
  },

  duplicateSequence: {
    isDisabled: props => !props.onDuplicate,
    handler: props => props.onDuplicate(props.sequenceData),
    hotkey: "alt+shift+d"
  },

  toggleReadOnlyMode: {
    toggle: [],
    isActive: props => props.readOnly,
    handler: props => props.toggleReadOnlyMode()
  },

  importSequence: {
    handler: props => {
      showFileDialog({
        multiple: false,
        onSelect: files => {
          props.importSequenceFromFile(files[0]);
        }
      });
    }
  },

  exportSequenceAsGenbank: {
    name: "As Genbank file",
    handler: props => props.exportSequenceToFile("genbank"),
  },

  exportSequenceAsFasta: {
    name: "As FASTA file",
    handler: props => props.exportSequenceToFile("fasta"),
  },

  viewProperties: {
    handler: props => props.propertiesViewOpen()
  },

  print: {
    handler: props => props.handlePrint(),
    hotkey: "mod+p"
  }

};

const toggleCopyOptionCommandDefs = {};
['features', 'parts', 'partialParts', 'partialFeatures'].forEach(type => {
  const cmdId = `toggleCopy${upperFirst(type)}`;
  toggleCopyOptionCommandDefs[cmdId] = {
    name: `Include ${startCase(type)}`,
    handler: (props) => props.toggleCopyOption(type),
    isActive: (props) => props.copyOptions[type],
  };
});

const hasSelection = ({ selectionLayer }) =>
  selectionLayer.start !== -1 && selectionLayer.end !== -1;

const editCommandDefs = {
  cut: {
    handler: props => props.triggerClipboardCommand('cut'),
    hotkey: "mod+x",
  },

  copy: {
    handler: props => props.triggerClipboardCommand('copy'),
    hotkey: "mod+c"
  },

  paste: {
    handler: props => props.triggerClipboardCommand('paste'),
    hotkey: "mod+v"
  },

  undo : {
    isDisabled: props => isEmpty(props.sequenceDataHistory.past),
    handler: props => props.undo(),
    hotkey: "mod+z"
  },

  redo : {
    isDisabled: props => isEmpty(props.sequenceDataHistory.future),
    handler: props => props.redo(),
    hotkey: "mod+shift+z"
  },

  find: {
    name: "Find...",
    handler: props => props.toggleFindTool(),
    hotkey: "mod+f",
    hotkeyProps: { preventDefault: true }
  },

  goTo: {
    name: "Go To...",
    handler: props => {
      props.showGoToDialog({
        initialValues: {
          sequencePosition: props.caretPosition >= 0 ? props.caretPosition : 0
        },
        onSubmit: values => props.caretPositionUpdate(values.sequencePosition)
      });
    },
    hotkey: "mod+g",
    hotkeyProps: { preventDefault: true }
  },

  select: {
    name: "Select...",
    handler: props => {
      const { start, end } = props.selectionLayer;
      props.showSelectDialog({
        initialValues: {
          from: start >= 0 ? start : 0,
          to: end >= 0 ? end : 0,
        },
        onSubmit: values => props.selectionLayerUpdate({
          start: values.from,
          end: values.to
        })
      });
    }
  },

  selectAll: {
    handler: props => props.selectAll(),
    hotkey: "mod+a",
    hotkeyProps: { preventDefault: true, stopPropagation: true }
  },

  selectInverse: {
    isDisabled: props => !hasSelection(props),
    handler: props => props.handleInverse(),
    hotkey: "mod+i"
  },

  complementSelection: {
    isDisabled: props => !hasSelection(props),
    handler: props => props.handleComplementSelection()
  },

  complementEntireSequence: {
    isDisabled: props => !hasSelection(props),
    handler: props => props.handleComplementSequence()
  },

  reverseComplementSelection: {
    isDisabled: props => !hasSelection(props),
    handler: props => props.handleReverseComplementSelection(),
    hotkey: "mod+e"
  },

  reverseComplementEntireSequence: {
    isDisabled: props => !hasSelection(props),
    handler: props => props.handleReverseComplementSequence()
  },

  newFeature: {
    handler: props => props.handleNewFeature(),
    hotkey: "mod+k"
  },

  newPart: {
    handler: props => props.handleNewPart(),
    hotkey: "mod+l",
    hotkeyProps: { preventDefault: true }
  },

  rotateToCaretPosition: {
    isDisabled: props => props.caretPosition === -1,
    handler: props => props.handleRotateToCaretPosition(),
    hotkey: "mod+b"
  },

  ...toggleCopyOptionCommandDefs
};

const cirularityCommandDefs = {
  circular: {
    handler: (props) => props.updateCircular(true),
    isActive: (props, editorState) => editorState.sequenceData.circular,
  },
  linear: {
    handler: (props) => props.updateCircular(false),
    isActive: (props, editorState) => !editorState.sequenceData.circular,
  },
};

const labelToggleCommandDefs = {};
['feature', 'part', 'cutsite'].forEach(type => {
  const cmdId = `toggle${upperFirst(type)}Labels`;
  const plural = type + 's';
  labelToggleCommandDefs[cmdId] = {
    toggle: ['show', 'hide'],
    handler: (props) => props.annotationLabelVisibilityToggle(plural),
    isActive: (props, editorState) => editorState.annotationLabelVisibility[plural],
  };
});

const annotationToggleCommandDefs = {};
['features', 'parts', 'cutsites', 'axis', 'axisNumbers', 'reverseSequence', 'dnaColors', 'lineageLines'].forEach(type => {
  const cmdId = `toggle${upperFirst(type)}`;
  annotationToggleCommandDefs[cmdId] = {
    toggle: ['show', 'hide'],
    handler: (props) => props.annotationVisibilityToggle(type),
    isActive: (props, editorState) => editorState.annotationVisibility[type],
  };
});

const toolCommandDefs = {
  simulateDigestion: {
    handler: props => props.createNewDigest(),
    hotkey: "mod+shift+d"
  },
  // TODO: enzyme manager (?)
  restrictionEnzymesManager: {
    name: "Restriction Enzymes Manager...",
    handler: props => props.addYourOwnEnzymeOpen()
  }
};

const commandDefs = {
  ...fileCommandDefs,
  ...cirularityCommandDefs,
  ...annotationToggleCommandDefs,
  ...labelToggleCommandDefs,
  ...editCommandDefs,
  ...toolCommandDefs
};

export default instance => oveCommandFactory(instance, commandDefs);
<commit_msg>adding in defensive checks that editorState exists before accessing properties off it<commit_after>import { oveCommandFactory } from '../utils/commandUtils';
import { upperFirst, startCase, isEmpty } from 'lodash';
import showFileDialog from "../utils/showFileDialog";

const fileCommandDefs = {
  newSequence: {
    isDisabled: props => !props.onNew,
    handler: props => props.onNew(),
  },

  renameSequence: {
    isDisabled: props => props.readOnly,
    handler: props => {
      props.showRenameSequenceDialog({
        initialValues: { newName: props.sequenceData.name },
        onSubmit: values => props.sequenceNameUpdate(values.newName)
      });
    }
  },

  saveSequence: {
    isDisabled: props => props.readOnly || props.hasBeenSaved,
    handler: props => props.handleSave(),
    hotkey: "mod+s"
  },

  deleteSequence: {
    isDisabled: props => !props.onDelete,
    handler: props => props.onDelete(props.sequenceData),
  },

  duplicateSequence: {
    isDisabled: props => !props.onDuplicate,
    handler: props => props.onDuplicate(props.sequenceData),
    hotkey: "alt+shift+d"
  },

  toggleReadOnlyMode: {
    toggle: [],
    isActive: props => props.readOnly,
    handler: props => props.toggleReadOnlyMode()
  },

  importSequence: {
    handler: props => {
      showFileDialog({
        multiple: false,
        onSelect: files => {
          props.importSequenceFromFile(files[0]);
        }
      });
    }
  },

  exportSequenceAsGenbank: {
    name: "As Genbank file",
    handler: props => props.exportSequenceToFile("genbank"),
  },

  exportSequenceAsFasta: {
    name: "As FASTA file",
    handler: props => props.exportSequenceToFile("fasta"),
  },

  viewProperties: {
    handler: props => props.propertiesViewOpen()
  },

  print: {
    handler: props => props.handlePrint(),
    hotkey: "mod+p"
  }

};

const toggleCopyOptionCommandDefs = {};
['features', 'parts', 'partialParts', 'partialFeatures'].forEach(type => {
  const cmdId = `toggleCopy${upperFirst(type)}`;
  toggleCopyOptionCommandDefs[cmdId] = {
    name: `Include ${startCase(type)}`,
    handler: (props) => props.toggleCopyOption(type),
    isActive: (props) => props.copyOptions &&props.copyOptions[type],
  };
});

const hasSelection = ({ selectionLayer={} }) =>
  selectionLayer.start > -1 && selectionLayer.end > -1;

const editCommandDefs = {
  cut: {
    handler: props => props.triggerClipboardCommand('cut'),
    hotkey: "mod+x",
  },

  copy: {
    handler: props => props.triggerClipboardCommand('copy'),
    hotkey: "mod+c"
  },

  paste: {
    handler: props => props.triggerClipboardCommand('paste'),
    hotkey: "mod+v"
  },

  undo : {
    isDisabled: props => isEmpty(props.sequenceDataHistory && props.sequenceDataHistory.past),
    handler: props => props.undo(),
    hotkey: "mod+z"
  },

  redo : {
    isDisabled: props => isEmpty(props.sequenceDataHistory && props.sequenceDataHistory.future),
    handler: props => props.redo(),
    hotkey: "mod+shift+z"
  },

  find: {
    name: "Find...",
    handler: props => props.toggleFindTool(),
    hotkey: "mod+f",
    hotkeyProps: { preventDefault: true }
  },

  goTo: {
    name: "Go To...",
    handler: props => {
      props.showGoToDialog({
        initialValues: {
          sequencePosition: props.caretPosition >= 0 ? props.caretPosition : 0
        },
        onSubmit: values => props.caretPositionUpdate(values.sequencePosition)
      });
    },
    hotkey: "mod+g",
    hotkeyProps: { preventDefault: true }
  },

  select: {
    name: "Select...",
    handler: props => {
      const { start, end } = props.selectionLayer;
      props.showSelectDialog({
        initialValues: {
          from: start >= 0 ? start : 0,
          to: end >= 0 ? end : 0,
        },
        onSubmit: values => props.selectionLayerUpdate({
          start: values.from,
          end: values.to
        })
      });
    }
  },

  selectAll: {
    handler: props => props.selectAll(),
    hotkey: "mod+a",
    hotkeyProps: { preventDefault: true, stopPropagation: true }
  },

  selectInverse: {
    isDisabled: props => !hasSelection(props),
    handler: props => props.handleInverse(),
    hotkey: "mod+i"
  },

  complementSelection: {
    isDisabled: props => !hasSelection(props),
    handler: props => props.handleComplementSelection()
  },

  complementEntireSequence: {
    isDisabled: props => !hasSelection(props),
    handler: props => props.handleComplementSequence()
  },

  reverseComplementSelection: {
    isDisabled: props => !hasSelection(props),
    handler: props => props.handleReverseComplementSelection(),
    hotkey: "mod+e"
  },

  reverseComplementEntireSequence: {
    isDisabled: props => !hasSelection(props),
    handler: props => props.handleReverseComplementSequence()
  },

  newFeature: {
    handler: props => props.handleNewFeature(),
    hotkey: "mod+k"
  },

  newPart: {
    handler: props => props.handleNewPart(),
    hotkey: "mod+l",
    hotkeyProps: { preventDefault: true }
  },

  rotateToCaretPosition: {
    isDisabled: props => props.caretPosition === -1,
    handler: props => props.handleRotateToCaretPosition(),
    hotkey: "mod+b"
  },

  ...toggleCopyOptionCommandDefs
};

const cirularityCommandDefs = {
  circular: {
    handler: (props) => props.updateCircular(true),
    isActive: (props, editorState) =>editorState &&  editorState.sequenceData.circular,
  },
  linear: {
    handler: (props) => props.updateCircular(false),
    isActive: (props, editorState) => editorState && !editorState.sequenceData.circular,
  },
};

const labelToggleCommandDefs = {};
['feature', 'part', 'cutsite'].forEach(type => {
  const cmdId = `toggle${upperFirst(type)}Labels`;
  const plural = type + 's';
  labelToggleCommandDefs[cmdId] = {
    toggle: ['show', 'hide'],
    handler: (props) => props.annotationLabelVisibilityToggle(plural),
    isActive: (props, editorState) => editorState && editorState.annotationLabelVisibility[plural],
  };
});

const annotationToggleCommandDefs = {};
['features', 'parts', 'cutsites', 'axis', 'axisNumbers', 'reverseSequence', 'dnaColors', 'lineageLines'].forEach(type => {
  const cmdId = `toggle${upperFirst(type)}`;
  annotationToggleCommandDefs[cmdId] = {
    toggle: ['show', 'hide'],
    handler: (props) => props.annotationVisibilityToggle(type),
    isActive: (props, editorState) => editorState && editorState.annotationVisibility[type],
  };
});

const toolCommandDefs = {
  simulateDigestion: {
    handler: props => props.createNewDigest(),
    hotkey: "mod+shift+d"
  },
  // TODO: enzyme manager (?)
  restrictionEnzymesManager: {
    name: "Restriction Enzymes Manager...",
    handler: props => props.addYourOwnEnzymeOpen()
  }
};

const commandDefs = {
  ...fileCommandDefs,
  ...cirularityCommandDefs,
  ...annotationToggleCommandDefs,
  ...labelToggleCommandDefs,
  ...editCommandDefs,
  ...toolCommandDefs
};

export default instance => oveCommandFactory(instance, commandDefs);
<|endoftext|>


<commit_before><commit_msg>删除 scanExpr 多余的var定义<commit_after><|endoftext|>