<commit_before>var async = require ( 'async' );
var officegen = require('../lib/index.js');
var _ = require('lodash');
var async = require('async');

var fs = require('fs');
var path = require('path');

var pptx = officegen('pptx');

var slide;
var pObj;

pptx.on('finalize', function (written) {
  console.log('Finish to create a PowerPoint file.\nTotal bytes created: ' + written + '\n');

  // clear the temporatory files
});

pptx.on('error', function (err) {
  console.log(err);
});

pptx.setDocTitle('Sample PPTX Document');

function generateExampleSlides(callback) {
  // do the rest things here
  // console.log('finalize');

  // Let's create a new slide:
  slide = pptx.makeNewSlide();

  slide.name = 'The first slide!';

  // Change the background color:
  slide.back = '000000';

  // Declare the default color to use on this slide:
  slide.color = 'ffffff';

  // Basic way to add text string:
  slide.addText('Created using Officegen version ' + officegen.version);
  slide.addText('Fast position', 0, 20);
  slide.addText('Full line', 0, 40, '100%', 20);

  // Add text box with multi colors and fonts:
  slide.addText([
    { text: 'Hello ', options: { font_size: 56 } },
    { text: 'World!', options: { font_size: 56, font_face: 'Arial', color: 'ffff00' } }
  ], { cx: '75%', cy: 66, y: 150 });
  // Please note that you can pass object as the text parameter to addText.

  // For a single text just pass a text string to addText:
  slide.addText('Office generator', { y: 66, x: 'c', cx: '50%', cy: 60, font_size: 48, color: '0000ff' });

  pObj = slide.addText('Boom\nBoom!!!', { y: 100, x: 10, cx: '70%', font_face: 'Wide Latin', font_size: 54, color: 'cc0000', bold: true, underline: true });
  pObj.options.y += 150;

  // 2nd slide:
  slide = pptx.makeNewSlide();

  // For every color property (including the back color property) you can pass object instead of the color string:
  slide.back = { type: 'solid', color: '004400' };
  pObj = slide.addText('Office generator', { y: 'c', x: 0, cx: '100%', cy: 66, font_size: 48, align: 'center', color: { type: 'solid', color: '008800' } });
  pObj.setShadowEffect('outerShadow', { bottom: true, right: true });

  slide = pptx.makeNewSlide();

  slide.show = false;
  slide.addText('Red line', 'ff0000');
  slide.addShape(pptx.shapes.OVAL, { fill: { type: 'solid', color: 'ff0000', alpha: 50 }, line: 'ffff00', y: 50, x: 50 });
  slide.addText('Red box 1', { color: 'ffffff', fill: 'ff0000', line: 'ffff00', line_size: 5, y: 100, rotate: 45 });
  slide.addShape(pptx.shapes.LINE, { line: '0000ff', y: 150, x: 150, cy: 0, cx: 300 });
  slide.addShape(pptx.shapes.LINE, { line: '0000ff', y: 150, x: 150, cy: 100, cx: 0 });
  slide.addShape(pptx.shapes.LINE, { line: '0000ff', y: 249, x: 150, cy: 0, cx: 300 });
  slide.addShape(pptx.shapes.LINE, { line: '0000ff', y: 150, x: 449, cy: 100, cx: 0 });
  slide.addShape(pptx.shapes.LINE, { line: '000088', y: 150, x: 150, cy: 100, cx: 300 });
  slide.addShape(pptx.shapes.LINE, { line: '000088', y: 150, x: 150, cy: 100, cx: 300 });
  slide.addShape(pptx.shapes.LINE, { line: '000088', y: 170, x: 150, cy: 100, cx: 300, line_head: 'triangle' });
  slide.addShape(pptx.shapes.LINE, { line: '000088', y: 190, x: 150, cy: 100, cx: 300, line_tail: 'triangle' });
  slide.addShape(pptx.shapes.LINE, { line: '000088', y: 210, x: 150, cy: 100, cx: 300, line_head: 'stealth', line_tail: 'stealth' });
  pObj = slide.addShape(pptx.shapes.LINE);
  pObj.options.line = '008888';
  pObj.options.y = 210;
  pObj.options.x = 150;
  pObj.options.cy = 100;
  pObj.options.cx = 300;
  pObj.options.line_head = 'stealth';
  pObj.options.line_tail = 'stealth';
  pObj.options.flip_vertical = true;
  slide.addText('Red box 2', { color: 'ffffff', fill: 'ff0000', line: 'ffff00', y: 350, x: 200, shape: pptx.shapes.ROUNDED_RECTANGLE, indentLevel: 1 });

  slide = pptx.makeNewSlide();

  slide.addImage(path.resolve(__dirname, 'images_for_examples/image1.png'), { y: 'c', x: 'c' });

  slide = pptx.makeNewSlide();

  slide.addImage(path.resolve(__dirname, 'images_for_examples/image2.jpg'), { y: 0, x: 0, cy: '100%', cx: '100%' });

  slide = pptx.makeNewSlide();
  slide.addImage(path.resolve(__dirname, 'images_for_examples/image3.png'), { y: 'c', x: 'c'});

  slide = pptx.makeNewSlide();

  slide.addImage(path.resolve(__dirname, 'images_for_examples/image2.jpg'), { y: 0, x: 0, cy: '100%', cx: '100%' });

  slide = pptx.makeNewSlide();

  slide.addImage(path.resolve(__dirname, 'images_for_examples/image2.jpg'), { y: 0, x: 0, cy: '100%', cx: '100%' });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_001.png'), { y: 10, x: 10 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_002.png'), { y: 10, x: 110 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_001.png'), { y: 110, x: 10 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_001.png'), { y: 110, x: 110 });

  slide = pptx.makeNewSlide();

  slide.addImage(path.resolve(__dirname, 'images_for_examples/image2.jpg'), { y: 0, x: 0, cy: '100%', cx: '100%' });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_001.png'), { y: 10, x: 10 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_002.png'), 110, 10);
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_003.png'), { y: 10, x: 210 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_004.png'), { y: 110, x: 10 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_001.png'), { y: 110, x: 110 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_003.png'), { y: 110, x: 210 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_002.png'), { y: 210, x: 10 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_004.png'), { y: 210, x: 110 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_004.png'), { y: 210, x: 210 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_004.png'), { y: '310', x: 10 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_002.png'), { y: 310, x: 110 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_003.png'), { y: 310, x: 210 });

  callback();
}

function generateTable(callback) {
  slide = pptx.makeNewSlide();

  var rows = [];
  for (var i = 0; i < 12; i++) {
    var row = [];
    for (var j = 0; j < 5; j++) {
      row.push("[" + i + "," + j + "]");
    }
    rows.push(row);
  }
  slide.addTable(rows, {});
  callback();
}

function finalize() {
  var out = fs.createWriteStream('out.pptx');

  out.on('error', function (err) {
    console.log(err);
  });

  pptx.generate(out);
}

async.series([
  generateTable,
  generateExampleSlides // inherited from original project
], finalize);<commit_msg>For pptx addTable() : add example for the 2 last commits<commit_after>var async = require ( 'async' );
var officegen = require('../lib/index.js');
var _ = require('lodash');
var async = require('async');

var fs = require('fs');
var path = require('path');

var pptx = officegen('pptx');

var slide;
var pObj;

pptx.on('finalize', function (written) {
  console.log('Finish to create a PowerPoint file.\nTotal bytes created: ' + written + '\n');

  // clear the temporatory files
});

pptx.on('error', function (err) {
  console.log(err);
});

pptx.setDocTitle('Sample PPTX Document');

function generateExampleSlides(callback) {
  // do the rest things here
  // console.log('finalize');

  // Let's create a new slide:
  slide = pptx.makeNewSlide();

  slide.name = 'The first slide!';

  // Change the background color:
  slide.back = '000000';

  // Declare the default color to use on this slide:
  slide.color = 'ffffff';

  // Basic way to add text string:
  slide.addText('Created using Officegen version ' + officegen.version);
  slide.addText('Fast position', 0, 20);
  slide.addText('Full line', 0, 40, '100%', 20);

  // Add text box with multi colors and fonts:
  slide.addText([
    { text: 'Hello ', options: { font_size: 56 } },
    { text: 'World!', options: { font_size: 56, font_face: 'Arial', color: 'ffff00' } }
  ], { cx: '75%', cy: 66, y: 150 });
  // Please note that you can pass object as the text parameter to addText.

  // For a single text just pass a text string to addText:
  slide.addText('Office generator', { y: 66, x: 'c', cx: '50%', cy: 60, font_size: 48, color: '0000ff' });

  pObj = slide.addText('Boom\nBoom!!!', { y: 100, x: 10, cx: '70%', font_face: 'Wide Latin', font_size: 54, color: 'cc0000', bold: true, underline: true });
  pObj.options.y += 150;

  // 2nd slide:
  slide = pptx.makeNewSlide();

  // For every color property (including the back color property) you can pass object instead of the color string:
  slide.back = { type: 'solid', color: '004400' };
  pObj = slide.addText('Office generator', { y: 'c', x: 0, cx: '100%', cy: 66, font_size: 48, align: 'center', color: { type: 'solid', color: '008800' } });
  pObj.setShadowEffect('outerShadow', { bottom: true, right: true });

  slide = pptx.makeNewSlide();

  slide.show = false;
  slide.addText('Red line', 'ff0000');
  slide.addShape(pptx.shapes.OVAL, { fill: { type: 'solid', color: 'ff0000', alpha: 50 }, line: 'ffff00', y: 50, x: 50 });
  slide.addText('Red box 1', { color: 'ffffff', fill: 'ff0000', line: 'ffff00', line_size: 5, y: 100, rotate: 45 });
  slide.addShape(pptx.shapes.LINE, { line: '0000ff', y: 150, x: 150, cy: 0, cx: 300 });
  slide.addShape(pptx.shapes.LINE, { line: '0000ff', y: 150, x: 150, cy: 100, cx: 0 });
  slide.addShape(pptx.shapes.LINE, { line: '0000ff', y: 249, x: 150, cy: 0, cx: 300 });
  slide.addShape(pptx.shapes.LINE, { line: '0000ff', y: 150, x: 449, cy: 100, cx: 0 });
  slide.addShape(pptx.shapes.LINE, { line: '000088', y: 150, x: 150, cy: 100, cx: 300 });
  slide.addShape(pptx.shapes.LINE, { line: '000088', y: 150, x: 150, cy: 100, cx: 300 });
  slide.addShape(pptx.shapes.LINE, { line: '000088', y: 170, x: 150, cy: 100, cx: 300, line_head: 'triangle' });
  slide.addShape(pptx.shapes.LINE, { line: '000088', y: 190, x: 150, cy: 100, cx: 300, line_tail: 'triangle' });
  slide.addShape(pptx.shapes.LINE, { line: '000088', y: 210, x: 150, cy: 100, cx: 300, line_head: 'stealth', line_tail: 'stealth' });
  pObj = slide.addShape(pptx.shapes.LINE);
  pObj.options.line = '008888';
  pObj.options.y = 210;
  pObj.options.x = 150;
  pObj.options.cy = 100;
  pObj.options.cx = 300;
  pObj.options.line_head = 'stealth';
  pObj.options.line_tail = 'stealth';
  pObj.options.flip_vertical = true;
  slide.addText('Red box 2', { color: 'ffffff', fill: 'ff0000', line: 'ffff00', y: 350, x: 200, shape: pptx.shapes.ROUNDED_RECTANGLE, indentLevel: 1 });

  slide = pptx.makeNewSlide();

  slide.addImage(path.resolve(__dirname, 'images_for_examples/image1.png'), { y: 'c', x: 'c' });

  slide = pptx.makeNewSlide();

  slide.addImage(path.resolve(__dirname, 'images_for_examples/image2.jpg'), { y: 0, x: 0, cy: '100%', cx: '100%' });

  slide = pptx.makeNewSlide();
  slide.addImage(path.resolve(__dirname, 'images_for_examples/image3.png'), { y: 'c', x: 'c'});

  slide = pptx.makeNewSlide();

  slide.addImage(path.resolve(__dirname, 'images_for_examples/image2.jpg'), { y: 0, x: 0, cy: '100%', cx: '100%' });

  slide = pptx.makeNewSlide();

  slide.addImage(path.resolve(__dirname, 'images_for_examples/image2.jpg'), { y: 0, x: 0, cy: '100%', cx: '100%' });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_001.png'), { y: 10, x: 10 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_002.png'), { y: 10, x: 110 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_001.png'), { y: 110, x: 10 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_001.png'), { y: 110, x: 110 });

  slide = pptx.makeNewSlide();

  slide.addImage(path.resolve(__dirname, 'images_for_examples/image2.jpg'), { y: 0, x: 0, cy: '100%', cx: '100%' });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_001.png'), { y: 10, x: 10 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_002.png'), 110, 10);
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_003.png'), { y: 10, x: 210 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_004.png'), { y: 110, x: 10 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_001.png'), { y: 110, x: 110 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_003.png'), { y: 110, x: 210 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_002.png'), { y: 210, x: 10 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_004.png'), { y: 210, x: 110 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_004.png'), { y: 210, x: 210 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_004.png'), { y: '310', x: 10 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_002.png'), { y: 310, x: 110 });
  slide.addImage(path.resolve(__dirname, 'images_for_examples/sword_003.png'), { y: 310, x: 210 });

  callback();
}

function generateTable(callback) {
  slide = pptx.makeNewSlide();

  var rows = [];
  var columnWidths = [];
  for (var i = 0; i < 12; i++) {
    var row = [];
    for (var j = 0; j < 5; j++) {
      row.push("[" + i + "," + j + "]");
    }
    rows.push(row);
    columnWidths.push( 300*1000 + Math.round(Math.random()*800*1000) );
  }

  slide.addTable(rows, {font_size:9, font_face:"Comic Sans MS", columnWidths:columnWidths});
  callback();
}

function finalize() {
  var out = fs.createWriteStream('out.pptx');

  out.on('error', function (err) {
    console.log(err);
  });

  pptx.generate(out);
}

async.series([
  generateTable,
  generateExampleSlides // inherited from original project
], finalize);<|endoftext|>


<commit_before>// This code was written by Tyler Akins and has been placed in the
// public domain.  It would be nice if you left this header intact.
// Base64 code from Tyler Akins -- http://rumkin.com

var Base64 = (function () {
    var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

    var obj = {
        /**
         * Encodes a string in base64
         * @param {String} input The string to encode in base64.
         */
        encode: function (input) {
            var output = "";
            var chr1, chr2, chr3;
            var enc1, enc2, enc3, enc4;
            var i = 0;

            do {
                chr1 = input.charCodeAt(i++);
                chr2 = input.charCodeAt(i++);
                chr3 = input.charCodeAt(i++);

                enc1 = chr1 >> 2;
                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                enc4 = chr3 & 63;

                if (isNaN(chr2)) {
                    enc3 = enc4 = 64;
                } else if (isNaN(chr3)) {
                    enc4 = 64;
                }

                output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) +
                    keyStr.charAt(enc3) + keyStr.charAt(enc4);
            } while (i < input.length);

            return output;
        },

        /**
         * Decodes a base64 string.
         * @param {String} input The string to decode.
         */
        decode: function (input) {
            var output = "";
            var chr1, chr2, chr3;
            var enc1, enc2, enc3, enc4;
            var i = 0;

            // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
            input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

            do {
                enc1 = keyStr.indexOf(input.charAt(i++));
                enc2 = keyStr.indexOf(input.charAt(i++));
                enc3 = keyStr.indexOf(input.charAt(i++));
                enc4 = keyStr.indexOf(input.charAt(i++));

                chr1 = (enc1 << 2) | (enc2 >> 4);
                chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
                chr3 = ((enc3 & 3) << 6) | enc4;

                output = output + String.fromCharCode(chr1);

                if (enc3 != 64) {
                    output = output + String.fromCharCode(chr2);
                }
                if (enc4 != 64) {
                    output = output + String.fromCharCode(chr3);
                }
            } while (i < input.length);

            return output;
        }
    };

    return obj;
})();

window.Base64 = Base64
<commit_msg>chore(base64) rm Base64<commit_after>// This code was written by Tyler Akins and has been placed in the
// public domain.  It would be nice if you left this header intact.
// Base64 code from Tyler Akins -- http://rumkin.com

var Base64 = (function () {
    var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

    var obj = {
        /**
         * Encodes a string in base64
         * @param {String} input The string to encode in base64.
         */
        encode: function (input) {
            var output = "";
            var chr1, chr2, chr3;
            var enc1, enc2, enc3, enc4;
            var i = 0;

            do {
                chr1 = input.charCodeAt(i++);
                chr2 = input.charCodeAt(i++);
                chr3 = input.charCodeAt(i++);

                enc1 = chr1 >> 2;
                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                enc4 = chr3 & 63;

                if (isNaN(chr2)) {
                    enc3 = enc4 = 64;
                } else if (isNaN(chr3)) {
                    enc4 = 64;
                }

                output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) +
                    keyStr.charAt(enc3) + keyStr.charAt(enc4);
            } while (i < input.length);

            return output;
        },

        /**
         * Decodes a base64 string.
         * @param {String} input The string to decode.
         */
        decode: function (input) {
            var output = "";
            var chr1, chr2, chr3;
            var enc1, enc2, enc3, enc4;
            var i = 0;

            // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
            input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

            do {
                enc1 = keyStr.indexOf(input.charAt(i++));
                enc2 = keyStr.indexOf(input.charAt(i++));
                enc3 = keyStr.indexOf(input.charAt(i++));
                enc4 = keyStr.indexOf(input.charAt(i++));

                chr1 = (enc1 << 2) | (enc2 >> 4);
                chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
                chr3 = ((enc3 & 3) << 6) | enc4;

                output = output + String.fromCharCode(chr1);

                if (enc3 != 64) {
                    output = output + String.fromCharCode(chr2);
                }
                if (enc4 != 64) {
                    output = output + String.fromCharCode(chr3);
                }
            } while (i < input.length);

            return output;
        }
    };

    return obj;
})();
<|endoftext|>


<commit_before>global.window = self; // egregious hack to get magic-string to work in a worker

const svelteCache = new Map();

function loadSvelte(version) {
	if (!svelteCache.has(version)) {
		if (version === 'local') {
			svelteCache.set(version, import(/* webpackChunkName: "svelte" */ 'svelte'));
		} else {
			svelteCache.set(version, new Promise((fulfil => {
				importScripts(`https://unpkg.com/svelte@${version}/compiler/svelte.js`);
				fulfil(global.svelte);
			})))
		}
	}

	return svelteCache.get(version).then(svelte => {
		global.svelte = svelte;
	});
}

export async function init(version) {
	await Promise.all([
		import(/* webpackChunkName: "rollup" */ 'rollup/dist/rollup.browser.js').then(r => {
			global.rollup = r;
		}),
		loadSvelte(version)
	]);

	return version === 'local' ? version : svelte.VERSION;
}

let cached = {
	dom: null,
	ssr: null
};

let currentToken;

async function getBundle(mode, cache, lookup) {
	let bundle;
	let error;
	let warningCount = 0;

	const info = {};

	try {
		bundle = await rollup.rollup({
			input: './App.html',
			external: id => {
				return id[0] !== '.';
			},
			plugins: [{
				resolveId(importee, importer) {
					if (importee in lookup) return importee;
				},
				load(id) {
					if (id in lookup) return lookup[id].source;
				},
				transform(code, id) {
					if (!/\.html$/.test(id)) return null;

					const name = id.replace(/^\.\//, '').replace(/\.html$/, '');

					const { js, css, stats } = svelte.compile(code, {
						generate: mode,
						format: 'es',
						cascade: false,
						store: true,
						skipIntroByDefault: true,
						nestedTransitions: true,
						name: name,
						filename: name + '.html',
						dev: true,
						shared: false,
						onwarn: warning => {
							console.warn(warning.message);
							console.log(warning.frame);
							warningCount += 1;
						}
					});

					if (stats) {
						if (Object.keys(stats.hooks).filter(hook => stats.hooks[hook]).length > 0) info.usesHooks = true;
					} else if (/[^_]oncreate/.test(code)) {
						info.usesHooks = true;
					}

					return js;
				}
			}],
			onwarn(warning) {
				console.warn(warning);
				warningCount += 1;
			},
			cache
		});
	} catch (error) {
		return { error, bundle: null, info: null, warningCount: null }
	}

	return { bundle, info, error: null, warningCount };
}

export async function bundle(components) {
	console.clear();
	console.log(`running Svelte compiler version %c${svelte.VERSION}`, 'font-weight: bold');

	const token = currentToken = {};

	const lookup = {};
	components.forEach(component => {
		const path = `./${component.name}.${component.type}`;
		lookup[path] = component;
	});

	let dom;
	let error;

	try {
		dom = await getBundle('dom', cached.dom, lookup);
		if (dom.error) {
			throw dom.error;
		}

		if (token !== currentToken) return;

		cached.dom = dom.bundle;

		let uid = 1;
		const importMap = new Map();

		const domResult = await dom.bundle.generate({
			format: 'iife',
			name: 'SvelteComponent',
			globals: id => {
				const name = `import_${uid++}`;
				importMap.set(id, name);
				return name;
			},
			sourcemap: true
		});

		if (token !== currentToken) return;

		const ssr = dom.info.usesHooks
			? await getBundle('ssr', cached.ssr, lookup)
			: null;

		if (ssr) {
			cached.ssr = ssr.bundle;
			if (ssr.error) {
				throw ssr.error;
			}
		}

		if (token !== currentToken) return;

		const ssrResult = ssr
			? await ssr.bundle.generate({
				format: 'iife',
				name: 'SvelteComponent',
				globals: id => importMap.get(id),
				sourcemap: true
			})
			: null;

		return {
			bundle: {
				imports: dom.bundle.imports,
				importMap
			},
			dom: domResult,
			ssr: ssrResult,
			warningCount: dom.warningCount,
			error: null
		};
	} catch (err) {
		const e = error || err;
		delete e.toString;

		return {
			bundle: null,
			dom: null,
			ssr: null,
			warningCount: dom.warningCount,
			error: Object.assign({}, e, {
				message: e.message,
				stack: e.stack
			})
		};
	}
}

export function compile(component) {
	try {
		const { js } = svelte.compile(component.source, {
			// TODO make options configurable
			cascade: false,
			name: component.name,
			filename: component.name + '.html',
			dev: true
		});

		return js.code;
	} catch (err) {
		let result = `/* Error compiling component\n\n${err.message}`;
		if (err.frame) result += `\n${err.frame}`;
		result += `\n\n*/`;
		return result;
	}
}<commit_msg>repl: make displayed code and executed bundle use same compiler options<commit_after>global.window = self; // egregious hack to get magic-string to work in a worker

const commonCompilerOptions = {
	cascade: false,
	store: true,
	skipIntroByDefault: true,
	nestedTransitions: true,
	dev: true,
};

const svelteCache = new Map();

function loadSvelte(version) {
	if (!svelteCache.has(version)) {
		if (version === 'local') {
			svelteCache.set(version, import(/* webpackChunkName: "svelte" */ 'svelte'));
		} else {
			svelteCache.set(version, new Promise((fulfil => {
				importScripts(`https://unpkg.com/svelte@${version}/compiler/svelte.js`);
				fulfil(global.svelte);
			})))
		}
	}

	return svelteCache.get(version).then(svelte => {
		global.svelte = svelte;
	});
}

export async function init(version) {
	await Promise.all([
		import(/* webpackChunkName: "rollup" */ 'rollup/dist/rollup.browser.js').then(r => {
			global.rollup = r;
		}),
		loadSvelte(version)
	]);

	return version === 'local' ? version : svelte.VERSION;
}

let cached = {
	dom: null,
	ssr: null
};

let currentToken;

async function getBundle(mode, cache, lookup) {
	let bundle;
	let error;
	let warningCount = 0;

	const info = {};

	try {
		bundle = await rollup.rollup({
			input: './App.html',
			external: id => {
				return id[0] !== '.';
			},
			plugins: [{
				resolveId(importee, importer) {
					if (importee in lookup) return importee;
				},
				load(id) {
					if (id in lookup) return lookup[id].source;
				},
				transform(code, id) {
					if (!/\.html$/.test(id)) return null;

					const name = id.replace(/^\.\//, '').replace(/\.html$/, '');

					const { js, css, stats } = svelte.compile(code, Object.assign({
						generate: mode,
						name: name,
						filename: name + '.html',
						onwarn: warning => {
							console.warn(warning.message);
							console.log(warning.frame);
							warningCount += 1;
						},
					}, commonCompilerOptions));

					if (stats) {
						if (Object.keys(stats.hooks).filter(hook => stats.hooks[hook]).length > 0) info.usesHooks = true;
					} else if (/[^_]oncreate/.test(code)) {
						info.usesHooks = true;
					}

					return js;
				}
			}],
			onwarn(warning) {
				console.warn(warning);
				warningCount += 1;
			},
			cache
		});
	} catch (error) {
		return { error, bundle: null, info: null, warningCount: null }
	}

	return { bundle, info, error: null, warningCount };
}

export async function bundle(components) {
	console.clear();
	console.log(`running Svelte compiler version %c${svelte.VERSION}`, 'font-weight: bold');

	const token = currentToken = {};

	const lookup = {};
	components.forEach(component => {
		const path = `./${component.name}.${component.type}`;
		lookup[path] = component;
	});

	let dom;
	let error;

	try {
		dom = await getBundle('dom', cached.dom, lookup);
		if (dom.error) {
			throw dom.error;
		}

		if (token !== currentToken) return;

		cached.dom = dom.bundle;

		let uid = 1;
		const importMap = new Map();

		const domResult = await dom.bundle.generate({
			format: 'iife',
			name: 'SvelteComponent',
			globals: id => {
				const name = `import_${uid++}`;
				importMap.set(id, name);
				return name;
			},
			sourcemap: true
		});

		if (token !== currentToken) return;

		const ssr = dom.info.usesHooks
			? await getBundle('ssr', cached.ssr, lookup)
			: null;

		if (ssr) {
			cached.ssr = ssr.bundle;
			if (ssr.error) {
				throw ssr.error;
			}
		}

		if (token !== currentToken) return;

		const ssrResult = ssr
			? await ssr.bundle.generate({
				format: 'iife',
				name: 'SvelteComponent',
				globals: id => importMap.get(id),
				sourcemap: true
			})
			: null;

		return {
			bundle: {
				imports: dom.bundle.imports,
				importMap
			},
			dom: domResult,
			ssr: ssrResult,
			warningCount: dom.warningCount,
			error: null
		};
	} catch (err) {
		const e = error || err;
		delete e.toString;

		return {
			bundle: null,
			dom: null,
			ssr: null,
			warningCount: dom.warningCount,
			error: Object.assign({}, e, {
				message: e.message,
				stack: e.stack
			})
		};
	}
}

export function compile(component) {
	try {
		const { js } = svelte.compile(component.source, Object.assign({
			// TODO make options configurable
			name: component.name,
			filename: component.name + '.html',
		}, commonCompilerOptions));

		return js.code;
	} catch (err) {
		let result = `/* Error compiling component\n\n${err.message}`;
		if (err.frame) result += `\n${err.frame}`;
		result += `\n\n*/`;
		return result;
	}
}
<|endoftext|>


<commit_before>$(function() {
    var $document = $(document),
        $nameShameForm = $("#name-shame-form"),
        $domainInput = $("[name=domainname]", $nameShameForm),

        playSound = function(name) {
            var instance = createjs.Sound.play(name);
        },

        domainLookupFail = function(jqXHR, textStatus, errorThrown) {
            // TODO: show error to the user
            console.error(jqXHR, textStatus, errorThrown);

            playSound("fail");
        },

        domainLookupDone = function(data, textStatus, jqXHR) {
            // TODO: use data
            console.log(data, textStatus, jqXHR);

            // Load the success or failure image
            var image="";
            if (data.isSecure){
              image="Success";
            } else {
              image="Failure";
            }
            var imageString="";
            $("#resultImageId").empty();
            $("#resultImageId").append(imageString);

            // Load the results text
            var resultString = "
DNSSEC Results
";
            resultString += "

Domain:  " + data.domain + "
";
            resultString += "
DNSSEC Secure:  " + data.isSecure + "
";
            resultString += "
";
            $("#resultId").empty();
            $("#resultId").append(resultString);

            // Load the tweet button
            var tweetResult = data.domain;
            if (data.isSecure) {
               tweetResult+=" has successfully implemented #DNSSEC";
            } else {
               tweetResult+=" has NOT successfully implemented #DNSSEC";
            }
	    var tweetString="

Tweet this result
";
            $("#tweetId").empty();
            $("#tweetId").append(tweetString);

            // play the sound
            if (data.isSecure === true) {
                playSound("done");
            } else {
                playSound("fail");
            }
        };

    (function() {
        createjs.Sound.registerSound("resources/audio/164089_2975503-lq.mp3", "fail");
        createjs.Sound.registerSound("resources/audio/109662_945474-lq.mp3", "done");
    }());

    (function() {
        var onSubmit = function(event) {
            event.preventDefault();

            var domainname = $domainInput.val(),
                onSubmitPromise = $.getJSON("/name-shame/", {
                    domainname: domainname
                })
                    .fail(domainLookupFail)
                    .done(domainLookupDone);

            return false;
        };

        $nameShameForm.on("submit", onSubmit);
    }());

    (function() {
        var getDomainFromUrl = function(url) {
            var domain = url.split("://")[1].split("/")[0];

            return domain;
        },
            doAjaxOnLinkClick = function(event) {
                event.preventDefault();

                var $target = $(event.target),
                    url = $target.attr("href"),
                    domain = getDomainFromUrl(url);

                $domainInput.val(domain);
                $nameShameForm.submit();

                return false;
            };

        $document.on("click", ".has-domains-to-check a", doAjaxOnLinkClick);
    }());
});
<commit_msg>Don't play a sound if there's a serve side failure, just resubmit the form as a hack solution<commit_after>$(function() {
    var $document = $(document),
        $nameShameForm = $("#name-shame-form"),
        $domainInput = $("[name=domainname]", $nameShameForm),

        playSound = function(name) {
            var instance = createjs.Sound.play(name);
        },

        domainLookupFail = function(jqXHR, textStatus, errorThrown) {
            // TODO: show error to the user
            console.error(jqXHR, textStatus, errorThrown);

            // HACK: Server error, resubmit the form
            $nameShameForm.submit();
        },

        domainLookupDone = function(data, textStatus, jqXHR) {
            // TODO: use data
            console.log(data, textStatus, jqXHR);

            // Load the success or failure image
            var image="";
            if (data.isSecure){
              image="Success";
            } else {
              image="Failure";
            }
            var imageString="";
            $("#resultImageId").empty();
            $("#resultImageId").append(imageString);

            // Load the results text
            var resultString = "
DNSSEC Results
";
            resultString += "

Domain:  " + data.domain + "
";
            resultString += "
DNSSEC Secure:  " + data.isSecure + "
";
            resultString += "
";
            $("#resultId").empty();
            $("#resultId").append(resultString);

            // Load the tweet button
            var tweetResult = data.domain;
            if (data.isSecure) {
               tweetResult+=" has successfully implemented #DNSSEC";
            } else {
               tweetResult+=" has NOT successfully implemented #DNSSEC";
            }
	    var tweetString="

Tweet this result
";
            $("#tweetId").empty();
            $("#tweetId").append(tweetString);

            // play the sound
            if (data.isSecure === true) {
                playSound("done");
            } else {
                playSound("fail");
            }
        };

    (function() {
        createjs.Sound.registerSound("resources/audio/164089_2975503-lq.mp3", "fail");
        createjs.Sound.registerSound("resources/audio/109662_945474-lq.mp3", "done");
    }());

    (function() {
        var onSubmit = function(event) {
            event.preventDefault();

            var domainname = $domainInput.val(),
                onSubmitPromise = $.getJSON("/name-shame/", {
                    domainname: domainname
                })
                    .fail(domainLookupFail)
                    .done(domainLookupDone);

            return false;
        };

        $nameShameForm.on("submit", onSubmit);
    }());

    (function() {
        var getDomainFromUrl = function(url) {
            var domain = url.split("://")[1].split("/")[0];

            return domain;
        },
            doAjaxOnLinkClick = function(event) {
                event.preventDefault();

                var $target = $(event.target),
                    url = $target.attr("href"),
                    domain = getDomainFromUrl(url);

                $domainInput.val(domain);
                $nameShameForm.submit();

                return false;
            };

        $document.on("click", ".has-domains-to-check a", doAjaxOnLinkClick);
    }());
});
<|endoftext|>


<commit_before>var margin = 10,
    width = 750 - margin*2,
    height = 500 - margin*2;

var colors = ['steelblue', 'red', 'green', 'purple', 'orange', 'gold']
colors = colors.concat(colors.map(function(d){ return d3.rgb(d).brighter(1) }))
colors = colors.concat(colors.map(function(d){ return d3.rgb(d).darker(1) }))
colors = colors.concat(colors.map(function(d){ return d3.rgb(d).darker(.01) }))
colors = colors.concat(colors.map(function(d){ return d3.rgb(d).brighter(.01) }))

//move to
!(function(){
  var drag = dragConstructor(update)

  function update(){
    svg.selectAll('circle').translate(f())
    path.attr('d', ['M' + circlePos.join('L')].join(' '))

    text.html('')
    circlePos.forEach(function(d, i){
      text.append('span').text(i ? ' L ' : 'M ')
      text.append('span.cord').datum(d).call(fmtLabel)
    })
  }

  var text = d3.select('#moveto').append('div.pathstr')

  var svg = d3.select('#moveto').append('svg')
      .attr({width: width + margin*2, height: height + margin*2})
    .append('g')
      .translate([margin, margin])
  svg.append('rect')
      .attr({width: width, height: height})
      .style('opacity', 0)
      .on('click', function(){
        var usedColors = circlePos.map(f('color'))
        var color = colors.filter(function(d){ return !_.contains(usedColors, d) })[0]

        var point = d3.mouse(this).map(Math.round)
        point.color = color

        circlePos.push(point)
        drawCircles()
        update()
      })

  var circlePos = [[100, 200], [400, 300], [123, 44]]
  circlePos.forEach(function(d, i){ d.color = colors[i] })

  function drawCircles(){
    var circles = svg.selectAll('circle')
        .data(circlePos, f('color'))

    circles.enter()
      .append('circle.draggable')
        .style('fill', f('color'))
        .style('stroke', f('color'))
        .call(drag)
        .on('mouseover', highlight)
        .on('dblclick', function(d){
          if (circlePos.length == 1) return
          circlePos = circlePos.filter(function(e){ return d != e })

          drawCircles()
          update()
        })
          .attr('r', 0)
        .transition()
          .attr('r', margin)

    circles.exit()
      .transition()
        .attr('r', 0)
        .remove(0)
  }

  var path = svg.append('path.editable')

  drawCircles()
  update()
})()

//beizer
!(function(){
  var drag = dragConstructor(update)

  var text = d3.select('#bez').append('div.pathstr')

  var svg = d3.select('#bez').append('svg')
      .attr({width: width + margin*2, height: height + margin*2})
    .append('g')
      .translate([margin, margin])
  svg.append('rect')
      .attr({width: width, height: height})
      .style('opacity', 0)
      .on('click', function(){ addPoint(d3.mouse(this)) })

  var ctrlG = svg.append('g')
  var path = svg.append('path.editable')

  var circlePos = []
  addPoint([100, 200], [400, 300])
  addPoint([123, 44], [10, 44])

  drawCircles()
  update()

  function addPoint(pos1, pos2){
        var usedColors = circlePos.map(f('color'))
        var color = colors.filter(function(d){ return !_.contains(usedColors, d) })[0]

        var ctrl = pos2 ? pos2 : pos1.map(function(d){ return Math.round(d*.8) })
        ctrl.isCtrl = true
        ctrl.color = color
        circlePos.push(ctrl)

        var point = pos1.map(Math.round)
        point.isCtrl = false
        point.color = color
        circlePos.push(point)

        if (circlePos.length < 6) return
        drawCircles()
        update()
  }

  function drawCircles(){
    var circle = svg.selectAll('circle')
        .data(circlePos, function(d){ return d.color + d.isCtrl })

    circle.enter()
      .append('circle.draggable')
        .classed('ctrl', f('isCtrl'))
        .style('fill',   f('color'))
        .style('stroke', f('color'))
        .call(drag)
        .on('dblclick', function(d){
          if (circlePos.length == 4) return

          var i = Math.floor(_.indexOf(circlePos, d)/2)
          circlePos.splice(i*2, 2)
          drawCircles()
          update()
        })
        .on('mouseover', highlight)
        .attr('r', 0)
      .transition()
        .attr('r', margin)

    circle.exit()
      .transition()
        .attr('r', 0)
        .remove()
  }

  function update(){
    svg.selectAll('circle').translate(f())

    ctrlG.selectAll('.ctrl-connect').remove()
    ctrlG.selectAll('.ctrl-connect')
        .data(circlePos.filter(function(d, i){ return i%2 })).enter()
      .append('path.ctrl-connect')
        .attr('d', function(d, i){ return ['M', d, 'L', circlePos[i*2]].join('') })
        .style('stroke', f('color'))

    var sIndexes = d3.range(2, circlePos.length/2)
    path.attr('d',  [ 'M', circlePos[0],
                      'C', circlePos.slice(1, 4).join(' '),
                      sIndexes.map(function(i){
                        console.log(i)
                        return ['S', circlePos[2*i], circlePos[2*i + 1]].join(' ')
                      })
                    ].join(' '))

    //not the best way of rendering template..
    text.html('')
    text.append('span').text('M ')
    text.append('span.cord').datum(circlePos[0]).call(fmtLabel)
    text.append('span').text(' C ')
    text.append('span.ctrl').datum(circlePos[1]).call(fmtLabel)
    text.append('span.ctrl').datum(circlePos[2]).call(fmtLabel)
    text.append('span.cord').datum(circlePos[3]).call(fmtLabel)

    sIndexes.forEach(function(i){
      text.append('span').text(' S ')
      text.append('span.ctrl').datum(circlePos[2*i])      .call(fmtLabel)
      text.append('span.cord').datum(circlePos[2*i + 1])  .call(fmtLabel)
    })
  }

})()

//arc
!(function(){
  var drag = dragConstructor(update)

  function update(){
    svg.selectAll('.draggable').translate(f())

    console.log(θ, θ*180/Math.PI)
    paths
        .attr('d', function(d){
          return ['M', circlePos[0], 'A', rx, ry, θ*180/Math.PI, d, circlePos[1]].join(' ') })
        .classed('editable', function(d){ return d == curFlag })

    text.html('')
    circlePos.forEach(function(d, i){
      text.append('span').text(i ? ' L ' : 'M ')
      text.append('span.cord').datum(d).call(fmtLabel)
    })

    //find the center of the ellipses
    //http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
    var c1 = circlePos[0]
    var c2 = circlePos[1]

    //compute transform
    var cosθ = Math.cos(θ)
    var sinθ = Math.sin(θ)

    var mx = (c1[0] - c2[0])/2
    var my = (c1[1] - c2[1])/2

    var x =  cosθ*mx + sinθ*my
    var y = -sinθ*mx + cosθ*my

    //center points of transformed ellipse
    var rx2 = Math.pow(rx, 2)
    var ry2 = Math.pow(ry, 2)
    var x2  = Math.pow(x, 2)
    var y2  = Math.pow(y, 2)

    var dist = Math.sqrt((rx2*ry2 - rx2*y2 - ry2*x2)/(rx2*y2 + ry2*x2))

    var cxT =  dist*rx*y/ry
    var cyT = -dist*ry*x/rx

    //revese translation
    var nx = (c1[0] + c2[0])/2
    var ny = (c1[1] + c2[1])/2

    var c1x =  cosθ*cxT - sinθ*cyT + nx
    var c1y =  sinθ*cxT + cosθ*cyT + ny

    var c2x = -cosθ*cxT + sinθ*cyT + nx
    var c2y = -sinθ*cxT - cosθ*cyT + ny

    centers.data([[c1x, c1y], [c2x, c2y]])
        .attr('transform', function(d){ return 'translate(' + d + ') rotate(' + θ*180/Math.PI + ')' })

    centers.selectAll('path')
      .attr('d', function(d, i){ return 'M0,0' + (i ? 'V' + ry : 'H' + rx) })

    centers.selectAll('.r-adjust')
      .translate(function(d, i){ return i ? [0, ry] : [rx, 0] })

    angleG.select('.angle-picker')
        .translate([Math.sin(θ)*angleSize, Math.cos(θ)*angleSize])
  }

  var text = d3.select('#arc').append('div.pathstr')

  var svg = d3.select('#arc').append('svg')
      .attr({width: width + margin*2, height: height + margin*2})
    .append('g')
      .translate([margin, margin])
  svg.append('rect')
      .attr({width: width, height: height})
      .style('opacity', 0)

  var circlePos = [[250, 200], [250, 300]]
  circlePos.forEach(function(d, i){ d.color = colors[i] })

  var flagData = [[0, 0], [0, 1], [1, 1], [1, 0]]
  curFlag = flagData[0]
  var paths = svg.append('g').selectAll('path')
      .data([[0, 0], [0, 1], [1, 1], [1, 0]]).enter()
    .append('path.arc')

  var θ = Math.PI/4,
      rx = 120,
      ry = 140

  var angleSize = 30,
      aData = {},
      angleG = svg.append('g')
          .datum(aData)
          .call(highlight)
          .translate([width - angleSize, angleSize])

  angleG.append('circle.angle-background').attr('r', angleSize)

  var angleDrag = d3.behavior.drag()
      .on('drag', function(){
        var pos = d3.mouse(angleG.node())
        θ = Math.atan2(pos[0], pos[1])
        update()
      })
  angleG.append('circle.angle-picker').attr('r', 8).call(angleDrag)

  var centers = svg.append('g').selectAll('g')
      .data([[0,0], [0,0]]).enter()
    .append('g')
      .translate(f())

  centers.append('circle.center')
      .attr('r', 3)

  var rData = [{}, {}]
  centers.selectAll('path')
      .data(rData).enter()
    .append('path.center')
      .style('stroke', function(d, i){ return i ? colors[3] : colors[5] })

  var startRx, startRy
  var radiusDrag = d3.behavior.drag()
      .on('dragstart', function(){
        var pos = d3.mouse(svg.node())
        startRx = rx - pos[0]
        startRy = ry - pos[1]
      })
      .on('drag', function(d, i){
        var pos = d3.mouse(svg.node())
        i ? ry = startRy + pos[1] : rx = startRx + pos[0]
        rx = Math.max(10, rx)
        ry = Math.max(10, ry)
        update()
      })
  centers.selectAll('r-adjust')
      .data(rData).enter()
    .append('circle.r-adjust')
      .attr('r', 10)
      .call(radiusDrag)
      .style('stroke', function(d, i){ return i ? colors[3] : colors[5] })
      .style('fill'  , function(d, i){ return i ? colors[3] : colors[5] })
      .on('mouseover', highlight)

  function drawCircles(){
    var circles = svg.selectAll('.draggable')
        .data(circlePos, f('color'))

    circles.enter()
      .append('circle.draggable')
        .style('fill', f('color'))
        .style('stroke', f('color'))
        .call(drag)
        .on('mouseover', highlight)
          .attr('r', 0)
        .transition()
          .attr('r', margin)

    circles.exit()
      .transition()
        .attr('r', 0)
        .remove(0)
  }

  drawCircles()
  update()
})()

function dragConstructor(updateFn){
  return d3.behavior.drag()
        .on('drag', function(d){
          d[0] = Math.round(Math.max(0, Math.min(width,  d3.event.x)))
          d[1] = Math.round(Math.max(0, Math.min(height, d3.event.y)))

          updateFn()
        })
        .origin(function(d){ return {x: d[0], y: d[1]} })
      }

function fmtLabel(sel){
  sel
      .text(f())
      .style('color', f('color'))
      .on('mouseover', highlight)
      .classed('highlight', function(d){ return d == curHighlight })
}

var curHighlight = null
function highlight(d){
  curHighlight = d
  d3.selectAll('.cord, .ctrl, path.center, circle')
      .classed('highlight', function(e){ return d == e })
}<commit_msg>fixes angle drag<commit_after>var margin = 10,
    width = 750 - margin*2,
    height = 500 - margin*2;

var colors = ['steelblue', 'red', 'green', 'purple', 'orange', 'gold']
colors = colors.concat(colors.map(function(d){ return d3.rgb(d).brighter(1) }))
colors = colors.concat(colors.map(function(d){ return d3.rgb(d).darker(1) }))
colors = colors.concat(colors.map(function(d){ return d3.rgb(d).darker(.01) }))
colors = colors.concat(colors.map(function(d){ return d3.rgb(d).brighter(.01) }))

//move to
!(function(){
  var drag = dragConstructor(update)

  function update(){
    svg.selectAll('circle').translate(f())
    path.attr('d', ['M' + circlePos.join('L')].join(' '))

    text.html('')
    circlePos.forEach(function(d, i){
      text.append('span').text(i ? ' L ' : 'M ')
      text.append('span.cord').datum(d).call(fmtLabel)
    })
  }

  var text = d3.select('#moveto').append('div.pathstr')

  var svg = d3.select('#moveto').append('svg')
      .attr({width: width + margin*2, height: height + margin*2})
    .append('g')
      .translate([margin, margin])
  svg.append('rect')
      .attr({width: width, height: height})
      .style('opacity', 0)
      .on('click', function(){
        var usedColors = circlePos.map(f('color'))
        var color = colors.filter(function(d){ return !_.contains(usedColors, d) })[0]

        var point = d3.mouse(this).map(Math.round)
        point.color = color

        circlePos.push(point)
        drawCircles()
        update()
      })

  var circlePos = [[100, 200], [400, 300], [123, 44]]
  circlePos.forEach(function(d, i){ d.color = colors[i] })

  function drawCircles(){
    var circles = svg.selectAll('circle')
        .data(circlePos, f('color'))

    circles.enter()
      .append('circle.draggable')
        .style('fill', f('color'))
        .style('stroke', f('color'))
        .call(drag)
        .on('mouseover', highlight)
        .on('dblclick', function(d){
          if (circlePos.length == 1) return
          circlePos = circlePos.filter(function(e){ return d != e })

          drawCircles()
          update()
        })
          .attr('r', 0)
        .transition()
          .attr('r', margin)

    circles.exit()
      .transition()
        .attr('r', 0)
        .remove(0)
  }

  var path = svg.append('path.editable')

  drawCircles()
  update()
})()

//beizer
!(function(){
  var drag = dragConstructor(update)

  var text = d3.select('#bez').append('div.pathstr')

  var svg = d3.select('#bez').append('svg')
      .attr({width: width + margin*2, height: height + margin*2})
    .append('g')
      .translate([margin, margin])
  svg.append('rect')
      .attr({width: width, height: height})
      .style('opacity', 0)
      .on('click', function(){ addPoint(d3.mouse(this)) })

  var ctrlG = svg.append('g')
  var path = svg.append('path.editable')

  var circlePos = []
  addPoint([100, 200], [400, 300])
  addPoint([123, 44], [10, 44])

  drawCircles()
  update()

  function addPoint(pos1, pos2){
        var usedColors = circlePos.map(f('color'))
        var color = colors.filter(function(d){ return !_.contains(usedColors, d) })[0]

        var ctrl = pos2 ? pos2 : pos1.map(function(d){ return Math.round(d*.8) })
        ctrl.isCtrl = true
        ctrl.color = color
        circlePos.push(ctrl)

        var point = pos1.map(Math.round)
        point.isCtrl = false
        point.color = color
        circlePos.push(point)

        if (circlePos.length < 6) return
        drawCircles()
        update()
  }

  function drawCircles(){
    var circle = svg.selectAll('circle')
        .data(circlePos, function(d){ return d.color + d.isCtrl })

    circle.enter()
      .append('circle.draggable')
        .classed('ctrl', f('isCtrl'))
        .style('fill',   f('color'))
        .style('stroke', f('color'))
        .call(drag)
        .on('dblclick', function(d){
          if (circlePos.length == 4) return

          var i = Math.floor(_.indexOf(circlePos, d)/2)
          circlePos.splice(i*2, 2)
          drawCircles()
          update()
        })
        .on('mouseover', highlight)
        .attr('r', 0)
      .transition()
        .attr('r', margin)

    circle.exit()
      .transition()
        .attr('r', 0)
        .remove()
  }

  function update(){
    svg.selectAll('circle').translate(f())

    ctrlG.selectAll('.ctrl-connect').remove()
    ctrlG.selectAll('.ctrl-connect')
        .data(circlePos.filter(function(d, i){ return i%2 })).enter()
      .append('path.ctrl-connect')
        .attr('d', function(d, i){ return ['M', d, 'L', circlePos[i*2]].join('') })
        .style('stroke', f('color'))

    var sIndexes = d3.range(2, circlePos.length/2)
    path.attr('d',  [ 'M', circlePos[0],
                      'C', circlePos.slice(1, 4).join(' '),
                      sIndexes.map(function(i){
                        return ['S', circlePos[2*i], circlePos[2*i + 1]].join(' ')
                      })
                    ].join(' '))

    //not the best way of rendering template..
    text.html('')
    text.append('span').text('M ')
    text.append('span.cord').datum(circlePos[0]).call(fmtLabel)
    text.append('span').text(' C ')
    text.append('span.ctrl').datum(circlePos[1]).call(fmtLabel)
    text.append('span.ctrl').datum(circlePos[2]).call(fmtLabel)
    text.append('span.cord').datum(circlePos[3]).call(fmtLabel)

    sIndexes.forEach(function(i){
      text.append('span').text(' S ')
      text.append('span.ctrl').datum(circlePos[2*i])      .call(fmtLabel)
      text.append('span.cord').datum(circlePos[2*i + 1])  .call(fmtLabel)
    })
  }

})()

//arc
!(function(){
  var drag = dragConstructor(update)

  function update(){
    svg.selectAll('.draggable').translate(f())

    paths
        .attr('d', function(d){
          return ['M', circlePos[0], 'A', rx, ry, θ*180/Math.PI, d, circlePos[1]].join(' ') })
        .classed('editable', function(d){ return d == curFlag })

    text.html('')
    circlePos.forEach(function(d, i){
      text.append('span').text(i ? ' L ' : 'M ')
      text.append('span.cord').datum(d).call(fmtLabel)
    })

    //find the center of the ellipses
    //http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
    var c1 = circlePos[0]
    var c2 = circlePos[1]

    //compute transform
    var cosθ = Math.cos(θ)
    var sinθ = Math.sin(θ)

    var mx = (c1[0] - c2[0])/2
    var my = (c1[1] - c2[1])/2

    var x =  cosθ*mx + sinθ*my
    var y = -sinθ*mx + cosθ*my

    //center points of transformed ellipse
    var rx2 = Math.pow(rx, 2)
    var ry2 = Math.pow(ry, 2)
    var x2  = Math.pow(x, 2)
    var y2  = Math.pow(y, 2)

    var dist = Math.sqrt((rx2*ry2 - rx2*y2 - ry2*x2)/(rx2*y2 + ry2*x2))

    var cxT =  dist*rx*y/ry
    var cyT = -dist*ry*x/rx

    //revese translation
    var nx = (c1[0] + c2[0])/2
    var ny = (c1[1] + c2[1])/2

    var c1x =  cosθ*cxT - sinθ*cyT + nx
    var c1y =  sinθ*cxT + cosθ*cyT + ny

    var c2x = -cosθ*cxT + sinθ*cyT + nx
    var c2y = -sinθ*cxT - cosθ*cyT + ny

    centers.data([[c1x, c1y], [c2x, c2y]])
        .attr('transform', function(d){ return 'translate(' + d + ') rotate(' + θ*180/Math.PI + ')' })

    centers.selectAll('path')
      .attr('d', function(d, i){ return 'M0,0' + (i ? 'V' + ry : 'H' + rx) })

    centers.selectAll('.r-adjust')
      .translate(function(d, i){ return i ? [0, ry] : [rx, 0] })

    angleG.select('.angle-picker')
        .translate([Math.sin(θ)*angleSize, Math.cos(θ)*angleSize])
  }

  var text = d3.select('#arc').append('div.pathstr')

  var svg = d3.select('#arc').append('svg')
      .attr({width: width + margin*2, height: height + margin*2})
    .append('g')
      .translate([margin, margin])
  svg.append('rect')
      .attr({width: width, height: height})
      .style('opacity', 0)

  var circlePos = [[250, 200], [250, 300]]
  circlePos.forEach(function(d, i){ d.color = colors[i] })

  var flagData = [[0, 0], [0, 1], [1, 1], [1, 0]]
  curFlag = flagData[0]
  var paths = svg.append('g').selectAll('path')
      .data([[0, 0], [0, 1], [1, 1], [1, 0]]).enter()
    .append('path.arc')

  var θ = Math.PI/4*0,
      rx = 120,
      ry = 140

  var angleSize = 30,
      aData = {},
      angleG = svg.append('g')
          .datum(aData)
          .call(highlight)
          .translate([width - angleSize, angleSize])

  angleG.append('circle.angle-background').attr('r', angleSize)

  var angleDrag = d3.behavior.drag()
      .on('drag', function(){
        var pos = d3.mouse(angleG.node())
        θ = Math.atan2(pos[0], pos[1])
        update()
      })
  angleG.append('circle.angle-picker').attr('r', 8).call(angleDrag)

  var centers = svg.append('g').selectAll('g')
      .data([[0,0], [0,0]]).enter()
    .append('g')
      .translate(f())

  centers.append('circle.center')
      .attr('r', 3)

  var rData = [{}, {}]
  centers.selectAll('path')
      .data(rData).enter()
    .append('path.center')
      .style('stroke', function(d, i){ return i ? colors[3] : colors[5] })

  var startRx, startRy, startPos
  var radiusDrag = d3.behavior.drag()
      .on('dragstart', function(){
        startPos = d3.mouse(svg.node())
        startRx = rx
        startRy = ry
      })
      .on('drag', function(d, i){
        var pos = d3.mouse(svg.node())
        var dx = pos[0] - startPos[0]
        var dy = pos[1] - startPos[1]

        var dist = Math.sqrt(dx*dx + dy*dy)
        var φ = Math.atan2(dx, dy)

        if (i){
          ry = startRy + dist*Math.cos(φ + θ)
        } else{
          rx = startRx + dist*Math.sin(φ + θ)
        }

        rx = Math.max(10, rx)
        ry = Math.max(10, ry)
        update()
      })
  centers.selectAll('r-adjust')
      .data(rData).enter()
    .append('circle.r-adjust')
      .attr('r', 10)
      .call(radiusDrag)
      .style('stroke', function(d, i){ return i ? colors[3] : colors[5] })
      .style('fill'  , function(d, i){ return i ? colors[3] : colors[5] })
      .on('mouseover', highlight)

  function drawCircles(){
    var circles = svg.selectAll('.draggable')
        .data(circlePos, f('color'))

    circles.enter()
      .append('circle.draggable')
        .style('fill', f('color'))
        .style('stroke', f('color'))
        .call(drag)
        .on('mouseover', highlight)
          .attr('r', 0)
        .transition()
          .attr('r', margin)

    circles.exit()
      .transition()
        .attr('r', 0)
        .remove(0)
  }

  drawCircles()
  update()
})()

function dragConstructor(updateFn){
  return d3.behavior.drag()
        .on('drag', function(d){
          d[0] = Math.round(Math.max(0, Math.min(width,  d3.event.x)))
          d[1] = Math.round(Math.max(0, Math.min(height, d3.event.y)))

          updateFn()
        })
        .origin(function(d){ return {x: d[0], y: d[1]} })
      }

function fmtLabel(sel){
  sel
      .text(f())
      .style('color', f('color'))
      .on('mouseover', highlight)
      .classed('highlight', function(d){ return d == curHighlight })
}

var curHighlight = null
function highlight(d){
  curHighlight = d
  d3.selectAll('.cord, .ctrl, path.center, circle')
      .classed('highlight', function(e){ return d == e })
}<|endoftext|>


<commit_before>var consecutiveNumber = 0;

var Util = {
  serializeArray: function (form) {
    var serialized = [];
    // https://github.com/jquery/jquery/blob/2.1-stable/src/serialize.js#L12
    var rCRLF = /\r?\n/g,
      rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
      rsubmittable = /^(?:input|select|textarea|keygen)/i,
      rcheckableType = /^(?:checkbox|radio)$/i;

    var nodeIterator = document.createNodeIterator(
      form,
      NodeFilter.SHOW_ELEMENT,
      function (node) {
        // The .serializeArray() method uses the standard W3C rules for
        // successful controls to determine which elements it should include;
        // in particular the element cannot be disabled and must contain a name
        // attribute. No submit button value is serialized since the form was
        // not submitted using a button. Data from file select elements is not
        // serialized.
        var type = node.type;

        return node.name &&
          !node.disabled &&
          rsubmittable.test(node.nodeName) &&
          !rsubmitterTypes.test(type) &&
          (node.checked || !rcheckableType.test(type))
            ? NodeFilter.FILTER_ACCEPT
            : NodeFilter.FILTER_REJECT;
      },
      false
    );
    var field;
    /*eslint-disable no-cond-assign */
    while (field = nodeIterator.nextNode()) {
      var val = field.value.replace(rCRLF, "\r\n");
      if (field.type === "number") {
        let number = parseFloat(val);
        val = !isNaN(number) ? number : val;
      }
      if (field.type === "checkbox") {
        val = !!val;
      }
      if (val != null) {
        serialized.push({name: field.name, value: val});
      }
    }
    /*eslint-enable no-cond-assign */
    return serialized;
  },
  serializedArrayToDictionary: function (serializedArray = []) {
    var sanitizePath = function (path) {
      return path
        .replace(/^\.|\.$/, "") // leading/trailing dots
        .replace(/\.\.+/, "."); // multiple dots
    };
    var parsePath = function (obj, position, tokens, value) {
      if (position === tokens.length) {
        return value;
      }
      const token = tokens[position];
      let matches = token.match(/(\w+)\[(\d*)]$/); // parse array notation

      if (!matches) {
        if (obj[token] === undefined) {
          obj[token] = {};
        }
        obj[token] = parsePath(obj[token], position + 1, tokens, value);
      } else {
        let [key, index] = matches.slice(1);
        if (obj[key] === undefined) {
          obj[key] = [];
        }
        if (index.length === 0) {
          index = obj[key].length;
        }
        if (obj[key][index] === undefined) {
          obj[key][index] = {};
        }
        obj[key][index] =
            parsePath(obj[key][index], position + 1, tokens, value);
      }
      return obj;
    };

    let json = {};
    for (let i = 0; i < serializedArray.length; i++) {
      const value = serializedArray[i].value;
      let tokens = sanitizePath(serializedArray[i].name).split(".");
      parsePath(json, 0, tokens, value);
    }
    return json;
  },
  initKeyValue: function (obj, key, value) {
    if (obj[key] === undefined) {
      obj[key] = value;
    }
  },
  isArray: Array.isArray || function (obj) {
    return toString.call(obj) === "[object Array]";
  },
  isNumber: function (obj) {
    return toString.call(obj) === "[object Number]";
  },
  isString: function (obj) {
    return toString.call(obj) === "[object String]";
  },
  isEmptyString: function (str) {
    return this.isString(str) && (str == null || str === "");
  },
  hasClass: function (element, className) {
    return element.className &&
      element.className.match(/\S+/g).indexOf(className) > -1;
  },
  noop: function () {},
  extendObject: function (...sources) {
    return Object.assign({}, ...sources);
  },
  // TODO: delete after #2105
  compactArray: function (arr) {
    if (!Util.isArray(arr)) {
      return arr;
    }
    return arr.map(function (item) {
      let compactedItem = {};
      for (let key in item) {
        if (item.hasOwnProperty(key)) {
          let val = item[key];
          if (val != null && val !== "") {
            compactedItem[key] = val;
          }
        }
      }
      if (Object.keys(compactedItem).length > 0) {
        return compactedItem;
      }
    }).filter(function (item) {
      return item != null;
    });
  },
  getUniqueId: function () {
    return ++consecutiveNumber;
  }
};

module.exports = Util;
<commit_msg>Introduce isValidPort and isValidPath helpers<commit_after>var consecutiveNumber = 0;

var Util = {
  serializeArray: function (form) {
    var serialized = [];
    // https://github.com/jquery/jquery/blob/2.1-stable/src/serialize.js#L12
    var rCRLF = /\r?\n/g,
      rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
      rsubmittable = /^(?:input|select|textarea|keygen)/i,
      rcheckableType = /^(?:checkbox|radio)$/i;

    var nodeIterator = document.createNodeIterator(
      form,
      NodeFilter.SHOW_ELEMENT,
      function (node) {
        // The .serializeArray() method uses the standard W3C rules for
        // successful controls to determine which elements it should include;
        // in particular the element cannot be disabled and must contain a name
        // attribute. No submit button value is serialized since the form was
        // not submitted using a button. Data from file select elements is not
        // serialized.
        var type = node.type;

        return node.name &&
          !node.disabled &&
          rsubmittable.test(node.nodeName) &&
          !rsubmitterTypes.test(type) &&
          (node.checked || !rcheckableType.test(type))
            ? NodeFilter.FILTER_ACCEPT
            : NodeFilter.FILTER_REJECT;
      },
      false
    );
    var field;
    /*eslint-disable no-cond-assign */
    while (field = nodeIterator.nextNode()) {
      var val = field.value.replace(rCRLF, "\r\n");
      if (field.type === "number") {
        let number = parseFloat(val);
        val = !isNaN(number) ? number : val;
      }
      if (field.type === "checkbox") {
        val = !!val;
      }
      if (val != null) {
        serialized.push({name: field.name, value: val});
      }
    }
    /*eslint-enable no-cond-assign */
    return serialized;
  },
  serializedArrayToDictionary: function (serializedArray = []) {
    var sanitizePath = function (path) {
      return path
        .replace(/^\.|\.$/, "") // leading/trailing dots
        .replace(/\.\.+/, "."); // multiple dots
    };
    var parsePath = function (obj, position, tokens, value) {
      if (position === tokens.length) {
        return value;
      }
      const token = tokens[position];
      let matches = token.match(/(\w+)\[(\d*)]$/); // parse array notation

      if (!matches) {
        if (obj[token] === undefined) {
          obj[token] = {};
        }
        obj[token] = parsePath(obj[token], position + 1, tokens, value);
      } else {
        let [key, index] = matches.slice(1);
        if (obj[key] === undefined) {
          obj[key] = [];
        }
        if (index.length === 0) {
          index = obj[key].length;
        }
        if (obj[key][index] === undefined) {
          obj[key][index] = {};
        }
        obj[key][index] =
            parsePath(obj[key][index], position + 1, tokens, value);
      }
      return obj;
    };

    let json = {};
    for (let i = 0; i < serializedArray.length; i++) {
      const value = serializedArray[i].value;
      let tokens = sanitizePath(serializedArray[i].name).split(".");
      parsePath(json, 0, tokens, value);
    }
    return json;
  },
  initKeyValue: function (obj, key, value) {
    if (obj[key] === undefined) {
      obj[key] = value;
    }
  },
  isArray: Array.isArray || function (obj) {
    return toString.call(obj) === "[object Array]";
  },
  isNumber: function (obj) {
    return toString.call(obj) === "[object Number]";
  },
  isString: function (obj) {
    return toString.call(obj) === "[object String]";
  },
  isEmptyString: function (str) {
    return this.isString(str) && (str == null || str === "");
  },
  isValidPort: function (value) {
    if (value == null || this.isEmptyString(value)) {
      return true;
    }
    var port = parseInt(value, 10);
    return (this.isNumber(port) && (port >= 0 && port <= 65535));
  },
  isValidPath: function (value) {
    if (value == null || this.isEmptyString(value)) {
      return true;
    }
    return value.match(/ /g) == null;
  },
  hasClass: function (element, className) {
    return element.className &&
      element.className.match(/\S+/g).indexOf(className) > -1;
  },
  noop: function () {},
  extendObject: function (...sources) {
    return Object.assign({}, ...sources);
  },
  // TODO: delete after #2105
  compactArray: function (arr) {
    if (!Util.isArray(arr)) {
      return arr;
    }
    return arr.map(function (item) {
      let compactedItem = {};
      for (let key in item) {
        if (item.hasOwnProperty(key)) {
          let val = item[key];
          if (val != null && val !== "") {
            compactedItem[key] = val;
          }
        }
      }
      if (Object.keys(compactedItem).length > 0) {
        return compactedItem;
      }
    }).filter(function (item) {
      return item != null;
    });
  },
  getUniqueId: function () {
    return ++consecutiveNumber;
  }
};

module.exports = Util;
<|endoftext|>


<commit_before>
import Wreqr from 'backbone.wreqr';
import Marionette from 'backbone.marionette';
import L from 'leaflet';
import osmAuth from 'osm-auth';
import OsmEditHelper from '../helper/osmEdit.js';
import MapUi from '../ui/map';
import CONST from '../const';
import template from '../../templates/movePoiContextual.ejs';
import OsmNodeModel from '../model/osmNode';
import ContributionErrorNotificationView from './contributionErrorNotification';
import Cache from '../core/cache';

export default Marionette.ItemView.extend({
    template: template,

    behaviors: {
        'l20n': {},
        'contextual': {
            'destroyOnClose': true,
        },
    },

    ui: {
        'saveBtn': '.save_btn',
        'cancelBtn': '.cancel_btn',
        'contextual': '.contextual',
    },

    events: {
        'click @ui.cancelBtn': 'onClickCancel',
        'click @ui.saveBtn': 'onClickSave',
    },

    initialize: function (options) {
        this._radio = Wreqr.radio.channel('global');
        this._map = this._radio.reqres.request('map');

        this._user = options.user;
        this._marker = options.marker;
        this._osmElement = options.osmElement;
        this._layerModel = options.layerModel;

        this.model = new OsmNodeModel({
            'id': this._osmElement.id,
            'type': this._osmElement.type,
            'version': this._osmElement.version,
            'lat': this._osmElement.lat,
            'lon': this._osmElement.lon,
            'tags': this._osmElement.tags,
        });

        this._osmEdit = new OsmEditHelper(
            osmAuth({
                'oauth_consumer_key': config.oauthConsumerKey,
                'oauth_secret': config.oauthSecret,
                'oauth_token': this._user.get('token'),
                'oauth_token_secret': this._user.get('tokenSecret'),
            })
        );

        return this.render();
    },

    open: function () {
        this.triggerMethod('open');
    },

    close: function () {
        this.triggerMethod('close');
    },

    onOpen: function () {
        MapUi.showContributionCross();
    },

    onClickSave: function () {
        MapUi.hideContributionCross();

        let mapCenter = this._map.getCenter();

        this.model.set('lat', mapCenter.lat);
        this.model.set('lon', mapCenter.lng);

        this._marker.setLatLng(
            L.latLng( mapCenter )
        );

        this._osmEdit.setId(this.model.get('id'));
        this._osmEdit.setChangesetCreatedBy(CONST.osm.changesetCreatedBy);
        this._osmEdit.setChangesetComment(CONST.osm.changesetComment);
        this._osmEdit.setType(this.model.get('type'));
        this._osmEdit.setVersion(this.model.get('version'));
        this._osmEdit.setTimestamp(this.model.get('timestamp'));
        this._osmEdit.setLatitude(this.model.get('lat'));
        this._osmEdit.setLongitude(this.model.get('lon'));
        this._osmEdit.setTags(this.model.get('tags'));
        this._osmEdit.setUid(this._user.get('osmId'));
        this._osmEdit.setDisplayName(this._user.get('displayName'));

        this.sendContributionToOSM();

        this.close();
    },

    sendContributionToOSM: function () {
        this._osmEdit.send()
        .then((version) => {
            this.model.set('version', version);

            this._radio.commands.execute(
                'map:updatePoiPopup',
                this._layerModel,
                this.model.toJSON()
            );

            Cache.save(this.model.attributes);
        })
        .catch((err) => {
            let notification = new ContributionErrorNotificationView({
                'retryCallback': this.sendContributionToOSM.bind(this)
            });

            notification.open();
        });
    },

    onClickCancel: function () {
        MapUi.hideContributionCross();
        this._marker.dragging.disable();
        this._marker.setLatLng(
            L.latLng(
                this._osmElement.lat,
                this._osmElement.lon
            )
        );

        this.close();
    },
});
<commit_msg>Closes the popup when moving a point<commit_after>
import Wreqr from 'backbone.wreqr';
import Marionette from 'backbone.marionette';
import L from 'leaflet';
import osmAuth from 'osm-auth';
import OsmEditHelper from '../helper/osmEdit.js';
import MapUi from '../ui/map';
import CONST from '../const';
import template from '../../templates/movePoiContextual.ejs';
import OsmNodeModel from '../model/osmNode';
import ContributionErrorNotificationView from './contributionErrorNotification';
import Cache from '../core/cache';

export default Marionette.ItemView.extend({
    template: template,

    behaviors: {
        'l20n': {},
        'contextual': {
            'destroyOnClose': true,
        },
    },

    ui: {
        'saveBtn': '.save_btn',
        'cancelBtn': '.cancel_btn',
        'contextual': '.contextual',
    },

    events: {
        'click @ui.cancelBtn': 'onClickCancel',
        'click @ui.saveBtn': 'onClickSave',
    },

    initialize: function (options) {
        this._radio = Wreqr.radio.channel('global');
        this._map = this._radio.reqres.request('map');

        this._user = options.user;
        this._marker = options.marker;
        this._osmElement = options.osmElement;
        this._layerModel = options.layerModel;

        this.model = new OsmNodeModel({
            'id': this._osmElement.id,
            'type': this._osmElement.type,
            'version': this._osmElement.version,
            'lat': this._osmElement.lat,
            'lon': this._osmElement.lon,
            'tags': this._osmElement.tags,
        });

        this._osmEdit = new OsmEditHelper(
            osmAuth({
                'oauth_consumer_key': config.oauthConsumerKey,
                'oauth_secret': config.oauthSecret,
                'oauth_token': this._user.get('token'),
                'oauth_token_secret': this._user.get('tokenSecret'),
            })
        );

        return this.render();
    },

    open: function () {
        this.triggerMethod('open');
    },

    close: function () {
        this.triggerMethod('close');
    },

    onOpen: function () {
        this._marker.closePopup();
        MapUi.showContributionCross();
    },

    onClickSave: function () {
        MapUi.hideContributionCross();

        let mapCenter = this._map.getCenter();

        this.model.set('lat', mapCenter.lat);
        this.model.set('lon', mapCenter.lng);

        this._marker.setLatLng(
            L.latLng( mapCenter )
        );

        this._osmEdit.setId(this.model.get('id'));
        this._osmEdit.setChangesetCreatedBy(CONST.osm.changesetCreatedBy);
        this._osmEdit.setChangesetComment(CONST.osm.changesetComment);
        this._osmEdit.setType(this.model.get('type'));
        this._osmEdit.setVersion(this.model.get('version'));
        this._osmEdit.setTimestamp(this.model.get('timestamp'));
        this._osmEdit.setLatitude(this.model.get('lat'));
        this._osmEdit.setLongitude(this.model.get('lon'));
        this._osmEdit.setTags(this.model.get('tags'));
        this._osmEdit.setUid(this._user.get('osmId'));
        this._osmEdit.setDisplayName(this._user.get('displayName'));

        this.sendContributionToOSM();

        this.close();
    },

    sendContributionToOSM: function () {
        this._osmEdit.send()
        .then((version) => {
            this.model.set('version', version);

            this._radio.commands.execute(
                'map:updatePoiPopup',
                this._layerModel,
                this.model.toJSON()
            );

            Cache.save(this.model.attributes);
        })
        .catch((err) => {
            let notification = new ContributionErrorNotificationView({
                'retryCallback': this.sendContributionToOSM.bind(this)
            });

            notification.open();
        });
    },

    onClickCancel: function () {
        MapUi.hideContributionCross();
        this._marker.dragging.disable();
        this._marker.setLatLng(
            L.latLng(
                this._osmElement.lat,
                this._osmElement.lon
            )
        );

        this.close();
    },
});
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the MIT license
 * If a copy of the MIT license was not distributed with this file, you can
 * obtain one at https://raw.github.com/mozilla/butter/master/LICENSE */

define( [ "dialog/dialog", "util/dragndrop", "util/lang", "text!layouts/track-handle.html" ],
  function( Dialog, DragNDrop, LangUtils, TRACK_HANDLE_LAYOUT ) {

  var ADD_TRACK_BUTTON_Y_ADJUSTMENT = 37;

  return function( butter, media, mediaInstanceRootElement, tracksContainer ) {

    var _media = media,
        _container = mediaInstanceRootElement.querySelector( ".track-handle-container" ),
        _listElement = _container.querySelector( ".handle-list" ),
        _addTrackButton = _container.querySelector( "button.add-track" ),
        _tracks = {},
        _menus = [],
        _this = this,
        _draggingHandleIndex,
        _draggingHandleId;

    _addTrackButton.addEventListener( "click", function() {
      butter.currentMedia.addTrack();
    }, false );

    function sortHandles(){
      if ( butter.currentMedia ) {
        var tracks = butter.currentMedia.orderedTracks,
            trackHandle;
        for ( var i = 0, l = tracks.length; i < l; ++i ) {
          trackHandle = _tracks[ tracks[ i ].id ];
          // It *is* possible for there to be more tracks than there are track handles while importing, so
          // do a check here to see if a handle exists first before ordering.
          if ( trackHandle ) {
            _listElement.appendChild( trackHandle.element );
          }
        }
      }
    }

    DragNDrop.listen( "sortstarted", function onSortStarted( e ) {
      var originalEvent = e.data,
          orderedTracks = butter.currentMedia.orderedTracks,
          id = originalEvent.target.getAttribute( "data-butter-track-id" );

      for ( var i = 0; i < orderedTracks.length; i++ ) {
        if ( orderedTracks[ i ].id === id ) {
          _draggingHandleIndex = i;
          _draggingHandleId = id;
        }
      }

    });

    var _sortable = DragNDrop.sortable( _listElement, {
      change: function( elements ) {
        var newIndex, id,
            orderedTracks = butter.currentMedia.orderedTracks,
            track,
            indexCache;

        for( var i = 0, l = elements.length; i < l; ++i ) {
          id = elements[ i ].getAttribute( "data-butter-track-id" );
          if ( id === _draggingHandleId ) {
            newIndex = i;
            break;
          }
        }

        track = orderedTracks[ _draggingHandleIndex ];
        orderedTracks.splice( _draggingHandleIndex, 1 );
        orderedTracks.splice( newIndex, 0, track );

        indexCache = newIndex;
        if ( newIndex < _draggingHandleIndex ) {
          var temp = _draggingHandleIndex;

          _draggingHandleIndex = newIndex;
          newIndex = temp;
        }

        butter.currentMedia.sortTracks( _draggingHandleIndex, newIndex );

        // We now need to set the values of "current index" to where we replaced since sortstarted
        // won't fire again until the mouse is let go and then an element is selected again.
        _draggingHandleIndex = indexCache;
      }
    });

    _media.listen( "trackorderchanged", function( e ) {
      var tracks = e.data;
      for ( var i = 0, l = tracks.length; i < l; i++ ) {
        var track = tracks[ i ],
            element = _tracks[ track.id ].element;
        element.querySelector( "span.title" ).textContent = track.name;
      }
    });

    function onTrackAdded( e ) {
      var track = e.data,
          trackId = track.id,
          trackDiv = LangUtils.domFragment( TRACK_HANDLE_LAYOUT, ".track-handle" ),
          menuDiv = trackDiv.querySelector( ".menu" ),
          deleteButton = menuDiv.querySelector( ".delete" );

      deleteButton.addEventListener( "click", function() {
        var dialog = Dialog.spawn( "delete-track", {
          data: track.name,
          events: {
            submit: function( e ){
              if( e.data === true ){
                var trackEvents = track.trackEvents;
                for ( var i = 0, l = trackEvents.length; i < l; i++ ) {
                  butter.editor.closeTrackEventEditor( trackEvents[ i ] );
                }
                media.removeTrack( track );
              } //if
              dialog.close();
            },
            cancel: function(){
              dialog.close();
            }
          }
        });
        dialog.open();
      }, false );

      trackDiv.addEventListener( "dblclick", function(){
        var dialog = Dialog.spawn( "track-data", {
          data: track,
          events: {
            submit: function( e ) {
              // wrap in a try catch so we know right away about any malformed JSON
              try {
                var trackData = JSON.parse( e.data ),
                    trackEvents = track.trackEvents,
                    trackDataEvents = trackData.trackEvents,
                    dontRemove = {},
                    toAdd = [],
                    i,
                    l;

                trackDiv.childNodes[ 0 ].textContent = track.name = trackData.name;
                // update every trackevent with it's new data
                for ( i = 0, l = trackDataEvents.length; i < l; i++ ) {
                  var teData = trackDataEvents[ i ],
                      te = track.getTrackEventById( teData.id );

                  // check to see if the current track event exists already
                  if ( te ) {
                    te.update( teData.popcornOptions );
                    /* remove it from our reference to the array of track events so we know
                     * which ones to remove later
                     */
                    dontRemove[ teData.id ] = teData;
                  // if we couldn't find the track event, it must be a new one
                  } else {
                    toAdd.push( { type: teData.type, popcornOptions: teData.popcornOptions } );
                  }
                }

                // remove all trackEvents that wern't updated
                for ( i = trackEvents.length, l = 0; i >= l; i-- ) {
                  if ( trackEvents[ i ] && !dontRemove[ trackEvents[ i ].id ] ) {
                    track.removeTrackEvent( trackEvents[ i ] );
                  }
                }

                // add all the trackEvents that didn't exist so far
                for ( i = 0, l = toAdd.length; i < l; i++ ) {
                  track.addTrackEvent( toAdd[ i ] );
                }
                // let the dialog know things went well
                dialog.send( "track-updated" );
              } catch ( error ) {
                // inform the dialog about the issue
                dialog.send( "error" );
              }
            }
          }
        });
        dialog.open();
      }, false );

      _menus.push( menuDiv );

      trackDiv.setAttribute( "data-butter-track-id", trackId );
      menuDiv.setAttribute( "data-butter-track-id", trackId );
      menuDiv.querySelector( ".delete" ).setAttribute( "data-butter-track-id", trackId );
      trackDiv.querySelector( "span.track-handle-icon" ).setAttribute( "data-butter-track-id", trackId );
      trackDiv.querySelector( "span.title" ).setAttribute( "data-butter-track-id", trackId );
      trackDiv.querySelector( "span.title" ).appendChild( document.createTextNode( track.name ) );

      _sortable.addItem( trackDiv );

      _listElement.appendChild( trackDiv );

      _tracks[ trackId ] = {
        id: trackId,
        track: track,
        element: trackDiv,
        menu: menuDiv
      };

      _addTrackButton.style.top = _listElement.offsetHeight - ADD_TRACK_BUTTON_Y_ADJUSTMENT + "px";

      sortHandles();
    }

    var existingTracks = _media.tracks;
    for( var i=0; i<existingTracks.length; ++i ){
      onTrackAdded({
        data: existingTracks[ i ]
      });
    }

    _media.listen( "trackadded", onTrackAdded );

    _media.listen( "trackremoved", function( e ){
      var trackId = e.data.id;
      _listElement.removeChild( _tracks[ trackId ].element );
      _sortable.removeItem( _tracks[ trackId ].element );
      _menus.splice( _menus.indexOf( _tracks[ trackId ].menu ), 1 );
      delete _tracks[ trackId ];
      _addTrackButton.style.top = _listElement.offsetHeight - ADD_TRACK_BUTTON_Y_ADJUSTMENT + "px";
    });

    tracksContainer.element.addEventListener( "scroll", function(){
      _container.scrollTop = tracksContainer.element.scrollTop;
    }, false );

    _container.addEventListener( "mousewheel", function( e ){
      if( e.wheelDeltaY ){
        tracksContainer.element.scrollTop -= e.wheelDeltaY;
        e.preventDefault();
      }
    }, false );

    // For Firefox
    _container.addEventListener( "DOMMouseScroll", function( e ){
      if( e.axis === e.VERTICAL_AXIS && !e.shiftKey ){
        tracksContainer.element.scrollTop += e.detail * 2;
        e.preventDefault();
      }
    }, false );

    this.update = function(){
      _container.scrollTop = tracksContainer.element.scrollTop;
      _addTrackButton.style.top = _listElement.offsetHeight - ADD_TRACK_BUTTON_Y_ADJUSTMENT + "px";
    };

    _this.update();

    Object.defineProperties( this, {
      element: {
        enumerable: true,
        get: function(){
          return _container;
        }
      }
    });

  }; //TrackHandles

});
<commit_msg>update lines of layer (TrackNetwork) when trackhandle sortable changes<commit_after>/* This Source Code Form is subject to the terms of the MIT license
 * If a copy of the MIT license was not distributed with this file, you can
 * obtain one at https://raw.github.com/mozilla/butter/master/LICENSE */

define( [ "dialog/dialog", "util/dragndrop", "util/lang", "text!layouts/track-handle.html" ],
  function( Dialog, DragNDrop, LangUtils, TRACK_HANDLE_LAYOUT ) {

  var ADD_TRACK_BUTTON_Y_ADJUSTMENT = 37;

  return function( butter, media, mediaInstanceRootElement, tracksContainer ) {

    var _media = media,
        _container = mediaInstanceRootElement.querySelector( ".track-handle-container" ),
        _listElement = _container.querySelector( ".handle-list" ),
        _addTrackButton = _container.querySelector( "button.add-track" ),
        _tracks = {},
        _menus = [],
        _this = this,
        _draggingHandleIndex,
        _draggingHandleId;

    _addTrackButton.addEventListener( "click", function() {
      butter.currentMedia.addTrack();
    }, false );

    function sortHandles(){
      if ( butter.currentMedia ) {
        var tracks = butter.currentMedia.orderedTracks,
            trackHandle;
        for ( var i = 0, l = tracks.length; i < l; ++i ) {
          trackHandle = _tracks[ tracks[ i ].id ];
          // It *is* possible for there to be more tracks than there are track handles while importing, so
          // do a check here to see if a handle exists first before ordering.
          if ( trackHandle ) {
            _listElement.appendChild( trackHandle.element );
          }
        }
      }
    }

    DragNDrop.listen( "sortstarted", function onSortStarted( e ) {
      var originalEvent = e.data,
          orderedTracks = butter.currentMedia.orderedTracks,
          id = originalEvent.target.getAttribute( "data-butter-track-id" );

      for ( var i = 0; i < orderedTracks.length; i++ ) {
        if ( orderedTracks[ i ].id === id ) {
          _draggingHandleIndex = i;
          _draggingHandleId = id;
        }
      }

    });

    var _sortable = DragNDrop.sortable( _listElement, {
      change: function( elements ) {
        var newIndex, id,
            orderedTracks = butter.currentMedia.orderedTracks,
            track,
            indexCache;

        for( var i = 0, l = elements.length; i < l; ++i ) {
          id = elements[ i ].getAttribute( "data-butter-track-id" );
          if ( id === _draggingHandleId ) {
            newIndex = i;
            break;
          }
        }

        track = orderedTracks[ _draggingHandleIndex ];
        orderedTracks.splice( _draggingHandleIndex, 1 );
        orderedTracks.splice( newIndex, 0, track );

        indexCache = newIndex;
        if ( newIndex < _draggingHandleIndex ) {
          var temp = _draggingHandleIndex;

          _draggingHandleIndex = newIndex;
          newIndex = temp;
        }

        butter.currentMedia.sortTracks( _draggingHandleIndex, newIndex );

        // We now need to set the values of "current index" to where we replaced since sortstarted
        // won't fire again until the mouse is let go and then an element is selected again.
        _draggingHandleIndex = indexCache;
        butter.trackNetwork.updateLinesOfLayer();
      }
    });

    _media.listen( "trackorderchanged", function( e ) {
      var tracks = e.data;
      for ( var i = 0, l = tracks.length; i < l; i++ ) {
        var track = tracks[ i ],
            element = _tracks[ track.id ].element;
        element.querySelector( "span.title" ).textContent = track.name;
      }
    });

    function onTrackAdded( e ) {
      var track = e.data,
          trackId = track.id,
          trackDiv = LangUtils.domFragment( TRACK_HANDLE_LAYOUT, ".track-handle" ),
          menuDiv = trackDiv.querySelector( ".menu" ),
          deleteButton = menuDiv.querySelector( ".delete" );

      deleteButton.addEventListener( "click", function() {
        var dialog = Dialog.spawn( "delete-track", {
          data: track.name,
          events: {
            submit: function( e ){
              if( e.data === true ){
                var trackEvents = track.trackEvents;
                for ( var i = 0, l = trackEvents.length; i < l; i++ ) {
                  butter.editor.closeTrackEventEditor( trackEvents[ i ] );
                }
                media.removeTrack( track );
              } //if
              dialog.close();
            },
            cancel: function(){
              dialog.close();
            }
          }
        });
        dialog.open();
      }, false );

      trackDiv.addEventListener( "dblclick", function(){
        var dialog = Dialog.spawn( "track-data", {
          data: track,
          events: {
            submit: function( e ) {
              // wrap in a try catch so we know right away about any malformed JSON
              try {
                var trackData = JSON.parse( e.data ),
                    trackEvents = track.trackEvents,
                    trackDataEvents = trackData.trackEvents,
                    dontRemove = {},
                    toAdd = [],
                    i,
                    l;

                trackDiv.childNodes[ 0 ].textContent = track.name = trackData.name;
                // update every trackevent with it's new data
                for ( i = 0, l = trackDataEvents.length; i < l; i++ ) {
                  var teData = trackDataEvents[ i ],
                      te = track.getTrackEventById( teData.id );

                  // check to see if the current track event exists already
                  if ( te ) {
                    te.update( teData.popcornOptions );
                    /* remove it from our reference to the array of track events so we know
                     * which ones to remove later
                     */
                    dontRemove[ teData.id ] = teData;
                  // if we couldn't find the track event, it must be a new one
                  } else {
                    toAdd.push( { type: teData.type, popcornOptions: teData.popcornOptions } );
                  }
                }

                // remove all trackEvents that wern't updated
                for ( i = trackEvents.length, l = 0; i >= l; i-- ) {
                  if ( trackEvents[ i ] && !dontRemove[ trackEvents[ i ].id ] ) {
                    track.removeTrackEvent( trackEvents[ i ] );
                  }
                }

                // add all the trackEvents that didn't exist so far
                for ( i = 0, l = toAdd.length; i < l; i++ ) {
                  track.addTrackEvent( toAdd[ i ] );
                }
                // let the dialog know things went well
                dialog.send( "track-updated" );
              } catch ( error ) {
                // inform the dialog about the issue
                dialog.send( "error" );
              }
            }
          }
        });
        dialog.open();
      }, false );

      _menus.push( menuDiv );

      trackDiv.setAttribute( "data-butter-track-id", trackId );
      menuDiv.setAttribute( "data-butter-track-id", trackId );
      menuDiv.querySelector( ".delete" ).setAttribute( "data-butter-track-id", trackId );
      trackDiv.querySelector( "span.track-handle-icon" ).setAttribute( "data-butter-track-id", trackId );
      trackDiv.querySelector( "span.title" ).setAttribute( "data-butter-track-id", trackId );
      trackDiv.querySelector( "span.title" ).appendChild( document.createTextNode( track.name ) );

      _sortable.addItem( trackDiv );

      _listElement.appendChild( trackDiv );

      _tracks[ trackId ] = {
        id: trackId,
        track: track,
        element: trackDiv,
        menu: menuDiv
      };

      _addTrackButton.style.top = _listElement.offsetHeight - ADD_TRACK_BUTTON_Y_ADJUSTMENT + "px";

      sortHandles();
    }

    var existingTracks = _media.tracks;
    for( var i=0; i<existingTracks.length; ++i ){
      onTrackAdded({
        data: existingTracks[ i ]
      });
    }

    _media.listen( "trackadded", onTrackAdded );

    _media.listen( "trackremoved", function( e ){
      var trackId = e.data.id;
      _listElement.removeChild( _tracks[ trackId ].element );
      _sortable.removeItem( _tracks[ trackId ].element );
      _menus.splice( _menus.indexOf( _tracks[ trackId ].menu ), 1 );
      delete _tracks[ trackId ];
      _addTrackButton.style.top = _listElement.offsetHeight - ADD_TRACK_BUTTON_Y_ADJUSTMENT + "px";
    });

    tracksContainer.element.addEventListener( "scroll", function(){
      _container.scrollTop = tracksContainer.element.scrollTop;
    }, false );

    _container.addEventListener( "mousewheel", function( e ){
      if( e.wheelDeltaY ){
        tracksContainer.element.scrollTop -= e.wheelDeltaY;
        e.preventDefault();
      }
    }, false );

    // For Firefox
    _container.addEventListener( "DOMMouseScroll", function( e ){
      if( e.axis === e.VERTICAL_AXIS && !e.shiftKey ){
        tracksContainer.element.scrollTop += e.detail * 2;
        e.preventDefault();
      }
    }, false );

    this.update = function(){
      _container.scrollTop = tracksContainer.element.scrollTop;
      _addTrackButton.style.top = _listElement.offsetHeight - ADD_TRACK_BUTTON_Y_ADJUSTMENT + "px";
    };

    _this.update();

    Object.defineProperties( this, {
      element: {
        enumerable: true,
        get: function(){
          return _container;
        }
      }
    });

  }; //TrackHandles

});
<|endoftext|>