<commit_before>var unbaffled = require('../index')
var path = require('path')

var webpackConfig = require('./webpack.config').webpackConfig
var devKeys = require('./webpack.config').development
var prodKeys = require('./webpack.config').production

var dir = {
    root: __dirname,
    vendor: 'bower_components/'
}

var options = {

    webpackConfig: webpackConfig,

    keys: {
        production: ["PRODUCTION"],
        development: ["DEVELOPMENT"]
    },

    split: false,
    // Split by name plugin

    versionsToKeep: 2,
    // If not supplied, keep all.  If an older version contains a required dependency it won't be deleted

    dir: {
        root: __dirname,
        dist: 'build',
        release: 'versions',
        development: 'development',
        vendor: dir.vendor,
        src: {
            js: 'src/js/'
        },
        languages: {
            js: 'src/js/'
        },
        manifest: {
            versions: {
                location: '.',
                name: 'manifest-versions'
            },
            development: {
                location: '.',
                name: 'manifest-development'
            }
        }
    },
    test: {
        fileGlob: '-test'
    },

    vendorFiles: [
        (dir.vendor + 'frameworkX.js'),
        (dir.vendor + 'pluginY.js')
    ],

    modules: {
        js: {
            // NOTE: Object form to allow future options for specific modules
            app: {},
            lib: {},
            'modules/moduleA': {},
            'modules/moduleB': {},
            'modules/moduleC': {}
        }
    }
};

unbaffled(options)<commit_msg>Remove extraneous properties<commit_after>var unbaffled = require('../index')
var path = require('path')

var webpackConfig = require('./webpack.config').webpackConfig
var devKeys = require('./webpack.config').development
var prodKeys = require('./webpack.config').production

var dir = {
    root: __dirname,
    vendor: 'bower_components/'
}

var options = {

    webpackConfig: webpackConfig,

    keys: {
        production: ["PRODUCTION"],
        development: ["DEVELOPMENT"]
    },

    split: false,
    // Split by name plugin

    versionsToKeep: 2,
    // If not supplied, keep all.  If an older version contains a required dependency it won't be deleted

    dir: {
        root: __dirname,
        dist: 'build',
        release: 'versions',
        development: 'development',
        vendor: dir.vendor,
        src: {
            js: 'src/js/'
        },
        languages: {
            js: 'src/js/'
        },
        manifest: {
            versions: {
                location: '.',
                name: 'manifest-versions'
            },
            development: {
                location: '.',
                name: 'manifest-development'
            }
        }
    },
    test: {
        fileGlob: '-test'
    },

    modules: {
        js: {
            // NOTE: Object form to allow future options for specific modules
            app: {},
            lib: {},
            'modules/moduleA': {},
            'modules/moduleB': {},
            'modules/moduleC': {}
        }
    }
};

unbaffled(options)<|endoftext|>


<commit_before>jQuery.fn.definePlugin('Slider', function ($) {
	'use strict';

	var names = {
		sliderClass: 'uilib-slider',
		pinClass: 'uilib-slider-pin',
		disabledClass: 'disabled',
		textClass:'uilib-text'
	};

	return {
		init: function(){
			this.markup();
			this.bindEvents();
			this.options.create.call(this);
			this.setValue(this.options.value);
		},
		getDefaults: function(){
			return {
				minValue: 0,
				maxValue: 100,
				value: 0,
				width: 80,
				preLabel: '',
				postLabel: '',
				className: 'default-uilib-slider-ui',
				toolTip: false,
				supportClick: true,
				slide: function () {},
				create: function () {}
			};
		},
		markup: function () {
			var leftOffset = this.$el.css('left');
			var style = {
				width : this.options.width
			};

			if(!this.$el.hasClass(names.sliderClass)){
				this.$el.addClass(names.sliderClass);
			}

			if(this.options.preLabel){
				this.$el.prepend('' + this.options.preLabel + '');
				style.left = 14;
			}

			this.$pin = $('
');
			this.$el.append(this.$pin);

			if(this.options.postLabel){
				this.$el.append('' + this.options.postLabel + '');
			}

			this.$el.addClass(names.sliderClass).css(style).addClass(this.options.className);

			this.$pin.addClass(names.pinClass);
			this.$pin.width(19);

			if(this.options.toolTip){
				this.$toolTip = $(_toolTipHtml());
				this.$pin.append(this.$toolTip.hide());
			}
		},
		getXFromEvent: function(event){
			return event.offsetX / this.$el.width()
		},
		bindEvents: function () {
			var $body = $(window);
			var slider = this;
			if (slider.options.supportClick){
				this.$el.on('click', function(evt){
					if(evt.target === slider.$el[0]){
						var x = slider.getXFromEvent(evt);
						slider.setValue(slider.transform(x));
						slider.triggerChangeEvent(slider.getValue());
					}
				});
			}
			this.$pin.on('mousedown', function (evt) {
                if(slider.$toolTip && !slider.$toolTip.is(":visible")){
                    slider.$toolTip.show();
                }
				slider.currentPos = slider.$pin.position().left;
				slider.startDragPos = evt.pageX;
				slider.disableTextSelection(evt);
				function mousemove_handler(evt) {
					slider.setPosition(evt);
				}
				function mouseup_handler(evt) {
                    if(slider.$toolTip){
                        slider.$toolTip.hide();
                    }
					slider.enableTextSelection();
					$body.off('mousemove', mousemove_handler);
					$body.off('mouseup', mouseup_handler);
					slider.triggerChangeEvent(slider.getValue());
				}
				$body.on('mousemove', mousemove_handler);
				$body.on('mouseup', mouseup_handler);
			});
		},
		getValue: function () {
			return this.transform(this.options.value);
		},
		setValue: function (valueInRange) {
			var val;
			this.options.value = this.valueInRangeToInnerRange(valueInRange);
			if (this.options.value !== this.last_value) {
				this.last_value = this.options.value;
				val = this.getValue();
				this.$el.trigger('slide', val);
				if(this.options.toolTip){
					this.$toolTip.find('.'+names.textClass).text(Math.round(val));
				}
				this.options.slide.call(this, val);
			}
			return this.update();
		},
		transform: function (valueInRange) {
			return this.options.minValue + valueInRange * (this.options.maxValue - this.options.minValue);
		},
		valueInRangeToInnerRange: function (value) {
			value = value < this.options.minValue ? this.options.minValue : value;
			value = value > this.options.maxValue ? this.options.maxValue : value;
			return (value - this.options.minValue) / (this.options.maxValue - this.options.minValue);
		},
		disableTextSelection: function (evt) {
			document.body.focus();
			//prevent text selection in IE
			document.onselectstart = function () { return false; };
			//evt.target.ondragstart = function() { return false; };
		},
		enableTextSelection: function () {
			document.onselectstart = null;
		},
		setPosition: function (evt) {
			if (this.isDisabled()) { return; }
			var x = evt.pageX - this.startDragPos;
			var pos = this.currentPos + x;
			var width = this.$el.width() - this.$pin.width();
			if (pos < 0) { pos = 0; }
			if (pos > width) { pos = width; }
			this.options.value = this.transform(pos / width);
			this.setValue(this.options.value);
			this.startDragPos = evt.pageX;
			this.currentPos = pos;
		},
		update: function () {
			this.$pin.css({
				left : this.options.value * (this.$el.width() - this.$pin.width())
			});
			return this;
		},
		disable: function () {
			this.$el.addClass(names.disabledClass);
		},
		enable: function () {
			this.$el.removeClass(names.disabledClass);
		},
		isDisabled: function () {
			return this.$el.hasClass(names.disabledClass);
		}
	};

	function _toolTipHtml() {
        return '
' +
            '

' +
            '

' +
            '
';
    }

});<commit_msg>Fix slider click producing NaN for Firefox.<commit_after>jQuery.fn.definePlugin('Slider', function ($) {
	'use strict';

	var names = {
		sliderClass: 'uilib-slider',
		pinClass: 'uilib-slider-pin',
		disabledClass: 'disabled',
		textClass:'uilib-text'
	};

	return {
		init: function(){
			this.markup();
			this.bindEvents();
			this.options.create.call(this);
			this.setValue(this.options.value);
		},
		getDefaults: function(){
			return {
				minValue: 0,
				maxValue: 100,
				value: 0,
				width: 80,
				preLabel: '',
				postLabel: '',
				className: 'default-uilib-slider-ui',
				toolTip: false,
				supportClick: true,
				slide: function () {},
				create: function () {}
			};
		},
		markup: function () {
			var leftOffset = this.$el.css('left');
			var style = {
				width : this.options.width
			};

			if(!this.$el.hasClass(names.sliderClass)){
				this.$el.addClass(names.sliderClass);
			}

			if(this.options.preLabel){
				this.$el.prepend('' + this.options.preLabel + '');
				style.left = 14;
			}

			this.$pin = $('
');
			this.$el.append(this.$pin);

			if(this.options.postLabel){
				this.$el.append('' + this.options.postLabel + '');
			}

			this.$el.addClass(names.sliderClass).css(style).addClass(this.options.className);

			this.$pin.addClass(names.pinClass);
			this.$pin.width(19);

			if(this.options.toolTip){
				this.$toolTip = $(_toolTipHtml());
				this.$pin.append(this.$toolTip.hide());
			}
		},
		getXFromEvent: function(event){
			var x = event.hasOwnProperty('offsetX') ?
					event.offsetX :
					event.clientX - event.target.getBoundingClientRect().left;
			return x / this.$el.width();
		},
		bindEvents: function () {
			var $body = $(window);
			var slider = this;
			if (slider.options.supportClick){
				this.$el.on('click', function(evt){
					if(evt.target === slider.$el[0]){
						var x = slider.getXFromEvent(evt);
						slider.setValue(slider.transform(x));
						slider.triggerChangeEvent(slider.getValue());
					}
				});
			}
			this.$pin.on('mousedown', function (evt) {
                if(slider.$toolTip && !slider.$toolTip.is(":visible")){
                    slider.$toolTip.show();
                }
				slider.currentPos = slider.$pin.position().left;
				slider.startDragPos = evt.pageX;
				slider.disableTextSelection(evt);
				function mousemove_handler(evt) {
					slider.setPosition(evt);
				}
				function mouseup_handler(evt) {
                    if(slider.$toolTip){
                        slider.$toolTip.hide();
                    }
					slider.enableTextSelection();
					$body.off('mousemove', mousemove_handler);
					$body.off('mouseup', mouseup_handler);
					slider.triggerChangeEvent(slider.getValue());
				}
				$body.on('mousemove', mousemove_handler);
				$body.on('mouseup', mouseup_handler);
			});
		},
		getValue: function () {
			return this.transform(this.options.value);
		},
		setValue: function (valueInRange) {
			var val;
			this.options.value = this.valueInRangeToInnerRange(valueInRange);
			if (this.options.value !== this.last_value) {
				this.last_value = this.options.value;
				val = this.getValue();
				this.$el.trigger('slide', val);
				if(this.options.toolTip){
					this.$toolTip.find('.'+names.textClass).text(Math.round(val));
				}
				this.options.slide.call(this, val);
			}
			return this.update();
		},
		transform: function (valueInRange) {
			return this.options.minValue + valueInRange * (this.options.maxValue - this.options.minValue);
		},
		valueInRangeToInnerRange: function (value) {
			value = value < this.options.minValue ? this.options.minValue : value;
			value = value > this.options.maxValue ? this.options.maxValue : value;
			return (value - this.options.minValue) / (this.options.maxValue - this.options.minValue);
		},
		disableTextSelection: function (evt) {
			document.body.focus();
			//prevent text selection in IE
			document.onselectstart = function () { return false; };
			//evt.target.ondragstart = function() { return false; };
		},
		enableTextSelection: function () {
			document.onselectstart = null;
		},
		setPosition: function (evt) {
			if (this.isDisabled()) { return; }
			var x = evt.pageX - this.startDragPos;
			var pos = this.currentPos + x;
			var width = this.$el.width() - this.$pin.width();
			if (pos < 0) { pos = 0; }
			if (pos > width) { pos = width; }
			this.options.value = this.transform(pos / width);
			this.setValue(this.options.value);
			this.startDragPos = evt.pageX;
			this.currentPos = pos;
		},
		update: function () {
			this.$pin.css({
				left : this.options.value * (this.$el.width() - this.$pin.width())
			});
			return this;
		},
		disable: function () {
			this.$el.addClass(names.disabledClass);
		},
		enable: function () {
			this.$el.removeClass(names.disabledClass);
		},
		isDisabled: function () {
			return this.$el.hasClass(names.disabledClass);
		}
	};

	function _toolTipHtml() {
        return '
' +
            '

' +
            '

' +
            '
';
    }

});<|endoftext|>


<commit_before>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
exports.minifyTask = exports.optimizeTask = exports.loaderConfig = void 0;
const es = require("event-stream");
const gulp = require("gulp");
const concat = require("gulp-concat");
const filter = require("gulp-filter");
const fancyLog = require("fancy-log");
const ansiColors = require("ansi-colors");
const path = require("path");
const pump = require("pump");
const VinylFile = require("vinyl");
const bundle = require("./bundle");
const i18n_1 = require("./i18n");
const stats_1 = require("./stats");
const util = require("./util");
const REPO_ROOT_PATH = path.join(__dirname, '../..');
function log(prefix, message) {
    fancyLog(ansiColors.cyan('[' + prefix + ']'), message);
}
function loaderConfig() {
    const result = {
        paths: {
            'vs': 'out-build/vs',
            'vscode': 'empty:'
        },
        amdModulesPattern: /^vs\//
    };
    result['vs/css'] = { inlineResources: true };
    return result;
}
exports.loaderConfig = loaderConfig;
const IS_OUR_COPYRIGHT_REGEXP = /Copyright \(C\) Microsoft Corporation/i;
function loader(src, bundledFileHeader, bundleLoader) {
    let sources = [
        `${src}/vs/loader.js`
    ];
    if (bundleLoader) {
        sources = sources.concat([
            `${src}/vs/css.js`,
            `${src}/vs/nls.js`
        ]);
    }
    let isFirst = true;
    return (gulp
        .src(sources, { base: `${src}` })
        .pipe(es.through(function (data) {
        if (isFirst) {
            isFirst = false;
            this.emit('data', new VinylFile({
                path: 'fake',
                base: '.',
                contents: Buffer.from(bundledFileHeader)
            }));
            this.emit('data', data);
        }
        else {
            this.emit('data', data);
        }
    }))
        .pipe(concat('vs/loader.js')));
}
function toConcatStream(src, bundledFileHeader, sources, dest, fileContentMapper) {
    const useSourcemaps = /\.js$/.test(dest) && !/\.nls\.js$/.test(dest);
    // If a bundle ends up including in any of the sources our copyright, then
    // insert a fake source at the beginning of each bundle with our copyright
    let containsOurCopyright = false;
    for (let i = 0, len = sources.length; i < len; i++) {
        const fileContents = sources[i].contents;
        if (IS_OUR_COPYRIGHT_REGEXP.test(fileContents)) {
            containsOurCopyright = true;
            break;
        }
    }
    if (containsOurCopyright) {
        sources.unshift({
            path: null,
            contents: bundledFileHeader
        });
    }
    const treatedSources = sources.map(function (source) {
        const root = source.path ? REPO_ROOT_PATH.replace(/\\/g, '/') : '';
        const base = source.path ? root + `/${src}` : '.';
        const path = source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake';
        const contents = source.path ? fileContentMapper(source.contents, path) : source.contents;
        return new VinylFile({
            path: path,
            base: base,
            contents: Buffer.from(contents)
        });
    });
    return es.readArray(treatedSources)
        .pipe(useSourcemaps ? util.loadSourcemaps() : es.through())
        .pipe(concat(dest))
        .pipe((0, stats_1.createStatsStream)(dest));
}
function toBundleStream(src, bundledFileHeader, bundles, fileContentMapper) {
    return es.merge(bundles.map(function (bundle) {
        return toConcatStream(src, bundledFileHeader, bundle.sources, bundle.dest, fileContentMapper);
    }));
}
const DEFAULT_FILE_HEADER = [
    '/*!--------------------------------------------------------',
    ' * Copyright (C) Microsoft Corporation. All rights reserved.',
    ' *--------------------------------------------------------*/'
].join('\n');
function optimizeTask(opts) {
    const src = opts.src;
    const entryPoints = opts.entryPoints;
    const resources = opts.resources;
    const loaderConfig = opts.loaderConfig;
    const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER;
    const bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader);
    const out = opts.out;
    const fileContentMapper = opts.fileContentMapper || ((contents, _path) => contents);
    return function () {
        const sourcemaps = require('gulp-sourcemaps');
        const bundlesStream = es.through(); // this stream will contain the bundled files
        const resourcesStream = es.through(); // this stream will contain the resources
        const bundleInfoStream = es.through(); // this stream will contain bundleInfo.json
        bundle.bundle(entryPoints, loaderConfig, function (err, result) {
            if (err || !result) {
                return bundlesStream.emit('error', JSON.stringify(err));
            }
            toBundleStream(src, bundledFileHeader, result.files, fileContentMapper).pipe(bundlesStream);
            // Remove css inlined resources
            const filteredResources = resources.slice();
            result.cssInlinedResources.forEach(function (resource) {
                if (process.env['VSCODE_BUILD_VERBOSE']) {
                    log('optimizer', 'excluding inlined: ' + resource);
                }
                filteredResources.push('!' + resource);
            });
            gulp.src(filteredResources, { base: `${src}`, allowEmpty: true }).pipe(resourcesStream);
            const bundleInfoArray = [];
            if (opts.bundleInfo) {
                bundleInfoArray.push(new VinylFile({
                    path: 'bundleInfo.json',
                    base: '.',
                    contents: Buffer.from(JSON.stringify(result.bundleData, null, '\t'))
                }));
            }
            es.readArray(bundleInfoArray).pipe(bundleInfoStream);
        });
        const result = es.merge(loader(src, bundledFileHeader, bundleLoader), bundlesStream, resourcesStream, bundleInfoStream);
        return result
            .pipe(sourcemaps.write('./', {
            sourceRoot: undefined,
            addComment: true,
            includeContent: true
        }))
            .pipe(opts.languages && opts.languages.length ? (0, i18n_1.processNlsFiles)({
            fileHeader: bundledFileHeader,
            languages: opts.languages
        }) : es.through())
            .pipe(gulp.dest(out));
    };
}
exports.optimizeTask = optimizeTask;
function minifyTask(src, sourceMapBaseUrl) {
    const esbuild = require('esbuild');
    const sourceMappingURL = sourceMapBaseUrl ? ((f) => `${sourceMapBaseUrl}/${f.relative}.map`) : undefined;
    return cb => {
        const cssnano = require('cssnano');
        const postcss = require('gulp-postcss');
        const sourcemaps = require('gulp-sourcemaps');
        const jsFilter = filter('**/*.js', { restore: true });
        const cssFilter = filter('**/*.css', { restore: true });
        pump(gulp.src([src + '/**', '!' + src + '/**/*.map']), jsFilter, sourcemaps.init({ loadMaps: true }), es.map((f, cb) => {
            esbuild.build({
                entryPoints: [f.path],
                minify: true,
                sourcemap: 'external',
                outdir: '.',
                platform: 'node',
                target: ['node12.18'],
                write: false
            }).then(res => {
                const jsFile = res.outputFiles.find(f => /\.js$/.test(f.path));
                const sourceMapFile = res.outputFiles.find(f => /\.js\.map$/.test(f.path));
                f.contents = Buffer.from(jsFile.contents);
                f.sourceMap = JSON.parse(sourceMapFile.text);
                cb(undefined, f);
            }, cb);
        }), jsFilter.restore, cssFilter, postcss([cssnano({ preset: 'default' })]), cssFilter.restore, sourcemaps.mapSources((sourcePath) => {
            if (sourcePath === 'bootstrap-fork.js') {
                return 'bootstrap-fork.orig.js';
            }
            return sourcePath;
        }), sourcemaps.write('./', {
            sourceMappingURL,
            sourceRoot: undefined,
            includeContent: true,
            addComment: true
        }), gulp.dest(src + '-min'), (err) => cb(err));
    };
}
exports.minifyTask = minifyTask;
<commit_msg>missing build<commit_after>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
exports.minifyTask = exports.optimizeTask = exports.loaderConfig = void 0;
const es = require("event-stream");
const gulp = require("gulp");
const concat = require("gulp-concat");
const filter = require("gulp-filter");
const fancyLog = require("fancy-log");
const ansiColors = require("ansi-colors");
const path = require("path");
const pump = require("pump");
const VinylFile = require("vinyl");
const bundle = require("./bundle");
const i18n_1 = require("./i18n");
const stats_1 = require("./stats");
const util = require("./util");
const REPO_ROOT_PATH = path.join(__dirname, '../..');
function log(prefix, message) {
    fancyLog(ansiColors.cyan('[' + prefix + ']'), message);
}
function loaderConfig() {
    const result = {
        paths: {
            'vs': 'out-build/vs',
            'vscode': 'empty:'
        },
        amdModulesPattern: /^vs\//
    };
    result['vs/css'] = { inlineResources: true };
    return result;
}
exports.loaderConfig = loaderConfig;
const IS_OUR_COPYRIGHT_REGEXP = /Copyright \(C\) Microsoft Corporation/i;
function loader(src, bundledFileHeader, bundleLoader) {
    let sources = [
        `${src}/vs/loader.js`
    ];
    if (bundleLoader) {
        sources = sources.concat([
            `${src}/vs/css.js`,
            `${src}/vs/nls.js`
        ]);
    }
    let isFirst = true;
    return (gulp
        .src(sources, { base: `${src}` })
        .pipe(es.through(function (data) {
        if (isFirst) {
            isFirst = false;
            this.emit('data', new VinylFile({
                path: 'fake',
                base: '.',
                contents: Buffer.from(bundledFileHeader)
            }));
            this.emit('data', data);
        }
        else {
            this.emit('data', data);
        }
    }))
        .pipe(concat('vs/loader.js')));
}
function toConcatStream(src, bundledFileHeader, sources, dest, fileContentMapper) {
    const useSourcemaps = /\.js$/.test(dest) && !/\.nls\.js$/.test(dest);
    // If a bundle ends up including in any of the sources our copyright, then
    // insert a fake source at the beginning of each bundle with our copyright
    let containsOurCopyright = false;
    for (let i = 0, len = sources.length; i < len; i++) {
        const fileContents = sources[i].contents;
        if (IS_OUR_COPYRIGHT_REGEXP.test(fileContents)) {
            containsOurCopyright = true;
            break;
        }
    }
    if (containsOurCopyright) {
        sources.unshift({
            path: null,
            contents: bundledFileHeader
        });
    }
    const treatedSources = sources.map(function (source) {
        const root = source.path ? REPO_ROOT_PATH.replace(/\\/g, '/') : '';
        const base = source.path ? root + `/${src}` : '.';
        const path = source.path ? root + '/' + source.path.replace(/\\/g, '/') : 'fake';
        const contents = source.path ? fileContentMapper(source.contents, path) : source.contents;
        return new VinylFile({
            path: path,
            base: base,
            contents: Buffer.from(contents)
        });
    });
    return es.readArray(treatedSources)
        .pipe(useSourcemaps ? util.loadSourcemaps() : es.through())
        .pipe(concat(dest))
        .pipe((0, stats_1.createStatsStream)(dest));
}
function toBundleStream(src, bundledFileHeader, bundles, fileContentMapper) {
    return es.merge(bundles.map(function (bundle) {
        return toConcatStream(src, bundledFileHeader, bundle.sources, bundle.dest, fileContentMapper);
    }));
}
const DEFAULT_FILE_HEADER = [
    '/*!--------------------------------------------------------',
    ' * Copyright (C) Microsoft Corporation. All rights reserved.',
    ' *--------------------------------------------------------*/'
].join('\n');
function optimizeTask(opts) {
    const src = opts.src;
    const entryPoints = opts.entryPoints;
    const resources = opts.resources;
    const loaderConfig = opts.loaderConfig;
    const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER;
    const bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader);
    const out = opts.out;
    const fileContentMapper = opts.fileContentMapper || ((contents, _path) => contents);
    return function () {
        const sourcemaps = require('gulp-sourcemaps');
        const bundlesStream = es.through(); // this stream will contain the bundled files
        const resourcesStream = es.through(); // this stream will contain the resources
        const bundleInfoStream = es.through(); // this stream will contain bundleInfo.json
        bundle.bundle(entryPoints, loaderConfig, function (err, result) {
            if (err || !result) {
                return bundlesStream.emit('error', JSON.stringify(err));
            }
            toBundleStream(src, bundledFileHeader, result.files, fileContentMapper).pipe(bundlesStream);
            // Remove css inlined resources
            const filteredResources = resources.slice();
            result.cssInlinedResources.forEach(function (resource) {
                if (process.env['VSCODE_BUILD_VERBOSE']) {
                    log('optimizer', 'excluding inlined: ' + resource);
                }
                filteredResources.push('!' + resource);
            });
            gulp.src(filteredResources, { base: `${src}`, allowEmpty: true }).pipe(resourcesStream);
            const bundleInfoArray = [];
            if (opts.bundleInfo) {
                bundleInfoArray.push(new VinylFile({
                    path: 'bundleInfo.json',
                    base: '.',
                    contents: Buffer.from(JSON.stringify(result.bundleData, null, '\t'))
                }));
            }
            es.readArray(bundleInfoArray).pipe(bundleInfoStream);
        });
        const result = es.merge(loader(src, bundledFileHeader, bundleLoader), bundlesStream, resourcesStream, bundleInfoStream);
        return result
            .pipe(sourcemaps.write('./', {
            sourceRoot: undefined,
            addComment: true,
            includeContent: true
        }))
            .pipe(opts.languages && opts.languages.length ? (0, i18n_1.processNlsFiles)({
            fileHeader: bundledFileHeader,
            languages: opts.languages
        }) : es.through())
            .pipe(gulp.dest(out));
    };
}
exports.optimizeTask = optimizeTask;
function minifyTask(src, sourceMapBaseUrl) {
    const esbuild = require('esbuild');
    const sourceMappingURL = sourceMapBaseUrl ? ((f) => `${sourceMapBaseUrl}/${f.relative}.map`) : undefined;
    return cb => {
        const cssnano = require('cssnano');
        const postcss = require('gulp-postcss');
        const sourcemaps = require('gulp-sourcemaps');
        const jsFilter = filter('**/*.js', { restore: true });
        const cssFilter = filter('**/*.css', { restore: true });
        pump(gulp.src([src + '/**', '!' + src + '/**/*.map']), jsFilter, sourcemaps.init({ loadMaps: true }), es.map((f, cb) => {
            esbuild.build({
                entryPoints: [f.path],
                minify: true,
                sourcemap: 'external',
                outdir: '.',
                platform: 'node',
                target: ['node14.16'],
                write: false
            }).then(res => {
                const jsFile = res.outputFiles.find(f => /\.js$/.test(f.path));
                const sourceMapFile = res.outputFiles.find(f => /\.js\.map$/.test(f.path));
                f.contents = Buffer.from(jsFile.contents);
                f.sourceMap = JSON.parse(sourceMapFile.text);
                cb(undefined, f);
            }, cb);
        }), jsFilter.restore, cssFilter, postcss([cssnano({ preset: 'default' })]), cssFilter.restore, sourcemaps.mapSources((sourcePath) => {
            if (sourcePath === 'bootstrap-fork.js') {
                return 'bootstrap-fork.orig.js';
            }
            return sourcePath;
        }), sourcemaps.write('./', {
            sourceMappingURL,
            sourceRoot: undefined,
            includeContent: true,
            addComment: true
        }), gulp.dest(src + '-min'), (err) => cb(err));
    };
}
exports.minifyTask = minifyTask;
<|endoftext|>


<commit_before>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import LoadingSpinner from '../loadingSpinner';
import cx from 'classnames';
import theme from './theme.css';

class Button extends PureComponent {
  getSpinnerColor() {
    const { inverse, level } = this.props;

    return level === 'secondary' || (level === 'outline' && !inverse) ? 'teal' : 'white';
  }

  handleMouseUp = event => {
    this.buttonNode.blur();
    if (this.props.onMouseUp) {
      this.props.onMouseUp(event);
    }
  };

  handleMouseLeave = event => {
    this.buttonNode.blur();
    if (this.props.onMouseLeave) {
      this.props.onMouseLeave(event);
    }
  };

  render() {
    const {
      children,
      className,
      level,
      disabled,
      element,
      active,
      fullWidth,
      icon,
      iconPlacement,
      inverse,
      label,
      size,
      type,
      processing,
      ...others
    } = this.props;

    const classNames = cx(
      theme['button'],
      theme[level],
      {
        [theme['has-icon-only']]: !label && !children,
        [theme['inverse']]: inverse && level === 'outline',
        [theme['is-disabled']]: disabled,
        [theme['is-full-width']]: fullWidth,
        [theme['processing']]: processing,
        [theme['active']]: active,
        [theme[size]]: theme[size],
      },
      className,
    );

    const props = {
      ...others,
      ref: node => {
        this.buttonNode = node;
      },
      className: classNames,
      disabled: element === 'button' ? disabled : null,
      onMouseUp: this.handleMouseUp,
      onMouseLeave: this.handleMouseLeave,
      type: element === 'button' ? type : null,
      'data-teamleader-ui': 'button',
    };

    return React.createElement(
      element,
      props,
      icon && iconPlacement === 'left' ? icon : null,
      label || children ? (

          {label}
          {children}

      ) : null,
      icon && iconPlacement === 'right' ? icon : null,
      processing ? (
        <LoadingSpinner
          className={theme['spinner']}
          color={this.getSpinnerColor()}
          size={size === 'small' ? 'small' : 'medium'}
        />
      ) : null,
    );
  }
}

Button.propTypes = {
  /** The content to display inside the button. */
  children: PropTypes.any,
  /** A class name for the button to give custom styles. */
  className: PropTypes.string,
  /** A custom element to be rendered */
  element: PropTypes.oneOfType([PropTypes.element, PropTypes.string]),
  /** Determines which kind of button to be rendered. */
  level: PropTypes.oneOf(['outline', 'primary', 'secondary', 'destructive']),
  /** If true, component will be disabled. */
  disabled: PropTypes.bool,
  /** If true, component will be shown in an active state */
  active: PropTypes.bool,
  /** If true, component will take the full width available. */
  fullWidth: PropTypes.bool,
  /** The icon displayed inside the button. */
  icon: PropTypes.element,
  /** The position of the icon inside the button. */
  iconPlacement: PropTypes.oneOf(['left', 'right']),
  /** If true, component will be rendered in inverse mode. */
  inverse: PropTypes.bool,
  /** The textual label displayed inside the button. */
  label: PropTypes.string,
  /** Callback function that is fired when mouse leaves the component. */
  onMouseLeave: PropTypes.func,
  /** Callback function that is fired when the mouse button is released. */
  onMouseUp: PropTypes.func,
  /** If true, component will show a loading spinner instead of label or children. */
  processing: PropTypes.bool,
  /** Size of the button. */
  size: PropTypes.oneOf(['small', 'medium', 'large']),
  /** Type of the button element. */
  type: PropTypes.string,
};

Button.defaultProps = {
  className: '',
  element: 'button',
  fullWidth: false,
  level: 'secondary',
  iconPlacement: 'left',
  inverse: false,
  processing: false,
  size: 'medium',
  type: 'button',
};

export default Button;
<commit_msg>Button: prevent extra icon margin when tooltipped<commit_after>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import LoadingSpinner from '../loadingSpinner';
import cx from 'classnames';
import theme from './theme.css';

class Button extends PureComponent {
  getSpinnerColor() {
    const { inverse, level } = this.props;

    return level === 'secondary' || (level === 'outline' && !inverse) ? 'teal' : 'white';
  }

  handleMouseUp = event => {
    this.buttonNode.blur();
    if (this.props.onMouseUp) {
      this.props.onMouseUp(event);
    }
  };

  handleMouseLeave = event => {
    this.buttonNode.blur();
    if (this.props.onMouseLeave) {
      this.props.onMouseLeave(event);
    }
  };

  render() {
    const {
      children,
      className,
      level,
      disabled,
      element,
      active,
      fullWidth,
      icon,
      iconPlacement,
      inverse,
      label,
      size,
      type,
      processing,
      ...others
    } = this.props;

    const classNames = cx(
      theme['button'],
      theme[level],
      {
        [theme['has-icon-only']]: (!children && !label) || (Array.isArray(children) && !children[0] && !label),
        [theme['inverse']]: inverse && level === 'outline',
        [theme['is-disabled']]: disabled,
        [theme['is-full-width']]: fullWidth,
        [theme['processing']]: processing,
        [theme['active']]: active,
        [theme[size]]: theme[size],
      },
      className,
    );

    const props = {
      ...others,
      ref: node => {
        this.buttonNode = node;
      },
      className: classNames,
      disabled: element === 'button' ? disabled : null,
      onMouseUp: this.handleMouseUp,
      onMouseLeave: this.handleMouseLeave,
      type: element === 'button' ? type : null,
      'data-teamleader-ui': 'button',
    };

    return React.createElement(
      element,
      props,
      icon && iconPlacement === 'left' && icon,
      (label || children) && (

          {label}
          {children}

      ),
      icon && iconPlacement === 'right' && icon,
      processing && (
        <LoadingSpinner
          className={theme['spinner']}
          color={this.getSpinnerColor()}
          size={size === 'small' ? 'small' : 'medium'}
        />
      ),
    );
  }
}

Button.propTypes = {
  /** The content to display inside the button. */
  children: PropTypes.any,
  /** A class name for the button to give custom styles. */
  className: PropTypes.string,
  /** A custom element to be rendered */
  element: PropTypes.oneOfType([PropTypes.element, PropTypes.string]),
  /** Determines which kind of button to be rendered. */
  level: PropTypes.oneOf(['outline', 'primary', 'secondary', 'destructive']),
  /** If true, component will be disabled. */
  disabled: PropTypes.bool,
  /** If true, component will be shown in an active state */
  active: PropTypes.bool,
  /** If true, component will take the full width available. */
  fullWidth: PropTypes.bool,
  /** The icon displayed inside the button. */
  icon: PropTypes.element,
  /** The position of the icon inside the button. */
  iconPlacement: PropTypes.oneOf(['left', 'right']),
  /** If true, component will be rendered in inverse mode. */
  inverse: PropTypes.bool,
  /** The textual label displayed inside the button. */
  label: PropTypes.string,
  /** Callback function that is fired when mouse leaves the component. */
  onMouseLeave: PropTypes.func,
  /** Callback function that is fired when the mouse button is released. */
  onMouseUp: PropTypes.func,
  /** If true, component will show a loading spinner instead of label or children. */
  processing: PropTypes.bool,
  /** Size of the button. */
  size: PropTypes.oneOf(['small', 'medium', 'large']),
  /** Type of the button element. */
  type: PropTypes.string,
};

Button.defaultProps = {
  className: '',
  element: 'button',
  fullWidth: false,
  level: 'secondary',
  iconPlacement: 'left',
  inverse: false,
  processing: false,
  size: 'medium',
  type: 'button',
};

export default Button;
<|endoftext|>


<commit_before>//
//   Copyright 2009-2014 Ilkka Oksanen <iao@iki.fi>
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing,
//   software distributed under the License is distributed on an "AS
//   IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
//   express or implied.  See the License for the specific language
//   governing permissions and limitations under the License.
//

'use strict';

/* globals $, FileAPI, emojify, titlenotifier, isMobile */

import Ember from 'ember';
import { play } from '../../../helpers/sound';
import UploadMixin from '../../../mixins/upload';

export default Ember.Component.extend(UploadMixin, {
    classNames: [ 'window', 'flex-grow-column' ],

    classNameBindings: [
        'animating:velocity-animating:',
        'expanded:expanded:',
        'visible:visible:hidden',
        'ircServerWindow:irc-server-window:',
        'type'
    ],

    expanded: false,
    animating: false,
    scrollLock: false,

    linesAmount: null,
    deletedLine: false,

    $messagePanel: null,
    $messagesEndAnchor: null,
    logModeEnabled: false,

    selectedDesktop: 0,

    row: Ember.computed.alias('content.row'),
    column: Ember.computed.alias('content.column'),
    desktop: Ember.computed.alias('content.desktop'),

    visible: Ember.computed('selectedDesktop', 'content.desktop', function() {
        return this.get('selectedDesktop') === this.get('content.desktop');
    }),

    logOrMobileModeEnabled: Ember.computed('logModeEnabled', function() {
        return this.get('logModeEnabled') || isMobile.any;
    }),

    ircServerWindow: Ember.computed('content.userId', function() {
        return this.get('content.userId') === 'iSERVER' ? 'irc-server-window' : '';
    }),

    isGroup: Ember.computed('content.type', function() {
        return this.get('content.type') === 'group';
    }),

    type: Ember.computed('content.type', function() {
        if (this.get('content.type') === 'group') {
            return 'group';
        } else if (this.get('content.userId') === 'iSERVER') {
            return 'server-1on1';
        } else {
            return 'private-1on1';
        }
    }),

    hiddenIfLogMode: Ember.computed('logModeEnabled', function() {
        return this.get('logModeEnabled') ? 'hidden' : '';
    }),

    hiddenIfMinimizedUserNames: Ember.computed('content.minimizedNamesList', function() {
        return this.get('content.minimizedNamesList') ? 'hidden' : '';
    }),

    wideUnlessminimizedNamesList: Ember.computed('content.minimizedNamesList', function() {
        return this.get('content.minimizedNamesList') ? '' : 'window-members-wide';
    }),

    windowChanged: Ember.observer('row', 'column', 'desktop', function() {
        this.sendAction('relayout', { animate: true });
    }),

    visibilityChanged: Ember.observer('visible', function() {
        if (this.get('visible')) {
            this.set('content.newMessagesCount', 0);
        }

        this.sendAction('relayout', { animate: false });
    }),

    _lineAdded() {
        let messages = this.get('content.messages');
        let cat = messages[messages.length - 1].cat; // Message that was just added.
        let importantMessage = cat === 'msg' || cat === 'error' || cat === 'action';

        if ((!this.get('visible') || this.get('scrollLock')) && importantMessage) {
            this.incrementProperty('content.newMessagesCount');
        }

        if (document.hidden && importantMessage) {
            // Browser title notification
            if (this.get('content.titleAlert')) {
                titlenotifier.add();
            }

            // Sound notification
            if (this.get('content.sounds')) {
                play();
            }
        }

        Ember.run.scheduleOnce('afterRender', this, function() {
            this._goToBottom(true);
        });
    },

    actions: {
        expand() {
            this.set('expanded', true);
            this.sendAction('relayout', { animate: true });
        },

        compress() {
            this.set('expanded', false);
            this.sendAction('relayout', { animate: true });
        },

        browse() {
            this.set('logModeEnabled', true);
            this.set('expanded', true);
            this.sendAction('relayout', { animate: true });
        },

        toggleMemberListWidth() {
            this.toggleProperty('content.minimizedNamesList');
        },

        sendMessage() {
            let message = this.get('newMessage');

            if (message) {
                this.sendAction('action', 'sendMessage', this.get('content'), message);
                this.set('newMessage', '');
            }
        },

        close() {
            this.sendAction('action', 'close', this.get('content'));
        },

        menu(operation) {
            this.sendAction('menuAction', operation, this.get('content'));
        },

        jumpToBottom() {
            this.set('scrollLock', false);
            this._goToBottom(true);
        },

        hideImages(message) {
            message.set('hideImages', true);
        }
    },

    move(dim, duration) {
        this.set('animating', true);

        this.$().velocity('stop').velocity(dim, {
            duration: duration,
            visibility: 'visible',
            complete: Ember.run.bind(this, function() {
                this.set('animating', false);
                this._goToBottom(false); // Make sure window shows the latest messages
                this._showImages();
            })
        });
    },

    mouseDown(event) {
        if (!$(event.target).hasClass('fa-arrows')) {
            return; // Not moving the window
        }

        event.preventDefault();
        this.sendAction('dragWindowStart', this, event);
    },

    didInsertElement() {
        let that = this;

        this.sendAction('register', this);

        this.$messagePanel = this.$('.window-messages');
        this.$messagesEndAnchor = this.$('.window-messages-end');

        this.$('.window-caption').tooltip();
        this.$messagePanel.tooltip({
            selector: '.timestamp',
            placement: 'right'
        });

        let selectedUserId;

        this.$('.window-members').contextmenu({
            target: '#window-contextMenu',
            before(e) {
                let $target = $(e.target);

                if ($target.hasClass('window-members')) {
                    return false;
                }

                e.preventDefault();
                let $row = $target.closest('.member-row');

                let selectedNick = $row.data('nick');
                let avatar = $row.find('.gravatar').attr('src');
                selectedUserId = $row.data('userid');

                this.getMenu().find('li').eq(0).html(
                    `<img class="menu-avatar" src="${avatar}">${selectedNick}`);

                // Only MAS users can be added to a contacts list.
                $('.window-contexMenu-request-friend').toggle(selectedUserId.charAt(0) === 'm');

                return true;
            },
            onItem(context, e) {
                let action = $(e.target).data('action');
                that.sendAction('action', action, that.content, selectedUserId);
            }
        });

        this.$('.window-members').click(function(e) {
            $(this).contextmenu('show', e);
            e.preventDefault();
            return false;
        });

        let emojisList = $.map(emojify.emojiNames, function(value, i) {
            return { id: i, name: value };
        });

        let emojiListTemplate = '
 ${name}
';

        this.$('.form-control').atwho({
            at: ':',
            displayTpl: emojiListTemplate,
            insertTpl: ':${name}:',
            data: emojisList,
            highlightFirst: false,
            limit: 20
        });

        function getNick(item) {
            return item.nick;
        }

        let nickList = this.get('content.operatorNames').map(getNick)
            .concat(this.get('content.voiceNames').map(getNick))
            .concat(this.get('content.userNames').map(getNick));

        this.$('.form-control').atwho({
            at: '@',
            data: nickList,
            limit: 10
        });

        this.$messagePanel.magnificPopup({
            type: 'image',
            delegate: '.user-img:not(.user-img-close)',
            closeOnContentClick: true,
            image: {
                verticalFit: false,
                titleSrc(item) {
                    let href = item.el.attr('href');

                    return 'Link to the original image:' + href + '';
                }
            }
        });

        let fileInput = this.$('.btn-file input')[0];

        FileAPI.event.on(fileInput, 'change', function(evt) {
            let files = FileAPI.getFiles(evt); // Retrieve file list
            this.send('upload', files, 'jpeg');
        }.bind(this));

        this.sendAction('relayout', { animate: false });

        this._addScrollHandler();

        // TBD: Can timer removed? Do this after first visible true and gotobottom call?
        Ember.run.later(this, function() {
            this._showImages();
            this._addLazyImageScrollHandler();
        }, 4000);

        this.get('content.messages').addArrayObserver(this);
    },

    arrayWillChange: function(array, offset, removeCount) {
        if (removeCount > 0) {
           this.set('deletedLine', true);
        }
    },

    arrayDidChange: function(array, offset, removeCount, addCount){
        if (addCount > 0) {
           this._lineAdded();
        }
    },

    willDestroyElement() {
        this.$().velocity('stop');
        this.sendAction('unregister', this);

        Ember.run.scheduleOnce('afterRender', this, function() {
            this.sendAction('relayout', { animate: true });
        });
    },

    _goToBottom(animate) {
        if (this.get('scrollLock') || !this.$messagesEndAnchor) {
            return;
        }

        let duration = animate ? 200 : 0;

        // There's an odd bug(?) in Chrome. Offset below can't be just some large enough number
        // to make sure we reach the bottom every time. If it is, Chrome scrolls beyond end of the
        // content. Spent several days figuring out what was going on. Problem is not related to
        // velocity.js. It happens with jQuery.scrollTop() as well.
        this.$messagesEndAnchor.velocity('stop').velocity('scroll', {
            container: this.$messagePanel,
            duration: duration,
            easing: 'spring',
            offset: -1 * this.$messagePanel.innerHeight() + 5, // 5px is padding
        });
    },

    _addScrollHandler() {
        let handler = function() {
            if (this.get('animating')) {
                return;
            }

            let $panel = this.$messagePanel;
            let scrollPos = $panel.scrollTop();

            // User doesn't need to scroll exactly to the end.
            let bottomTreshhold = $panel.prop('scrollHeight') - 5;

            if (scrollPos + $panel.innerHeight() >= bottomTreshhold) {
                this.set('scrollLock', false);
                Ember.Logger.info('scrollock off');
            } else if (!this.get('deletedLine')) {
                this.set('scrollLock', true);
                Ember.Logger.info('scrollock on');
            }

            this.set('deletedLine', false); // Hack
        };

        this.$messagePanel.on('scroll', () => {
            // Delay nust be longer than goToBottom animation
            Ember.run.throttle(this, handler, 250, false);
        });
    },

    _addLazyImageScrollHandler() {
        this.$messagePanel.on('scroll', () => {
            Ember.run.throttle(this, this._showImages, 250, true);
        });
    },

    _showImages() {
        let $imgContainers = this.$('ul[data-has-images="true"]');

        if (!$imgContainers) {
            return;
        }

        const placeHolderHeight = 31;
        let panelHeight = this.$messagePanel.height();
        let that = this;

        $imgContainers.each(function() {
            let $imgContainer = $(this);
            // We want to know image's position in .window-messages container div. For position()
            // to work correctly, .window-messages has to have position set to 'relative'. See
            // jQuery offsetParent() documentation for details.
            let pos = $imgContainer.position().top;

            if (pos + placeHolderHeight >= 0 && pos <= panelHeight) {
                // Images of this message are in view port. Start to lazy load images.
                let message = that.get('content.messages').findBy('gid', $imgContainer.data('gid'));
                let images = message.get('images') || [];

                for (let i = 0; i < images.length; i++) {
                    let image = images[i];

                    if (image.get('source')) {
                        // Image has been already loaded
                        continue;
                    }

                    image.set('source', image.get('url'));

                    let $image = $imgContainer.find('img').eq(i);

                    $image.one('load error', function(e) {
                        if (e.type === 'error') {
                            $image.hide();
                        }

                        Ember.run(function() {
                            Ember.Logger.info('Lazy loaded image');

                            image.set('loaded', true);

                            Ember.run.scheduleOnce('afterRender', this, function() {
                                that._goToBottom(true);
                            });
                        });
                    });
                }
            }
        });
    }
});
<commit_msg>Bring back nick name completion<commit_after>//
//   Copyright 2009-2014 Ilkka Oksanen <iao@iki.fi>
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing,
//   software distributed under the License is distributed on an "AS
//   IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
//   express or implied.  See the License for the specific language
//   governing permissions and limitations under the License.
//

'use strict';

/* globals $, FileAPI, emojify, titlenotifier, isMobile */

import Ember from 'ember';
import { play } from '../../../helpers/sound';
import UploadMixin from '../../../mixins/upload';

export default Ember.Component.extend(UploadMixin, {
    classNames: [ 'window', 'flex-grow-column' ],

    classNameBindings: [
        'animating:velocity-animating:',
        'expanded:expanded:',
        'visible:visible:hidden',
        'ircServerWindow:irc-server-window:',
        'type'
    ],

    expanded: false,
    animating: false,
    scrollLock: false,

    linesAmount: null,
    deletedLine: false,

    $messagePanel: null,
    $messagesEndAnchor: null,
    logModeEnabled: false,

    selectedDesktop: 0,

    row: Ember.computed.alias('content.row'),
    column: Ember.computed.alias('content.column'),
    desktop: Ember.computed.alias('content.desktop'),

    visible: Ember.computed('selectedDesktop', 'content.desktop', function() {
        return this.get('selectedDesktop') === this.get('content.desktop');
    }),

    logOrMobileModeEnabled: Ember.computed('logModeEnabled', function() {
        return this.get('logModeEnabled') || isMobile.any;
    }),

    ircServerWindow: Ember.computed('content.userId', function() {
        return this.get('content.userId') === 'iSERVER' ? 'irc-server-window' : '';
    }),

    isGroup: Ember.computed('content.type', function() {
        return this.get('content.type') === 'group';
    }),

    type: Ember.computed('content.type', function() {
        if (this.get('content.type') === 'group') {
            return 'group';
        } else if (this.get('content.userId') === 'iSERVER') {
            return 'server-1on1';
        } else {
            return 'private-1on1';
        }
    }),

    hiddenIfLogMode: Ember.computed('logModeEnabled', function() {
        return this.get('logModeEnabled') ? 'hidden' : '';
    }),

    hiddenIfMinimizedUserNames: Ember.computed('content.minimizedNamesList', function() {
        return this.get('content.minimizedNamesList') ? 'hidden' : '';
    }),

    wideUnlessminimizedNamesList: Ember.computed('content.minimizedNamesList', function() {
        return this.get('content.minimizedNamesList') ? '' : 'window-members-wide';
    }),

    windowChanged: Ember.observer('row', 'column', 'desktop', function() {
        this.sendAction('relayout', { animate: true });
    }),

    visibilityChanged: Ember.observer('visible', function() {
        if (this.get('visible')) {
            this.set('content.newMessagesCount', 0);
        }

        this.sendAction('relayout', { animate: false });
    }),

    nickCompletion: Ember.observer('content.userNames.@each', 'content.voiceNames.@each',
        'content.operatorNames.@each', function() {
        this._updateNickCompletionList();
    }),

    _updateNickCompletionList() {
        let target = this.$('.form-control');

        if (!target) {
            return;
        }

        let nickList = this.get('content.operatorNames').concat(this.get('content.voiceNames'),
            this.get('content.userNames')).map(item => item.nick);

        target.atwho({
            at: '@',
            data: nickList,
            limit: 15
        });
    },

    _lineAdded() {
        let messages = this.get('content.messages');
        let cat = messages[messages.length - 1].cat; // Message that was just added.
        let importantMessage = cat === 'msg' || cat === 'error' || cat === 'action';

        if ((!this.get('visible') || this.get('scrollLock')) && importantMessage) {
            this.incrementProperty('content.newMessagesCount');
        }

        if (document.hidden && importantMessage) {
            // Browser title notification
            if (this.get('content.titleAlert')) {
                titlenotifier.add();
            }

            // Sound notification
            if (this.get('content.sounds')) {
                play();
            }
        }

        Ember.run.scheduleOnce('afterRender', this, function() {
            this._goToBottom(true);
        });
    },

    actions: {
        expand() {
            this.set('expanded', true);
            this.sendAction('relayout', { animate: true });
        },

        compress() {
            this.set('expanded', false);
            this.sendAction('relayout', { animate: true });
        },

        browse() {
            this.set('logModeEnabled', true);
            this.set('expanded', true);
            this.sendAction('relayout', { animate: true });
        },

        toggleMemberListWidth() {
            this.toggleProperty('content.minimizedNamesList');
        },

        sendMessage() {
            let message = this.get('newMessage');

            if (message) {
                this.sendAction('action', 'sendMessage', this.get('content'), message);
                this.set('newMessage', '');
            }
        },

        close() {
            this.sendAction('action', 'close', this.get('content'));
        },

        menu(operation) {
            this.sendAction('menuAction', operation, this.get('content'));
        },

        jumpToBottom() {
            this.set('scrollLock', false);
            this._goToBottom(true);
        },

        hideImages(message) {
            message.set('hideImages', true);
        }
    },

    move(dim, duration) {
        this.set('animating', true);

        this.$().velocity('stop').velocity(dim, {
            duration: duration,
            visibility: 'visible',
            complete: Ember.run.bind(this, function() {
                this.set('animating', false);
                this._goToBottom(false); // Make sure window shows the latest messages
                this._showImages();
            })
        });
    },

    mouseDown(event) {
        if (!$(event.target).hasClass('fa-arrows')) {
            return; // Not moving the window
        }

        event.preventDefault();
        this.sendAction('dragWindowStart', this, event);
    },

    didInsertElement() {
        let that = this;

        this.sendAction('register', this);

        this.$messagePanel = this.$('.window-messages');
        this.$messagesEndAnchor = this.$('.window-messages-end');

        this.$('.window-caption').tooltip();
        this.$messagePanel.tooltip({
            selector: '.timestamp',
            placement: 'right'
        });

        let selectedUserId;

        this.$('.window-members').contextmenu({
            target: '#window-contextMenu',
            before(e) {
                let $target = $(e.target);

                if ($target.hasClass('window-members')) {
                    return false;
                }

                e.preventDefault();
                let $row = $target.closest('.member-row');

                let selectedNick = $row.data('nick');
                let avatar = $row.find('.gravatar').attr('src');
                selectedUserId = $row.data('userid');

                this.getMenu().find('li').eq(0).html(
                    `<img class="menu-avatar" src="${avatar}">${selectedNick}`);

                // Only MAS users can be added to a contacts list.
                $('.window-contexMenu-request-friend').toggle(selectedUserId.charAt(0) === 'm');

                return true;
            },
            onItem(context, e) {
                let action = $(e.target).data('action');
                that.sendAction('action', action, that.content, selectedUserId);
            }
        });

        this.$('.window-members').click(function(e) {
            $(this).contextmenu('show', e);
            e.preventDefault();
            return false;
        });

        let emojisList = $.map(emojify.emojiNames, function(value, i) {
            return { id: i, name: value };
        });

        let emojiListTemplate = '
 ${name}
';

        this.$('.form-control').atwho({
            at: ':',
            displayTpl: emojiListTemplate,
            insertTpl: ':${name}:',
            data: emojisList,
            highlightFirst: false,
            limit: 20
        });

        this._updateNickCompletionList();

        this.$messagePanel.magnificPopup({
            type: 'image',
            delegate: '.user-img:not(.user-img-close)',
            closeOnContentClick: true,
            image: {
                verticalFit: false,
                titleSrc(item) {
                    let href = item.el.attr('href');

                    return 'Link to the original image:' + href + '';
                }
            }
        });

        let fileInput = this.$('.btn-file input')[0];

        FileAPI.event.on(fileInput, 'change', function(evt) {
            let files = FileAPI.getFiles(evt); // Retrieve file list
            this.send('upload', files, 'jpeg');
        }.bind(this));

        this.sendAction('relayout', { animate: false });

        this._addScrollHandler();

        // TBD: Can timer removed? Do this after first visible true and gotobottom call?
        Ember.run.later(this, function() {
            this._showImages();
            this._addLazyImageScrollHandler();
        }, 4000);

        this.get('content.messages').addArrayObserver(this);
    },

    arrayWillChange: function(array, offset, removeCount) {
        if (removeCount > 0) {
           this.set('deletedLine', true);
        }
    },

    arrayDidChange: function(array, offset, removeCount, addCount){
        if (addCount > 0) {
           this._lineAdded();
        }
    },

    willDestroyElement() {
        this.$().velocity('stop');
        this.sendAction('unregister', this);

        Ember.run.scheduleOnce('afterRender', this, function() {
            this.sendAction('relayout', { animate: true });
        });
    },

    _goToBottom(animate) {
        if (this.get('scrollLock') || !this.$messagesEndAnchor) {
            return;
        }

        let duration = animate ? 200 : 0;

        // There's an odd bug(?) in Chrome. Offset below can't be just some large enough number
        // to make sure we reach the bottom every time. If it is, Chrome scrolls beyond end of the
        // content. Spent several days figuring out what was going on. Problem is not related to
        // velocity.js. It happens with jQuery.scrollTop() as well.
        this.$messagesEndAnchor.velocity('stop').velocity('scroll', {
            container: this.$messagePanel,
            duration: duration,
            easing: 'spring',
            offset: -1 * this.$messagePanel.innerHeight() + 5, // 5px is padding
        });
    },

    _addScrollHandler() {
        let handler = function() {
            if (this.get('animating')) {
                return;
            }

            let $panel = this.$messagePanel;
            let scrollPos = $panel.scrollTop();

            // User doesn't need to scroll exactly to the end.
            let bottomTreshhold = $panel.prop('scrollHeight') - 5;

            if (scrollPos + $panel.innerHeight() >= bottomTreshhold) {
                this.set('scrollLock', false);
                Ember.Logger.info('scrollock off');
            } else if (!this.get('deletedLine')) {
                this.set('scrollLock', true);
                Ember.Logger.info('scrollock on');
            }

            this.set('deletedLine', false); // Hack
        };

        this.$messagePanel.on('scroll', () => {
            // Delay nust be longer than goToBottom animation
            Ember.run.throttle(this, handler, 250, false);
        });
    },

    _addLazyImageScrollHandler() {
        this.$messagePanel.on('scroll', () => {
            Ember.run.throttle(this, this._showImages, 250, true);
        });
    },

    _showImages() {
        let $imgContainers = this.$('ul[data-has-images="true"]');

        if (!$imgContainers) {
            return;
        }

        const placeHolderHeight = 31;
        let panelHeight = this.$messagePanel.height();
        let that = this;

        $imgContainers.each(function() {
            let $imgContainer = $(this);
            // We want to know image's position in .window-messages container div. For position()
            // to work correctly, .window-messages has to have position set to 'relative'. See
            // jQuery offsetParent() documentation for details.
            let pos = $imgContainer.position().top;

            if (pos + placeHolderHeight >= 0 && pos <= panelHeight) {
                // Images of this message are in view port. Start to lazy load images.
                let message = that.get('content.messages').findBy('gid', $imgContainer.data('gid'));
                let images = message.get('images') || [];

                for (let i = 0; i < images.length; i++) {
                    let image = images[i];

                    if (image.get('source')) {
                        // Image has been already loaded
                        continue;
                    }

                    image.set('source', image.get('url'));

                    let $image = $imgContainer.find('img').eq(i);

                    $image.one('load error', function(e) {
                        if (e.type === 'error') {
                            $image.hide();
                        }

                        Ember.run(function() {
                            Ember.Logger.info('Lazy loaded image');

                            image.set('loaded', true);

                            Ember.run.scheduleOnce('afterRender', this, function() {
                                that._goToBottom(true);
                            });
                        });
                    });
                }
            }
        });
    }
});
<|endoftext|>


<commit_before>// This is the JavaScript interface between CodeBox.elm and ace.js.
//
// Relevant Ports:
//   aceInTheHole -- Is where new (partial) Models to be rendered come from
//   theTurn      -- Is where what become Events for things like code updates go
//

window.initialPortValues["theTurn"] = { evt : "init"
                                      , strArg : ""
                                      , cursorArg : { row : 0 , column : 0 }
                                      , selectionArg : []
                                      , exNameArg : ""
                                      }

window.initializers.push(function (elmRuntime) {

  // Holds on to the current document name for error recovery purposes
  var exName = "";

  var Range = ace.require('ace/range').Range

  //So we can dynamically add CSS classes, which is needed to style the markers
  //Generally only touches the DOM to add new ones if absolutely needed
  var style = document.createElement('style');
  style.id = "autogenerated_css_classes";
  style.type = 'text/css';
  document.getElementsByTagName('head')[0].appendChild(style);
  var classDict = {};

  function makeCSSClass(colorStr) {
      var autogenName = ".autogenerated_class_" + colorStr
      if (!(classDict.hasOwnProperty(autogenName))) {
          style.innerHTML = style.innerHTML
                              + ".ace_marker-layer "
                              + autogenName
                              + " { background-color : " + colorStr+ "; "
                              + "position : absolute; "
                              + "z-index : 2; "
                              + "} ";
          document.getElementById("autogenerated_css_classes").innerHTML = style.innerHTML;
          classDict[autogenName] = true;
      }
      return "autogenerated_class_" + colorStr;
  }

  var editor = ace.edit("editor");
  editor.$blockScrolling = Infinity;
  editor.setTheme("ace/theme/chrome");
  // editor.setFontSize(14);
  editor.setFontSize(20);
  editor.getSession().setMode("ace/mode/little");

  //If we reloaded from a crash, then we should do a few things differently:
  // - Set the initial text to what it was when we crashed
  // - Send an event to Elm to let Elm know that we just crashed
  var maybeError = localStorage.getItem("__ErrorSave");
  if (maybeError !== null) {
      localStorage.removeItem("__ErrorSave");
      console.log(maybeError);
      var errorObj = JSON.parse(maybeError);
      var defaultScratch = errorObj.strArg;
      elmRuntime.ports.theTurn.send(
              { evt : errorObj.evt
              , strArg : errorObj.strArg
              , cursorArg : errorObj.cursorArg
              , selectionArg : errorObj.selectionArg
              , exNameArg : errorObj.exNameArg
              }
      );
  } else {
      //Set the default scratch text to display before the first load
      var defaultScratch =
      "\n" +
      "; Write a little program below.\n" +
      "; Or choose an example from the list.\n" +
      ";\n" +
      "; Changes to this *Scratch* example will be saved and\n" +
      "; restored when navigating to and from other examples.\n" +
      "; For the remaining named examples, changes will be\n" +
      "; discarded when choosing a different example.\n" +
      "\n" +
      "(svg [(rect 'maroon' 100 15 200 15)])\n" +
      "\n";
  }
  editor.setValue(defaultScratch);
  editor.moveCursorTo(0,0);

  var markers = [];

  elmRuntime.ports.aceInTheHole.subscribe(function(codeBoxInfo) {
      //If a poke, do nothing
      if (codeBoxInfo.kind == "poke") {
          editor.resize();
          reembed(false);
          //If we should bounce an update back (force a rerender) then do so
          bounce(codeBoxInfo.bounce);
          //Set the contents to the correct manipulable state
          if (!codeBoxInfo.manipulable) {
              editor.container.style.zIndex = "0";
              editor.container.style.pointerEvents = "auto";
              editor.setReadOnly(true);
          } else {
              editor.container.style.zIndex = "1";
              editor.container.style.pointerEvents = "auto";
              editor.setReadOnly(false);
          }
          return;
      }

      //Resize the editor window if the div size has changed
      editor.resize();

      //First, check to see what kind of request it was
      if (codeBoxInfo.kind == "assertion") {
          //If it's an assertion, install the values appropriately
          makeAssertion(codeBoxInfo);
      } else if (codeBoxInfo.kind == "saveRequest") {
          //If it's a request for the Editor state, oblige
          sendState("saveResponse");
          //For error recovery purposes
          exName = codeBoxInfo.exName;
      } else if (codeBoxInfo.kind == "runRequest") {
          //Same as above
          sendState("runResponse");
      } else if (codeBoxInfo.kind == "cleanRequest") {
        sendState("cleanResponse");
      } else if (codeBoxInfo.kind == "codeRequest") {
        sendState("codeResponse");
      } else { //We don't recognize the request; log and do nothing
          console.log("codeBoxInfo type " + codeBoxInfo.kind + " unrecognized.");
      }
  });

  var errorPrefix = "[Little Error]"; // NOTE: same as errorPrefix in Lang.elm

  //We recover from fatal errors by setting a special key in the local key/value
  // store before reloading the page. Then we check for this key on load and set
  // up appropriately if we're loading after a crash.
  window.onerror = function(msg, url, linenumber) {
    //We disallow saving to this key in Elm to avoid possible confusion
    //If the error was something that we didn't want to catch (e.g. not prefaced
    // with errorPrefix) then don't do anything
    // Checking for string containment, rather than trimming the prefix
    // because of different error strings in different browsers.

    // TODO change this back
    // if (msg.indexOf(errorPrefix) != 1) {
    if (msg.indexOf("notify function has been called synchronously!") != 1) {
        localStorage.setItem('__ErrorSave', JSON.stringify(
          { evt : msg
          , strArg : editor.getSession().getDocument().getValue()
          , cursorArg : editor.getCursorPosition()
          , selectionArg : editor.selection.getAllRanges()
          , exNameArg : exName
          }
        ));
        location.reload();
    }
  }

  //Packages and sends the Editor state appropriately
  function sendState(evt) {
    elmRuntime.ports.theTurn.send(
      { evt : evt
      , strArg : editor.getSession().getDocument().getValue()
      , cursorArg : editor.getCursorPosition()
      , selectionArg : editor.selection.getAllRanges()
      , exNameArg : ""
      }
    );
  }

  //Re-embeds the editor in the "editor" div
  function reembed(force) {
      //If the div rerendered (kept track of with a special attribute) then we
      // should copy the editor back into it
      var editorDiv = document.getElementById("editor");
      if (force || editorDiv.getAttribute("rendered") !== "true") {
        editorDiv.parentNode.replaceChild(editor.container, editorDiv);
        editorDiv.setAttribute("rendered","true");
      }
  }

  //Bounces a message back to rerender, if applicable
  function bounce(check) {
    if (check) {
        elmRuntime.ports.theTurn.send(
            { evt : "Rerender"
            , strArg : ""
            , cursorArg : editor.getCursorPosition()
            , selectionArg : []
            , exNameArg : ""
            }
        );
    }
  }

  // Installs all the values that we got from the assertion from Elm
  function makeAssertion(codeBoxInfo) {
      //Set the value of the code editor with what we got from Elm
      editor.getSession().setValue(codeBoxInfo.code, 0);
      //Set the cursor position to what we got from Elm
      editor.moveCursorTo(codeBoxInfo.cursorPos.row, codeBoxInfo.cursorPos.column);
      //Set the selections appropriately
      //Note that we need to turn the Elm Ranges into Ace Range Objects
      editor.selection.clearSelection();

      /* No need for this anymore, as assertions are not on every input
      //We need to treat the first one differently, so we must iterate
      //This is undocumented outside of the tests, see:
      // https://github.com/ajaxorg/ace/blob/0a3b002e285a41a4884ce42f94d2f68673e43b30/lib/ace/multi_select_test.js#L168
      //For the special namespacing, see:
      // http://stackoverflow.com/questions/10452869/when-i-try-to-create-a-range-object-in-ace-js-an-illegal-constructor-error-is
      var numRanges = codeBoxInfo.selections.length;
      for (var i = 0; i < numRanges; i++) {
          elmRange = codeBoxInfo.selections[i];
          var aceRange = new Range(elmRange.start.row,
                                   elmRange.start.column,
                                   elmRange.end.row,
                                   elmRange.end.column);
          if (i === 0) {
              //We only allow backwards selections if there is just one selection
              //We deduce if it's backwards by comparing the cursor position to
              // the end of the selection (which always orients itself such that
              // it's > the start in the process of constucting the Range)
              //Note that we use compareEnd here because the compare functions are
              // a little wonky - compareStart returns -1, for instance, if the
              // cursor is at the start.
              if (numRanges === 1) {
                  if (aceRange.compareEnd(codeBoxInfo.cursorPos.row,
                                          codeBoxInfo.cursorPos.column) === 1) {
                      var backwards = false;
                  } else {
                      var backwards = true;
                  }
                  editor.selection.setSelectionRange(aceRange, backwards);
              } else {
                  editor.selection.fromOrientedRange(aceRange);
              }
          } else {
              editor.selection.addRange(aceRange, false);
          }
      }
      */

      //Add the special syntax highlighting for changes and such
      //These are 'markers', see:
      //http://ace.c9.io/#nav=api&api=edit_session
      //ctl+f addMarker
      for (mi in markers) {
          editor.getSession().removeMarker(markers[mi]);
      }
      markers = [];
      for (hi in codeBoxInfo.highlights) {
          hiRange = codeBoxInfo.highlights[hi].range;
          var aceRange = new Range(hiRange.start.row - 1, //Indexing from 1 in Elm?
                                   hiRange.start.column - 1,
                                   hiRange.end.row - 1,
                                   hiRange.end.column - 1);
          var hiClass = makeCSSClass(codeBoxInfo.highlights[hi].color);
          var mid = editor.getSession().addMarker(aceRange,hiClass,"text", false);
          editor.resize();
          markers.push(mid);
      }
      editor.updateSelectionMarkers();

      //If the div rerendered (kept track of with a special attribute) then we
      // should copy the editor back into it
      reembed(false);

      //Set the contents to the correct manipulable state
      if (!codeBoxInfo.manipulable) {
          editor.container.style.zIndex = "0";
          editor.container.style.pointerEvents = "auto";
          editor.setReadOnly(true);
      } else {
          editor.container.style.zIndex = "1";
          editor.container.style.pointerEvents = "auto";
          editor.setReadOnly(false);
      }

      //If we should bounce an update back (force a rerender) then do so
      bounce(codeBoxInfo.bounce);

      //Remember the current document name (for error recovery purposes)
      exName = codeBoxInfo.exName;
  }

});
<commit_msg>fontSize<commit_after>// This is the JavaScript interface between CodeBox.elm and ace.js.
//
// Relevant Ports:
//   aceInTheHole -- Is where new (partial) Models to be rendered come from
//   theTurn      -- Is where what become Events for things like code updates go
//

window.initialPortValues["theTurn"] = { evt : "init"
                                      , strArg : ""
                                      , cursorArg : { row : 0 , column : 0 }
                                      , selectionArg : []
                                      , exNameArg : ""
                                      }

window.initializers.push(function (elmRuntime) {

  // Holds on to the current document name for error recovery purposes
  var exName = "";

  var Range = ace.require('ace/range').Range

  //So we can dynamically add CSS classes, which is needed to style the markers
  //Generally only touches the DOM to add new ones if absolutely needed
  var style = document.createElement('style');
  style.id = "autogenerated_css_classes";
  style.type = 'text/css';
  document.getElementsByTagName('head')[0].appendChild(style);
  var classDict = {};

  function makeCSSClass(colorStr) {
      var autogenName = ".autogenerated_class_" + colorStr
      if (!(classDict.hasOwnProperty(autogenName))) {
          style.innerHTML = style.innerHTML
                              + ".ace_marker-layer "
                              + autogenName
                              + " { background-color : " + colorStr+ "; "
                              + "position : absolute; "
                              + "z-index : 2; "
                              + "} ";
          document.getElementById("autogenerated_css_classes").innerHTML = style.innerHTML;
          classDict[autogenName] = true;
      }
      return "autogenerated_class_" + colorStr;
  }

  var editor = ace.edit("editor");
  editor.$blockScrolling = Infinity;
  editor.setTheme("ace/theme/chrome");
  editor.setFontSize(14);
  editor.getSession().setMode("ace/mode/little");

  //If we reloaded from a crash, then we should do a few things differently:
  // - Set the initial text to what it was when we crashed
  // - Send an event to Elm to let Elm know that we just crashed
  var maybeError = localStorage.getItem("__ErrorSave");
  if (maybeError !== null) {
      localStorage.removeItem("__ErrorSave");
      console.log(maybeError);
      var errorObj = JSON.parse(maybeError);
      var defaultScratch = errorObj.strArg;
      elmRuntime.ports.theTurn.send(
              { evt : errorObj.evt
              , strArg : errorObj.strArg
              , cursorArg : errorObj.cursorArg
              , selectionArg : errorObj.selectionArg
              , exNameArg : errorObj.exNameArg
              }
      );
  } else {
      //Set the default scratch text to display before the first load
      var defaultScratch =
      "\n" +
      "; Write a little program below.\n" +
      "; Or choose an example from the list.\n" +
      ";\n" +
      "; Changes to this *Scratch* example will be saved and\n" +
      "; restored when navigating to and from other examples.\n" +
      "; For the remaining named examples, changes will be\n" +
      "; discarded when choosing a different example.\n" +
      "\n" +
      "(svg [(rect 'maroon' 100 15 200 15)])\n" +
      "\n";
  }
  editor.setValue(defaultScratch);
  editor.moveCursorTo(0,0);

  var markers = [];

  elmRuntime.ports.aceInTheHole.subscribe(function(codeBoxInfo) {
      //If a poke, do nothing
      if (codeBoxInfo.kind == "poke") {
          editor.resize();
          reembed(false);
          //If we should bounce an update back (force a rerender) then do so
          bounce(codeBoxInfo.bounce);
          //Set the contents to the correct manipulable state
          if (!codeBoxInfo.manipulable) {
              editor.container.style.zIndex = "0";
              editor.container.style.pointerEvents = "auto";
              editor.setReadOnly(true);
          } else {
              editor.container.style.zIndex = "1";
              editor.container.style.pointerEvents = "auto";
              editor.setReadOnly(false);
          }
          return;
      }

      //Resize the editor window if the div size has changed
      editor.resize();

      //First, check to see what kind of request it was
      if (codeBoxInfo.kind == "assertion") {
          //If it's an assertion, install the values appropriately
          makeAssertion(codeBoxInfo);
      } else if (codeBoxInfo.kind == "saveRequest") {
          //If it's a request for the Editor state, oblige
          sendState("saveResponse");
          //For error recovery purposes
          exName = codeBoxInfo.exName;
      } else if (codeBoxInfo.kind == "runRequest") {
          //Same as above
          sendState("runResponse");
      } else if (codeBoxInfo.kind == "cleanRequest") {
        sendState("cleanResponse");
      } else if (codeBoxInfo.kind == "codeRequest") {
        sendState("codeResponse");
      } else { //We don't recognize the request; log and do nothing
          console.log("codeBoxInfo type " + codeBoxInfo.kind + " unrecognized.");
      }
  });

  var errorPrefix = "[Little Error]"; // NOTE: same as errorPrefix in Lang.elm

  //We recover from fatal errors by setting a special key in the local key/value
  // store before reloading the page. Then we check for this key on load and set
  // up appropriately if we're loading after a crash.
  window.onerror = function(msg, url, linenumber) {
    //We disallow saving to this key in Elm to avoid possible confusion
    //If the error was something that we didn't want to catch (e.g. not prefaced
    // with errorPrefix) then don't do anything
    // Checking for string containment, rather than trimming the prefix
    // because of different error strings in different browsers.

    // TODO change this back
    // if (msg.indexOf(errorPrefix) != 1) {
    if (msg.indexOf("notify function has been called synchronously!") != 1) {
        localStorage.setItem('__ErrorSave', JSON.stringify(
          { evt : msg
          , strArg : editor.getSession().getDocument().getValue()
          , cursorArg : editor.getCursorPosition()
          , selectionArg : editor.selection.getAllRanges()
          , exNameArg : exName
          }
        ));
        location.reload();
    }
  }

  //Packages and sends the Editor state appropriately
  function sendState(evt) {
    elmRuntime.ports.theTurn.send(
      { evt : evt
      , strArg : editor.getSession().getDocument().getValue()
      , cursorArg : editor.getCursorPosition()
      , selectionArg : editor.selection.getAllRanges()
      , exNameArg : ""
      }
    );
  }

  //Re-embeds the editor in the "editor" div
  function reembed(force) {
      //If the div rerendered (kept track of with a special attribute) then we
      // should copy the editor back into it
      var editorDiv = document.getElementById("editor");
      if (force || editorDiv.getAttribute("rendered") !== "true") {
        editorDiv.parentNode.replaceChild(editor.container, editorDiv);
        editorDiv.setAttribute("rendered","true");
      }
  }

  //Bounces a message back to rerender, if applicable
  function bounce(check) {
    if (check) {
        elmRuntime.ports.theTurn.send(
            { evt : "Rerender"
            , strArg : ""
            , cursorArg : editor.getCursorPosition()
            , selectionArg : []
            , exNameArg : ""
            }
        );
    }
  }

  // Installs all the values that we got from the assertion from Elm
  function makeAssertion(codeBoxInfo) {
      //Set the value of the code editor with what we got from Elm
      editor.getSession().setValue(codeBoxInfo.code, 0);
      //Set the cursor position to what we got from Elm
      editor.moveCursorTo(codeBoxInfo.cursorPos.row, codeBoxInfo.cursorPos.column);
      //Set the selections appropriately
      //Note that we need to turn the Elm Ranges into Ace Range Objects
      editor.selection.clearSelection();

      /* No need for this anymore, as assertions are not on every input
      //We need to treat the first one differently, so we must iterate
      //This is undocumented outside of the tests, see:
      // https://github.com/ajaxorg/ace/blob/0a3b002e285a41a4884ce42f94d2f68673e43b30/lib/ace/multi_select_test.js#L168
      //For the special namespacing, see:
      // http://stackoverflow.com/questions/10452869/when-i-try-to-create-a-range-object-in-ace-js-an-illegal-constructor-error-is
      var numRanges = codeBoxInfo.selections.length;
      for (var i = 0; i < numRanges; i++) {
          elmRange = codeBoxInfo.selections[i];
          var aceRange = new Range(elmRange.start.row,
                                   elmRange.start.column,
                                   elmRange.end.row,
                                   elmRange.end.column);
          if (i === 0) {
              //We only allow backwards selections if there is just one selection
              //We deduce if it's backwards by comparing the cursor position to
              // the end of the selection (which always orients itself such that
              // it's > the start in the process of constucting the Range)
              //Note that we use compareEnd here because the compare functions are
              // a little wonky - compareStart returns -1, for instance, if the
              // cursor is at the start.
              if (numRanges === 1) {
                  if (aceRange.compareEnd(codeBoxInfo.cursorPos.row,
                                          codeBoxInfo.cursorPos.column) === 1) {
                      var backwards = false;
                  } else {
                      var backwards = true;
                  }
                  editor.selection.setSelectionRange(aceRange, backwards);
              } else {
                  editor.selection.fromOrientedRange(aceRange);
              }
          } else {
              editor.selection.addRange(aceRange, false);
          }
      }
      */

      //Add the special syntax highlighting for changes and such
      //These are 'markers', see:
      //http://ace.c9.io/#nav=api&api=edit_session
      //ctl+f addMarker
      for (mi in markers) {
          editor.getSession().removeMarker(markers[mi]);
      }
      markers = [];
      for (hi in codeBoxInfo.highlights) {
          hiRange = codeBoxInfo.highlights[hi].range;
          var aceRange = new Range(hiRange.start.row - 1, //Indexing from 1 in Elm?
                                   hiRange.start.column - 1,
                                   hiRange.end.row - 1,
                                   hiRange.end.column - 1);
          var hiClass = makeCSSClass(codeBoxInfo.highlights[hi].color);
          var mid = editor.getSession().addMarker(aceRange,hiClass,"text", false);
          editor.resize();
          markers.push(mid);
      }
      editor.updateSelectionMarkers();

      //If the div rerendered (kept track of with a special attribute) then we
      // should copy the editor back into it
      reembed(false);

      //Set the contents to the correct manipulable state
      if (!codeBoxInfo.manipulable) {
          editor.container.style.zIndex = "0";
          editor.container.style.pointerEvents = "auto";
          editor.setReadOnly(true);
      } else {
          editor.container.style.zIndex = "1";
          editor.container.style.pointerEvents = "auto";
          editor.setReadOnly(false);
      }

      //If we should bounce an update back (force a rerender) then do so
      bounce(codeBoxInfo.bounce);

      //Remember the current document name (for error recovery purposes)
      exName = codeBoxInfo.exName;
  }

});
<|endoftext|>


<commit_before>var url = "/data/matrix.json",
  height = 600;
var width = 600;

// Colors Can be substituted to preference, in many ways less colors makes it nice...
var colorRange = ["#1a9850", "#d73027", "#fc8d59", "#fee08b", "#ffffbf", "#d9ef8b", "#91cf60"];
var fill = d3.scale.ordinal()
  .domain(d3.range(colorRange.length))
  .range(colorRange);

var fill = d3.scale.category20b();

var outerRadius = Math.min(width, height) / 2 - 8,
  innerRadius = outerRadius - 30;

var arc = d3.svg.arc()
  .innerRadius(innerRadius)
  .outerRadius(outerRadius);

var svg = d3.select('#chart')
  .append('svg')
  .attr('width', width)
  .attr('height', height)
  .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

function fadeChords(opacity, data) {
  return function(g, i) {
    var selected, notSelected, nonSelectIndexes;

    selected = svg.selectAll("g.chord path")
      .filter(function(d) {
        return d.source.index == i || d.target.index == i;
      });

    notSelected = svg.selectAll("g.chord path")
      .filter(function(d) {
        return d.source.index != i && d.target.index != i;
      });

    nonSelectIndexes = data[i]
      .map(function(d, i) {
        if (d == 0) {
          return i;
        }
        return undefined;
      })
      .filter(function(d) {
        return d != undefined;
      });

    nonSelectPaths = svg.selectAll("g.group path")
      .filter(function(g, i) {
        return ($.inArray(i, nonSelectIndexes) > -1);
      });

      console.log(nonSelectPaths);
    // Actions
    notSelected
      .transition()
      .style({
        "opacity": opacity
      });

   nonSelectPaths
      .transition()
      .style({
        "opacity": opacity
      });
  };
}

$.getJSON(url, function(data) {
  var layout = d3.layout.chord()
    .padding(.02) // feasibly could put a sort right here
    .matrix(data);

  svg.append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
    .attr("class", "group animate")
    .selectAll("path")
    .data(layout.groups)
    .enter()
    .append("path")
    .style("fill", function(d) {
      return fill(d.index);
    })
    .style("stroke", function(d) {
      return fill(d.index);
    })
    .attr("d", arc)
    .on("mouseover", fadeChords(0, data))
    .on("mouseout", fadeChords(1, data));

  svg.append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
    .attr("class", "chord animate")
    .selectAll("path")
    .data(layout.chords)
    .enter().append("path")
    .style("fill", function(d) {
      return fill(d.target.index);
    })
    .attr("d", d3.svg.chord().radius(innerRadius));
});
<commit_msg>NONWORK: having trouble, adding in the edges, trying the layout instead of data<commit_after>var url = "/data/matrix.json",
  height = 600;
var width = 600;

// Colors Can be substituted to preference, in many ways less colors makes it nice...
var colorRange = ["#1a9850", "#d73027", "#fc8d59", "#fee08b", "#ffffbf", "#d9ef8b", "#91cf60"];
var fill = d3.scale.ordinal()
  .domain(d3.range(colorRange.length))
  .range(colorRange);

var fill = d3.scale.category20b();

var outerRadius = Math.min(width, height) / 2 - 8,
  innerRadius = outerRadius - 30;

var arc = d3.svg.arc()
  .innerRadius(innerRadius)
  .outerRadius(outerRadius);

var svg = d3.select('#chart')
  .append('svg')
  .attr('width', width)
  .attr('height', height)
  .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

function fadeChords(opacity, data) {
  return function(g, i) {
    var selected, notSelected, nonSelectIndexes;

    selected = svg.selectAll("g.chord path")
      .filter(function(d) {
        return d.source.index == i || d.target.index == i;
      });

    notSelected = svg.selectAll("g.chord path")
      .filter(function(d) {
        return d.source.index != i && d.target.index != i;
      });

    nonSelectIndexes = [];

    svg.selectAll("g.chord path")
      .filter(function(d) {
        return d.source.index != i && d.target.index == i;
      })
      .each(function(d) {
          nonSelectIndexes.push(d.source.index);
        }
      );

    svg.selectAll("g.chord path")
      .filter(function(d) {
        return d.source.index == i && d.target.index != i;
      })
      .each(function(d) {
          nonSelectIndexes.push(d.target.index);
        }
      );

    // nonSelectIndexes = data[i]
    //   .map(function(d, i) {
    //     if (d == 0) {
    //       return i;
    //     }
    //     return undefined;
    //   })
    //   .filter(function(d) {
    //     return d != undefined;
    //   });

    nonSelectPaths = svg.selectAll("g.group path")
      .filter(function(g, i) {
        return ($.inArray(i, nonSelectIndexes) > -1);
      });

    console.log(nonSelectPaths);
    // Actions
    notSelected
      .transition()
      .style({
        "opacity": opacity
      });

    // nonSelectPaths
    //   .transition()
    //   .style({
    //     "opacity": opacity
    //   });
  };
}

$.getJSON(url, function(data) {
  var layout = d3.layout.chord()
    .padding(.02) // feasibly could put a sort right here
    .matrix(data);

  svg.append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
    .attr("class", "group animate")
    .selectAll("path")
    .data(layout.groups)
    .enter()
    .append("path")
    .style("fill", function(d) {
      return fill(d.index);
    })
    .style("stroke", function(d) {
      return fill(d.index);
    })
    .attr("d", arc)
    .on("mouseover", fadeChords(0, data))
    .on("mouseout", fadeChords(1, data));

  svg.append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
    .attr("class", "chord animate")
    .selectAll("path")
    .data(layout.chords)
    .enter().append("path")
    .style("fill", function(d) {
      return fill(d.target.index);
    })
    .attr("d", d3.svg.chord().radius(innerRadius));
});
<|endoftext|>