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

/**
 * Markdown-plus-plus is a project of markdown syntax highlighting for Notepad++, by customized UDL file (user defined language).
 * This project is open source on:
 * [Source]{@link https://github.com/Edditoria/markdown-plus-plus}.
 * Code released under the MIT license:
 * [License]{@link https://github.com/Edditoria/validid/blob/master/LICENSE.txt}.
 *
 * @file Build UML XML file(s) in current working directory.
 * @auther Edditoria
 * @license MIT
 */

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

/*
Expected usage:
```cmd
npx markdown-plus-plus [options]    # In UDL folder of Notepad++
mpp [options]                       # After install this package globally
npm run mpp -- [options]            # Develop in package directory
````
*/
/* @type {Array<string>} - Usage messages to print */
var usageMsg = [
	'Build UML XML file(s) for Notepad++ in current working directory.',
	'',
	'Usage: npx markdown-plus-plus [theme-name...] [--all] [-f | --force]',
	'',
	'Options:',
	'theme-name       Build UDL file(s) for specified theme(s)',
	'                 You can give multiple theme names',
	'                 e.g. npx markdown-plus-plus solarized zenburn deep-black',
	'-f, --force      Force to overwrite any file that already exists in directory',
	'-l, --list       List bundled themes in this package',
	'-v, --version    Print current version of this package',
	'-h, --help       Print usage',
	'',
	'Examples:',
	'npx markdown-plus-plus               Build all UDL files without overwrite',
	'npx markdown-plus-plus zenburn       Build Zenburn UDL file without overwrite',
	'npx markdown-plus-plus zenburn -f    Build Zenburn UDL file and overwrite',
	''
];

/* @type {string} - Version of this npm package. */
var version = process.env.npm_package_version;
/* @type {Array<string>} - Arguments from node. */
var args = process.argv.slice(2);
/* @type {string} - Current working directory. */
var cwd = process.cwd();
/* @type {string} - Root directory of this NPM package. */
var packagePath = path.resolve(__dirname, '../');
/* @type {string} - Path for <udl/> in this package. */
var udlPath = packagePath + '/udl';

/*
 * Parse arguments passed from user command input.
 * "-f" can only be passed at first or last argument.
 * "-l/-h/-v" can only be passed at first argument.
 * @param {Array<string>} args - Arguments from Node's `process.argv.slice(2)`.
 * @param {Array<string>} buildinThemes - Basically the theme names in <config/>.
 * @return {Object} - The parsed object passing to build steps.
 */
var parseArgs = function(args, buildinThemes) {
	var options = {
		themeNames: [],
		shouldContinue: false,
		isForce: false
	};
	// Parse the first argument. Quit asap if user put a proper flag.
	var firstArg = args[0];
	switch (firstArg) {
		case '-l': case '--list':
			console.log(buildinThemes.join('\n'));
			return options;
		case '-v': case '--version':
			console.log(version);
			return options;
		case '-h': case '--help':
			console.log(usageMsg.join('\n'));
			return options;
	}
	// Loop all arguments. Match the theme names, otherwise the program should quits.
	var arg;
	for (var i = 0; i < args.length; i++) {
		arg = args[i];
		if (arg === '-f' || arg === '--force') {
			if (i === 0 || i === args.length - 1) {
				console.log('Warning! In force mode, any existing file(s) will be overwritten.\n');
				options.isForce = true;
			} else {
				console.log('arg[' + i + ']: You pass the \"' + arg + '\" flag in wrong position. Quit for safety.');
				return options;
			}
		} else if (buildinThemes.indexOf(arg) >= 0) {
			options.themeNames.push(arg);
		} else {
			console.log('arg[' + i + ']: ' + 'Unsupported option \"' + arg + '\" or combination of options.');
			return options;
		}
	}
	options.shouldContinue = true;
	return options;
};

/**
 * Get file list in a directory.
 * Similar to `dir /w` in command prompt and `ls` in bash.
 * Expect program quit with error if it does not find the directory.
 * @param {string} dir - Path of a directory.
 * @return {string[]} - An array as a list of filenames.
 */
var getFileList = function(dir) {
	return fs.readdirSync(dir);
};

/**
 * Get theme name from a UDL XML filename, assuming the filename is in proper format.
 * @param {string} filename - Expected format: 'markdown.hyphen-lowercase-theme-name.udl.xml'.
 * @return {string}
 */
var getThemeName = function(filename) {
	var reHead = /^(markdown\.)/;
	var reTail = /(\.udl\.xml)$/;
	return filename.replace(reHead, '').replace(reTail, '');
};

/**
 * Get a list of theme names in a directory.
 * Theme names are stripped from filename of the built-in UDL files in <udl/>.
 * @param {Array<string>} - A list of theme names, e.g. ['default', 'zenburn'].
 */
var getThemeList = function(dir) {
	var files = getFileList(dir);
	var themeList = [];
	for (var i = 0; i < files.length; i++) {
		themeList.push(getThemeName(files[i]));
	}
	return themeList;
};

/**
 * Copy file from source to destination using `fs.createReadSteam()`.
 * This function will overwritten any files that already exists.
 * This function is created because `fs.copyFile()` requires Node v8.5+.
 * This NPM package targets to serve under Node v4+.
 * @param {string} src - Path of source directory.
 * @param {string} dest - Path of destination directory.
 */
var copyFile = function(src, dest) {
	var readSteam = fs.createReadStream(src);
	readSteam.once('error', function(error) {
		console.log(error);
	});
	// readSteam.once('end', function() {
	// 	console.log('copyFile() done');
	// });
	readSteam.pipe(fs.createWriteStream(dest));
};

/**
 * Build UDL XML file(s) in current working directory.
 * @param {Array} args - This array is produced by Node's `process.argv`.
 */
var main = function(args) {
	/* @type {string[]} - A list of filenames in <udl/> in this package. */
	var fileList = getFileList(packagePath + '/udl');
	// Loop the file list.
	var filename, src, dest, themeName, isExist;
	for (var i = 0; i < fileList.length; i++) {
		filename = fileList[i];
		src = packagePath + '/udl/' + filename;
		dest = cwd + '/' + filename;
		themeName = getThemeName(filename);
		// Synchronously check whether file exists.
		isExist = fs.existsSync(dest);
		// Jump to next iteration if file already exists.
		if (isExist) {
			console.log('[' + themeName + '] Warning: File already exists. Have skipped this one.');
			continue; // Jump to next iteration.
		}
		copyFile(src, dest);
		console.log('[' + themeName + '] Done: UDL file is created');
	}
};

/* @type {Array} - A list of theme names found in <udl/>. */
var buildinThemes = getThemeList(udlPath);
/* @type {Object} - Parse args into options object. */
var options = parseArgs(args, buildinThemes);
console.log(options);
// main(options);
<commit_msg>Add `createBuildinUdls()`; Improve arguments parser again:<commit_after>#!/usr/bin/env node

/**
 * Markdown-plus-plus is a project of markdown syntax highlighting for Notepad++, by customized UDL file (user defined language).
 * This project is open source on:
 * [Source]{@link https://github.com/Edditoria/markdown-plus-plus}.
 * Code released under the MIT license:
 * [License]{@link https://github.com/Edditoria/validid/blob/master/LICENSE.txt}.
 *
 * @file Build UML XML file(s) in current working directory.
 * @auther Edditoria
 * @license MIT
 */

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

/*
Expected usage:
```cmd
npx markdown-plus-plus [options]    # In UDL folder of Notepad++
mpp [options]                       # After install this package globally
npm run mpp -- [options]            # Develop in package directory
````
*/
/* @type {Array<string>} - Usage messages to print */
var usageMsg = [
	'Build UML XML file(s) for Notepad++ in current working directory.',
	'',
	'Usage: npx markdown-plus-plus [theme-name...] [--all] [-f | --force]',
	'',
	'Options:',
	'theme-name       Build UDL file(s) for specified theme(s)',
	'                 You can give multiple theme names',
	'                 e.g. npx markdown-plus-plus solarized zenburn deep-black',
	'-f, --force      Force to overwrite any file that already exists in directory',
	'-l, --list       List bundled themes in this package',
	'-v, --version    Print current version of this package',
	'-h, --help       Print usage',
	'',
	'Examples:',
	'npx markdown-plus-plus               Build all UDL files without overwrite',
	'npx markdown-plus-plus zenburn       Build Zenburn UDL file without overwrite',
	'npx markdown-plus-plus zenburn -f    Build Zenburn UDL file and overwrite',
	''
];

/* @type {string} - Version of this npm package. */
var version = process.env.npm_package_version;
/* @type {Array<string>} - Arguments from node. */
var args = process.argv.slice(2);
/* @type {string} - Current working directory. */
var cwd = process.cwd();
/* @type {string} - Root directory of this NPM package. */
var packagePath = path.resolve(__dirname, '../');
/* @type {string} - Path for <udl/> in this package. */
var udlPath = packagePath + '/udl';

/*
 * Parse arguments passed from user command input.
 * "-f" can only be passed at first or last argument.
 * "-l/-h/-v" can only be passed at first argument.
 * @param {Array<string>} args - Arguments from Node's `process.argv.slice(2)`.
 * @param {buildinUdls} buildinUdls - Basically the theme names and filenames in <udl/>.
 * @return {Object} - The parsed object passing to build steps.
 */
var parseArgs = function(args, buildinUdls) {
	var options = {
		themeList: [],
		fileList: [],
		shouldContinue: false,
		isForce: false
	};
	// Parse the first argument. Quit asap if user put a proper flag.
	var firstArg = args[0];
	switch (firstArg) {
		case '-l': case '--list':
			console.log(buildinUdls.themeList.join('\n'));
			return options;
		case '-v': case '--version':
			console.log(version);
			return options;
		case '-h': case '--help':
			console.log(usageMsg.join('\n'));
			return options;
	}
	// Loop all arguments. Match the theme names, otherwise the program should quits.
	var arg, indexOfTheme;
	for (var i = 0; i < args.length; i++) {
		arg = args[i];
		if (arg === '-f' || arg === '--force') {
			if (i === 0 || i === args.length - 1) {
				console.log('Warning! In force mode, any existing file(s) will be overwritten.\n');
				options.isForce = true;
			} else {
				console.log('arg[' + i + ']: You pass the \"' + arg + '\" flag in wrong position. Quit for safety.');
				return options;
			}
		} else if (buildinUdls.themeList.indexOf(arg) >= 0) {
			options.themeList.push(arg);
			indexOfTheme = buildinUdls.themeList.indexOf(arg);
			options.fileList.push(buildinUdls.fileList[indexOfTheme]);
		} else {
			console.log('arg[' + i + ']: ' + 'Unsupported option \"' + arg + '\" or combination of options.');
			return options;
		}
	}
	options.shouldContinue = true;
	return options;
};

/**
 * Get file list in a directory.
 * Similar to `dir /w` in command prompt and `ls` in bash.
 * Expect program quit with error if it does not find the directory.
 * @param {string} dir - Path of a directory.
 * @return {string[]} - An array as a list of filenames.
 */
var getFileList = function(dir) {
	return fs.readdirSync(dir);
};

/**
 * Get theme name from a UDL XML filename, assuming the filename is in proper format.
 * @param {string} filename - Expected format: 'markdown.hyphen-lowercase-theme-name.udl.xml'.
 * @return {string}
 */
var getThemeName = function(filename) {
	var reHead = /^(markdown\.)/;
	var reTail = /(\.udl\.xml)$/;
	return filename.replace(reHead, '').replace(reTail, '');
};

/**
 * Get a list of theme names in a directory.
 * Theme names are stripped from filename of the built-in UDL files in <udl/>.
 * @param {Array<string>} - A list of theme names, e.g. ['default', 'zenburn'].
 */
var getThemeList = function(dir) {
	var files = getFileList(dir);
	var themeList = [];
	for (var i = 0; i < files.length; i++) {
		themeList.push(getThemeName(files[i]));
	}
	return themeList;
};

/**
 * @typedef {Object} BuildinUdls
 * @description An object that contains a list of theme names and a list of their filenames.
 * @property {Array<string>} themeList - A list of theme names corresponding to the file list.
 * @property {Array<string>} fileList - A list of filenames in <udl/> of this package.
 */
/**
 * Create a special object that contains information of files in <udl/>.
 * This approach could avoid some wired theme names, e.g. '__proto__'
 * @param {udlPath} - The path of <udl/>.
 * @return {BuildinUdls}
 */
var createBuildinUdls = function(udlPath) {
	var fileList = getFileList(udlPath);
	var themeList = [];
	var filename, themeName;
	for (var i = 0; i < fileList.length; i++) {
		filename = fileList[i];
		themeName = getThemeName(filename);
		themeList.push(themeName);
	}
	return { themeList: themeList, fileList: fileList };
};

/**
 * Copy file from source to destination using `fs.createReadSteam()`.
 * This function will overwritten any files that already exists.
 * This function is created because `fs.copyFile()` requires Node v8.5+.
 * This NPM package targets to serve under Node v4+.
 * @param {string} src - Path of source directory.
 * @param {string} dest - Path of destination directory.
 */
var copyFile = function(src, dest) {
	var readSteam = fs.createReadStream(src);
	readSteam.once('error', function(error) {
		console.log(error);
	});
	// readSteam.once('end', function() {
	// 	console.log('copyFile() done');
	// });
	readSteam.pipe(fs.createWriteStream(dest));
};

/**
 * Build UDL XML file(s) in current working directory.
 * @param {Array} args - This array is produced by Node's `process.argv`.
 */
var main = function(args) {
	/* @type {string[]} - A list of filenames in <udl/> in this package. */
	var fileList = getFileList(packagePath + '/udl');
	// Loop the file list.
	var filename, src, dest, themeName, isExist;
	for (var i = 0; i < fileList.length; i++) {
		filename = fileList[i];
		src = packagePath + '/udl/' + filename;
		dest = cwd + '/' + filename;
		themeName = getThemeName(filename);
		// Synchronously check whether file exists.
		isExist = fs.existsSync(dest);
		// Jump to next iteration if file already exists.
		if (isExist) {
			console.log('[' + themeName + '] Warning: File already exists. Have skipped this one.');
			continue; // Jump to next iteration.
		}
		copyFile(src, dest);
		console.log('[' + themeName + '] Done: UDL file is created');
	}
};

/* @type {BuildinUdls} - Create a special object that contains theme list and file list. */
var buildinUdls = createBuildinUdls(udlPath);
/* @type {Object} - Parse args into options object. */
var options = parseArgs(args, buildinUdls);
console.log(options);
// main(options);
<|endoftext|>


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

// Copyright (C) 2014, Microsoft Corporation. All rights reserved.
// This code is governed by the BSD License found in the LICENSE file.
const DEFAULT_TEST_TIMEOUT = 10000;

const compile = require('test262-compiler');
const fs = require('fs');
const Path = require('path');
const globber = require('../lib/globber.js');
const cli = require('../lib/cli.js');
const argv = cli.argv;
const validator = require('../lib/validator.js');
const Rx = require('rx');
const util = require('util');
const resultsEmitter = require('../lib/resultsEmitter.js');
const agentPool = require('../lib/agentPool.js');
const test262Finder = require('../lib/findTest262.js');
const scenariosForTest = require('../lib/scenarios.js');

// test262 directory (used to locate includes unless overridden with includesDir)
let test262Dir = argv.test262Dir;
// where to load includes from (usually a subdirectory of test262dir)
let includesDir = argv.includesDir;

// print version of test262-harness
if (argv.version) {
  printVersion();
  process.exit(0);
}

// initialize reporter by attempting to load lib/reporters/${reporter}
// defaults to 'simple'
let reporter;
if (fs.existsSync(Path.join(__dirname, '../lib/reporters', `${argv.reporter}.js`))) {
  reporter = require(`../lib/reporters/${argv.reporter}.js`);
} else {
  console.error(`Reporter ${argv.reporter} not found.`);
  process.exit(1);
}

// load preload contents
let preludeContents;
if (argv.prelude) {
  preludeContents = fs.readFileSync(argv.prelude, 'utf8');
} else {
  preludeContents = '';
}

// Select hostType and hostPath. hostType defaults to 'node'.
// If using default hostType, hostPath defaults to the current node executable location.
let hostType;
let hostPath;

if (argv.hostType) {
  hostType = argv.hostType;

  if (!argv.hostPath) {
    console.error('Missing host path. Pass --hostPath with a path to the host executable you want to test.');
    process.exit(1);
  }

  hostPath = argv.hostPath;
} else {
  hostType = 'node';

  if (argv.hostPath) {
    hostPath = argv.hostPath;
  } else {
    hostPath = process.execPath;
  }
}

argv.timeout = argv.timeout || DEFAULT_TEST_TIMEOUT;

// Show help if no arguments provided
if (!argv._.length) {
  cli.showHelp();
  process.exit(1);
}

// Test Pipeline
const pool = agentPool(Number(argv.threads), hostType, argv.hostArgs, hostPath, { timeout: argv.timeout });
const paths = globber(argv._);
if (!includesDir && !test262Dir) {
  test262Dir = test262Finder(paths.fileEvents[0]);
}
const files = paths.map(pathToTestFile);
const tests = files.map(compileFile);
const scenarios = tests.flatMap(scenariosForTest);
const pairs = Rx.Observable.zip(pool, scenarios);
const rawResults = pairs.flatMap(pool.runTest).tapOnCompleted(() => pool.destroy());
const results = rawResults.map(test => {
  test.result = validator(test);
  return test;
});
const resultEmitter = resultsEmitter(results);
reporter(resultEmitter);

function printVersion() {
  const p = require(Path.resolve(__dirname, "..", "package.json"));
  console.log(`v${p.version}`);
}

function pathToTestFile(path) {
  return { file: path, contents: fs.readFileSync(path, 'utf-8')};
}

function compileFile(test) {
  const endFrontmatterRe = /---\*\/\r?\n/g;
  const match = endFrontmatterRe.exec(test.contents);
  if (match) {
    test.contents = test.contents.slice(0, endFrontmatterRe.lastIndex)
                    + preludeContents
                    + test.contents.slice(endFrontmatterRe.lastIndex);
  } else {
    test.contents = preludeContents + test.contents;
  }
  return compile(test, { test262Dir, includesDir });
}
<commit_msg>Avoid truncating output when exiting<commit_after>#!/usr/bin/env node

// Copyright (C) 2014, Microsoft Corporation. All rights reserved.
// This code is governed by the BSD License found in the LICENSE file.
const DEFAULT_TEST_TIMEOUT = 10000;

const compile = require('test262-compiler');
const fs = require('fs');
const Path = require('path');
const globber = require('../lib/globber.js');
const cli = require('../lib/cli.js');
const argv = cli.argv;
const validator = require('../lib/validator.js');
const Rx = require('rx');
const util = require('util');
const resultsEmitter = require('../lib/resultsEmitter.js');
const agentPool = require('../lib/agentPool.js');
const test262Finder = require('../lib/findTest262.js');
const scenariosForTest = require('../lib/scenarios.js');

// test262 directory (used to locate includes unless overridden with includesDir)
let test262Dir = argv.test262Dir;
// where to load includes from (usually a subdirectory of test262dir)
let includesDir = argv.includesDir;

// print version of test262-harness
if (argv.version) {
  printVersion();
  return;
}

// initialize reporter by attempting to load lib/reporters/${reporter}
// defaults to 'simple'
let reporter;
if (fs.existsSync(Path.join(__dirname, '../lib/reporters', `${argv.reporter}.js`))) {
  reporter = require(`../lib/reporters/${argv.reporter}.js`);
} else {
  console.error(`Reporter ${argv.reporter} not found.`);
  process.exitCode = 1;
  return;
}

// load preload contents
let preludeContents;
if (argv.prelude) {
  preludeContents = fs.readFileSync(argv.prelude, 'utf8');
} else {
  preludeContents = '';
}

// Select hostType and hostPath. hostType defaults to 'node'.
// If using default hostType, hostPath defaults to the current node executable location.
let hostType;
let hostPath;

if (argv.hostType) {
  hostType = argv.hostType;

  if (!argv.hostPath) {
    console.error('Missing host path. Pass --hostPath with a path to the host executable you want to test.');
    process.exitCode = 1;
    return;
  }

  hostPath = argv.hostPath;
} else {
  hostType = 'node';

  if (argv.hostPath) {
    hostPath = argv.hostPath;
  } else {
    hostPath = process.execPath;
  }
}

argv.timeout = argv.timeout || DEFAULT_TEST_TIMEOUT;

// Show help if no arguments provided
if (!argv._.length) {
  cli.showHelp();
  process.exitCode = 1;
  return;
}

// Test Pipeline
const pool = agentPool(Number(argv.threads), hostType, argv.hostArgs, hostPath, { timeout: argv.timeout });
const paths = globber(argv._);
if (!includesDir && !test262Dir) {
  test262Dir = test262Finder(paths.fileEvents[0]);
}
const files = paths.map(pathToTestFile);
const tests = files.map(compileFile);
const scenarios = tests.flatMap(scenariosForTest);
const pairs = Rx.Observable.zip(pool, scenarios);
const rawResults = pairs.flatMap(pool.runTest).tapOnCompleted(() => pool.destroy());
const results = rawResults.map(test => {
  test.result = validator(test);
  return test;
});
const resultEmitter = resultsEmitter(results);
reporter(resultEmitter);

function printVersion() {
  const p = require(Path.resolve(__dirname, "..", "package.json"));
  console.log(`v${p.version}`);
}

function pathToTestFile(path) {
  return { file: path, contents: fs.readFileSync(path, 'utf-8')};
}

function compileFile(test) {
  const endFrontmatterRe = /---\*\/\r?\n/g;
  const match = endFrontmatterRe.exec(test.contents);
  if (match) {
    test.contents = test.contents.slice(0, endFrontmatterRe.lastIndex)
                    + preludeContents
                    + test.contents.slice(endFrontmatterRe.lastIndex);
  } else {
    test.contents = preludeContents + test.contents;
  }
  return compile(test, { test262Dir, includesDir });
}
<|endoftext|>


<commit_before>import angular from "angular";
import metadataPlugin from "phylocanvas-plugin-metadata";
import exportSVgPlugin from "phylocanvas-plugin-export-svg";
import { METADATA, TREE } from "./../../constants";
import "../../../../../../css/pages/phylocanvas-metadata.css";

const PHYLOCANVAS_DIV = "phylocanvas";
const BOTTOM_PADDING = 180;

/*
  Initial settings for displaying the metadata.
 */
const metadataFormat = {
  showHeaders: true,
  showLabels: true,
  blockLength: 32,
  blockSize: 32,
  padding: 25,
  columns: [],
  propertyName: "data",
  underlineHeaders: true,
  headerAngle: 0,
  fillStyle: "black",
  strokeStyle: "black",
  lineWidth: 1,
};

/**
 * Updates th size of the canvas to be the size of the available space in teh window.
 * @param {object} $window angular window object.
 */
const setCanvasHeight = ($window) => {
  const canvas = document.querySelector(`#${PHYLOCANVAS_DIV}`);
  canvas.style.height = `${$window.innerHeight - BOTTOM_PADDING}px`;
};

/**
 * Angular controller function for this scope.
 * @param {object} $window AngularJS window object
 * @param {object} $scope AngularJS $scope object for current dom
 * @param {object} $q AngularJS promise object
 * @param {object} Phylocanvas angular injection of the Phylocanvas library.
 * @param {object} PhylocanvasService angular service for server exchanges for newick data
 * @param {object} MetadataService angular service for getting metedata terms
 */
function phylocanvasController(
  $window,
  $scope,
  $q,
  Phylocanvas,
  PhylocanvasService,
  MetadataService
) {
  // Make the canvas fill the viewable window.
  setCanvasHeight($window);

  // Initialize the plugins.
  Phylocanvas.plugin(metadataPlugin);
  Phylocanvas.plugin(exportSVgPlugin);

  // Initialize phylocanvas.
  const tree = Phylocanvas.createTree(PHYLOCANVAS_DIV, {
    lineWidth: 2,
    metadata: metadataFormat,
  });

  const promises = [];

  // Create a promise for when the metadata is given.
  const metadataPromise = $q.defer();
  promises.push(metadataPromise.promise);

  this.$onInit = () => {
    /**
     * Kick everything off by getting the newick file and the
     * initial metadata.
     */
    const newickPromise = PhylocanvasService.getNewickData(this.newickurl).then(
      (result) => result,
      () => {
        $scope.$emit(TREE.NOT_LOADED);
      }
    );
    promises.push(newickPromise);

    // Create the tree when the promises complete.
    $q.all(promises).then((results) => {
      const newick = results[1];
      if (angular.isString(newick)) {
        tree.load(newick);
      }
      $scope.$emit(TREE.COMPLETED);
    });
  };

  // Set tree defaults
  tree.setTreeType("rectangular");
  tree.alignLabels = true;

  /**
   * Listen for changes to the metadata structure and update
   * the phylocanvas accordingly.
   */
  $scope.$on(METADATA.UPDATED, (event, args) => {
    if (args.columns.length > 0) {
      tree.metadata.active = true;
      tree.metadata.columns = args.columns;
    } else {
      tree.metadata.active = false;
    }
    tree.draw();
    tree.fitInPanel();
    tree.draw();
  });

  $scope.$on(METADATA.EMPTY, () => {
    metadataPromise.resolve();
  });

  $scope.$on(METADATA.LOADED, (event, args) => {
    const { metadata } = args;
    // Add the metadata to the branches before the tree is drawn.
    tree.on("beforeFirstDraw", () => {
      for (const leaf of tree.leaves) {
        leaf.data = metadata[leaf.label];
      }
    });
    metadataPromise.resolve();
  });

  /**
   * Lister for when a metadata template is applied.
   * This forces phylocanvas to updates the metadata fields displayed.
   */
  $scope.$on(METADATA.TEMPLATE, (event, args) => {
    const { fields } = args;
    tree.metadata.columns = MetadataService.getSortedAndFilteredColumns(fields);
    tree.draw();
    tree.fitInPanel();
    tree.draw();
  });

  /**
   * Listener for notification to export the phylocanvas image as an SVG.
   */
  $scope.$on(TREE.EXPORT_SVG, () => {
    const svg = tree.exportSVG.getSerialisedSVG();
    const url = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
    const link = document.createElement("a");
    link.href = url;
    document.body.appendChild(link);
    link.download = `tree-${Date.now()}.svg`;
    link.click();
    document.body.removeChild(link);
  });
}

phylocanvasController.$inject = [
  "$window",
  "$scope",
  "$q",
  "Phylocanvas",
  "PhylocanvasService",
  "MetadataService",
];

export const PhylocanvasComponent = {
  bindings: {
    newickurl: "@",
  },
  templateUrl: "phylocanvas.tmpl.html",
  controller: phylocanvasController,
};
<commit_msg>this is to fix - https://github.com/phac-nml/irida/issues/941<commit_after>import angular from "angular";
import metadataPlugin from "phylocanvas-plugin-metadata";
import exportSVgPlugin from "phylocanvas-plugin-export-svg";
import { METADATA, TREE } from "./../../constants";
import "../../../../../../css/pages/phylocanvas-metadata.css";

const PHYLOCANVAS_DIV = "phylocanvas";
const BOTTOM_PADDING = 180;

/*
  Initial settings for displaying the metadata.
 */
const metadataFormat = {
  showHeaders: true,
  showLabels: true,
  blockLength: 32,
  blockSize: 32,
  padding: 25,
  columns: [],
  propertyName: "data",
  underlineHeaders: true,
  headerAngle: 0,
  fillStyle: "black",
  strokeStyle: "black",
  lineWidth: 1,
};

/**
 * Updates th size of the canvas to be the size of the available space in teh window.
 * @param {object} $window angular window object.
 */
const setCanvasHeight = ($window) => {
  const canvas = document.querySelector(`#${PHYLOCANVAS_DIV}`);
  canvas.style.height = `${$window.innerHeight - BOTTOM_PADDING}px`;
};

/**
 * Angular controller function for this scope.
 * @param {object} $window AngularJS window object
 * @param {object} $scope AngularJS $scope object for current dom
 * @param {object} $q AngularJS promise object
 * @param {object} Phylocanvas angular injection of the Phylocanvas library.
 * @param {object} PhylocanvasService angular service for server exchanges for newick data
 * @param {object} MetadataService angular service for getting metedata terms
 */
function phylocanvasController(
  $window,
  $scope,
  $q,
  Phylocanvas,
  PhylocanvasService,
  MetadataService
) {
  // Make the canvas fill the viewable window.
  setCanvasHeight($window);

  // Initialize the plugins.
  Phylocanvas.plugin(metadataPlugin);
  Phylocanvas.plugin(exportSVgPlugin);

  // Initialize phylocanvas.
  const tree = Phylocanvas.createTree(PHYLOCANVAS_DIV, {
    lineWidth: 2,
    metadata: metadataFormat,
  });

  const promises = [];

  // Create a promise for when the metadata is given.
  const metadataPromise = $q.defer();
  promises.push(metadataPromise.promise);

  this.$onInit = () => {
    /**
     * Kick everything off by getting the newick file and the
     * initial metadata.
     */
    const newickPromise = PhylocanvasService.getNewickData(this.newickurl).then(
      (result) => result,
      () => {
        $scope.$emit(TREE.NOT_LOADED);
      }
    );
    promises.push(newickPromise);

    // Create the tree when the promises complete.
    $q.all(promises).then((results) => {
      const newick = results[1];
      if (angular.isString(newick)) {
        tree.load(newick);
      }
      $scope.$emit(TREE.COMPLETED);
    });
  };

  // Set tree defaults
  tree.setTreeType("rectangular");
  tree.alignLabels = true;

  /**
   * Listen for changes to the metadata structure and update
   * the phylocanvas accordingly.
   */
  $scope.$on(METADATA.UPDATED, (event, args) => {
    if (args.columns.length > 0) {
      tree.metadata.active = true;
      tree.metadata.columns = args.columns;
    } else {
      tree.metadata.active = false;
    }
    tree.draw();
    tree.fitInPanel();
    tree.draw();
  });

  $scope.$on(METADATA.EMPTY, () => {
    metadataPromise.resolve();
  });

  $scope.$on(METADATA.LOADED, (event, args) => {
    const { metadata } = args;
    // Add the metadata to the branches before the tree is drawn.
    console.log("METADATA: ", metadata);
    tree.on("beforeFirstDraw", () => {
      for (const leaf of tree.leaves) {
        console.log("LEAF: ", leaf.label);
        if (metadata.hasOwnProperty(leaf.label)){
          leaf.data = metadata[leaf.label];
        }else{
          leaf.data = metadata.reference;
        }
      }
    });
    metadataPromise.resolve();
  });

  /**
   * Lister for when a metadata template is applied.
   * This forces phylocanvas to updates the metadata fields displayed.
   */
  $scope.$on(METADATA.TEMPLATE, (event, args) => {
    const { fields } = args;
    tree.metadata.columns = MetadataService.getSortedAndFilteredColumns(fields);
    tree.draw();
    tree.fitInPanel();
    tree.draw();
  });

  /**
   * Listener for notification to export the phylocanvas image as an SVG.
   */
  $scope.$on(TREE.EXPORT_SVG, () => {
    const svg = tree.exportSVG.getSerialisedSVG();
    const url = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
    const link = document.createElement("a");
    link.href = url;
    document.body.appendChild(link);
    link.download = `tree-${Date.now()}.svg`;
    link.click();
    document.body.removeChild(link);
  });
}

phylocanvasController.$inject = [
  "$window",
  "$scope",
  "$q",
  "Phylocanvas",
  "PhylocanvasService",
  "MetadataService",
];

export const PhylocanvasComponent = {
  bindings: {
    newickurl: "@",
  },
  templateUrl: "phylocanvas.tmpl.html",
  controller: phylocanvasController,
};
<|endoftext|>


<commit_before>/**
 * @type {String}
 *
 * @properties={typeid:35,uuid:"70C9A8A9-DF72-4450-B242-EF06129E6956"}
 */
var _license_dsa_mosaic_WEB_cms = 'Module: _dsa_mosaic_WEB_cms \
									Copyright (C) 2011-2013 Data Mosaic \
									MIT Licensed';

/**
 * @properties={typeid:24,uuid:"4C05C95F-1431-4C01-9912-26708524802D"}
 */
function INIT_asset() {

	// main data object to build
	var asset = new Object()

	// form with info about this asset
	asset.formName = controller.getName()

	// meta rows
	asset.meta = {
//		height : 'INTEGER',
//		width : 'INTEGER'
	}

	return asset
}

/**
 * @properties={typeid:24,uuid:"8B9BBDD7-FB8F-4B2D-9790-E308D20CFB40"}
 */
function ASSET_actions(input,assetRecord) {
	//menu items
	var valuelist = new Array(
					'Copy link'
				)

	//called to depress menu
	if (input instanceof JSEvent) {
		//set up menu with arguments
		var menu = new Array()

		for ( var i = 0 ; i < valuelist.length ; i++ ) {
			menu[i] = plugins.popupmenu.createMenuItem(valuelist[i],ASSET_actions)

			menu[i].setMethodArguments(i,assetRecord)

			if (menu[i].text == '----') {
				menu[i].setEnabled(false)
			}
		}
		//popup
		var elem = forms[input.getFormName()].elements[input.getElementName()]
		if (elem != null) {
			plugins.popupmenu.showPopupMenu(elem, menu)
		}
	}
	//menu shown and item chosen
	else {
		switch( input ) {
			case 0:	//
				ASSET_copy_link(assetRecord)
				break
		}
	}
}

/**
 * @param	{JSRecord}	[assetRecord] Record that we are working with
 * @param	{Boolean}	[editMode] Save data or leave in pseudo-transaction
 *
 * @properties={typeid:24,uuid:"C37CDF64-0B6B-4908-9DD2-52593E9A0F1D"}
 */
function ASSET_copy_link(assetRecord,editMode) {

	if (!assetRecord instanceof JSRecord) {
		assetRecord = foundset.getSelectedRecord()
	}

	if (editMode) {
		_editMode = true
	}
	else {
		_editMode = false
	}

	//save outstanding data and turn autosave off
	if (!_editMode) {
		databaseManager.saveData()
		databaseManager.setAutoSave(false)
	}

	//get default asset instance
	var srcAsset = assetRecord.web_asset_to_asset_instance__initial.getRecord(1)

	var template 	= '/{{path}}/{{name}}'
	var data		= { path : srcAsset.asset_directory, name : srcAsset.asset_title }
	var link		= globals.CMS.markup.merge(template,data)

	application.setClipboardContent(link)
}

<commit_msg>get correct link to asset file from asset library<commit_after>/**
 * @type {String}
 *
 * @properties={typeid:35,uuid:"70C9A8A9-DF72-4450-B242-EF06129E6956"}
 */
var _license_dsa_mosaic_WEB_cms = 'Module: _dsa_mosaic_WEB_cms \
									Copyright (C) 2011-2013 Data Mosaic \
									MIT Licensed';

/**
 * @properties={typeid:24,uuid:"4C05C95F-1431-4C01-9912-26708524802D"}
 */
function INIT_asset() {

	// main data object to build
	var asset = new Object()

	// form with info about this asset
	asset.formName = controller.getName()

	// meta rows
	asset.meta = {
//		height : 'INTEGER',
//		width : 'INTEGER'
	}

	return asset
}

/**
 * @properties={typeid:24,uuid:"8B9BBDD7-FB8F-4B2D-9790-E308D20CFB40"}
 */
function ASSET_actions(input,assetRecord) {
	//menu items
	var valuelist = new Array(
					'Copy link'
				)

	//called to depress menu
	if (input instanceof JSEvent) {
		//set up menu with arguments
		var menu = new Array()

		for ( var i = 0 ; i < valuelist.length ; i++ ) {
			menu[i] = plugins.popupmenu.createMenuItem(valuelist[i],ASSET_actions)

			menu[i].setMethodArguments(i,assetRecord)

			if (menu[i].text == '----') {
				menu[i].setEnabled(false)
			}
		}
		//popup
		var elem = forms[input.getFormName()].elements[input.getElementName()]
		if (elem != null) {
			plugins.popupmenu.showPopupMenu(elem, menu)
		}
	}
	//menu shown and item chosen
	else {
		switch( input ) {
			case 0:	//
				ASSET_copy_link(assetRecord)
				break
		}
	}
}

/**
 * @param	{JSRecord}	[assetRecord] Record that we are working with
 * @param	{Boolean}	[editMode] Save data or leave in pseudo-transaction
 *
 * @properties={typeid:24,uuid:"C37CDF64-0B6B-4908-9DD2-52593E9A0F1D"}
 */
function ASSET_copy_link(assetRecord,editMode) {

	if (!assetRecord instanceof JSRecord) {
		assetRecord = foundset.getSelectedRecord()
	}

	if (editMode) {
		_editMode = true
	}
	else {
		_editMode = false
	}

	//save outstanding data and turn autosave off
	if (!_editMode) {
		databaseManager.saveData()
		databaseManager.setAutoSave(false)
	}

	//get default asset instance
	var srcAsset = assetRecord.web_asset_to_asset_instance__initial.getRecord(1)

	application.setClipboardContent(globals.CMS.token.getFile(srcAsset).link)
}

<|endoftext|>


<commit_before>module.exports = function boardGameListShortCode (data) {
    return `
${data.host == undefined ? '' : `<h2>${data.host}</h2>`}

${data.list.map(entry =>
    `

        ${entry.title}

`
).join('\n')}

`;
}<commit_msg>Temp delete<commit_after><|endoftext|>


<commit_before>/* jshint noyield:true */
import Ember from 'ember';
import EmberUploader from 'ember-uploader';
import { task } from 'ember-concurrency';

const { Component } = Ember;
const { computed } = Ember;
const { inject } = Ember;
const { isBlank } = Ember;
const { isEmpty } = Ember;
const { service } = inject;
const { String } = Ember;
const { dasherize } = String;
const { htmlSafe } = String;

export default Component.extend({
  ajax: service(),
  toast: service(),
  fieldHeaderValue: computed('modelName', 'field', function(){
    const { modelName, field } = this.getProperties('modelName', 'field');

    return !isBlank(modelName) && !isBlank(field) ? dasherize(`${modelName}.${field}`) : null;
  }),
  deleteFile: task(function * (){
    this.get('valueChanged')(null);
  }).drop(),
  uploadFile: task(function * (files){
    if (!isEmpty(files)) {
      let ajax = this.get('ajax');
      ajax.setHeaders();
      let headers = ajax.get('headers');
      const fieldHeaderValue = this.get('fieldHeaderValue');

      if(!isBlank(fieldHeaderValue)) {
        headers['X-Mist-Field-Target'] = fieldHeaderValue;
      }

      let uploaderOptions = {
        type: 'POST',
        ajaxSettings: {
          headers: headers
        }
      };

      // lets check for a possible other endpoint
      const componentOptions = this.get('options');
      if(!isBlank(componentOptions) && componentOptions.endpoint) {
        uploaderOptions['url'] = `${ajax.get('endpoint')}${componentOptions.endpoint}`;
      } else {
        // no alternative endpoint found. Lets use the default one
        uploaderOptions['url'] = `${ajax.get('endpoint')}file/files`;
      }

      let uploader = EmberUploader.Uploader.extend(uploaderOptions).create();
      let fieldValue = [];

      let activeFile = 0;
      let shouldContinue = true;
      for(let file of files) {
        activeFile++;

        this.set('totalFiles', files.length);
        this.set('activeFile', activeFile);

        if(shouldContinue) {
          yield uploader.upload(file).then((data) => {
            let fileObject = {};
            fileObject.id = data.data.id;
            fileObject.filename = data.data.attributes.filename;
            fileObject.uri = data.data.attributes.uri;
            fileObject.url = data.data.attributes.url;
            fileObject.filemime = data.data.attributes.filemime;
            fileObject.filesize = data.data.attributes.filesize;
            fileObject.hash = data.data.attributes.hash;

            if(this.get('multiple')) {
              fieldValue.push(fileObject);
            } else {
              fieldValue = fileObject;
              shouldContinue = false;
            }
          })
          .catch((error) => {
            let errorMessage = 'File upload failed';

            if(error.responseJSON) {
              if('error_description' in error.responseJSON){
                errorMessage = error.responseJSON.error_description;
              } else if('error' in error.responseJSON){
                errorMessage = error.responseJSON.error;
              }
            }

            errorMessage = `(${htmlSafe(file.name)}) ${errorMessage}`;
            this.get('toast').error(errorMessage, errorMessage);
          });
        }
      }

      this.get('valueChanged')(fieldValue);
    }
  }).drop(),
  actions: {
    valueChanged: function(value){
      this.get('uploadFile').perform(value);
    }
  }
});
<commit_msg>Added custom headers to Upload file component.<commit_after>/* jshint noyield:true */
import Ember from 'ember';
import EmberUploader from 'ember-uploader';
import { task } from 'ember-concurrency';

const { Component } = Ember;
const { computed } = Ember;
const { inject } = Ember;
const { isBlank } = Ember;
const { isEmpty } = Ember;
const { service } = inject;
const { String } = Ember;
const { merge } = Ember;
const { dasherize } = String;
const { htmlSafe } = String;

export default Component.extend({
  ajax: service(),
  toast: service(),
  fieldHeaderValue: computed('modelName', 'field', function(){
    const { modelName, field } = this.getProperties('modelName', 'field');

    return !isBlank(modelName) && !isBlank(field) ? dasherize(`${modelName}.${field}`) : null;
  }),
  deleteFile: task(function * (){
    this.get('valueChanged')(null);
  }).drop(),
  uploadFile: task(function * (files){
    if (!isEmpty(files)) {
      let ajax = this.get('ajax');
      ajax.setHeaders();
      let headers = ajax.get('headers');
      const fieldHeaderValue = this.get('fieldHeaderValue');
      const componentOptions = this.get('options');

      // Merge the headers with the possible
      if(!isBlank(componentOptions) && componentOptions.headers){
        merge(headers, componentOptions.headers);
      }

      if(!isBlank(fieldHeaderValue)) {
        headers['X-Mist-Field-Target'] = fieldHeaderValue;
      }

      let uploaderOptions = {
        type: 'POST',
        ajaxSettings: {
          headers: headers
        }
      };

      // lets check for a possible other endpoint
      if(!isBlank(componentOptions) && componentOptions.endpoint) {
        uploaderOptions['url'] = `${ajax.get('endpoint')}${componentOptions.endpoint}`;
      } else {
        // no alternative endpoint found. Lets use the default one
        uploaderOptions['url'] = `${ajax.get('endpoint')}file/files`;
      }

      let uploader = EmberUploader.Uploader.extend(uploaderOptions).create();
      let fieldValue = [];

      let activeFile = 0;
      let shouldContinue = true;
      for(let file of files) {
        activeFile++;

        this.set('totalFiles', files.length);
        this.set('activeFile', activeFile);

        if(shouldContinue) {
          yield uploader.upload(file).then((data) => {
            let fileObject = {};
            fileObject.id = data.data.id;
            fileObject.filename = data.data.attributes.filename;
            fileObject.uri = data.data.attributes.uri;
            fileObject.url = data.data.attributes.url;
            fileObject.filemime = data.data.attributes.filemime;
            fileObject.filesize = data.data.attributes.filesize;
            fileObject.hash = data.data.attributes.hash;

            if(this.get('multiple')) {
              fieldValue.push(fileObject);
            } else {
              fieldValue = fileObject;
              shouldContinue = false;
            }
          })
          .catch((error) => {
            let errorMessage = 'File upload failed';

            if(error.responseJSON) {
              if('error_description' in error.responseJSON){
                errorMessage = error.responseJSON.error_description;
              } else if('error' in error.responseJSON){
                errorMessage = error.responseJSON.error;
              }
            }

            errorMessage = `(${htmlSafe(file.name)}) ${errorMessage}`;
            this.get('toast').error(errorMessage, errorMessage);
          });
        }
      }

      this.get('valueChanged')(fieldValue);
    }
  }).drop(),
  actions: {
    valueChanged: function(value){
      this.get('uploadFile').perform(value);
    }
  }
});
<|endoftext|>


<commit_before>openerp.web_dashboard = function(openerp) {
var QWeb = openerp.web.qweb;
QWeb.add_template('/web_dashboard/static/src/xml/web_dashboard.xml');

openerp.web.form.DashBoard = openerp.web.form.Widget.extend({
    init: function(view, node) {
        this._super(view, node);
        this.template = 'DashBoard';
        this.actions_attrs = {};
        this.action_managers = [];
    },
    start: function() {
        var self = this;
        this._super.apply(this, arguments);

        this.$element.find('.oe-dashboard-column').sortable({
            connectWith: '.oe-dashboard-column',
            handle: '.oe-dashboard-action-header',
            scroll: false
        }).disableSelection().bind('sortstop', self.do_save_dashboard);

        // Events
        this.$element.find('.oe-dashboard-link-undo').click(this.on_undo);
        this.$element.find('.oe-dashboard-link-reset').click(this.on_reset);
        this.$element.find('.oe-dashboard-link-add_widget').click(this.on_add_widget);
        this.$element.find('.oe-dashboard-link-change_layout').click(this.on_change_layout);

        this.$element.delegate('.oe-dashboard-column .oe-dashboard-fold', 'click', this.on_fold_action);
        this.$element.delegate('.oe-dashboard-column .ui-icon-closethick', 'click', this.on_close_action);

        this.actions_attrs = {};
        // Init actions
        _.each(this.node.children, function(column) {
            _.each(column.children, function(action) {
                delete(action.attrs.width);
                delete(action.attrs.height);
                delete(action.attrs.colspan);
                self.actions_attrs[action.attrs.name] = action.attrs;
                self.rpc('/web/action/load', {
                    action_id: parseInt(action.attrs.name, 10)
                }, self.on_load_action);
            });
        });

        //this.$element.find('a.oe-dashboard-action-rename').live('click', this.on_rename);
        this.$element.find('.oe-dashboard-action').live('mouseover mouseout', function(event) {
            $(this).find('.oe-dashboard-action-header .ui-icon, .oe-dashboard-action-header .oe-dashboard-action-rename').toggle(event.type == 'mouseover');
        });
    },
    on_undo: function() {
        this.rpc('/web/view/undo_custom', {
            view_id: this.view.fields_view.view_id
        }, this.do_reload);
    },
    on_reset: function() {
        this.rpc('/web/view/undo_custom', {
            view_id: this.view.fields_view.view_id,
            reset: true
        }, this.do_reload);
    },
    on_add_widget: function() {
        var self = this;
        var action_manager = new openerp.web.ActionManager(this);
        var dialog = new openerp.web.Dialog(this, {
            title : 'Actions',
            width: 800,
            height: 600,
            buttons : {
                Cancel : function() {
                    $(this).dialog('destroy');
                },
                Add : function() {
                    self.do_add_widget(action_manager.inner_viewmanager.views.list.controller);
                    $(this).dialog('destroy');
                }
            }
        }).start().open();
        action_manager.appendTo(dialog.$element);
        action_manager.do_action({
            res_model : 'ir.actions.actions',
            views : [[false, 'list']],
            type : 'ir.actions.act_window',
            limit : 80,
            auto_search : true,
            flags : {
                sidebar : false,
                views_switcher : false,
                action_buttons : false
            }
        });
        // TODO: should bind ListView#select_record in order to catch record clicking
    },
    do_add_widget : function(listview) {
        var self = this,
            actions = listview.groups.get_selection().ids,
            results = [],
            qdict = { view : this.view };
        // TODO: should load multiple actions at once
        _.each(actions, function(aid) {
            self.rpc('/web/action/load', {
                action_id: aid
            }, function(result) {
                self.actions_attrs[aid] = {
                    name: aid,
                    string: _.trim(result.result.name)
                };
                qdict.action = {
                    attrs : self.actions_attrs[aid]
                };
                self.$element.find('.oe-dashboard-column:first').prepend(QWeb.render('DashBoard.action', qdict));
                self.do_save_dashboard();
                self.on_load_action(result)
            });
        });
    },
    on_rename : function(e) {
        var self = this,
            id = parseInt($(e.currentTarget).parents('.oe-dashboard-action:first').attr('data-id'), 10),
            $header = $(e.currentTarget).parents('.oe-dashboard-action-header:first'),
            $rename = $header.find('a.oe-dashboard-action-rename').hide(),
            $title = $header.find('span.oe-dashboard-action-title').hide(),
            $input = $header.find('input[name=title]');
        $input.val($title.text()).show().focus().bind('keydown', function(e) {
            if (e.which == 13 || e.which == 27) {
                if (e.which == 13) { //enter
                    var val = $input.val();
                    if (!val) {
                        return false;
                    }
                    $title.text(val);
                    self.actions_attrs[id].string = val;
                    self.do_save_dashboard();
                }
                $input.unbind('keydown').hide();
                $rename.show();
                $title.show();
            }
        });
    },
    on_change_layout: function() {
        var self = this;
        var qdict = {
            current_layout : this.$element.find('.oe-dashboard').attr('data-layout')
        };
        var $dialog = $('<div>').dialog({
                            modal: true,
                            title: 'Edit Layout',
                            width: 'auto',
                            height: 'auto'
                        }).html(QWeb.render('DashBoard.layouts', qdict));
        $dialog.find('li').click(function() {
            var layout = $(this).attr('data-layout');
            $dialog.dialog('destroy');
            self.do_change_layout(layout);
        });
    },
    do_change_layout: function(new_layout) {
        var $dashboard = this.$element.find('.oe-dashboard');
        var current_layout = $dashboard.attr('data-layout');
        if (current_layout != new_layout) {
            var clayout = current_layout.split('-').length,
                nlayout = new_layout.split('-').length,
                column_diff = clayout - nlayout;
            if (column_diff > 0) {
                var $last_column = $();
                $dashboard.find('.oe-dashboard-column').each(function(k, v) {
                    if (k >= nlayout) {
                        $(v).find('.oe-dashboard-action').appendTo($last_column);
                    } else {
                        $last_column = $(v);
                    }
                });
            }
            $dashboard.toggleClass('oe-dashboard-layout_' + current_layout + ' oe-dashboard-layout_' + new_layout);
            $dashboard.attr('data-layout', new_layout);
            this.do_save_dashboard();
        }
    },
    on_fold_action: function(e) {
        var $e = $(e.currentTarget),
            $action = $e.parents('.oe-dashboard-action:first'),
            id = parseInt($action.attr('data-id'), 10);
        if ($e.is('.ui-icon-minusthick')) {
            this.actions_attrs[id].fold = '1';
        } else {
            delete(this.actions_attrs[id].fold);
        }
        $e.toggleClass('ui-icon-minusthick ui-icon-plusthick');
        $action.find('.oe-dashboard-action-content').toggle();
        this.do_save_dashboard();
    },
    on_close_action: function(e) {
        $(e.currentTarget).parents('.oe-dashboard-action:first').remove();
        this.do_save_dashboard();
    },
    do_save_dashboard: function() {
        var self = this;
        var board = {
                form_title : this.view.fields_view.arch.attrs.string,
                style : this.$element.find('.oe-dashboard').attr('data-layout'),
                columns : []
            };
        this.$element.find('.oe-dashboard-column').each(function() {
            var actions = [];
            $(this).find('.oe-dashboard-action').each(function() {
                var action_id = $(this).attr('data-id');
                actions.push(self.actions_attrs[action_id]);
            });
            board.columns.push(actions);
        });
        var arch = QWeb.render('DashBoard.xml', board);
        this.rpc('/web/view/add_custom', {
            view_id: this.view.fields_view.view_id,
            arch: arch
        }, function() {
            self.$element.find('.oe-dashboard-link-undo, .oe-dashboard-link-reset').show();
        });
    },
    on_load_action: function(result) {
        var action = result.result;
        action.flags = {
            search_view : false,
            sidebar : false,
            views_switcher : false,
            action_buttons : false,
            pager: false,
            low_profile: true
        };
        var am = new openerp.web.ActionManager(this);
        this.action_managers.push(am);
        am.appendTo($("#"+this.view.element_id + '_action_' + action.id));
        am.do_action(action);
    },
    render: function() {
        // We should start with three columns available
        for (var i = this.node.children.length; i < 3; i++) {
            this.node.children.push({
                tag: 'column',
                attrs: {},
                children: []
            });
        }
        return QWeb.render(this.template, this);
    },
    do_reload: function() {
        _.each(this.action_managers, function(am) {
            am.stop();
        });
        this.action_managers = [];
        this.view.stop();
        this.view.start();
    }
});
openerp.web.form.DashBoardLegacy = openerp.web.form.DashBoard.extend({
    render: function() {
        if (this.node.tag == 'hpaned') {
            this.node.attrs.style = '2-1';
        } else if (this.node.tag == 'vpaned') {
            this.node.attrs.style = '1';
        }
        this.node.tag = 'board';
        _.each(this.node.children, function(child) {
            if (child.tag.indexOf('child') == 0) {
                child.tag = 'column';
                var actions = [], first_child = child.children[0];
                if (first_child && first_child.tag == 'vpaned') {
                    _.each(first_child.children, function(subchild) {
                        actions.push.apply(actions, subchild.children);
                    });
                    child.children = actions;
                }
            }
        });
        return this._super(this, arguments);
    }
});

openerp.web.form.widgets.add('hpaned', 'openerp.web.form.DashBoardLegacy');
openerp.web.form.widgets.add('vpaned', 'openerp.web.form.DashBoardLegacy');
openerp.web.form.widgets.add('board', 'openerp.web.form.DashBoard');

openerp.web.client_actions.add(
    'board.config.overview', 'openerp.web_dashboard.ConfigOverview'
);
if (!openerp.web_dashboard) {
    /** @namespace */
    openerp.web_dashboard = {};
}
openerp.web_dashboard.ConfigOverview = openerp.web.View.extend({
    template: 'ConfigOverview',
    init: function (parent) {
        this._super(parent);
        this.dataset = new openerp.web.DataSetSearch(
                this, 'ir.actions.todo');
        this.dataset.domain = [['type', '=', 'manual']];
    },
    start: function () {
        this._super();
        $.when(this.dataset.read_slice(['state', 'action_id', 'category_id']),
               this.dataset.call('progress'))
            .then(this.on_records_loaded);
    },
    on_records_loaded: function (read_response, progress_response) {
        var records = read_response,
           progress = progress_response[0];

        var grouped_todos = _(records).chain()
            .map(function (record) {
                return {
                    id: record.id,
                    name: record.action_id[1],
                    done: record.state !== 'open',
                    to_do: record.state === 'open',
                    category: record['category_id'][1] || "Uncategorized"
                }
            })
            .groupBy(function (record) {return record.category})
            .value();
        this.$element.html(QWeb.render('ConfigOverview.content', {
            completion: 100 * progress.done / progress.total,
            groups: grouped_todos
        }));
        var $progress = this.$element.find('div.oe-config-progress-bar');
        $progress.progressbar({value: $progress.data('completion')});

        var self = this;
        this.$element.find('dl')
            .delegate('input', 'click', function (e) {
                // switch todo status
                e.stopImmediatePropagation();
                var new_state = this.checked ? 'done' : 'open',
                      todo_id = parseInt($(this).val(), 10);
                self.dataset.write(todo_id, {state: new_state}, {}, function () {
                    self.start();
                });
            })
            .delegate('li:not(.oe-done)', 'click', function () {
                self.widget_parent.widget_parent.widget_parent.do_execute_action({
                        type: 'object',
                        name: 'action_launch'
                    }, self.dataset,
                    $(this).data('id'), function () {
                        // after action popup closed, refresh configuration
                        // thingie
                        self.start();
                    });
            });
    }
});

openerp.web.client_actions.add(
    'board.home.applications', 'openerp.web_dashboard.ApplicationTiles');
openerp.web_dashboard.ApplicationTiles = openerp.web.View.extend({
    template: 'ApplicationTiles',
    start: function () {
        this._super();
        var self = this;
        return new openerp.web.DataSetSearch(
                this, 'ir.ui.menu', null, [['parent_id', '=', false]])
            .read_slice( ['name', 'web_icon_data', 'web_icon_hover_data'], {}, function (applications) {
                // Create a matrix of 3*x applications
                var rows = [];
                while (applications.length) {
                    rows.push(applications.splice(0, 3));
                }
                self.$element
                    .append(QWeb.render(
                        'ApplicationTiles.content', {rows: rows}))
                    .find('.oe-dashboard-home-tile')
                        .click(function () {
                            var $this = $(this);
                            $this.closest('.openerp')
                                 .find('.menu a[data-menu=' + $this.data('menuid') + ']')
                                 .click();});
            });
    }
});
openerp.web.client_actions.add(
    'board.home.widgets', 'openerp.web_dashboard.Widget');
openerp.web_dashboard.Widget = openerp.web.View.extend(/** @lends openerp.web_dashboard.Widgets# */{
    template: 'HomeWidget',
    /**
     * Initializes a "HomeWidget" client widget: handles the display of a given
     * res.widget objects in an OpenERP view (mainly a dashboard).
     *
     * @constructs openerp.web_dashboard.Widget
     * @extends openerp.web.View
     *
     * @param {Object} parent
     * @param {Object} options
     * @param {Number} options.widget_id
     */
    init: function (parent, options) {
        this._super(parent);
        this.widget_id = options.widget_id;
    },
    start: function () {
        this._super();
        return new openerp.web.DataSet(this, 'res.widget').read_ids(
                [this.widget_id], ['title'], this.on_widget_loaded);
    },
    on_widget_loaded: function (widgets) {
        var widget = widgets[0];
        var url = _.sprintf(
            '/web_dashboard/widgets/content?session_id=%s&widget_id=%d',
            this.session.session_id, widget.id);
        this.$element.html(QWeb.render('HomeWidget.content', {
            widget: widget,
            url: url
        }));
    }
});
};
<commit_msg>[FIX] show all configuration wizard in administrator dashboard.<commit_after>openerp.web_dashboard = function(openerp) {
var QWeb = openerp.web.qweb;
QWeb.add_template('/web_dashboard/static/src/xml/web_dashboard.xml');

openerp.web.form.DashBoard = openerp.web.form.Widget.extend({
    init: function(view, node) {
        this._super(view, node);
        this.template = 'DashBoard';
        this.actions_attrs = {};
        this.action_managers = [];
    },
    start: function() {
        var self = this;
        this._super.apply(this, arguments);

        this.$element.find('.oe-dashboard-column').sortable({
            connectWith: '.oe-dashboard-column',
            handle: '.oe-dashboard-action-header',
            scroll: false
        }).disableSelection().bind('sortstop', self.do_save_dashboard);

        // Events
        this.$element.find('.oe-dashboard-link-undo').click(this.on_undo);
        this.$element.find('.oe-dashboard-link-reset').click(this.on_reset);
        this.$element.find('.oe-dashboard-link-add_widget').click(this.on_add_widget);
        this.$element.find('.oe-dashboard-link-change_layout').click(this.on_change_layout);

        this.$element.delegate('.oe-dashboard-column .oe-dashboard-fold', 'click', this.on_fold_action);
        this.$element.delegate('.oe-dashboard-column .ui-icon-closethick', 'click', this.on_close_action);

        this.actions_attrs = {};
        // Init actions
        _.each(this.node.children, function(column) {
            _.each(column.children, function(action) {
                delete(action.attrs.width);
                delete(action.attrs.height);
                delete(action.attrs.colspan);
                self.actions_attrs[action.attrs.name] = action.attrs;
                self.rpc('/web/action/load', {
                    action_id: parseInt(action.attrs.name, 10)
                }, self.on_load_action);
            });
        });

        //this.$element.find('a.oe-dashboard-action-rename').live('click', this.on_rename);
        this.$element.find('.oe-dashboard-action').live('mouseover mouseout', function(event) {
            $(this).find('.oe-dashboard-action-header .ui-icon, .oe-dashboard-action-header .oe-dashboard-action-rename').toggle(event.type == 'mouseover');
        });
    },
    on_undo: function() {
        this.rpc('/web/view/undo_custom', {
            view_id: this.view.fields_view.view_id
        }, this.do_reload);
    },
    on_reset: function() {
        this.rpc('/web/view/undo_custom', {
            view_id: this.view.fields_view.view_id,
            reset: true
        }, this.do_reload);
    },
    on_add_widget: function() {
        var self = this;
        var action_manager = new openerp.web.ActionManager(this);
        var dialog = new openerp.web.Dialog(this, {
            title : 'Actions',
            width: 800,
            height: 600,
            buttons : {
                Cancel : function() {
                    $(this).dialog('destroy');
                },
                Add : function() {
                    self.do_add_widget(action_manager.inner_viewmanager.views.list.controller);
                    $(this).dialog('destroy');
                }
            }
        }).start().open();
        action_manager.appendTo(dialog.$element);
        action_manager.do_action({
            res_model : 'ir.actions.actions',
            views : [[false, 'list']],
            type : 'ir.actions.act_window',
            limit : 80,
            auto_search : true,
            flags : {
                sidebar : false,
                views_switcher : false,
                action_buttons : false
            }
        });
        // TODO: should bind ListView#select_record in order to catch record clicking
    },
    do_add_widget : function(listview) {
        var self = this,
            actions = listview.groups.get_selection().ids,
            results = [],
            qdict = { view : this.view };
        // TODO: should load multiple actions at once
        _.each(actions, function(aid) {
            self.rpc('/web/action/load', {
                action_id: aid
            }, function(result) {
                self.actions_attrs[aid] = {
                    name: aid,
                    string: _.trim(result.result.name)
                };
                qdict.action = {
                    attrs : self.actions_attrs[aid]
                };
                self.$element.find('.oe-dashboard-column:first').prepend(QWeb.render('DashBoard.action', qdict));
                self.do_save_dashboard();
                self.on_load_action(result)
            });
        });
    },
    on_rename : function(e) {
        var self = this,
            id = parseInt($(e.currentTarget).parents('.oe-dashboard-action:first').attr('data-id'), 10),
            $header = $(e.currentTarget).parents('.oe-dashboard-action-header:first'),
            $rename = $header.find('a.oe-dashboard-action-rename').hide(),
            $title = $header.find('span.oe-dashboard-action-title').hide(),
            $input = $header.find('input[name=title]');
        $input.val($title.text()).show().focus().bind('keydown', function(e) {
            if (e.which == 13 || e.which == 27) {
                if (e.which == 13) { //enter
                    var val = $input.val();
                    if (!val) {
                        return false;
                    }
                    $title.text(val);
                    self.actions_attrs[id].string = val;
                    self.do_save_dashboard();
                }
                $input.unbind('keydown').hide();
                $rename.show();
                $title.show();
            }
        });
    },
    on_change_layout: function() {
        var self = this;
        var qdict = {
            current_layout : this.$element.find('.oe-dashboard').attr('data-layout')
        };
        var $dialog = $('<div>').dialog({
                            modal: true,
                            title: 'Edit Layout',
                            width: 'auto',
                            height: 'auto'
                        }).html(QWeb.render('DashBoard.layouts', qdict));
        $dialog.find('li').click(function() {
            var layout = $(this).attr('data-layout');
            $dialog.dialog('destroy');
            self.do_change_layout(layout);
        });
    },
    do_change_layout: function(new_layout) {
        var $dashboard = this.$element.find('.oe-dashboard');
        var current_layout = $dashboard.attr('data-layout');
        if (current_layout != new_layout) {
            var clayout = current_layout.split('-').length,
                nlayout = new_layout.split('-').length,
                column_diff = clayout - nlayout;
            if (column_diff > 0) {
                var $last_column = $();
                $dashboard.find('.oe-dashboard-column').each(function(k, v) {
                    if (k >= nlayout) {
                        $(v).find('.oe-dashboard-action').appendTo($last_column);
                    } else {
                        $last_column = $(v);
                    }
                });
            }
            $dashboard.toggleClass('oe-dashboard-layout_' + current_layout + ' oe-dashboard-layout_' + new_layout);
            $dashboard.attr('data-layout', new_layout);
            this.do_save_dashboard();
        }
    },
    on_fold_action: function(e) {
        var $e = $(e.currentTarget),
            $action = $e.parents('.oe-dashboard-action:first'),
            id = parseInt($action.attr('data-id'), 10);
        if ($e.is('.ui-icon-minusthick')) {
            this.actions_attrs[id].fold = '1';
        } else {
            delete(this.actions_attrs[id].fold);
        }
        $e.toggleClass('ui-icon-minusthick ui-icon-plusthick');
        $action.find('.oe-dashboard-action-content').toggle();
        this.do_save_dashboard();
    },
    on_close_action: function(e) {
        $(e.currentTarget).parents('.oe-dashboard-action:first').remove();
        this.do_save_dashboard();
    },
    do_save_dashboard: function() {
        var self = this;
        var board = {
                form_title : this.view.fields_view.arch.attrs.string,
                style : this.$element.find('.oe-dashboard').attr('data-layout'),
                columns : []
            };
        this.$element.find('.oe-dashboard-column').each(function() {
            var actions = [];
            $(this).find('.oe-dashboard-action').each(function() {
                var action_id = $(this).attr('data-id');
                actions.push(self.actions_attrs[action_id]);
            });
            board.columns.push(actions);
        });
        var arch = QWeb.render('DashBoard.xml', board);
        this.rpc('/web/view/add_custom', {
            view_id: this.view.fields_view.view_id,
            arch: arch
        }, function() {
            self.$element.find('.oe-dashboard-link-undo, .oe-dashboard-link-reset').show();
        });
    },
    on_load_action: function(result) {
        var action = result.result;
        action.flags = {
            search_view : false,
            sidebar : false,
            views_switcher : false,
            action_buttons : false,
            pager: false,
            low_profile: true
        };
        var am = new openerp.web.ActionManager(this);
        this.action_managers.push(am);
        am.appendTo($("#"+this.view.element_id + '_action_' + action.id));
        am.do_action(action);
    },
    render: function() {
        // We should start with three columns available
        for (var i = this.node.children.length; i < 3; i++) {
            this.node.children.push({
                tag: 'column',
                attrs: {},
                children: []
            });
        }
        return QWeb.render(this.template, this);
    },
    do_reload: function() {
        _.each(this.action_managers, function(am) {
            am.stop();
        });
        this.action_managers = [];
        this.view.stop();
        this.view.start();
    }
});
openerp.web.form.DashBoardLegacy = openerp.web.form.DashBoard.extend({
    render: function() {
        if (this.node.tag == 'hpaned') {
            this.node.attrs.style = '2-1';
        } else if (this.node.tag == 'vpaned') {
            this.node.attrs.style = '1';
        }
        this.node.tag = 'board';
        _.each(this.node.children, function(child) {
            if (child.tag.indexOf('child') == 0) {
                child.tag = 'column';
                var actions = [], first_child = child.children[0];
                if (first_child && first_child.tag == 'vpaned') {
                    _.each(first_child.children, function(subchild) {
                        actions.push.apply(actions, subchild.children);
                    });
                    child.children = actions;
                }
            }
        });
        return this._super(this, arguments);
    }
});

openerp.web.form.widgets.add('hpaned', 'openerp.web.form.DashBoardLegacy');
openerp.web.form.widgets.add('vpaned', 'openerp.web.form.DashBoardLegacy');
openerp.web.form.widgets.add('board', 'openerp.web.form.DashBoard');

openerp.web.client_actions.add(
    'board.config.overview', 'openerp.web_dashboard.ConfigOverview'
);
if (!openerp.web_dashboard) {
    /** @namespace */
    openerp.web_dashboard = {};
}
openerp.web_dashboard.ConfigOverview = openerp.web.View.extend({
    template: 'ConfigOverview',
    init: function (parent) {
        this._super(parent);
        this.dataset = new openerp.web.DataSetSearch(
                this, 'ir.actions.todo');
    },
    start: function () {
        this._super();
        $.when(this.dataset.read_slice(['state', 'action_id', 'category_id']),
               this.dataset.call('progress'))
            .then(this.on_records_loaded);
    },
    on_records_loaded: function (read_response, progress_response) {
        var records = read_response,
           progress = progress_response[0];

        var grouped_todos = _(records).chain()
            .map(function (record) {
                return {
                    id: record.id,
                    name: record.action_id[1],
                    done: record.state !== 'open',
                    to_do: record.state === 'open',
                    category: record['category_id'][1] || "Uncategorized"
                }
            })
            .groupBy(function (record) {return record.category})
            .value();
        this.$element.html(QWeb.render('ConfigOverview.content', {
            completion: 100 * progress.done / progress.total,
            groups: grouped_todos
        }));
        var $progress = this.$element.find('div.oe-config-progress-bar');
        $progress.progressbar({value: $progress.data('completion')});

        var self = this;
        this.$element.find('dl')
            .delegate('input', 'click', function (e) {
                // switch todo status
                e.stopImmediatePropagation();
                var new_state = this.checked ? 'done' : 'open',
                      todo_id = parseInt($(this).val(), 10);
                self.dataset.write(todo_id, {state: new_state}, {}, function () {
                    self.start();
                });
            })
            .delegate('li:not(.oe-done)', 'click', function () {
                self.widget_parent.widget_parent.widget_parent.do_execute_action({
                        type: 'object',
                        name: 'action_launch'
                    }, self.dataset,
                    $(this).data('id'), function () {
                        // after action popup closed, refresh configuration
                        // thingie
                        self.start();
                    });
            });
    }
});

openerp.web.client_actions.add(
    'board.home.applications', 'openerp.web_dashboard.ApplicationTiles');
openerp.web_dashboard.ApplicationTiles = openerp.web.View.extend({
    template: 'ApplicationTiles',
    start: function () {
        this._super();
        var self = this;
        return new openerp.web.DataSetSearch(
                this, 'ir.ui.menu', null, [['parent_id', '=', false]])
            .read_slice( ['name', 'web_icon_data', 'web_icon_hover_data'], {}, function (applications) {
                // Create a matrix of 3*x applications
                var rows = [];
                while (applications.length) {
                    rows.push(applications.splice(0, 3));
                }
                self.$element
                    .append(QWeb.render(
                        'ApplicationTiles.content', {rows: rows}))
                    .find('.oe-dashboard-home-tile')
                        .click(function () {
                            var $this = $(this);
                            $this.closest('.openerp')
                                 .find('.menu a[data-menu=' + $this.data('menuid') + ']')
                                 .click();});
            });
    }
});
openerp.web.client_actions.add(
    'board.home.widgets', 'openerp.web_dashboard.Widget');
openerp.web_dashboard.Widget = openerp.web.View.extend(/** @lends openerp.web_dashboard.Widgets# */{
    template: 'HomeWidget',
    /**
     * Initializes a "HomeWidget" client widget: handles the display of a given
     * res.widget objects in an OpenERP view (mainly a dashboard).
     *
     * @constructs openerp.web_dashboard.Widget
     * @extends openerp.web.View
     *
     * @param {Object} parent
     * @param {Object} options
     * @param {Number} options.widget_id
     */
    init: function (parent, options) {
        this._super(parent);
        this.widget_id = options.widget_id;
    },
    start: function () {
        this._super();
        return new openerp.web.DataSet(this, 'res.widget').read_ids(
                [this.widget_id], ['title'], this.on_widget_loaded);
    },
    on_widget_loaded: function (widgets) {
        var widget = widgets[0];
        var url = _.sprintf(
            '/web_dashboard/widgets/content?session_id=%s&widget_id=%d',
            this.session.session_id, widget.id);
        this.$element.html(QWeb.render('HomeWidget.content', {
            widget: widget,
            url: url
        }));
    }
});
};
<|endoftext|>


<commit_before>import {
	ADD_FILTER,
	CLEAR_FILTER,
	CLEAR_ALL_FILTERS,
	SET_ACTIVE_SEARCH,
	SET_ACTIVE_SORT,
	SET_ACTIVE_COLUMNS,
	SET_ACTIVE_LIST,
} from '../constants';
import { setCurrentPage } from '../actions';

/**
 * Active actions
 */
export function setActiveSearch (searchString) {
	return {
		type: SET_ACTIVE_SEARCH,
		searchString,
	};
}

export function setActiveSort (path) {
	return (dispatch, getState) => {
		// TODO Decouple from state somehow
		const list = getState().lists.currentList;
		const sort = list.expandSort(path);
		dispatch({
			type: SET_ACTIVE_SORT,
			sort,
		});
	};
}

export function setActiveColumns (columns) {
	return (dispatch, getState) => {
		// TODO Decouple from state somehow
		const list = getState().lists.currentList;
		const expandedColumns = list.expandColumns(columns);
		dispatch({
			type: SET_ACTIVE_COLUMNS,
			columns: expandedColumns,
		});
	};
}

export function setActiveList (list) {
	return {
		type: SET_ACTIVE_LIST,
		list,
	};
}

/**
 * Filtering actions
 */
function addFilter (filter) {
	return {
		type: ADD_FILTER,
		filter,
	};
}

export function clearFilter (path) {
	return {
		type: CLEAR_FILTER,
		path,
	};
}

export function clearAllFilters () {
	return {
		type: CLEAR_ALL_FILTERS,
	};
}

export function setFilter (path, value) {
	return (dispatch, getState) => {
		const state = getState();
		const activeFilters = state.active.filters;
		const currentList = state.lists.currentList;
		// Get current filter
		let filter = activeFilters.filter(i => i.field.path === path)[0];
		// If a filter exists already, update its value
		if (filter) {
			filter.value = value;
		// Otherwise construct a new one
		} else {
			const field = currentList.fields[path];
			if (!field) {
				console.warn('Invalid Filter path specified:', path);
				return;
			}
			filter = {
				field,
				value,
			};
		}
		dispatch(addFilter(filter));
		dispatch(setCurrentPage(1));
	};
}
<commit_msg>Make filtering functinal again<commit_after>import {
	ADD_FILTER,
	CLEAR_FILTER,
	CLEAR_ALL_FILTERS,
	SET_ACTIVE_SEARCH,
	SET_ACTIVE_SORT,
	SET_ACTIVE_COLUMNS,
	SET_ACTIVE_LIST,
} from '../constants';
import { setCurrentPage, loadItems } from '../actions';

/**
 * Active actions
 */
export function setActiveSearch (searchString) {
	return {
		type: SET_ACTIVE_SEARCH,
		searchString,
	};
}

export function setActiveSort (path) {
	return (dispatch, getState) => {
		// TODO Decouple from state somehow
		const list = getState().lists.currentList;
		const sort = list.expandSort(path);
		dispatch({
			type: SET_ACTIVE_SORT,
			sort,
		});
	};
}

export function setActiveColumns (columns) {
	return (dispatch, getState) => {
		// TODO Decouple from state somehow
		const list = getState().lists.currentList;
		const expandedColumns = list.expandColumns(columns);
		dispatch({
			type: SET_ACTIVE_COLUMNS,
			columns: expandedColumns,
		});
	};
}

export function setActiveList (list) {
	return {
		type: SET_ACTIVE_LIST,
		list,
	};
}

/**
 * Filtering actions
 */
function addFilter (filter) {
	// TODO Make this a pure function again, find better way to call loadItems()
	// after each filtering change!
	return (dispatch) => {
		dispatch({
			type: ADD_FILTER,
			filter,
		});
		dispatch(loadItems());
	};
}

export function clearFilter (path) {
	// TODO Make this a pure function again, find better way to call loadItems()
	// after each filtering change!
	return (dispatch) => {
		dispatch({
			type: CLEAR_FILTER,
			path,
		});
		dispatch(loadItems());
	};
}

export function clearAllFilters () {
	// TODO Make this a pure function again, find better way to call loadItems()
	// after each filtering change!
	return (dispatch) => {
		dispatch({
			type: CLEAR_ALL_FILTERS,
		});
		dispatch(loadItems());
	};
}

export function setFilter (path, value) {
	return (dispatch, getState) => {
		const state = getState();
		const activeFilters = state.active.filters;
		const currentList = state.lists.currentList;
		// Get current filter
		let filter = activeFilters.filter(i => i.field.path === path)[0];
		// If a filter exists already, update its value
		if (filter) {
			filter.value = value;
		// Otherwise construct a new one
		} else {
			const field = currentList.fields[path];
			if (!field) {
				console.warn('Invalid Filter path specified:', path);
				return;
			}
			filter = {
				field,
				value,
			};
		}
		dispatch(addFilter(filter));
		dispatch(loadItems());
		dispatch(setCurrentPage(1));
	};
}
<|endoftext|>


<commit_before>(function(angular){
    'use strict';
    var app = angular.module('courses');

    app.controller('CourseListController', [
        '$scope', 'Course', 'Lesson',
        function ($scope, Course, Lesson) {
            $scope.courseList = [];
            $scope.ordering = 'id';
            $scope.reverse = false;
            $scope.filters = {
                all: false,
                published : true,
                listed : true,
                draft : true,
                textsearch: '',
                check : function(course){
                    var f = $scope.filters;
                    var search = f.textsearch.toLowerCase();
                    var target = course.name.toLowerCase();

                    return (
                        f.all || f[course.status]
                    ) && (
                        !search || target.match(search)
                    );
                }
            };

            $scope.loadLessons = function(course) {
                if(!course.lessons) {
                    Lesson.query({'course__id': course.id}).$promise
                        .then(function(lessons){
                            course.lessons = lessons;
                        });
                }
            }

            Course.query(function(list){
                $scope.courseList = list;
            });
        }
    ]);
})(window.angular);
<commit_msg>missing semicollon<commit_after>(function(angular){
    'use strict';
    var app = angular.module('courses');

    app.controller('CourseListController', [
        '$scope', 'Course', 'Lesson',
        function ($scope, Course, Lesson) {
            $scope.courseList = [];
            $scope.ordering = 'id';
            $scope.reverse = false;
            $scope.filters = {
                all: false,
                published : true,
                listed : true,
                draft : true,
                textsearch: '',
                check : function(course){
                    var f = $scope.filters;
                    var search = f.textsearch.toLowerCase();
                    var target = course.name.toLowerCase();

                    return (
                        f.all || f[course.status]
                    ) && (
                        !search || target.match(search)
                    );
                }
            };

            $scope.loadLessons = function(course) {
                if(!course.lessons) {
                    Lesson.query({'course__id': course.id}).$promise
                        .then(function(lessons){
                            course.lessons = lessons;
                        });
                }
            };

            Course.query(function(list){
                $scope.courseList = list;
            });
        }
    ]);
})(window.angular);
<|endoftext|>


<commit_before>Titanium = Ti = {};

//NOTE: these are only for iPhone XHR bridge and will be compiled in conditionally (eventually)
Ti._hexish = function(a){var r='';var e=a.length;var c=0;var h;while(c<e){h=a.charCodeAt(c++).toString(16);r+='\\u';var l=4-h.length;while(l-->0){r+='0'};r+=h;}return r;};
Ti._bridgeEnc = function(o){return '<'+Ti._hexish(o)+'>';};

Ti.JSON = {};
Ti.JSON.stringify=function(object,bridge)
{
	var type = typeof object;
	switch (type)
	{
		case 'undefined': case 'function': case 'unknown': return undefined;
		case 'number': case 'boolean': return object;
		case 'string':
			if (bridge===1) return Ti._bridgeEnc(object);
			return '"' + object.replace(/"/g,'"').replace(/\n/g,"\n").replace(/\r/g,"\r") + '"'; /*"*/
	}
	if((object===null) || (object.nodeType==1)) return 'null';
	if(object.constructor.toString().indexOf('Date') != -1) {
		return 'new Date(' + object.getTime() + ')';
	}
	if(object.constructor.toString().indexOf('Array') != -1)
	{
		var res='[';var pre='';var len=object.length;
		for(var i=0;i<len;i++){
			var value = object[i];
			if(value !== undefined)value=Ti.JSON.stringify(value,bridge);
			if(value !== undefined){res+=pre+value;pre=', ';}
		}
		return res + ']';
	}
	var objects = [];
	for (var prop in object)
	{
		var value = object[prop];
		if (value !== undefined){value = Ti.JSON.stringify(value,bridge);}
		if (value !== undefined){objects.push(Ti.JSON.stringify(prop,bridge) + ': ' + value);}
	}
	return '{' + objects.join(',') + '}';
};

//TODO: certain statics can be placed in by compiler such as: platform, version, etc.
//TODO: need to define setInterval, setTimeout in KJS

// right now this is defined but this could just be compiled in along with the bridge switch below
Ti._bridgeType = typeof(window)!='undefined' ? 1 : 2;

/*(function()
		{*/
			// TODO: we need to ensure that if user uses XMLHttpRequest it triggers Ti.Network.createHTTPClient dependency

			function bridgeInvoke(t,m,p,a)
			{
				//TODO: this needs to be expanded to wrap/unwrap vars on android
				//NOTE: exception throws can happen on native side since we're doing eval
				var result = null;
				var data = null;
				var args = typeof(a)!='undefined' ? Ti.JSON.stringify(a,Ti._bridgeType) : null;
				if (Ti._bridgeType!==1)
				{
					// native bridge
					data = TiBridgeInvoker(String(t),m,p,args);
				}
				else
				{
				}
				if (data!==null)
				{
					// if (m!='API') Ti.API.debug("result was ["+data+"]");
					eval(data);
				}
				return result;
			};

			function makeGetter(module,prop,cache)
			{
				if (cache!==true)
				{
					return function()
					{
						return bridgeInvoke(2,module,prop);
					};
				}
				var varname = prop+'$';
				var ns = Ti[module];
				return function()
				{
					var value = ns[varname];
					if (typeof(value)=='undefined' || value===null)
					{
						value = bridgeInvoke(2,module,prop);
						ns[varname] = value;
					}
					return value;
				};
			};

			function makeSetter(module,prop,cache)
			{
				if (cache!==true)
				{
					return function(value)
					{
						bridgeInvoke(3,module,prop,value);
						return undefined;
					};
				}
				var varname = prop+'$';
				var ns = Ti[module];
				return function(value)
				{
					ns[varname] = bridgeInvoke(3,module,prop,value);
				};
			};

			function ensureNS(module)
			{
				if (typeof(Ti[module])=='undefined')
				{
					Ti[module]={};
				}
			};

			function makeProperties(module,prop,cache,submodule)
			{
				ensureNS(module);
				submodule = (typeof submodule=='undefined') ? module : submodule;
				// defaults to not cacheable
				cache = typeof cache == 'undefined' ? false : cache;
				Ti[module].__defineGetter__(prop,makeGetter(submodule,prop,cache));
				Ti[module].__defineSetter__(prop,makeSetter(submodule,prop,cache));
			};

			var listenerId = 0;

			function makeCallback(fn)
			{
				// we check to see if we have a function id property
				// on the function and if so we just reference it
				var fid = fn.fid$;
				if (fid) return fid;

				var id = String(listenerId++);
				if (!Ti.callbacks$)
				{
					Ti.callbacks$={};
				}
				Ti.callbacks$[id]=fn;
				fn.fid$=id;
				return id;
			};

			function deleteCallback(id)
			{
				if (Ti.callbacks$)
				{
					var fn = Ti.callbacks$[id];
					delete Ti.callbacks$[id];
					if (fn)
					{
						delete fn.fid$;
					}
					//Ti.API.debug("deleted callback = "+id+" => "+typeof(fn));
				}
			};

			// defined in global so the native side can invoke it
			Ti.BridgeCallbackDelete=function(id)
			{
				//Ti.API.debug("deleting callback: "+id);
				deleteCallback(id);
			};

			// defined in global so the Native side can invoke it
			Ti.BridgeCallback=function(id,args,del)
			{
				if (Ti.callbacks$)
				{
					var fn = Ti.callbacks$[id];
					if (fn)
					{
						fn.call(fn,args);
						if (del)
						{
							deleteCallback(id);
						}
					}
				}
			};

			// called to delete the bridge proxy object
			Ti.BridgeProxyDelete=function(proxyid)
			{
				//Ti.API.debug("deleting: "+proxyId);
				try { delete Ti[proxyid]; } catch(E) { }
			};

			// called to create a bridge proxy object
			Ti.BridgeMakeProxy=function(proxyid,fns,props)
			{
				var obj = {fid$:proxyid,proxy$:true};
				Ti[proxyid]=obj;
				makeModuleFunctions(proxyid,fns);
				makeModuleProperties(proxyid,props);
				return obj;
			};

			// called to resolve a bridge proxy
			Ti.BridgeReturnProxy=function(proxyid)
			{
				return Ti[proxyid];
			};

			function makeFunction(module,prop,submodule)
			{
				ensureNS(module);
				submodule = (typeof submodule=='undefined') ? module : submodule;
				Ti[module][prop]=function()
				{
					var args = null;
					if (typeof(arguments)!='undefined')
					{
						args = [];
						for (var c=0;c<arguments.length;c++)
						{
							var arg = arguments[c];
							//TODO: move this into JSON encoder
							if (typeof(arg)=='function')
							{
								arg = makeCallback(arg);
							}
							args[c] = arg;
						}
					}
					return bridgeInvoke(1,submodule,prop,args);
				};
			};

			function makeModuleFunctions(m,f,s)
			{
				if (f)
				{
					for (var c=0;c<f.length;c++)
					{
						makeFunction(m,f[c],s);
					}
				}
			};

			function makeModuleProperties(m,p,s,cache)
			{
				if (p)
				{
					s = (typeof(s)=='undefined' || s===null) ? m : s;
					for (var c=0;c<p.length;c++)
					{
						makeProperties(m,p[c],cache,s);
					}
				}
			};

			// make some functions - this would normally be injected on compile by the compiler

			// NOTE: in the future we'll generate a hash here that will be used as jump table dispatch
			// on lookup of hash to function pointer in C++

//			makeModuleFunctions('API',['debug','info','warn','error']);
//			makeModuleFunctions('UI',['createWindow','createTableView','createView','createButton','createTabGroup','createTab','createWebView']);
//			makeModuleProperties('Platform',['displayCaps','id','availableMemory']);
//			makeModuleFunctions('Platform',['createUUID']);
//			makeModuleProperties('UI',['ANIMATION_CURVE_EASE_IN_OUT','ANIMATION_CURVE_EASE_IN','ANIMATION_CURVE_EASE_OUT','ANIMATION_CURVE_LINEAR'],null,true);

			//TODO: delegate to submodules

//		})();

<commit_msg>removed unnecessary tiboot.js<commit_after><|endoftext|>