<commit_before>/* global THREE, Circle, Particles */

var Blocks = function(){

  var scene, cube, mesh, holder;
  var spot = -200;
  var boxAmount = 64;
  var boxSize = 4;
  var boxes = [];
  var material = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0xffffff, shininess: 50 } );

  var x, y;
  var radOffset = -150;
  var radius = (window.innerWidth < window.innerHeight ? window.innerWidth + radOffset : window.innerHeight + radOffset) / 4;
  var h = radius;
  var k = radius;
  var r = radius;

  var step = 2*Math.PI/boxAmount;
  var theta = step * (boxAmount / 4) * -1;

  this.hide = function() {
    holder.position.z = 1000;
  };

  this.update = function(data) {
    holder.position.z = 0;
    var diff = Math.floor(data.spectrum.length / boxes.length);
    _.each(boxes, function(box, index){
      var toScale = data.spectrum[diff * index] * 0.03;
      box.mesh.scale.y = toScale < 0.01 ? 0.01 : toScale;
    });
  };

  this.init = function(threeScene) {
    scene = threeScene;

    holder = new THREE.Object3D();
    holder.position.z = 0;
    scene.add(holder);

    for (var i = 0; i < boxAmount; i++) {
      addObject();
    }
  };

  function addObject(){
    cube = new THREE.BoxGeometry(boxSize, boxSize*3, boxSize);

    mesh = new THREE.Mesh(cube, material);
    mesh.name = "box"+boxes.length;

    x = h + r * Math.cos(theta);
    y = k - r * Math.sin(theta);

    mesh.position.x = x -radius;
    mesh.position.y = y -radius;
    mesh.position.z = -40;

    var boxNum = boxes.length;
    var kerroin = boxNum / boxAmount;
    var rotation = 360 * kerroin;

    mesh.rotation.z = rotation * (Math.PI/180) * -1;

    boxes.push({
      mesh: mesh,
      originalPosition: {
        x: mesh.position.x,
        y: mesh.position.y,
        z: mesh.position.z
      },
    });

    holder.add(mesh);

    //spot += boxSize + 10;
    theta += step;
  }
};
<commit_msg>make blocks have solid base, scaling outwards<commit_after>/* global THREE, Circle, Particles */

var Blocks = function(){

  var scene, cube, mesh, holder;
  var spot = -200;
  var boxAmount = 64;
  var boxSize = 4;
  var boxes = [];
  var material = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0xffffff, shininess: 50 } );

  var x, y;
  var radOffset = -150;
  var radius = (window.innerWidth < window.innerHeight ? window.innerWidth + radOffset : window.innerHeight + radOffset) / 4;
  var h = radius;
  var k = radius;
  var r = radius;

  var step = 2*Math.PI/boxAmount;
  var theta = step * (boxAmount / 4) * -1;

  this.hide = function() {
    holder.position.z = 1000;
  };

  this.update = function(data) {
    holder.position.z = 0;
    var diff = Math.floor(data.spectrum.length / boxes.length);
    _.each(boxes, function(box, index){
      var scale = data.spectrum[diff * index] * 0.03;
      var toScale = scale < 0.01 ? 0.01 : scale;
      box.mesh.scale.y = toScale;
      box.mesh.position.y = boxSize * 1.5 * toScale;
    });
  };

  this.init = function(threeScene) {
    scene = threeScene;

    holder = new THREE.Object3D();
    holder.position.z = 0;
    scene.add(holder);

    for (var i = 0; i < boxAmount; i++) {
      addObject();
    }
  };

  function addObject(){
    cube = new THREE.BoxGeometry(boxSize, boxSize*3, boxSize);

    var meshHolder = new THREE.Object3D();
    meshHolder.name = "box"+boxes.length;

    mesh = new THREE.Mesh(cube, material);

    x = h + r * Math.cos(theta);
    y = k - r * Math.sin(theta);

    meshHolder.position.x = x -radius;
    meshHolder.position.y = y -radius;
    meshHolder.position.z = -40;

    mesh.position.y = boxSize*3;

    var boxNum = boxes.length;
    var kerroin = boxNum / boxAmount;
    var rotation = 360 * kerroin;

    meshHolder.rotation.z = rotation * (Math.PI/180) * -1;
    //mesh.rotation.x = 45;

    boxes.push({
      mesh: mesh,
      originalPosition: {
        x: meshHolder.position.x,
        y: meshHolder.position.y,
        z: meshHolder.position.z
      },
    });

    meshHolder.add(mesh);

    holder.add(meshHolder);

    //spot += boxSize + 10;
    theta += step;
  }
};
<|endoftext|>


<commit_before>import path from 'path'
import fse from 'fs-extra'
import rimTheRaf from 'rimraf'
import filesize from 'filesize'
import {promisify} from 'es6-promisify'
import webpackIntegration from '@sanity/webpack-integration/v3'
import getConfig from '@sanity/util/lib/getConfig'
import {getWebpackCompiler, getDocumentElement, ReactDOM} from '@sanity/server'
import sortModulesBySize from '../../stats/sortModulesBySize'
import checkStudioDependencyVersions from '../../util/checkStudioDependencyVersions'
import {tryInitializePluginConfigs} from '../config/reinitializePluginConfigs'
import compressJavascript from './compressJavascript'

const rimraf = promisify(rimTheRaf)
const absoluteMatch = /^https?:\/\//i

export default async (args, context) => {
  const overrides = args.overrides || {}
  const {output, prompt, workDir} = context
  const flags = Object.assign(
    {minify: true, profile: false, stats: false, 'source-maps': false},
    args.extOptions
  )

  const unattendedMode = flags.yes || flags.y
  const defaultOutputDir = path.resolve(path.join(workDir, 'dist'))
  const outputDir = path.resolve(args.argsWithoutOptions[0] || defaultOutputDir)
  const config = getConfig(workDir, {env: 'production'})
  const compilationConfig = {
    env: 'production',
    staticPath: resolveStaticPath(workDir, config.get('server')),
    basePath: workDir,
    outputPath: path.join(outputDir, 'static'),
    sourceMaps: flags['source-maps'],
    skipMinify: !flags.minify,
    profile: flags.profile,
    project: Object.assign({}, config.get('project'), overrides.project)
  }

  await tryInitializePluginConfigs({workDir, output, env: 'production'})

  checkStudioDependencyVersions(workDir)

  const envVars = webpackIntegration.getSanityEnvVars({env: 'production', basePath: workDir})
  const envVarKeys = Object.keys(envVars)
  if (envVarKeys.length > 0) {
    output.print(
      '\nIncluding the following environment variables as part of the JavaScript bundle:'
    )
    envVarKeys.forEach(key => output.print(`- ${key}`))
    output.print('')
  }

  const compiler = getWebpackCompiler(compilationConfig)
  const compile = promisify(compiler.run.bind(compiler))
  let shouldDelete = true

  if (outputDir !== defaultOutputDir && !unattendedMode) {
    shouldDelete = await prompt.single({
      type: 'confirm',
      message: `Do you want to delete the existing directory (${outputDir}) first?`,
      default: true
    })
  }

  let spin

  if (shouldDelete) {
    const deleteStart = Date.now()
    spin = output.spinner('Clearing output folder').start()
    await rimraf(outputDir)
    spin.text = `Clearing output folder (${Date.now() - deleteStart}ms)`
    spin.succeed()
  }

  spin = output.spinner('Building Sanity').start()

  const bundle = {}

  try {
    // Compile the bundle
    const statistics = await compile()
    const stats = statistics.toJson()
    if (stats.errors && stats.errors.length > 0) {
      throw new Error(`Errors while building:\n\n${stats.errors.join('\n\n')}`)
    }

    spin.text = `Building Sanity (${stats.time}ms)`
    spin.succeed()

    // Get hashes for each chunk
    const chunkMap = {}
    stats.chunks.forEach(chunk =>
      chunk.files.forEach(file => {
        chunkMap[file] = chunk.hash
      })
    )

    bundle.stats = stats

    if (flags.profile) {
      await fse.writeFile(
        path.join(workDir, 'build-stats.json'),
        JSON.stringify(statistics.toJson('verbose'))
      )
    }

    // Build new index document with correct hashes
    const indexStart = Date.now()
    spin = output.spinner('Building index document').start()
    const doc = await getDocumentElement(
      {...compilationConfig, hashes: chunkMap},
      {
        scripts: ['vendor.bundle.js', 'app.bundle.js'].map(asset => {
          const assetPath = absoluteMatch.test(asset) ? asset : `js/${asset}`
          return {
            path: assetPath,
            hash: chunkMap[assetPath] || chunkMap[asset]
          }
        })
      }
    )

    // Write index file to output destination
    await fse.writeFile(
      path.join(outputDir, 'index.html'),
      `<!doctype html>${ReactDOM.renderToStaticMarkup(doc)}`
    )

    // Print build output, optionally stats if requested
    bundle.stats.warnings.forEach(output.print)
    spin.text = `Building index document (${Date.now() - indexStart}ms)`
    spin.succeed()

    if (flags.stats) {
      output.print('\nLargest modules (unminified, uncompressed sizes):')
      sortModulesBySize(bundle.stats.modules)
        .slice(0, 10)
        .forEach(module => output.print(`[${filesize(module.size)}] ${module.name}`))
    }

    // Now compress the JS bundles
    if (!compilationConfig.skipMinify) {
      spin = output.spinner('Minifying JavaScript bundles').start()
      const compressStart = Date.now()
      await Promise.all(
        Object.keys(chunkMap)
          .filter(fileName => path.extname(fileName) === '.js')
          .map(fileName => path.join(compilationConfig.outputPath, fileName))
          .map(compressJavascript)
      )

      spin.text = `Minifying JavaScript bundles (${Date.now() - compressStart}ms)`
      spin.succeed()
    }

    // Copy static assets (from /static folder) to output dir
    await fse.copy(path.join(workDir, 'static'), path.join(outputDir, 'static'), {overwrite: false})
  } catch (err) {
    spin.fail()
    throw err
  }

  return bundle
}

function resolveStaticPath(rootDir, config) {
  const {staticPath} = config
  return path.isAbsolute(staticPath) ? staticPath : path.resolve(path.join(rootDir, staticPath))
}
<commit_msg>[core] Prevent throwing on missing static folder when building (#1934)<commit_after>import path from 'path'
import fse from 'fs-extra'
import rimTheRaf from 'rimraf'
import filesize from 'filesize'
import {promisify} from 'es6-promisify'
import webpackIntegration from '@sanity/webpack-integration/v3'
import getConfig from '@sanity/util/lib/getConfig'
import {getWebpackCompiler, getDocumentElement, ReactDOM} from '@sanity/server'
import sortModulesBySize from '../../stats/sortModulesBySize'
import checkStudioDependencyVersions from '../../util/checkStudioDependencyVersions'
import {tryInitializePluginConfigs} from '../config/reinitializePluginConfigs'
import compressJavascript from './compressJavascript'

const rimraf = promisify(rimTheRaf)
const absoluteMatch = /^https?:\/\//i

export default async (args, context) => {
  const overrides = args.overrides || {}
  const {output, prompt, workDir} = context
  const flags = Object.assign(
    {minify: true, profile: false, stats: false, 'source-maps': false},
    args.extOptions
  )

  const unattendedMode = flags.yes || flags.y
  const defaultOutputDir = path.resolve(path.join(workDir, 'dist'))
  const outputDir = path.resolve(args.argsWithoutOptions[0] || defaultOutputDir)
  const config = getConfig(workDir, {env: 'production'})
  const compilationConfig = {
    env: 'production',
    staticPath: resolveStaticPath(workDir, config.get('server')),
    basePath: workDir,
    outputPath: path.join(outputDir, 'static'),
    sourceMaps: flags['source-maps'],
    skipMinify: !flags.minify,
    profile: flags.profile,
    project: Object.assign({}, config.get('project'), overrides.project)
  }

  await tryInitializePluginConfigs({workDir, output, env: 'production'})

  checkStudioDependencyVersions(workDir)

  const envVars = webpackIntegration.getSanityEnvVars({env: 'production', basePath: workDir})
  const envVarKeys = Object.keys(envVars)
  if (envVarKeys.length > 0) {
    output.print(
      '\nIncluding the following environment variables as part of the JavaScript bundle:'
    )
    envVarKeys.forEach(key => output.print(`- ${key}`))
    output.print('')
  }

  const compiler = getWebpackCompiler(compilationConfig)
  const compile = promisify(compiler.run.bind(compiler))
  let shouldDelete = true

  if (outputDir !== defaultOutputDir && !unattendedMode) {
    shouldDelete = await prompt.single({
      type: 'confirm',
      message: `Do you want to delete the existing directory (${outputDir}) first?`,
      default: true
    })
  }

  let spin

  if (shouldDelete) {
    const deleteStart = Date.now()
    spin = output.spinner('Clearing output folder').start()
    await rimraf(outputDir)
    spin.text = `Clearing output folder (${Date.now() - deleteStart}ms)`
    spin.succeed()
  }

  spin = output.spinner('Building Sanity').start()

  const bundle = {}

  try {
    // Compile the bundle
    const statistics = await compile()
    const stats = statistics.toJson()
    if (stats.errors && stats.errors.length > 0) {
      throw new Error(`Errors while building:\n\n${stats.errors.join('\n\n')}`)
    }

    spin.text = `Building Sanity (${stats.time}ms)`
    spin.succeed()

    // Get hashes for each chunk
    const chunkMap = {}
    stats.chunks.forEach(chunk =>
      chunk.files.forEach(file => {
        chunkMap[file] = chunk.hash
      })
    )

    bundle.stats = stats

    if (flags.profile) {
      await fse.writeFile(
        path.join(workDir, 'build-stats.json'),
        JSON.stringify(statistics.toJson('verbose'))
      )
    }

    // Build new index document with correct hashes
    const indexStart = Date.now()
    spin = output.spinner('Building index document').start()
    const doc = await getDocumentElement(
      {...compilationConfig, hashes: chunkMap},
      {
        scripts: ['vendor.bundle.js', 'app.bundle.js'].map(asset => {
          const assetPath = absoluteMatch.test(asset) ? asset : `js/${asset}`
          return {
            path: assetPath,
            hash: chunkMap[assetPath] || chunkMap[asset]
          }
        })
      }
    )

    // Write index file to output destination
    await fse.writeFile(
      path.join(outputDir, 'index.html'),
      `<!doctype html>${ReactDOM.renderToStaticMarkup(doc)}`
    )

    // Print build output, optionally stats if requested
    bundle.stats.warnings.forEach(output.print)
    spin.text = `Building index document (${Date.now() - indexStart}ms)`
    spin.succeed()

    if (flags.stats) {
      output.print('\nLargest modules (unminified, uncompressed sizes):')
      sortModulesBySize(bundle.stats.modules)
        .slice(0, 10)
        .forEach(module => output.print(`[${filesize(module.size)}] ${module.name}`))
    }

    // Now compress the JS bundles
    if (!compilationConfig.skipMinify) {
      spin = output.spinner('Minifying JavaScript bundles').start()
      const compressStart = Date.now()
      await Promise.all(
        Object.keys(chunkMap)
          .filter(fileName => path.extname(fileName) === '.js')
          .map(fileName => path.join(compilationConfig.outputPath, fileName))
          .map(compressJavascript)
      )

      spin.text = `Minifying JavaScript bundles (${Date.now() - compressStart}ms)`
      spin.succeed()
    }

    // Copy static assets (from /static folder) to output dir
    await fse
      .copy(path.join(workDir, 'static'), path.join(outputDir, 'static'), {overwrite: false})
      .catch(err => {
        // Allow missing static folder
        if (err.code !== 'ENOENT') {
          throw err
        }
      })
  } catch (err) {
    spin.fail()
    throw err
  }

  return bundle
}

function resolveStaticPath(rootDir, config) {
  const {staticPath} = config
  return path.isAbsolute(staticPath) ? staticPath : path.resolve(path.join(rootDir, staticPath))
}
<|endoftext|>


<commit_before>$(function () {
  $("[data-mask]").inputmask();
});

// $(function(){
// 	$("#custom1val").ipAddress({s:4});
// 	$("#custom2val").ipAddress({s:4});
// 	$("#custom3val").ipAddress({v:6});
// 	$("#custom4val").ipAddress({v:6});

// 	$("#DHCPfrom").ipAddress({s:4});
// 	$("#DHCPto").ipAddress({s:4});
// 	$("#DHCProuter").ipAddress({s:4});
// });

$(".confirm-reboot").confirm({
	text: "Are you sure you want to send a reboot command to your Pi-Hole?",
	title: "Confirmation required",
	confirm(button) {
		$("#rebootform").submit();
	},
	cancel(button) {
		// nothing to do
	},
	confirmButton: "Yes, reboot",
	cancelButton: "No, go back",
	post: true,
	confirmButtonClass: "btn-danger",
	cancelButtonClass: "btn-success",
	dialogClass: "modal-dialog modal-mg" // Bootstrap classes for mid-size modal
});

$(".confirm-restartdns").confirm({
	text: "Are you sure you want to send a restart command to your DNS server?",
	title: "Confirmation required",
	confirm(button) {
		$("#restartdnsform").submit();
	},
	cancel(button) {
		// nothing to do
	},
	confirmButton: "Yes, restart DNS",
	cancelButton: "No, go back",
	post: true,
	confirmButtonClass: "btn-danger",
	cancelButtonClass: "btn-success",
	dialogClass: "modal-dialog modal-mg"
});

$(".confirm-flushlogs").confirm({
	text: "By default, the log is flushed at the end of the day via cron, but a very large log file can slow down the Web interface, so flushing it can be useful. Note that your statistics will be reset and you lose the statistics up to this point. Are you sure you want to flush your logs?",
	title: "Confirmation required",
	confirm(button) {
		$("#flushlogsform").submit();
	},
	cancel(button) {
		// nothing to do
	},
	confirmButton: "Yes, flush logs",
	cancelButton: "No, go back",
	post: true,
	confirmButtonClass: "btn-danger",
	cancelButtonClass: "btn-success",
	dialogClass: "modal-dialog modal-mg"
});

$("#DHCPchk").click(function() {
	$("input.DHCPgroup").prop("disabled", !this.checked);
	$("#dhcpnotice").prop("hidden", !this.checked).addClass("lookatme");
});

var leasetable, staticleasetable;
$(document).ready(function() {
	if(document.getElementById("DHCPLeasesTable"))
	{
		leasetable = $("#DHCPLeasesTable").DataTable({
			dom: "<'row'<'col-sm-12'tr>><'row'<'col-sm-6'i><'col-sm-6'f>>",
			"paging": false,
			"scrollCollapse": true,
			"scrollY": "200px",
			"scrollX" : true
		});
	$("#leaseexpand").on( "click", function () {
		setTimeout(function(){leasetable.draw();},100);
		} );
	}
	if(document.getElementById("DHCPStaticLeasesTable"))
	{
		staticleasetable = $("#DHCPStaticLeasesTable").DataTable({
			dom: "<'row'<'col-sm-12'tr>><'row'<'col-sm-12'i>>",
			"columnDefs": [ { "bSortable": false, "orderable": false, targets: -1} ],
			"paging": false,
			"scrollCollapse": true,
			"scrollY": "200px",
			"scrollX" : true
		});
	$("#leaseexpand").on( "click", function () {
		setTimeout(function(){staticleasetable.draw();},100);
		} );
	}
} );

// Handle hiding of alerts
$(function(){
    $("[data-hide]").on("click", function(){
        $(this).closest("." + $(this).attr("data-hide")).hide();
    });
});

// DHCP leases tooltips
$(document).ready(function(){
    $("[data-toggle=\"tooltip\"]").tooltip({"html": true, container : "body"});
});

<commit_msg>Remove commented code<commit_after>$(function () {
  $("[data-mask]").inputmask();
});

$(".confirm-reboot").confirm({
	text: "Are you sure you want to send a reboot command to your Pi-Hole?",
	title: "Confirmation required",
	confirm(button) {
		$("#rebootform").submit();
	},
	cancel(button) {
		// nothing to do
	},
	confirmButton: "Yes, reboot",
	cancelButton: "No, go back",
	post: true,
	confirmButtonClass: "btn-danger",
	cancelButtonClass: "btn-success",
	dialogClass: "modal-dialog modal-mg" // Bootstrap classes for mid-size modal
});

$(".confirm-restartdns").confirm({
	text: "Are you sure you want to send a restart command to your DNS server?",
	title: "Confirmation required",
	confirm(button) {
		$("#restartdnsform").submit();
	},
	cancel(button) {
		// nothing to do
	},
	confirmButton: "Yes, restart DNS",
	cancelButton: "No, go back",
	post: true,
	confirmButtonClass: "btn-danger",
	cancelButtonClass: "btn-success",
	dialogClass: "modal-dialog modal-mg"
});

$(".confirm-flushlogs").confirm({
	text: "By default, the log is flushed at the end of the day via cron, but a very large log file can slow down the Web interface, so flushing it can be useful. Note that your statistics will be reset and you lose the statistics up to this point. Are you sure you want to flush your logs?",
	title: "Confirmation required",
	confirm(button) {
		$("#flushlogsform").submit();
	},
	cancel(button) {
		// nothing to do
	},
	confirmButton: "Yes, flush logs",
	cancelButton: "No, go back",
	post: true,
	confirmButtonClass: "btn-danger",
	cancelButtonClass: "btn-success",
	dialogClass: "modal-dialog modal-mg"
});

$("#DHCPchk").click(function() {
	$("input.DHCPgroup").prop("disabled", !this.checked);
	$("#dhcpnotice").prop("hidden", !this.checked).addClass("lookatme");
});

var leasetable, staticleasetable;
$(document).ready(function() {
	if(document.getElementById("DHCPLeasesTable"))
	{
		leasetable = $("#DHCPLeasesTable").DataTable({
			dom: "<'row'<'col-sm-12'tr>><'row'<'col-sm-6'i><'col-sm-6'f>>",
			"paging": false,
			"scrollCollapse": true,
			"scrollY": "200px",
			"scrollX" : true
		});
	$("#leaseexpand").on( "click", function () {
		setTimeout(function(){leasetable.draw();},100);
		} );
	}
	if(document.getElementById("DHCPStaticLeasesTable"))
	{
		staticleasetable = $("#DHCPStaticLeasesTable").DataTable({
			dom: "<'row'<'col-sm-12'tr>><'row'<'col-sm-12'i>>",
			"columnDefs": [ { "bSortable": false, "orderable": false, targets: -1} ],
			"paging": false,
			"scrollCollapse": true,
			"scrollY": "200px",
			"scrollX" : true
		});
	$("#leaseexpand").on( "click", function () {
		setTimeout(function(){staticleasetable.draw();},100);
		} );
	}
} );

// Handle hiding of alerts
$(function(){
    $("[data-hide]").on("click", function(){
        $(this).closest("." + $(this).attr("data-hide")).hide();
    });
});

// DHCP leases tooltips
$(document).ready(function(){
    $("[data-toggle=\"tooltip\"]").tooltip({"html": true, container : "body"});
});

<|endoftext|>


<commit_before>/*! Licensed under MIT, https://github.com/linkgod/marker */
(function(){
    var root = this,
        Marker;

    Marker = function(config){
        this.config = {
            dom: 'body',
            type: [{
                name: 'Mark',
                color: '#00f127'
            }]
        };
        if($.type(config) === 'string'){
            this.config.dom = config;
        }else if ($.type(config) === 'object'){
            $.extend(this.config, config);
        }else{
            throw '你的marker配置类型错误，不应该是' + $.type(config);
        }

        this.$this = $(this.config.dom);
        this.keywordList = [];
        this._selection = window.getSelection();

        // init toolbar
        this.toolbar();

        return this;
    };

    Marker.prototype.addKeyword = function(range, typeNum) {
        marker = this;

        // define Keyword
        var Keyword = function(range, typeNum){
            var id = +new Date();
            // Add DOM
            var keywordNode = document.createElement('span');
            keywordNode.id = 'mark' + id;
            keywordNode.setAttribute('data-type-num', typeNum);
            keywordNode.className = 'markpen-mark';
            keywordNode.title = marker.config.type[typeNum].name;
            keywordNode.style.backgroundColor = marker.config.type[typeNum].color;
            range.surroundContents(keywordNode);

            this.id = id;
            this.content = range.toString();
            this.typeNum = typeNum || 0;
            this.type = marker.config.type[typeNum].name;
            this.node = keywordNode;
        };
        var keyword = new Keyword(range, typeNum);

        this.keywordList.push(keyword);

        // Add listener
        $(keyword.node).click(function(e){
            e.stopPropagation();
            e.preventDefault();

            // show toolbar
            marker.toolbar.$this.find('.markpen-toolbar-delete').show();
            marker.toolbar.$this.find('.markpen-toolbar-tag').hide();
            marker.toolbar.$this.css({
                position: 'absolute',
                top: e.currentTarget.offsetTop - marker.toolbar.$this.height(),
                left: e.currentTarget.offsetLeft
            }).show();

            marker._currentKeyword = keyword;
            return false;
        }).mouseup(function(e){
            e.stopPropagation();
            return false;
        });
    };

    Marker.prototype.delectKeyword = function(keyword){
        var i;

        // TODO: 有待改进，会分割单个6DOM为多个#text
        $(keyword.node).replaceWith(keyword.node.childNodes);

        // delete keyword from keyword list
        for(i = 0;i < this.keywordList.length; i++){
            if(this.keywordList[i] === keyword){
                this.keywordList.splice(i, 1);
            }
        }
    };

    // get keyword list
    Marker.prototype.getKeywordList = function(){
        return this.keywordList;
    };

    Marker.prototype.markedAll = function(){
        var isMarkedAll = true;

        $.each(this.$this, function(k, v){
            var marks = $(v).find('.markpen-mark');
            if( marks.length === 0){
                isMarkedAll = false;
                console.log('还有内容没有标记', v);
            }
        });

        return isMarkedAll;
    };

    // transform html to templet
    Marker.prototype.getTemplet = function(){
        // TODO: export templet
    };

    Marker.prototype.toolbar = function(){
        var marker = this,
            $this = marker.$this;

        // define toolbar
        var Toolbar = function(){
            var toolbarTpl ='',
                selectValue = '',
                offset,
                i;

            // init toolbar
            toolbarTpl += '';
            for(i = 0; i < marker.config.type.length; i++){
                toolbarTpl += '' + marker.config.type[i].name + '';
            }
            toolbarTpl += '删除';
            $toolbar = $(toolbarTpl).hide();

            $this.append($toolbar);

            // Add listener to mark word
            $toolbar.find('.markpen-toolbar-tag').click(function(e){
                e.stopPropagation();
                try{
                    marker.addKeyword(marker._range, e.currentTarget.dataset.typeNum);
                }catch(error){
                    console.log(error, '无法跨行标记');
                }
                $toolbar.hide();
                return false;
            }).mouseup(function(e){
                e.stopPropagation();
                return false;
            });

            // Add listener to delete marked word
            $toolbar.find('.markpen-toolbar-delete').click(function(e){
                e.stopPropagation();
                marker.delectKeyword(marker._currentKeyword);
                $toolbar.hide();
                return false;
            }).mouseup(function(e){
                e.stopPropagation();
                return false;
            });

            var showToolbar = function(){
                var offset = marker._range.getBoundingClientRect(),
                    top = offset.top - 8,
                    left = offset.left + offset.width / 2;

                // don't show delete option
                $toolbar.find('.markpen-toolbar-tag').show();
                $toolbar.find('.markpen-toolbar-delete').hide();

                // set position and show it
                $toolbar.css({
                    position: 'fixed',
                    top: top - $toolbar.height(),
                    left: left - $toolbar.width() / 2
                }).show();
            };

            var hideToolbar = function (){
                $toolbar.hide();
            };

            return {
                $this: $toolbar,
                showToolbar: showToolbar,
                hideToolbar: hideToolbar
            };
        };
        marker.toolbar = Toolbar();

        // auto show toolbar after select words
        $this.mouseup(function(){
            var range;

            if(!marker._selection.isCollapsed){
                range = marker._selection.getRangeAt(0);
                // highlight whether start and end points in same container
                // if(range.startContainer === range.endContainer){
                    marker._range = marker._selection.getRangeAt(0);
                    marker.toolbar.showToolbar();
                // }
            }
        });

        // auto hide toolbar
        $(window).mouseup(function(){
            if(marker._selection.isCollapsed){
                marker.toolbar.hideToolbar();
            }
        });

        // change menu offset when window resize / scroll
        var setpos = function() {
            if(marker.toolbar.$this.css('display') !== 'none'){
                if(marker.toolbar.$this.css('position') !== 'absolute'){
                    marker.toolbar.showToolbar();
                }
            }
        };
        window.addEventListener('resize', setpos);
        window.addEventListener('scroll', setpos);
    };

    // support AMD and Node
    if(typeof define === "function" && typeof define.amd){
        define(function(){
            return Marker;
        });
    }else if(typeof exports !== 'undefined') {
        if(typeof module !== 'undefined' && module.exports) {
          exports = module.exports = Marker;
        }
        exports.Marker = Marker;
    } else {
        root.Marker = Marker;
    }

}).call(this);
<commit_msg>It won't show toolbar if startContainer is not same as endContainer<commit_after>/*! Licensed under MIT, https://github.com/linkgod/marker */
(function(){
    var root = this,
        Marker;

    Marker = function(config){
        this.config = {
            dom: 'body',
            type: [{
                name: 'Mark',
                color: '#00f127'
            }]
        };
        if($.type(config) === 'string'){
            this.config.dom = config;
        }else if ($.type(config) === 'object'){
            $.extend(this.config, config);
        }else{
            throw '你的marker配置类型错误，不应该是' + $.type(config);
        }

        this.$this = $(this.config.dom);
        this.keywordList = [];
        this._selection = window.getSelection();

        // init toolbar
        this.toolbar();

        return this;
    };

    Marker.prototype.addKeyword = function(range, typeNum) {
        marker = this;

        // define Keyword
        var Keyword = function(range, typeNum){
            var id = +new Date();
            // Add DOM
            var keywordNode = document.createElement('span');
            keywordNode.id = 'mark' + id;
            keywordNode.setAttribute('data-type-num', typeNum);
            keywordNode.className = 'markpen-mark';
            keywordNode.title = marker.config.type[typeNum].name;
            keywordNode.style.backgroundColor = marker.config.type[typeNum].color;
            range.surroundContents(keywordNode);

            this.id = id;
            this.content = range.toString();
            this.typeNum = typeNum || 0;
            this.type = marker.config.type[typeNum].name;
            this.node = keywordNode;
        };
        var keyword = new Keyword(range, typeNum);

        this.keywordList.push(keyword);

        // Add listener
        $(keyword.node).click(function(e){
            e.stopPropagation();
            e.preventDefault();

            // show toolbar
            marker.toolbar.$this.find('.markpen-toolbar-delete').show();
            marker.toolbar.$this.find('.markpen-toolbar-tag').hide();
            marker.toolbar.$this.css({
                position: 'absolute',
                top: e.currentTarget.offsetTop - marker.toolbar.$this.height(),
                left: e.currentTarget.offsetLeft
            }).show();

            marker._currentKeyword = keyword;
            return false;
        }).mouseup(function(e){
            e.stopPropagation();
            return false;
        });
    };

    Marker.prototype.delectKeyword = function(keyword){
        var i;

        // TODO: 有待改进，会让单个DOM为多个#text，有多个childNodes
        $(keyword.node).replaceWith(keyword.node.childNodes);

        // delete keyword from keyword list
        for(i = 0;i < this.keywordList.length; i++){
            if(this.keywordList[i] === keyword){
                this.keywordList.splice(i, 1);
            }
        }
    };

    // get keyword list
    Marker.prototype.getKeywordList = function(){
        return this.keywordList;
    };

    Marker.prototype.markedAll = function(){
        var isMarkedAll = true;

        $.each(this.$this, function(k, v){
            var marks = $(v).find('.markpen-mark');
            if( marks.length === 0){
                isMarkedAll = false;
                console.log('还有内容没有标记', v);
            }
        });

        return isMarkedAll;
    };

    // transform html to templet
    Marker.prototype.getTemplet = function(){
        // TODO: export templet
    };

    Marker.prototype.toolbar = function(){
        var marker = this,
            $this = marker.$this;

        // define toolbar
        var Toolbar = function(){
            var toolbarTpl ='',
                selectValue = '',
                offset,
                i;

            // init toolbar
            toolbarTpl += '';
            for(i = 0; i < marker.config.type.length; i++){
                toolbarTpl += '' + marker.config.type[i].name + '';
            }
            toolbarTpl += '删除';
            $toolbar = $(toolbarTpl).hide();

            $this.append($toolbar);

            // Add listener to mark word
            $toolbar.find('.markpen-toolbar-tag').click(function(e){
                e.stopPropagation();
                try{
                    marker.addKeyword(marker._range, e.currentTarget.dataset.typeNum);
                }catch(error){
                    console.log(error, '无法跨行标记');
                }
                $toolbar.hide();
                return false;
            }).mouseup(function(e){
                e.stopPropagation();
                return false;
            });

            // Add listener to delete marked word
            $toolbar.find('.markpen-toolbar-delete').click(function(e){
                e.stopPropagation();
                marker.delectKeyword(marker._currentKeyword);
                $toolbar.hide();
                return false;
            }).mouseup(function(e){
                e.stopPropagation();
                return false;
            });

            var showToolbar = function(){
                var offset = marker._range.getBoundingClientRect(),
                    top = offset.top - 8,
                    left = offset.left + offset.width / 2;

                // don't show delete option
                $toolbar.find('.markpen-toolbar-tag').show();
                $toolbar.find('.markpen-toolbar-delete').hide();

                // set position and show it
                $toolbar.css({
                    position: 'fixed',
                    top: top - $toolbar.height(),
                    left: left - $toolbar.width() / 2
                }).show();
            };

            var hideToolbar = function (){
                $toolbar.hide();
            };

            return {
                $this: $toolbar,
                showToolbar: showToolbar,
                hideToolbar: hideToolbar
            };
        };
        marker.toolbar = Toolbar();

        // auto show toolbar after select words
        $this.mouseup(function(){
            var range,
                startContainer,
                endContainer;

            if(!marker._selection.isCollapsed){
                range = marker._selection.getRangeAt(0);
                // highlight whether start and end points in same container
                startContainer = range.startContainer.nodeType === 3 ? range.startContainer.parentNode : range.startContainer;
                endContainer = range.endContainer.nodeType === 3 ? range.endContainer.parentNode : range.endContainer;

                if(startContainer === endContainer){
                    marker._range = marker._selection.getRangeAt(0);
                    marker.toolbar.showToolbar();
                }
            }
        });

        // auto hide toolbar
        $(window).mouseup(function(){
            if(marker._selection.isCollapsed){
                marker.toolbar.hideToolbar();
            }
        });

        // change menu offset when window resize / scroll
        var setpos = function() {
            if(marker.toolbar.$this.css('display') !== 'none'){
                if(marker.toolbar.$this.css('position') !== 'absolute'){
                    marker.toolbar.showToolbar();
                }
            }
        };
        window.addEventListener('resize', setpos);
        window.addEventListener('scroll', setpos);
    };

    // support AMD and Node
    if(typeof define === "function" && typeof define.amd){
        define(function(){
            return Marker;
        });
    }else if(typeof exports !== 'undefined') {
        if(typeof module !== 'undefined' && module.exports) {
          exports = module.exports = Marker;
        }
        exports.Marker = Marker;
    } else {
        root.Marker = Marker;
    }

}).call(this);
<|endoftext|>


<commit_before>!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):"object"==typeof exports?exports.ReactRecaptcha=t(require("react")):e.ReactRecaptcha=t(e.React)}(this,function(e){return function(e){function t(a){if(r[a])return r[a].exports;var o=r[a]={exports:{},id:a,loaded:!1};return e[a].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var r={};return t.m=e,t.c=r,t.p="",t(0)}([function(e,t,r){"use strict";function a(e){return e&&e.__esModule?e:{"default":e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function n(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var l=function(){function e(e,t){for(var r=0;r<t.length;r++){var a=t[r];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(e,a.key,a)}}return function(t,r,a){return r&&e(t.prototype,r),a&&e(t,a),t}}(),p=function(e,t,r){for(var a=!0;a;){var o=e,n=t,l=r;p=c=i=void 0,a=!1,null===o&&(o=Function.prototype);var p=Object.getOwnPropertyDescriptor(o,n);if(void 0!==p){if("value"in p)return p.value;var i=p.get;return void 0===i?void 0:i.call(l)}var c=Object.getPrototypeOf(o);if(null===c)return void 0;e=c,t=n,r=l,a=!0}},i=r(1),c=a(i),s={className:c["default"].PropTypes.string,onloadCallbackName:c["default"].PropTypes.string,elementID:c["default"].PropTypes.string,onloadCallback:c["default"].PropTypes.func,verifyCallback:c["default"].PropTypes.func,render:c["default"].PropTypes.string,sitekey:c["default"].PropTypes.string,theme:c["default"].PropTypes.string,type:c["default"].PropTypes.string,verifyCallbackName:c["default"].PropTypes.string},u={elementID:"g-recaptcha",onloadCallback:void 0,onloadCallbackName:"onloadCallback",verifyCallbackName:"verifyCallback",verifyCallback:void 0,render:"onload",theme:"light",type:"image"},f=function(e){function t(){o(this,t),p(Object.getPrototypeOf(t.prototype),"constructor",this).apply(this,arguments)}return n(t,e),l(t,[{key:"render",value:function(){var e=this;return"explicit"===this.props.render&&this.props.onloadCallback?(window[this.props.onloadCallbackName]=function(){grecaptcha.render(e.props.elementID,{sitekey:e.props.sitekey,callback:e.props.verifyCallback?e.props.verifyCallback:void 0,theme:e.props.theme,type:e.props.type}),e.props.onloadCallback&&e.props.onloadCallback()},c["default"].createElement("div",{id:this.props.elementID,"data-onloadcallbackname":this.props.onloadCallbackName,"data-verifycallbackname":this.props.verifyCallbackName})):c["default"].createElement("div",{className:"g-recaptcha","data-sitekey":this.props.sitekey,"data-theme":this.props.theme,"data-type":this.props.type})}}]),t}(c["default"].Component);t["default"]=f,f.propTypes=s,f.defaultProps=u,e.exports=t["default"]},function(t,r){t.exports=e}])});<commit_msg>update dist file<commit_after>!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):"object"==typeof exports?exports.ReactRecaptcha=t(require("react")):e.ReactRecaptcha=t(e.React)}(this,function(e){return function(e){function t(r){if(a[r])return a[r].exports;var o=a[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var a={};return t.m=e,t.c=a,t.p="",t(0)}([function(e,t,a){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function p(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var l=function(){function e(e,t){for(var a=0;a<t.length;a++){var r=t[a];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,a,r){return a&&e(t.prototype,a),r&&e(t,r),t}}(),n=function(e,t,a){for(var r=!0;r;){var o=e,p=t,l=a;n=s=i=void 0,r=!1,null===o&&(o=Function.prototype);var n=Object.getOwnPropertyDescriptor(o,p);if(void 0!==n){if("value"in n)return n.value;var i=n.get;return void 0===i?void 0:i.call(l)}var s=Object.getPrototypeOf(o);if(null===s)return void 0;e=s,t=p,a=l,r=!0}},i=a(1),s=r(i),c={className:s["default"].PropTypes.string,onloadCallbackName:s["default"].PropTypes.string,elementID:s["default"].PropTypes.string,onloadCallback:s["default"].PropTypes.func,verifyCallback:s["default"].PropTypes.func,render:s["default"].PropTypes.string,sitekey:s["default"].PropTypes.string,theme:s["default"].PropTypes.string,type:s["default"].PropTypes.string,verifyCallbackName:s["default"].PropTypes.string,size:s["default"].PropTypes.string,tabindex:s["default"].PropTypes.string},d={elementID:"g-recaptcha",onloadCallback:void 0,onloadCallbackName:"onloadCallback",verifyCallback:void 0,verifyCallbackName:"verifyCallback",expiredCallback:void 0,expiredCallbackName:"expiredCallback",render:"onload",theme:"light",type:"image",size:"normal",tabindex:0},u=function(e){function t(){o(this,t),n(Object.getPrototypeOf(t.prototype),"constructor",this).apply(this,arguments)}return p(t,e),l(t,[{key:"render",value:function(){var e=this;return"explicit"===this.props.render&&this.props.onloadCallback?(window[this.props.onloadCallbackName]=function(){grecaptcha.render(e.props.elementID,{sitekey:e.props.sitekey,callback:e.props.verifyCallback?e.props.verifyCallback:void 0,theme:e.props.theme,type:e.props.type,size:e.props.size,tabindex:e.props.tabindex,"expired-callback":e.props.expiredCallback?e.props.expiredCallback:void 0}),e.props.onloadCallback&&e.props.onloadCallback()},s["default"].createElement("div",{id:this.props.elementID,"data-onloadcallbackname":this.props.onloadCallbackName,"data-verifycallbackname":this.props.verifyCallbackName})):s["default"].createElement("div",{className:"g-recaptcha","data-sitekey":this.props.sitekey,"data-theme":this.props.theme,"data-type":this.props.type,"data-size":this.props.size,"data-tabindex":this.props.tabindex})}}]),t}(s["default"].Component);t["default"]=u,u.propTypes=c,u.defaultProps=d,e.exports=t["default"]},function(t,a){t.exports=e}])});<|endoftext|>


<commit_before>/*eslint-env browser */
/*globals require: false, module: false */
'use strict';

var React = require('react');
var _ = require('./underscore_ext');
var MenuItem = require('react-bootstrap/lib/MenuItem');
var SplitButton = require('react-bootstrap/lib/SplitButton');
var Resizable = require('react-resizable').Resizable;
var DefaultTextInput = require('./DefaultTextInput');
var {RefGeneAnnotation} = require('./refGeneExons');
var xenaQuery = require('./xenaQuery');

// XXX move this?
function download([fields, rows]) {
	var txt = _.map([fields].concat(rows), row => row.join('\t')).join('\n');
	// use blob for bug in chrome: https://code.google.com/p/chromium/issues/detail?id=373182
	var url = URL.createObjectURL(new Blob([txt], { type: 'text/tsv' }));
	var a = document.createElement('a');
	var filename = 'xenaDownload.tsv';
	_.extend(a, { id: filename, download: filename, href: url });
	document.body.appendChild(a);
	a.click();
	document.body.removeChild(a);
}

// For geneProbesMatrix we will average across probes to compute KM. For
// other types, we can't support multiple fields. This should really be
// in a prop set by the column, or in a multimethod. Having this here is bad.

function disableKM(column, hasSurvival) {
	if (!hasSurvival) {
		return [true, 'No survival data for cohort'];
	}
	if (column.fields.length > 1 && column.dataType !== 'geneProbesMatrix') {
		return [true, 'Unsupported for multiple genes/ids'];
	}
	return [false, ''];
}

var Column = React.createClass({
	onResizeStop: function (ev, {size}) {
		this.props.callback(['resize', this.props.id, size]);
	},
	onRemove: function () {
		this.props.callback(['remove', this.props.id]);
	},
	onDownload: function () {
		download(this.props.download());
	},
	onAbout: function () {
    var {column} = this.props;
    var dsID = column.dsID;
		var [host, dataset] = xenaQuery.parse_host(dsID);
		var url = `../datapages/?dataset=${encodeURIComponent(dataset)}&host=${encodeURIComponent(host)}`;
		window.open(url);
	},
	onViz: function () {
		this.props.onViz(this.props.id);
	},
	onKm: function () {
		let {callback, id} = this.props;
		callback(['km-open', id]);
	},
	render: function () {
		var {id, callback, plot, legend, column, zoom, menu, data, hasSurvival} = this.props,
			{width, columnLabel, fieldLabel} = column,
			[kmDisabled, kmTitle] = disableKM(column, hasSurvival),
			// move this to state to generalize to other annotations.
			doRefGene = column.dataType === 'mutationVector',
			// In FF spans don't appear as event targets. In Chrome, they do.
			// If we omit Sortable-handle here, Chrome will only catch events
			// in the button but not in the span. If we omit Sortable-handle
			// in SplitButton, FF will catch no events, since span doesn't
			// emit any.
			moveIcon = (
			);

		return (

				<SplitButton className='Sortable-handle' title={moveIcon} bsSize='xsmall'>
					{menu}
					{menu && <MenuItem divider />}
					<MenuItem title={kmTitle} onSelect={this.onKm} disabled={kmDisabled}>Kaplan Meier Plot</MenuItem>
					<MenuItem onSelect={this.onDownload}>Download</MenuItem>
					<MenuItem onSelect={this.onAbout}>About the Dataset</MenuItem>
					<MenuItem onSelect={this.onViz}>Viz Settings</MenuItem>
					<MenuItem onSelect={this.onRemove}>Remove</MenuItem>
				</SplitButton>

				<DefaultTextInput
					dsID={id}
					callback={callback}
					eventName='columnLabel'
					value={columnLabel} />
				<DefaultTextInput
					dsID={id}
					callback={callback}
					eventName='fieldLabel'
					value={fieldLabel} />

					{doRefGene && data ?
						<RefGeneAnnotation
							width={width}
							refGene={data.refGene[column.fields[0]]}
							layout={column.layout}
							position={{gene: column.fields[0]}}/> : null}

				<Resizable handleSize={[20, 20]}
					onResizeStop={this.onResizeStop}
					width={width}
					height={zoom.height}>

						{plot}

				</Resizable>
				{legend}

		);
	}
});

module.exports = Column;
<commit_msg>overlay while resizing.<commit_after>/*eslint-env browser */
/*globals require: false, module: false */
'use strict';

var React = require('react');
var _ = require('./underscore_ext');
var MenuItem = require('react-bootstrap/lib/MenuItem');
var SplitButton = require('react-bootstrap/lib/SplitButton');
var Resizable = require('react-resizable').Resizable;
var DefaultTextInput = require('./DefaultTextInput');
var {RefGeneAnnotation} = require('./refGeneExons');
var xenaQuery = require('./xenaQuery');

// XXX move this?
function download([fields, rows]) {
	var txt = _.map([fields].concat(rows), row => row.join('\t')).join('\n');
	// use blob for bug in chrome: https://code.google.com/p/chromium/issues/detail?id=373182
	var url = URL.createObjectURL(new Blob([txt], { type: 'text/tsv' }));
	var a = document.createElement('a');
	var filename = 'xenaDownload.tsv';
	_.extend(a, { id: filename, download: filename, href: url });
	document.body.appendChild(a);
	a.click();
	document.body.removeChild(a);
}

// For geneProbesMatrix we will average across probes to compute KM. For
// other types, we can't support multiple fields. This should really be
// in a prop set by the column, or in a multimethod. Having this here is bad.

function disableKM(column, hasSurvival) {
	if (!hasSurvival) {
		return [true, 'No survival data for cohort'];
	}
	if (column.fields.length > 1 && column.dataType !== 'geneProbesMatrix') {
		return [true, 'Unsupported for multiple genes/ids'];
	}
	return [false, ''];
}

var ResizeOverlay = React.createClass({
	getInitialState: () => ({zooming: false}),
	onResizeStart: function () {
		var {width, height} = this.props;
		this.setState({zooming: true, zoomSize: {width, height}});
	},
	onResize: function (ev, {size}) {
		this.setState({zoomSize: size});
	},
	onResizeStop: function (...args) {
		var {onResizeStop} = this.props;
		this.setState({zooming: false});
		if (onResizeStop) {
			onResizeStop(...args);
		}
	},
	render: function () {
		var {zooming, zoomSize} = this.state;
		return (

				{zooming ?
 : null}
				<Resizable handleSize={[20, 20]}
					onResizeStop={this.onResizeStop}
					onResize={this.onResize}
					onResizeStart={this.onResizeStart}
					width={this.props.width}
					height={this.props.height}>

						{this.props.children}

				</Resizable>

		);
	}
});

var Column = React.createClass({
	onResizeStop: function (ev, {size}) {
		this.props.callback(['resize', this.props.id, size]);
	},
	onRemove: function () {
		this.props.callback(['remove', this.props.id]);
	},
	onDownload: function () {
		download(this.props.download());
	},
	onAbout: function () {
    var {column} = this.props;
    var dsID = column.dsID;
		var [host, dataset] = xenaQuery.parse_host(dsID);
		var url = `../datapages/?dataset=${encodeURIComponent(dataset)}&host=${encodeURIComponent(host)}`;
		window.open(url);
	},
	onViz: function () {
		this.props.onViz(this.props.id);
	},
	onKm: function () {
		let {callback, id} = this.props;
		callback(['km-open', id]);
	},
	render: function () {
		var {id, callback, plot, legend, column, zoom, menu, data, hasSurvival} = this.props,
			{width, columnLabel, fieldLabel} = column,
			[kmDisabled, kmTitle] = disableKM(column, hasSurvival),
			// move this to state to generalize to other annotations.
			doRefGene = column.dataType === 'mutationVector',
			// In FF spans don't appear as event targets. In Chrome, they do.
			// If we omit Sortable-handle here, Chrome will only catch events
			// in the button but not in the span. If we omit Sortable-handle
			// in SplitButton, FF will catch no events, since span doesn't
			// emit any.
			moveIcon = (
			);

		return (

				<SplitButton className='Sortable-handle' title={moveIcon} bsSize='xsmall'>
					{menu}
					{menu && <MenuItem divider />}
					<MenuItem title={kmTitle} onSelect={this.onKm} disabled={kmDisabled}>Kaplan Meier Plot</MenuItem>
					<MenuItem onSelect={this.onDownload}>Download</MenuItem>
					<MenuItem onSelect={this.onAbout}>About the Dataset</MenuItem>
					<MenuItem onSelect={this.onViz}>Viz Settings</MenuItem>
					<MenuItem onSelect={this.onRemove}>Remove</MenuItem>
				</SplitButton>

				<DefaultTextInput
					dsID={id}
					callback={callback}
					eventName='columnLabel'
					value={columnLabel} />
				<DefaultTextInput
					dsID={id}
					callback={callback}
					eventName='fieldLabel'
					value={fieldLabel} />

					{doRefGene && data ?
						<RefGeneAnnotation
							width={width}
							refGene={data.refGene[column.fields[0]]}
							layout={column.layout}
							position={{gene: column.fields[0]}}/> : null}

				<ResizeOverlay
					onResizeStop={this.onResizeStop}
					width={width}
					height={zoom.height}>

						{plot}
				</ResizeOverlay>
				{legend}

		);
	}
});

module.exports = Column;
<|endoftext|>


<commit_before>/* global ENABLE_DEV_FEATURES */
import React from 'react';
import { FlexGroup } from '@keystonejs/ui/src/primitives/layout';
import { Pill } from '@keystonejs/ui/src/primitives/pill';
import { gridSize } from '@keystonejs/ui/src/theme';

import AnimateHeight from '../../../components/AnimateHeight';
import EditFilterPopout from './EditFilterPopout';

const pillStyle = { marginBottom: gridSize / 2, marginTop: gridSize / 2 };

export type FilterType = {
  field: { label: string, list: Object, path: string, type: string },
  filter: { type: string, label: string, getInitialValue: () => string },
  label: string,
  value: string,
};
type Props = {
  filterList: Array<FilterType>,
  onClear: FilterType => void,
  onRemove: FilterType => void,
  onUpdate: FilterType => void,
};

export default function ActiveFilters({
  filterList,
  onClear,
  onRemove,
  onUpdate,
}: Props) {
  if (!ENABLE_DEV_FEATURES) return null;

  return (
    <AnimateHeight>
      <FlexGroup style={{ paddingTop: gridSize }} wrap>
        {filterList.length
          ? filterList.map(filter => {
              const label = filter.field.formatFilter(filter);
              return (
                <EditFilterPopout
                  key={label}
                  onChange={onUpdate}
                  filter={filter}
                  target={
                    <Pill
                      appearance="primary"
                      onRemove={onRemove(filter)}
                      style={pillStyle}
                    >
                      {label}
                    </Pill>
                  }
                />
              );
            })
          : null}

        {filterList.length > 1 ? (
          <Pill key="clear" onClick={onClear} style={pillStyle}>
            Clear All
          </Pill>
        ) : null}
      </FlexGroup>
    </AnimateHeight>
  );
}
<commit_msg>fix bug where filters would always animate padding on mount<commit_after>/* global ENABLE_DEV_FEATURES */
import React from 'react';
import { FlexGroup } from '@keystonejs/ui/src/primitives/layout';
import { Pill } from '@keystonejs/ui/src/primitives/pill';
import { gridSize } from '@keystonejs/ui/src/theme';

import AnimateHeight from '../../../components/AnimateHeight';
import EditFilterPopout from './EditFilterPopout';

const pillStyle = { marginBottom: gridSize / 2, marginTop: gridSize / 2 };

export type FilterType = {
  field: { label: string, list: Object, path: string, type: string },
  filter: { type: string, label: string, getInitialValue: () => string },
  label: string,
  value: string,
};
type Props = {
  filterList: Array<FilterType>,
  onClear: FilterType => void,
  onRemove: FilterType => void,
  onUpdate: FilterType => void,
};

export default function ActiveFilters({
  filterList,
  onClear,
  onRemove,
  onUpdate,
}: Props) {
  if (!ENABLE_DEV_FEATURES) return null;

  return (
    <AnimateHeight style={{ paddingTop: gridSize }}>
      <FlexGroup wrap>
        {filterList.length
          ? filterList.map(filter => {
              const label = filter.field.formatFilter(filter);
              return (
                <EditFilterPopout
                  key={label}
                  onChange={onUpdate}
                  filter={filter}
                  target={
                    <Pill
                      appearance="primary"
                      onRemove={onRemove(filter)}
                      style={pillStyle}
                    >
                      {label}
                    </Pill>
                  }
                />
              );
            })
          : null}

        {filterList.length > 1 ? (
          <Pill key="clear" onClick={onClear} style={pillStyle}>
            Clear All
          </Pill>
        ) : null}
      </FlexGroup>
    </AnimateHeight>
  );
}
<|endoftext|>


<commit_before>define(["pat-tooltip", "pat-inject"], function(pattern, inject) {
    var utils = {
        createTooltip: function(c) {
            var cfg = c || {};
            return $("", {
                "id":   cfg.id || "tooltip",
                "href": cfg.href || "#anchor",
                "title": cfg.title || "tooltip title attribute",
                "data-pat-tooltip": "" || cfg.data,
                "class": "pat-tooltip"
            }).appendTo($("div#lab"));
        },

        removeTooltip: function removeTooltip() {
            var $el = $("a#tooltip");
            $el.remove();
        },

        createTooltipSource: function() {
            return $(""+
                    "<stong>Local content")
                .appendTo($("div#lab"));
        },

        click: {
            type: "click",
            preventDefault: function () {}
        }
    };

    describe("pat-tooltip", function () {
        beforeEach(function() {
            $("
", {id: "lab"}).appendTo(document.body);
        });

        afterEach(function() {
            $("#lab").remove();
        });

        describe("A Tooltip", function () {

            it("will be closed when a form with class .close-panel is submitted", function () {
                runs(function () {
                    var $div = $("
", {id: "content"});
                    var $form = $("<form/>", {"class": "close-panel"});
                    $div.appendTo(document.body);
                    $form.appendTo($div[0]);
                    utils.createTooltip({
                        data: "source: content",
                        href: "#content"
                    });
                    var $el = $("a#tooltip");
                    spyOn(pattern, "show").andCallThrough();
                    spyOn(pattern, "hide").andCallThrough();
                    pattern.init($el);
                    $el.trigger(utils.click);
                    expect(pattern.show).toHaveBeenCalled();
                });
                waits(100); // hide events get registered 50 ms after show
                runs(function () {
                    $(document).on("submit", function (ev) { ev.preventDefault(); });
                    $("form.close-panel").submit();
                    expect(pattern.hide).toHaveBeenCalled();
                    $("div#content").remove();
                });
            });

            it("will NOT be closed when a form WITHOUT class .close-panel is submitted", function () {
                runs(function () {
                    var $div = $("
", {id: "content"});
                    var $form = $("<form/>");
                    $div.appendTo(document.body);
                    $form.appendTo($div[0]);
                    utils.createTooltip({
                        data: "source: content",
                        href: "#content"
                    });
                    var $el = $("a#tooltip");
                    spyOn(pattern, "show").andCallThrough();
                    spyOn(pattern, "hide").andCallThrough();
                    pattern.init($el);
                    $el.trigger(utils.click);
                    expect(pattern.show).toHaveBeenCalled();
                });
                waits(100); // hide events get registered 50 ms after show
                runs(function () {
                    $(document).on("submit", function (ev) { ev.preventDefault(); });
                    $("#content form").submit();
                    expect(pattern.hide).not.toHaveBeenCalled();
                    $("div#content").remove();
                });
            });

            it("gets a .close-panel element when closing=close-button", function () {
                utils.createTooltip({
                    data: "closing: close-button",
                    href: "/tests/content.html#content"
                });
                var $el = $("a#tooltip");
                pattern.init($el);
                $el.trigger(utils.click);
                expect($(".close-panel").length).toBeTruthy();
            });

            it("is closed when one clicks on a .close-panel element", function () {
                runs(function () {
                    utils.createTooltip({
                        data: "trigger: click; closing: close-button",
                        href: "/tests/content.html#content"
                    });
                    spyOn(pattern, "show").andCallThrough();
                    spyOn(pattern, "hide").andCallThrough();
                    var $el = $("a#tooltip");
                    pattern.init($el);
                    $el.trigger(utils.click);
                    expect(pattern.show).toHaveBeenCalled();
                });
                waits(100); // hide events get registered 50 ms after show
                runs(function () {
                    $(".close-panel").click();
                    expect(pattern.hide).toHaveBeenCalled();
                });
            });

            it("is NOT closed when an injection happens", function () {
                    runs(function () {
                        utils.createTooltip({
                            data: "trigger: click; closing: auto",
                            href: "/tests/content.html#content"
                        });
                        var $el = $("a#tooltip");
                        spyOn(pattern, "show").andCallThrough();
                        spyOn(pattern, "hide").andCallThrough();
                        pattern.init($el);
                        $el.trigger(utils.click);
                        expect(pattern.show).toHaveBeenCalled();
                    });
                    waits(100); // hide events get registered 50 ms after show
                    runs(function () {
                        var $el = $("a#tooltip");
                        var $container = $el.data("patterns.tooltip.container");
                        $container.trigger("patterns-inject-triggered");
                    });
                    waits(100); // hide events get registered 50 ms after show
                    runs(function () {
                        expect(pattern.hide).not.toHaveBeenCalled();
                    });
            });
        });

        describe("When a tooltip is clicked", function () {
            describe("if the tootip is a hyperlink", function () {
                beforeEach(function() {
                    utils.createTooltip();
                });
                afterEach(function() {
                    utils.removeTooltip();
                });
                it("the default click action is prevented", function () {
                    var $el = $("a#tooltip");
                    spyOn(pattern, "show").andCallThrough();
                    spyOn(utils.click, "preventDefault");
                    pattern.init($el);
                    $el.trigger(utils.click);
                    expect(pattern.show).toHaveBeenCalled();
                    expect(utils.click.preventDefault).toHaveBeenCalled();
                });
            });

            describe("if the 'source' parameter is 'title'", function () {
                afterEach(function() {
                    utils.removeTooltip();
                });
                it("will show the contents of the 'title' attribute", function () {
                    utils.createTooltip({data: "source: title"});
                    var $el = $("a#tooltip");
                    spyOn(pattern, "show").andCallThrough();
                    var title = $el.attr("title");
                    pattern.init($el);
                    // The 'title' attr gets removed, otherwise the browser's
                    // tooltip will appear
                    expect($el.attr("title")).toBeFalsy();

                    $el.trigger(utils.click);
                    expect(pattern.show).toHaveBeenCalled();
                    var $container = $el.data("patterns.tooltip.container");
                    expect($container.text()).toBe(title);
                });
            });

            describe("if the 'source' parameter is 'ajax'", function () {
                afterEach(function() {
                    utils.removeTooltip();
                });
                it("will fetch its contents via ajax", function () {
                    utils.createTooltip({data: "source: auto", href: "/tests/content.html#content"});
                    var $el = $("a#tooltip");
                    spyOn(pattern, "show").andCallThrough();
                    spyOn(inject, "execute"); //.andCallThrough();
                    pattern.init($el);
                    runs(function () {
                        $el.trigger(utils.click);
                    });
                    waits(200);
                    runs(function () {
                        expect(pattern.show).toHaveBeenCalled();
                        expect(inject.execute).toHaveBeenCalled();
                        /* XXX: The ajax call works fine in the browser but not
                         * via PhantomJS. Will have to debug later.
                         *
                        var $container = $el.data("patterns.tooltip.container");
                        // Content is fetched from ./tests/content.html#content
                        expect($container.text()).toBe(
                            "External content fetched via an HTTP request.");
                        */
                    });
                });
            });

            describe("if the 'source' parameter is 'content'", function () {
                afterEach(function() {
                    utils.removeTooltip();
                });
                it("will clone a DOM element from the page", function () {
                    utils.createTooltip({data: "source: content", href: "#tooltip-source"});
                    utils.createTooltipSource();
                    var $el = $("a#tooltip");
                    spyOn(pattern, "show").andCallThrough();
                    pattern.init($el);
                    $el.trigger(utils.click);
                    expect(pattern.show).toHaveBeenCalled();
                    var $container = $el.data("patterns.tooltip.container");
                    expect($container.text()).toBe("Local content");
                });
            });

            describe("if the 'source' parameter is 'auto'", function () {
                afterEach(function() {
                    utils.removeTooltip();
                });
                it("will revert to 'ajax' if 'href' points to an external URL", function () {
                    utils.createTooltip({data: "source: auto", href: "/tests/content.html#content"});
                    var $el = $("a#tooltip");
                    pattern.init($el);
                    var options = $el.data("patterns.tooltip");
                    expect(options.source).toBe("ajax");
                });
                it("will revert to 'content' if 'href' points to a document fragment", function () {
                    utils.createTooltipSource();
                    utils.createTooltip({data: "source: auto", href: "#tooltip-source"});
                    var $el = $("a#tooltip");
                    pattern.init($el);
                    var options = $el.data("patterns.tooltip");
                    expect(options.source).toBe("content");
                });
            });
        });

        describe("A tooltip that opens on click and contains another tooltip trigger", function () {
            beforeEach(function() {
                utils.createTooltip({
                    data: "trigger: click; source: content",
                    href: "#tooltip-content"
                });
                $("
", {
                    "id":   "tooltip-content"
                }).appendTo($("div#lab"));
                $("", {
                    "id":   "nested-tooltip",
                    "href": "#nested-tooltip-content",
                    "title": "nested tooltip title attribute",
                    "data-pat-tooltip": "trigger: click; source: content",
                    "class": "pat-tooltip"
                }).appendTo($("div#tooltip-content"));
            });
            afterEach(function() {
                utils.removeTooltip();
            });
            it("will not close if the contained trigger is clicked", function () {
                runs(function () {
                    spyOn(pattern, "show").andCallThrough();
                    var $el = $("a#tooltip");
                    pattern.init($el);
                    pattern.init($("a#nested-tooltip"));
                    $el.trigger(utils.click);
                    expect(pattern.show).toHaveBeenCalled();
                });
                waits(100); // hide events get registered 50 ms after show
                runs(function () {
                    $(".tooltip-container a#nested-tooltip").trigger(utils.click);
                    expect($(".tooltip-container a#nested-tooltip").css("visibility")).toBe("visible");
                });
            });
        });
    });
});
// jshint indent: 4, browser: true, jquery: true, quotmark: double
<commit_msg>Indentation.<commit_after>define(["pat-tooltip", "pat-inject"], function(pattern, inject) {
    var utils = {
        createTooltip: function(c) {
            var cfg = c || {};
            return $("", {
                "id":   cfg.id || "tooltip",
                "href": cfg.href || "#anchor",
                "title": cfg.title || "tooltip title attribute",
                "data-pat-tooltip": "" || cfg.data,
                "class": "pat-tooltip"
            }).appendTo($("div#lab"));
        },

        removeTooltip: function removeTooltip() {
            var $el = $("a#tooltip");
            $el.remove();
        },

        createTooltipSource: function() {
            return $(""+
                    "<stong>Local content")
                .appendTo($("div#lab"));
        },

        click: {
            type: "click",
            preventDefault: function () {}
        }
    };

    describe("pat-tooltip", function () {
        beforeEach(function() {
            $("
", {id: "lab"}).appendTo(document.body);
        });

        afterEach(function() {
            $("#lab").remove();
        });

        describe("A Tooltip", function () {

            it("will be closed when a form with class .close-panel is submitted", function () {
                runs(function () {
                    var $div = $("
", {id: "content"});
                    var $form = $("<form/>", {"class": "close-panel"});
                    $div.appendTo(document.body);
                    $form.appendTo($div[0]);
                    utils.createTooltip({
                        data: "source: content",
                        href: "#content"
                    });
                    var $el = $("a#tooltip");
                    spyOn(pattern, "show").andCallThrough();
                    spyOn(pattern, "hide").andCallThrough();
                    pattern.init($el);
                    $el.trigger(utils.click);
                    expect(pattern.show).toHaveBeenCalled();
                });
                waits(100); // hide events get registered 50 ms after show
                runs(function () {
                    $(document).on("submit", function (ev) { ev.preventDefault(); });
                    $("form.close-panel").submit();
                    expect(pattern.hide).toHaveBeenCalled();
                    $("div#content").remove();
                });
            });

            it("will NOT be closed when a form WITHOUT class .close-panel is submitted", function () {
                runs(function () {
                    var $div = $("
", {id: "content"});
                    var $form = $("<form/>");
                    $div.appendTo(document.body);
                    $form.appendTo($div[0]);
                    utils.createTooltip({
                        data: "source: content",
                        href: "#content"
                    });
                    var $el = $("a#tooltip");
                    spyOn(pattern, "show").andCallThrough();
                    spyOn(pattern, "hide").andCallThrough();
                    pattern.init($el);
                    $el.trigger(utils.click);
                    expect(pattern.show).toHaveBeenCalled();
                });
                waits(100); // hide events get registered 50 ms after show
                runs(function () {
                    $(document).on("submit", function (ev) { ev.preventDefault(); });
                    $("#content form").submit();
                    expect(pattern.hide).not.toHaveBeenCalled();
                    $("div#content").remove();
                });
            });

            it("gets a .close-panel element when closing=close-button", function () {
                utils.createTooltip({
                    data: "closing: close-button",
                    href: "/tests/content.html#content"
                });
                var $el = $("a#tooltip");
                pattern.init($el);
                $el.trigger(utils.click);
                expect($(".close-panel").length).toBeTruthy();
            });

            it("is closed when one clicks on a .close-panel element", function () {
                runs(function () {
                    utils.createTooltip({
                        data: "trigger: click; closing: close-button",
                        href: "/tests/content.html#content"
                    });
                    spyOn(pattern, "show").andCallThrough();
                    spyOn(pattern, "hide").andCallThrough();
                    var $el = $("a#tooltip");
                    pattern.init($el);
                    $el.trigger(utils.click);
                    expect(pattern.show).toHaveBeenCalled();
                });
                waits(100); // hide events get registered 50 ms after show
                runs(function () {
                    $(".close-panel").click();
                    expect(pattern.hide).toHaveBeenCalled();
                });
            });

            it("is NOT closed when an injection happens", function () {
                runs(function () {
                    utils.createTooltip({
                        data: "trigger: click; closing: auto",
                        href: "/tests/content.html#content"
                    });
                    var $el = $("a#tooltip");
                    spyOn(pattern, "show").andCallThrough();
                    spyOn(pattern, "hide").andCallThrough();
                    pattern.init($el);
                    $el.trigger(utils.click);
                    expect(pattern.show).toHaveBeenCalled();
                });
                waits(100); // hide events get registered 50 ms after show
                runs(function () {
                    var $el = $("a#tooltip");
                    var $container = $el.data("patterns.tooltip.container");
                    $container.trigger("patterns-inject-triggered");
                });
                waits(100); // hide events get registered 50 ms after show
                runs(function () {
                    expect(pattern.hide).not.toHaveBeenCalled();
                });
            });
        });

        describe("When a tooltip is clicked", function () {
            describe("if the tootip is a hyperlink", function () {
                beforeEach(function() {
                    utils.createTooltip();
                });
                afterEach(function() {
                    utils.removeTooltip();
                });
                it("the default click action is prevented", function () {
                    var $el = $("a#tooltip");
                    spyOn(pattern, "show").andCallThrough();
                    spyOn(utils.click, "preventDefault");
                    pattern.init($el);
                    $el.trigger(utils.click);
                    expect(pattern.show).toHaveBeenCalled();
                    expect(utils.click.preventDefault).toHaveBeenCalled();
                });
            });

            describe("if the 'source' parameter is 'title'", function () {
                afterEach(function() {
                    utils.removeTooltip();
                });
                it("will show the contents of the 'title' attribute", function () {
                    utils.createTooltip({data: "source: title"});
                    var $el = $("a#tooltip");
                    spyOn(pattern, "show").andCallThrough();
                    var title = $el.attr("title");
                    pattern.init($el);
                    // The 'title' attr gets removed, otherwise the browser's
                    // tooltip will appear
                    expect($el.attr("title")).toBeFalsy();

                    $el.trigger(utils.click);
                    expect(pattern.show).toHaveBeenCalled();
                    var $container = $el.data("patterns.tooltip.container");
                    expect($container.text()).toBe(title);
                });
            });

            describe("if the 'source' parameter is 'ajax'", function () {
                afterEach(function() {
                    utils.removeTooltip();
                });
                it("will fetch its contents via ajax", function () {
                    utils.createTooltip({data: "source: auto", href: "/tests/content.html#content"});
                    var $el = $("a#tooltip");
                    spyOn(pattern, "show").andCallThrough();
                    spyOn(inject, "execute"); //.andCallThrough();
                    pattern.init($el);
                    runs(function () {
                        $el.trigger(utils.click);
                    });
                    waits(200);
                    runs(function () {
                        expect(pattern.show).toHaveBeenCalled();
                        expect(inject.execute).toHaveBeenCalled();
                        /* XXX: The ajax call works fine in the browser but not
                         * via PhantomJS. Will have to debug later.
                         *
                        var $container = $el.data("patterns.tooltip.container");
                        // Content is fetched from ./tests/content.html#content
                        expect($container.text()).toBe(
                            "External content fetched via an HTTP request.");
                        */
                    });
                });
            });

            describe("if the 'source' parameter is 'content'", function () {
                afterEach(function() {
                    utils.removeTooltip();
                });
                it("will clone a DOM element from the page", function () {
                    utils.createTooltip({data: "source: content", href: "#tooltip-source"});
                    utils.createTooltipSource();
                    var $el = $("a#tooltip");
                    spyOn(pattern, "show").andCallThrough();
                    pattern.init($el);
                    $el.trigger(utils.click);
                    expect(pattern.show).toHaveBeenCalled();
                    var $container = $el.data("patterns.tooltip.container");
                    expect($container.text()).toBe("Local content");
                });
            });

            describe("if the 'source' parameter is 'auto'", function () {
                afterEach(function() {
                    utils.removeTooltip();
                });
                it("will revert to 'ajax' if 'href' points to an external URL", function () {
                    utils.createTooltip({data: "source: auto", href: "/tests/content.html#content"});
                    var $el = $("a#tooltip");
                    pattern.init($el);
                    var options = $el.data("patterns.tooltip");
                    expect(options.source).toBe("ajax");
                });
                it("will revert to 'content' if 'href' points to a document fragment", function () {
                    utils.createTooltipSource();
                    utils.createTooltip({data: "source: auto", href: "#tooltip-source"});
                    var $el = $("a#tooltip");
                    pattern.init($el);
                    var options = $el.data("patterns.tooltip");
                    expect(options.source).toBe("content");
                });
            });
        });

        describe("A tooltip that opens on click and contains another tooltip trigger", function () {
            beforeEach(function() {
                utils.createTooltip({
                    data: "trigger: click; source: content",
                    href: "#tooltip-content"
                });
                $("
", {
                    "id":   "tooltip-content"
                }).appendTo($("div#lab"));
                $("", {
                    "id":   "nested-tooltip",
                    "href": "#nested-tooltip-content",
                    "title": "nested tooltip title attribute",
                    "data-pat-tooltip": "trigger: click; source: content",
                    "class": "pat-tooltip"
                }).appendTo($("div#tooltip-content"));
            });
            afterEach(function() {
                utils.removeTooltip();
            });
            it("will not close if the contained trigger is clicked", function () {
                runs(function () {
                    spyOn(pattern, "show").andCallThrough();
                    var $el = $("a#tooltip");
                    pattern.init($el);
                    pattern.init($("a#nested-tooltip"));
                    $el.trigger(utils.click);
                    expect(pattern.show).toHaveBeenCalled();
                });
                waits(100); // hide events get registered 50 ms after show
                runs(function () {
                    $(".tooltip-container a#nested-tooltip").trigger(utils.click);
                    expect($(".tooltip-container a#nested-tooltip").css("visibility")).toBe("visible");
                });
            });
        });
    });
});
// jshint indent: 4, browser: true, jquery: true, quotmark: double
<|endoftext|>


<commit_before>const fs = require("fs");
const path = require("path");
const glob = require("glob");
const DIR = "_data/events_gdcr2019";

const toWelcomeTweetModerators = moderators => {
  const names = moderators.map(mod => {
    if (typeof mod === "string") return mod;
    if (mod.url && mod.url.includes("twitter.com"))
      return "@" + mod.url.split("/").slice(-1)[0];
    return mod.name;
  });
  if (names.length === 1) return names[0];
  return names.slice(0, -1).join(", ") + " & " + names.slice(-1)[0];
};

const toWelcomeTweet = event => {
  const moderators = toWelcomeTweetModerators(event.moderators);
  return `🌐 Welcome ${event.location.city}, ${
    event.location.country
  } with ${moderators} to the Global Day Of Coderetreat 2019! #gdcr19 #coderetreat ${
    event.url
  }`;
};

const events = glob
  .sync(path.resolve(__dirname, "../_data/events_gdcr2019/") + "/*.json")
  .sort((fa, fb) => fs.statSync(fa).mtimeMs - fs.statSync(fb).mtimeMs)
  .map(file => JSON.parse(fs.readFileSync(file)))
  .map(toWelcomeTweet);

console.log(events.join("\n"));
<commit_msg>Fix printing tweets if theres no moderators at all<commit_after>const fs = require("fs");
const path = require("path");
const glob = require("glob");
const DIR = "_data/events_gdcr2019";

const toWelcomeTweetModerators = moderators => {
  const names = moderators.map(mod => {
    if (typeof mod === "string") return mod;
    if (mod.url && mod.url.includes("twitter.com"))
      return "@" + mod.url.split("/").slice(-1)[0];
    return mod.name;
  });
  if (names.length === 0) return "";
  if (names.length === 1) return " with " + names[0];
  return " with " + names.slice(0, -1).join(", ") + " & " + names.slice(-1)[0];
};

const toWelcomeTweet = event => {
  const moderators = toWelcomeTweetModerators(event.moderators);
  return `🌐 Welcome ${event.location.city}, ${
    event.location.country
  }${moderators} to the Global Day Of Coderetreat 2019! #gdcr19 #coderetreat ${
    event.url
  }`;
};

const events = glob
  .sync(path.resolve(__dirname, "../_data/events_gdcr2019/") + "/*.json")
  .sort((fa, fb) => fs.statSync(fa).mtimeMs - fs.statSync(fb).mtimeMs)
  .map(file => JSON.parse(fs.readFileSync(file)))
  .map(toWelcomeTweet);

console.log(events.join("\n"));
<|endoftext|>