<commit_before>'use babel';

/*eslint-env node*/
/*eslint vars-on-top: 0*/

import async from 'async';
import fs from 'fs';
import less from 'less';
import mkdirp from 'mkdirp';
import path from 'path';
import readline from 'readline';
import postcss from 'postcss';
import postcssPlugins from './postcss-plugins.js';

var inProgress = false;

export default class AutocompileView {

	constructor(serializeState) {
		atom.commands.add('atom-workspace', {
			'core:save': () => {
				if (!inProgress) {
					this.handleSave();
				}
			}
		});
	}

	serialize() {}

	destroy() {}

	handleSave() {
		this.activeEditor = atom.workspace.getActiveTextEditor();

		if (this.activeEditor) {
			this.filePath = this.activeEditor.getURI();
			this.fileExt = path.extname(this.filePath);

			if (this.fileExt === '.less') {
				this.getParams(this.filePath, (params) => {
					this.compileLess(params);
				});
			}
		}
	}

	writeFiles(output, newPath, newFile) {

		async.series({
			css: (callback) => {
				if (output.css) {
					this.writeFile(output.css, newPath, newFile, function() {
						callback(null, newFile);
					});
				} else {
					callback(null, null);
				}
			},
			map: (callback) => {

				let newFileMap = `${newFile}.map`;

				if (output.map) {

					this.writeFile(output.map, newPath, newFileMap, function() {
						callback(null, newFileMap);
					});
				} else {
					callback(null, null);
				}
			},
			oldie: (callback) => {
				if (output.oldie) {
					let newFileOldie = newFile.replace('.css', '.oldie.css');

					this.writeFile(output.oldie, newPath, newFileOldie, function() {
						callback(null, newFileOldie);
					});
				} else {
					callback(null, null);
				}
			}
		}, function(err, results) {
			if (err) {
				return atom.notifications.addError(err, {
					dismissable: true
				});
			} else {
				inProgress = false;
				if (results.map !== null) {
					atom.notifications.addSuccess('Files created', {
						detail: `${results.css}\n${results.map}`
					});
				} else {
					atom.notifications.addSuccess('File created', {
						detail: results.css
					});
				}
			}
		});
	}

	compileLess(params) {

		if (!params.out) {
			return;
		}

		inProgress = true;

		var firstLine = true;
		var contentFile = [];
		var optionsLess = {
			paths: [path.dirname(path.resolve(params.file))],
			filename: path.basename(params.file),
			sourceMap: params.sourcemap === 'true' ? ({}) : false
		};

		var optionsPostcss = {};

		postcssPlugins(params, optionsPostcss);

		var rl = readline.createInterface({
			input: fs.createReadStream(params.file),
			terminal: false
		});

		rl.on('line', function(line) {
			if (!firstLine) {
				contentFile.push(line);
			} else {
				firstLine = false;
			}
			return firstLine;
		});

		rl.on('close', () => {
			this.renderLess(params, contentFile, optionsLess, optionsPostcss);
		});

	}

	renderLess(params, contentFile, optionsLess, optionsPostcss) {

		var contentFileJoined = contentFile.join('\n');

		less.render(contentFileJoined, optionsLess).then((output) => {

			var newFile = path.resolve(path.dirname(params.file), params.out);
			var newPath = path.dirname(newFile);

			if (!optionsPostcss.plugins.length) {
				this.writeFiles(output, newPath, newFile);
			} else {
				this.processPostcss(output, newPath, newFile, optionsPostcss);
			}

		}, function(err) {

			if (err) {
				inProgress = false;
				atom.notifications.addError(err.message, {
					detail: `${err.filename}:${err.line}`,
					dismissable: true
				});
			}

		});

	}

	processPostcss(lessOutput, newPath, newFile, optionsPostcss) {

		var oldieIndex = optionsPostcss.plugins.findIndex((plugin) => plugin.postcssPlugin === 'oldie');
		var oldie = (oldieIndex > -1) ? optionsPostcss.plugins.splice(oldieIndex, 1) : null;

		postcss(optionsPostcss.plugins).process(lessOutput.css, {
			from: this.filePath,
			to: newFile,
			map: {
				prev: lessOutput.map,
				annotation: true
			}
		})
		.then((result) => {

			var resultBeforeOldie = result;

			if (!oldie) {
				this.writeFiles(result, newPath, newFile);
			} else {
				postcss(oldie).process(resultBeforeOldie.css, {
					from: this.filePath,
					to: newFile,
					map: false
				})
				.then((result) => {
					resultBeforeOldie.oldie = result.css;
					this.writeFiles(resultBeforeOldie, newPath, newFile);
				});
			}
		});

	}

	writeFile(contentFile, newPath, newFile, callback) {
		return mkdirp(newPath, function(err) {
			if (err) {
				inProgress = false;
				atom.notifications.addError(err, {
					dismissable: true
				});
			} else {
				fs.writeFile(newFile, contentFile, callback);
			}
		});
	}

	getParams(filePath, callback) {

		if (!fs.existsSync(filePath)) {
			atom.notifications.addError(`${filePath} not exist`, {
				dismissable: true
			});

			return;
		}

		this.params = {
			file: filePath
		};

		this.firstLine = true;

		var rl = readline.createInterface({
			input: fs.createReadStream(filePath),
			terminal: false
		});

		rl.on('line', (line) => {
			this.parseFirstLine(line);
		});

		rl.on('close', () => {
			if (this.params.main) {
				this.compileMainFiles(filePath, this.params.main, callback);
			} else {
				callback(this.params);
			}
		});
	}

	// Iterate through each main file and compile them.
	// Wait until the last file is processed before continuing.
	compileMainFiles(filePath, items, callback, currentIndex) {

		var i = 0;
		var that = this;

		function waitBeforeIteration() {
			setTimeout(function() {
				that.compileMainFiles(filePath, items, callback, i);
			}, 100);
		}

		if (currentIndex !== undefined) {
			i = currentIndex;
		}

		for (; i < items.length; i++) {
			if (inProgress) {
				waitBeforeIteration();
				break;
			}
			this.getParams(path.resolve(path.dirname(filePath), items[i]), callback);
			inProgress = true;
		}

	}

	parseFirstLine(line) {

		if (!this.firstLine) {
			return;
		}

		this.firstLine = false;

		line.split(',').forEach((item) => {
			var i = item.indexOf(':');

			if (i < 0) {
				return;
			}

			var key = item.substr(0, i).trim();
			var match = /^\s*\/\/\s*(.+)/.exec(key);

			if (match) {
				key = match[1];
			}

			this.params[key] = item.substr(i + 1).trim();

		});

		if (this.params.main) {
			var mains = this.params.main;
			this.params.main = [];

			mains.split('|').forEach((item) => {
				this.params.main.push(item);
			});
		}

	}
}
<commit_msg>Fix behavior with missing or false sourcemap param<commit_after>'use babel';

/*eslint-env node*/
/*eslint vars-on-top: 0*/

import async from 'async';
import fs from 'fs';
import less from 'less';
import mkdirp from 'mkdirp';
import path from 'path';
import readline from 'readline';
import postcss from 'postcss';
import postcssPlugins from './postcss-plugins.js';

var inProgress = false;

export default class AutocompileView {

	constructor(serializeState) {
		atom.commands.add('atom-workspace', {
			'core:save': () => {
				if (!inProgress) {
					this.handleSave();
				}
			}
		});
	}

	serialize() {}

	destroy() {}

	handleSave() {
		this.activeEditor = atom.workspace.getActiveTextEditor();

		if (this.activeEditor) {
			this.filePath = this.activeEditor.getURI();
			this.fileExt = path.extname(this.filePath);

			if (this.fileExt === '.less') {
				this.getParams(this.filePath, (params) => {
					this.compileLess(params);
				});
			}
		}
	}

	writeFiles(output, newPath, newFile) {

		async.series({
			css: (callback) => {
				if (output.css) {
					this.writeFile(output.css, newPath, newFile, function() {
						callback(null, newFile);
					});
				} else {
					callback(null, null);
				}
			},
			map: (callback) => {

				let newFileMap = `${newFile}.map`;

				if (output.map) {

					this.writeFile(output.map, newPath, newFileMap, function() {
						callback(null, newFileMap);
					});
				} else {
					callback(null, null);
				}
			},
			oldie: (callback) => {
				if (output.oldie) {
					let newFileOldie = newFile.replace('.css', '.oldie.css');

					this.writeFile(output.oldie, newPath, newFileOldie, function() {
						callback(null, newFileOldie);
					});
				} else {
					callback(null, null);
				}
			}
		}, function(err, results) {
			if (err) {
				return atom.notifications.addError(err, {
					dismissable: true
				});
			} else {
				inProgress = false;
				if (results.map !== null) {
					atom.notifications.addSuccess('Files created', {
						detail: `${results.css}\n${results.map}`
					});
				} else {
					atom.notifications.addSuccess('File created', {
						detail: results.css
					});
				}
			}
		});
	}

	compileLess(params) {

		if (!params.out) {
			return;
		}

		inProgress = true;

		var firstLine = true;
		var contentFile = [];
		var optionsLess = {
			paths: [path.dirname(path.resolve(params.file))],
			filename: path.basename(params.file),
			sourceMap: params.sourcemap === 'true' ? ({}) : false
		};

		var optionsPostcss = {};

		postcssPlugins(params, optionsPostcss);

		var rl = readline.createInterface({
			input: fs.createReadStream(params.file),
			terminal: false
		});

		rl.on('line', function(line) {
			if (!firstLine) {
				contentFile.push(line);
			} else {
				firstLine = false;
			}
			return firstLine;
		});

		rl.on('close', () => {
			this.renderLess(params, contentFile, optionsLess, optionsPostcss);
		});

	}

	renderLess(params, contentFile, optionsLess, optionsPostcss) {

		var contentFileJoined = contentFile.join('\n');

		less.render(contentFileJoined, optionsLess).then((output) => {

			var newFile = path.resolve(path.dirname(params.file), params.out);
			var newPath = path.dirname(newFile);

			if (!optionsPostcss.plugins.length) {
				this.writeFiles(output, newPath, newFile);
			} else {
				this.processPostcss(output, newPath, newFile, optionsPostcss);
			}

		}, function(err) {

			if (err) {
				inProgress = false;
				atom.notifications.addError(err.message, {
					detail: `${err.filename}:${err.line}`,
					dismissable: true
				});
			}

		});

	}

	processPostcss(lessOutput, newPath, newFile, optionsPostcss) {

		var oldieIndex = optionsPostcss.plugins.findIndex((plugin) => plugin.postcssPlugin === 'oldie');
		var oldie = (oldieIndex > -1) ? optionsPostcss.plugins.splice(oldieIndex, 1) : null;
		var mapOpts = (!lessOutput.map) ? false : { prev: lessOutput.map, annotation: true };

		postcss(optionsPostcss.plugins).process(lessOutput.css, {
			from: this.filePath,
			to: newFile,
			map: mapOpts
		})
		.then((result) => {

			var resultBeforeOldie = result;

			if (!oldie) {
				this.writeFiles(result, newPath, newFile);
			} else {
				postcss(oldie).process(resultBeforeOldie.css, {
					from: this.filePath,
					to: newFile,
					map: false
				})
				.then((result) => {
					resultBeforeOldie.oldie = result.css;
					this.writeFiles(resultBeforeOldie, newPath, newFile);
				});
			}
		});

	}

	writeFile(contentFile, newPath, newFile, callback) {
		return mkdirp(newPath, function(err) {
			if (err) {
				inProgress = false;
				atom.notifications.addError(err, {
					dismissable: true
				});
			} else {
				fs.writeFile(newFile, contentFile, callback);
			}
		});
	}

	getParams(filePath, callback) {

		if (!fs.existsSync(filePath)) {
			atom.notifications.addError(`${filePath} not exist`, {
				dismissable: true
			});

			return;
		}

		this.params = {
			file: filePath
		};

		this.firstLine = true;

		var rl = readline.createInterface({
			input: fs.createReadStream(filePath),
			terminal: false
		});

		rl.on('line', (line) => {
			this.parseFirstLine(line);
		});

		rl.on('close', () => {
			if (this.params.main) {
				this.compileMainFiles(filePath, this.params.main, callback);
			} else {
				callback(this.params);
			}
		});
	}

	// Iterate through each main file and compile them.
	// Wait until the last file is processed before continuing.
	compileMainFiles(filePath, items, callback, currentIndex) {

		var i = 0;
		var that = this;

		function waitBeforeIteration() {
			setTimeout(function() {
				that.compileMainFiles(filePath, items, callback, i);
			}, 100);
		}

		if (currentIndex !== undefined) {
			i = currentIndex;
		}

		for (; i < items.length; i++) {
			if (inProgress) {
				waitBeforeIteration();
				break;
			}
			this.getParams(path.resolve(path.dirname(filePath), items[i]), callback);
			inProgress = true;
		}

	}

	parseFirstLine(line) {

		if (!this.firstLine) {
			return;
		}

		this.firstLine = false;

		line.split(',').forEach((item) => {
			var i = item.indexOf(':');

			if (i < 0) {
				return;
			}

			var key = item.substr(0, i).trim();
			var match = /^\s*\/\/\s*(.+)/.exec(key);

			if (match) {
				key = match[1];
			}

			this.params[key] = item.substr(i + 1).trim();

		});

		if (this.params.main) {
			var mains = this.params.main;
			this.params.main = [];

			mains.split('|').forEach((item) => {
				this.params.main.push(item);
			});
		}

	}
}
<|endoftext|>


<commit_before>'use babel';

/** @jsx etch.dom */
/* @flow*/
import etch from 'etch';
import { Emitter, CompositeDisposable, Disposable, TextEditor } from 'atom';
import { normalizeString } from '../helpers';
import type { Message } from '../types';

// TODO
// - resize columns
export default class ResultView {
  properties: {
    messages: Array<Message>;
    ansiToHtml: boolean;
    softWrap: ?boolean;
    runningTestersCount: number;
 }
  refs: any;
  element: any;
  panel: any;
  emitter: Emitter;
  disposables: CompositeDisposable;
  sortKey: string;
  desc: boolean;
  currentTest: Message;

  constructor(properties:Object) {
    this.properties = properties;
    this.emitter = new Emitter();
    this.disposables = new CompositeDisposable();
    if (!this.properties.messages) {
      this.properties.messages = [];
    }
    this.sortKey = '';
    this.desc = false;
    etch.initialize(this);

    const softWrapHandler = async () => {
      await this.update({ softWrap: this.refs.softWrap.checked });
    };
    this.refs.softWrap.addEventListener('click', softWrapHandler);
    this.disposables.add(new Disposable(() => { this.refs.softWrap.removeEventListener('click', softWrapHandler()); }));
  }

  render() {
    const failedTests = this.properties.messages.filter(result => result.state === 'failed').length;
    const skippedTests = this.properties.messages.filter(result => result.state === 'skipped').length;
    const passedTests = this.properties.messages.filter(result => result.state === 'passed').length;
    return (

             0 ? 'inline-block text-error' : 'inline-block'}>Failed: {failedTests}
             0 ? 'inline-block text-warning' : 'inline-block'}>Skipped: {skippedTests}
             0 ? 'inline-block text-success' : 'inline-block'}>Passed: {passedTests}

              <input class='input-checkbox' ref='softWrap' type='checkbox' checked={this.properties.softWrap}/> Soft Wrap

              {etch.dom(TextEditor, {
                ref: 'additionalArgs',
                mini: true,
                placeholderText: 'Additional command line args',
              })}

            <button class={this.properties.runningTestersCount > 0 ?
              'inline-block-tight btn btn-sm tester-wait-button' :
              'inline-block-tight btn btn-sm'}
              title='Test Project'
              ref='testProject'
              onclick={this.handleTestButtonClick.bind(this)} disabled={this.properties.runningTestersCount > 0}>Test Project</button>

State

Duration

Title

Error

Location

 0 ? 'display: none;' : ''}>No tester messages

          {this.properties.messages.map((message, index) =>

                      {message.state || 'unknown'}

{message.duration || 0}ms

{message.title || ''}

                      {atom.project.relativizePath(message.filePath)[1] || message.filePath || ''}{message.lineNumber ? `:${message.lineNumber}` : ''}

)}

    );
  }

  update(newProperties:Object) {
    if (this.properties.messages !== newProperties.messages ||
      this.properties.softWrap !== newProperties.softWrap) {
      if (newProperties.messages) {
        this.properties.messages = newProperties.messages;
        this.sortMessages(this.sortKey, this.desc);
      }
      if (typeof newProperties.softWrap === 'boolean') {
        this.properties.softWrap = newProperties.softWrap;
      }
      if (typeof newProperties.runningTestersCount === 'number') {
        this.properties.runningTestersCount = newProperties.runningTestersCount;
      }
      return etch.update(this);
    }
    return Promise.resolve();
  }

  async destroy() {
    await etch.destroy(this);
    this.disposables.dispose();
  }

  getTitle() {
    return 'Tester Results';
  }

  getIconName() {
    return 'beaker';
  }

  getDefaultLocation() {
    return 'bottom';
  }

  getAllowedLocations() {
    return ['left', 'right', 'bottom'];
  }

  getURI() {
    return 'atom://tester-result-view';
  }

  getElement() {
    return this.element;
  }

  getAdditionalArgs() {
    return this.refs.additionalArgs ? this.refs.additionalArgs.getText() : '';
  }

  onTestButtonClick(callback : Function) : Disposable {
    return this.emitter.on('test-project-button-click', callback);
  }

  goToNextTest() {
    if (this.properties.messages.length === 0) {
      return;
    }
    if (!this.currentTest) {
      this.currentTest = this.properties.messages[0];
    } else {
      const index = this.properties.messages.indexOf(this.currentTest);
      if (index >= 0 && index < this.properties.messages.length - 1) {
        this.currentTest = this.properties.messages[index + 1];
      }
    }
    this.openTest(this.currentTest);
  }

  goToPreviousTest() {
    if (this.properties.messages.length === 0) {
      return;
    }
    if (!this.currentTest) {
      this.currentTest = this.properties.messages[this.properties.messages.length - 1];
    } else {
      const index = this.properties.messages.indexOf(this.currentTest);
      if (index > 0 && index <= this.properties.messages.length - 1) {
        this.currentTest = this.properties.messages[index - 1];
      }
    }
    this.openTest(this.currentTest);
  }

  openTest(message: Message) {
    if (!message || !message.filePath) {
      return;
    }
    atom.workspace.open(message.filePath, { initialLine: message.lineNumber });
  }

  handleTestButtonClick():void {
    this.emitter.emit('test-project-button-click', this.getAdditionalArgs());
  }

  handleRowClick(selectedIndex: number): void {
    const message = this.properties.messages[selectedIndex];
    this.currentTest = message;
    this.openTest(message);
  }

  async handleSortByClick(key: string) {
    if (!this.properties.messages || this.properties.messages.length === 0) {
      return;
    }
    const ref = `header-${key}`;
    const headerElement = this.refs[ref];
    const desc = headerElement.className.includes('asc');

    this.refs['header-state'].classList.remove('asc', 'desc', 'icon-triangle-up', 'icon-triangle-down');
    this.refs['header-duration'].classList.remove('asc', 'desc', 'icon-triangle-up', 'icon-triangle-down');
    this.refs['header-title'].classList.remove('asc', 'desc', 'icon-triangle-up', 'icon-triangle-down');
    this.refs['header-error'].classList.remove('asc', 'desc', 'icon-triangle-up', 'icon-triangle-down');
    this.refs['header-filePath'].classList.remove('asc', 'desc', 'icon-triangle-up', 'icon-triangle-down');

    this.sortKey = key;
    this.desc = desc;
    this.sortMessages(this.sortKey, this.desc);
    if (desc) {
      headerElement.classList.add('desc', 'icon', 'icon-triangle-down');
    } else {
      headerElement.classList.add('asc', 'icon', 'icon-triangle-up');
    }
    await etch.update(this);
  }

  sortMessages(key: string, desc: boolean) {
    this.properties.messages.sort((current, next) => {
      const currentValue = (key === 'error') ? (current.error ? current.error.message : '') : current[key];
      const nextValue = (key === 'error') ? (next.error ? next.error.message : '') : next[key];

      if (currentValue < nextValue) {
        return desc ? 1 : -1;
      }
      if (currentValue > nextValue) {
        return desc ? -1 : 1;
      }
      return 0;
    });
  }
}
<commit_msg>fix line number in ResultView<commit_after>'use babel';

/** @jsx etch.dom */
/* @flow*/
import etch from 'etch';
import { Emitter, CompositeDisposable, Disposable, TextEditor } from 'atom';
import { normalizeString } from '../helpers';
import type { Message } from '../types';

// TODO
// - resize columns
export default class ResultView {
  properties: {
    messages: Array<Message>;
    ansiToHtml: boolean;
    softWrap: ?boolean;
    runningTestersCount: number;
 }
  refs: any;
  element: any;
  panel: any;
  emitter: Emitter;
  disposables: CompositeDisposable;
  sortKey: string;
  desc: boolean;
  currentTest: Message;

  constructor(properties:Object) {
    this.properties = properties;
    this.emitter = new Emitter();
    this.disposables = new CompositeDisposable();
    if (!this.properties.messages) {
      this.properties.messages = [];
    }
    this.sortKey = '';
    this.desc = false;
    etch.initialize(this);

    const softWrapHandler = async () => {
      await this.update({ softWrap: this.refs.softWrap.checked });
    };
    this.refs.softWrap.addEventListener('click', softWrapHandler);
    this.disposables.add(new Disposable(() => { this.refs.softWrap.removeEventListener('click', softWrapHandler()); }));
  }

  render() {
    const failedTests = this.properties.messages.filter(result => result.state === 'failed').length;
    const skippedTests = this.properties.messages.filter(result => result.state === 'skipped').length;
    const passedTests = this.properties.messages.filter(result => result.state === 'passed').length;
    return (

             0 ? 'inline-block text-error' : 'inline-block'}>Failed: {failedTests}
             0 ? 'inline-block text-warning' : 'inline-block'}>Skipped: {skippedTests}
             0 ? 'inline-block text-success' : 'inline-block'}>Passed: {passedTests}

              <input class='input-checkbox' ref='softWrap' type='checkbox' checked={this.properties.softWrap}/> Soft Wrap

              {etch.dom(TextEditor, {
                ref: 'additionalArgs',
                mini: true,
                placeholderText: 'Additional command line args',
              })}

            <button class={this.properties.runningTestersCount > 0 ?
              'inline-block-tight btn btn-sm tester-wait-button' :
              'inline-block-tight btn btn-sm'}
              title='Test Project'
              ref='testProject'
              onclick={this.handleTestButtonClick.bind(this)} disabled={this.properties.runningTestersCount > 0}>Test Project</button>

State

Duration

Title

Error

Location

 0 ? 'display: none;' : ''}>No tester messages

          {this.properties.messages.map((message, index) =>

                      {message.state || 'unknown'}

{message.duration || 0}ms

{message.title || ''}

                      {atom.project.relativizePath(message.filePath)[1] || message.filePath || ''}
                      {message.lineNumber ? `:${message.lineNumber + 1}` : ''}

)}

    );
  }

  update(newProperties:Object) {
    if (this.properties.messages !== newProperties.messages ||
      this.properties.softWrap !== newProperties.softWrap) {
      if (newProperties.messages) {
        this.properties.messages = newProperties.messages;
        this.sortMessages(this.sortKey, this.desc);
      }
      if (typeof newProperties.softWrap === 'boolean') {
        this.properties.softWrap = newProperties.softWrap;
      }
      if (typeof newProperties.runningTestersCount === 'number') {
        this.properties.runningTestersCount = newProperties.runningTestersCount;
      }
      return etch.update(this);
    }
    return Promise.resolve();
  }

  async destroy() {
    await etch.destroy(this);
    this.disposables.dispose();
  }

  getTitle() {
    return 'Tester Results';
  }

  getIconName() {
    return 'beaker';
  }

  getDefaultLocation() {
    return 'bottom';
  }

  getAllowedLocations() {
    return ['left', 'right', 'bottom'];
  }

  getURI() {
    return 'atom://tester-result-view';
  }

  getElement() {
    return this.element;
  }

  getAdditionalArgs() {
    return this.refs.additionalArgs ? this.refs.additionalArgs.getText() : '';
  }

  onTestButtonClick(callback : Function) : Disposable {
    return this.emitter.on('test-project-button-click', callback);
  }

  goToNextTest() {
    if (this.properties.messages.length === 0) {
      return;
    }
    if (!this.currentTest) {
      this.currentTest = this.properties.messages[0];
    } else {
      const index = this.properties.messages.indexOf(this.currentTest);
      if (index >= 0 && index < this.properties.messages.length - 1) {
        this.currentTest = this.properties.messages[index + 1];
      }
    }
    this.openTest(this.currentTest);
  }

  goToPreviousTest() {
    if (this.properties.messages.length === 0) {
      return;
    }
    if (!this.currentTest) {
      this.currentTest = this.properties.messages[this.properties.messages.length - 1];
    } else {
      const index = this.properties.messages.indexOf(this.currentTest);
      if (index > 0 && index <= this.properties.messages.length - 1) {
        this.currentTest = this.properties.messages[index - 1];
      }
    }
    this.openTest(this.currentTest);
  }

  openTest(message: Message) {
    if (!message || !message.filePath) {
      return;
    }
    atom.workspace.open(message.filePath, { initialLine: message.lineNumber });
  }

  handleTestButtonClick():void {
    this.emitter.emit('test-project-button-click', this.getAdditionalArgs());
  }

  handleRowClick(selectedIndex: number): void {
    const message = this.properties.messages[selectedIndex];
    this.currentTest = message;
    this.openTest(message);
  }

  async handleSortByClick(key: string) {
    if (!this.properties.messages || this.properties.messages.length === 0) {
      return;
    }
    const ref = `header-${key}`;
    const headerElement = this.refs[ref];
    const desc = headerElement.className.includes('asc');

    this.refs['header-state'].classList.remove('asc', 'desc', 'icon-triangle-up', 'icon-triangle-down');
    this.refs['header-duration'].classList.remove('asc', 'desc', 'icon-triangle-up', 'icon-triangle-down');
    this.refs['header-title'].classList.remove('asc', 'desc', 'icon-triangle-up', 'icon-triangle-down');
    this.refs['header-error'].classList.remove('asc', 'desc', 'icon-triangle-up', 'icon-triangle-down');
    this.refs['header-filePath'].classList.remove('asc', 'desc', 'icon-triangle-up', 'icon-triangle-down');

    this.sortKey = key;
    this.desc = desc;
    this.sortMessages(this.sortKey, this.desc);
    if (desc) {
      headerElement.classList.add('desc', 'icon', 'icon-triangle-down');
    } else {
      headerElement.classList.add('asc', 'icon', 'icon-triangle-up');
    }
    await etch.update(this);
  }

  sortMessages(key: string, desc: boolean) {
    this.properties.messages.sort((current, next) => {
      const currentValue = (key === 'error') ? (current.error ? current.error.message : '') : current[key];
      const nextValue = (key === 'error') ? (next.error ? next.error.message : '') : next[key];

      if (currentValue < nextValue) {
        return desc ? 1 : -1;
      }
      if (currentValue > nextValue) {
        return desc ? -1 : 1;
      }
      return 0;
    });
  }
}
<|endoftext|>


<commit_before>var protoclass = require("protoclass"),
bindable       = require("bindable"),
type           = require("type-component"),
factories      = require("factories"),
hoist          = require("hoist"),
janitor        = require("janitorjs"),
BaseView       = require("../base"),
_              = require("underscore");

function ListView (data, application) {
  ListView.parent.call(this, data, application);
}

/**
 */

function onOptionChange (onRef) {
  var binding, selfFn, self = this;
  return selfFn = function (value) {

    if (binding) {
      binding.dispose();
      binding = undefined;
    }

    if (typeof value === "string") {
      binding = self.bind(value, onRef).now();
    } else {
      onRef(value);
    }
  }
}

/**
 */

protoclass(BaseView, ListView, {

  /**
   */

  chunk: 10,

  /**
   */

  delay: 0,

  /**
   * make sure decorations don't get activated for this view
   */

  _decorated: true,

  /**
   */

  __isList: true,

  /**
   */

  define: ["filter", "sort", "map", "length", "modelViewFactory", "modelViewClass", "viewClass", "source"],

  /**
   */

  initialize: function (data) {
    ListView.__super__.initialize.call(this, data);

    this._insertQueue = [];

    // the views of this list
    // _views is deprecated
    this._views = this.children = new bindable.Collection();

    this._views.bind("length", { target: this, to: "length" }).now();

    // TODO - need to check for model view factory here
    this._modelViewFactory = factories.factory.create(this.modelViewFactory || this.modelViewClass || this.viewClass);

    this._onFilterChange  = _.bind(this._onFilterChange, this);
    this._onSourceChange  = _.bind(this._onSourceChange, this);
    this._onSortChange    = _.bind(this._onSortChange, this);
    this._onInsertModel   = _.bind(this._onInsertModel, this);
    this._onReplaceModels = _.bind(this._onReplaceModels, this);
    this._onResetModels   = _.bind(this._onResetModels, this);
    this._onRemoveModel   = _.bind(this._onRemoveModel, this);
    this._onMapChange     = _.bind(this._onMapChange, this);
    this._insertNow       = _.bind(this._insertNow, this);
  },

  /**
   */

  _render: function () {
    ListView.__super__._render.call(this);

    // running in test mode, or in node? cannot have any delay.
    if (typeof window === "undefined" || this.application.fake) {
      this.delay = false;
    }

    if (this._rjanitor) this._rjanitor.dispose();

    this._rjanitor = janitor();

    this._rjanitor.
      add(this.bind("sort", onOptionChange.call(this, this._onSortChange)).now()).
      add(this.bind("filter", onOptionChange.call(this, this._onFilterChange)).now()).
      add(this.bind("map", onOptionChange.call(this, this._onMapChange)).now()).
      add(this.bind("source", onOptionChange.call(this, this._onSourceChange)).now());
  },

  /**
   */

  _onSourceChange: function (source) {

    if (this._sjanitor) this._sjanitor.dispose();
    this._insertQueue = [];

    // is it an array? convert into a bindable collection
    if (type(source) === "array") {
      source = new bindable.Collection(source);
    }

    this._source = source;

    var j = this._sjanitor = janitor();

    // TODO - bottleneck - need to dispose items without calling section.removeAll()
    // for children
    for(var i = this._views.length; i--;) {
      this._views.at(i).dispose();
    }

    // remove all the views
    this._views.source([]);

    if (!source) return;

    // listen to the source for any changes
    j.
      add(source.on("insert", this._onInsertModel)).
      add(source.on("remove", this._onRemoveModel)).
      add(source.on("reset", this._onResetModels)).
      add(source.on("replace", this._onReplaceModels));

    // insert all the items in the source collection
    this._onResetModels(source.source());
  },

  /**
   */

  _onMapChange: function (map) {
    this._map = map;
  },

  /**
   */

  _onResetModels: function (newModels, oldModels) {
    if (oldModels) this._removeModels(oldModels);
    this._insertModels(newModels);
  },

  /**
   */

  _insertModels: function (models) {
    for (var i = 0, n = models.length; i < n; i++) {

      var model = models[i];

      if(this._map) {
        model = this._map(model);
      }

      this._sjanitor.add(this._watchModelChanges(model));

      if (this._filter && !this._filter(model, this)) {
        continue;
      }

      // uneccessary overhead calling .get()
      if (!model.__context._id) {
        model.set("_id", Date.now() + "." + Math.round(Math.random() * 999999));
      }

      var self = this;

      if (this.delay) {
        this._insertLater(model);
      } else {
        this._insertNow(model, true);
      }
    }
  },

  /**
   */

  _removeModels: function (models) {
    var self = this;
    models.forEach(function (model) {
      self._onRemoveModel(model);
    })
  },

  /**
   */

  _onReplaceModels: function (newModels, oldModels) {
    this._removeModels(oldModels);
    this._insertModels(newModels);
  },

  /**
   */

  _onInsertModel: function (model, index) {
    this._insertModels([model]);
  },

  /**
   */

  _insertLater: function (model) {

    // might happen on filter
    if(~this._insertQueue.indexOf(model)) {
      return;
    }

    this._insertQueue.push(model);
    if (this._runLater) return;

    var self = this

    function tick () {

      // synchronously add these models
      var models = self._insertQueue.splice(0, self.chunk);

      // no more items? stop the timer
      if (!models.length || !self._runLater) {
        self._runLater = false;
        return;
      }

      for(var model, i = 0, n = models.length; i < n; i++) {
        model = models[i];
        self._insertNow(model, false);
      }

      self._resort();

      requestAnimationFrame(tick);
    }

    this._runLater = true;

    requestAnimationFrame(tick);
  },

  /**
   */

  remove: function () {
    ListView.__super__.remove.call(this);
    if (this._runLater) this._runLater = false;
    if (this._sjanitor) this._sjanitor.dispose();
    if (this._rjanitor) this._rjanitor.dispose();
    this._source = undefined;
    this._views.source([]);
    this._insertQueue = [];
  },

  /**
   */

  _insertNow: function (model, resort) {

    // create the view
    var view = this._modelViewFactory.create({
      model        : model,
      parent       : this,
      application  : this.application
    });

    // add to the collection for a reference point
    this._views.push(view);

    // add to this section

    this.section.append(view.render().toFragment());

    if(resort) this._resort();
  },

  /**
   */

  _watchModelChanges: function (model) {
    var self = this;
    return model.on("change", function () {
      self._refilter([model]);
    });
  },

  /**
   */

  _onRemoveModel: function (model, index, viewIndex) {

    var i;

    // remove the item that has not been added to the DOM yet
    if (~(i = this._insertQueue.indexOf(model))) {
      this._insertQueue.splice(i, 1);
    }

    if (viewIndex === undefined) {
      viewIndex = this._views.searchIndex({ _id: model.__context._id });
    }

    if (!~viewIndex) {
      return;
    }

    var view = this._views.at(viewIndex);
    view.dispose();
    this._views.splice(viewIndex, 1);
  },

  /**
   */

  _onSortChange: function (sort) {
    this._sort = sort;
    this._resort();
  },

  /**
   */

  _resort: function () {
    if (!this._sort) return;

    var frag = this._views.source().sort(this._sort).map(function (view) {
      return view.section.toFragment();
    });

    this.section.append(this.application.nodeFactory.createFragment(frag));
  },

  /**
   */

  _onFilterChange: function (filter) {
    this._filter = filter;

    if (this._source && filter) {
      this._refilter(this._source.source());
    }
  },

  /**
   */

  _refilter: function (models) {

    if (!this._filter) return;

    var i, model, useModel, modelIndex;

    for (i = models.length; i--;) {
      model       = models[i];
      useModel    = !!this._filter(model, this);
      modelIndex  = this._views.searchIndex({ _id: model.__context._id });

      if (useModel === !!~modelIndex) {
        continue;
      }

      if (useModel) {
        this._onInsertModel(model);
      } else {
        this._onRemoveModel(model, undefined, modelIndex);
      }
    }

  }

});

module.exports = ListView;<commit_msg>create frag for batch<commit_after>var protoclass = require("protoclass"),
bindable       = require("bindable"),
type           = require("type-component"),
factories      = require("factories"),
hoist          = require("hoist"),
janitor        = require("janitorjs"),
BaseView       = require("../base"),
_              = require("underscore");

function ListView (data, application) {
  ListView.parent.call(this, data, application);
}

/**
 */

function onOptionChange (onRef) {
  var binding, selfFn, self = this;
  return selfFn = function (value) {

    if (binding) {
      binding.dispose();
      binding = undefined;
    }

    if (typeof value === "string") {
      binding = self.bind(value, onRef).now();
    } else {
      onRef(value);
    }
  }
}

/**
 */

protoclass(BaseView, ListView, {

  /**
   */

  chunk: 10,

  /**
   */

  delay: 0,

  /**
   * make sure decorations don't get activated for this view
   */

  _decorated: true,

  /**
   */

  __isList: true,

  /**
   */

  define: ["filter", "sort", "map", "length", "modelViewFactory", "modelViewClass", "viewClass", "source"],

  /**
   */

  initialize: function (data) {
    ListView.__super__.initialize.call(this, data);

    this._insertQueue = [];

    // the views of this list
    // _views is deprecated
    this._views = this.children = new bindable.Collection();

    this._views.bind("length", { target: this, to: "length" }).now();

    // TODO - need to check for model view factory here
    this._modelViewFactory = factories.factory.create(this.modelViewFactory || this.modelViewClass || this.viewClass);

    this._onFilterChange  = _.bind(this._onFilterChange, this);
    this._onSourceChange  = _.bind(this._onSourceChange, this);
    this._onSortChange    = _.bind(this._onSortChange, this);
    this._onInsertModel   = _.bind(this._onInsertModel, this);
    this._onReplaceModels = _.bind(this._onReplaceModels, this);
    this._onResetModels   = _.bind(this._onResetModels, this);
    this._onRemoveModel   = _.bind(this._onRemoveModel, this);
    this._onMapChange     = _.bind(this._onMapChange, this);
    this._insertNow       = _.bind(this._insertNow, this);
  },

  /**
   */

  _render: function () {
    ListView.__super__._render.call(this);

    // running in test mode, or in node? cannot have any delay.
    if (typeof window === "undefined" || this.application.fake) {
      this.delay = false;
    }

    if (this._rjanitor) this._rjanitor.dispose();

    this._rjanitor = janitor();

    this._rjanitor.
      add(this.bind("sort", onOptionChange.call(this, this._onSortChange)).now()).
      add(this.bind("filter", onOptionChange.call(this, this._onFilterChange)).now()).
      add(this.bind("map", onOptionChange.call(this, this._onMapChange)).now()).
      add(this.bind("source", onOptionChange.call(this, this._onSourceChange)).now());
  },

  /**
   */

  _onSourceChange: function (source) {

    if (this._sjanitor) this._sjanitor.dispose();
    this._insertQueue = [];

    // is it an array? convert into a bindable collection
    if (type(source) === "array") {
      source = new bindable.Collection(source);
    }

    this._source = source;

    var j = this._sjanitor = janitor();

    // TODO - bottleneck - need to dispose items without calling section.removeAll()
    // for children
    for(var i = this._views.length; i--;) {
      this._views.at(i).dispose();
    }

    // remove all the views
    this._views.source([]);

    if (!source) return;

    // listen to the source for any changes
    j.
      add(source.on("insert", this._onInsertModel)).
      add(source.on("remove", this._onRemoveModel)).
      add(source.on("reset", this._onResetModels)).
      add(source.on("replace", this._onReplaceModels));

    // insert all the items in the source collection
    this._onResetModels(source.source());
  },

  /**
   */

  _onMapChange: function (map) {
    this._map = map;
  },

  /**
   */

  _onResetModels: function (newModels, oldModels) {
    if (oldModels) this._removeModels(oldModels);
    this._insertModels(newModels);
  },

  /**
   */

  _insertModels: function (models) {
    var modelsToInsert = [];
    for (var i = 0, n = models.length; i < n; i++) {

      var model = models[i];

      if(this._map) {
        model = this._map(model);
      }

      this._sjanitor.add(this._watchModelChanges(model));

      if (this._filter && !this._filter(model, this)) {
        continue;
      }
      modelsToInsert.push(model);

      // uneccessary overhead calling .get()
      if (!model.__context._id) {
        model.set("_id", Date.now() + "." + Math.round(Math.random() * 999999));
      }

      var self = this;

      if (this.delay) {
        this._insertLater(model);
      }
    }

    if (!this.delay) {
      this._insertNow(modelsToInsert, true);
    }
  },

  /**
   */

  _removeModels: function (models) {
    var self = this;
    models.forEach(function (model) {
      self._onRemoveModel(model);
    })
  },

  /**
   */

  _onReplaceModels: function (newModels, oldModels) {
    this._removeModels(oldModels);
    this._insertModels(newModels);
  },

  /**
   */

  _onInsertModel: function (model, index) {
    this._insertModels([model]);
  },

  /**
   */

  _insertLater: function (model) {

    // might happen on filter
    if(~this._insertQueue.indexOf(model)) {
      return;
    }

    this._insertQueue.push(model);
    if (this._runLater) return;

    var self = this

    function tick () {

      // synchronously add these models
      var models = self._insertQueue.splice(0, self.chunk);

      // no more items? stop the timer
      if (!models.length || !self._runLater) {
        self._runLater = false;
        return;
      }

      self._insertNow(models, false);
      self._resort();

      requestAnimationFrame(tick);
    }

    this._runLater = true;

    requestAnimationFrame(tick);
  },

  /**
   */

  remove: function () {
    ListView.__super__.remove.call(this);
    if (this._runLater) this._runLater = false;
    if (this._sjanitor) this._sjanitor.dispose();
    if (this._rjanitor) this._rjanitor.dispose();
    this._source = undefined;
    this._views.source([]);
    this._insertQueue = [];
  },

  /**
   */

  _insertNow: function (models, resort) {

    var view, model, views = [], frags = [];

    for (var i = 0, n = models.length; i < n; i++) {
      model = models[i];

      // create the view
      view = this._modelViewFactory.create({
        model        : model,
        parent       : this,
        application  : this.application
      });

      views.push(view);
      frags.push(view.render().toFragment());
    }

    this._views.splice.apply(this._views, [this._views.length, 0].concat(views));
    this.section.append(this.application.nodeFactory.createFragment(frags));

    if(resort) this._resort();
  },

  /**
   */

  _watchModelChanges: function (model) {
    var self = this;
    return model.on("change", function () {
      self._refilter([model]);
    });
  },

  /**
   */

  _onRemoveModel: function (model, index, viewIndex) {

    var i;

    // remove the item that has not been added to the DOM yet
    if (~(i = this._insertQueue.indexOf(model))) {
      this._insertQueue.splice(i, 1);
    }

    if (viewIndex === undefined) {
      viewIndex = this._views.searchIndex({ _id: model.__context._id });
    }

    if (!~viewIndex) {
      return;
    }

    var view = this._views.at(viewIndex);
    view.dispose();
    this._views.splice(viewIndex, 1);
  },

  /**
   */

  _onSortChange: function (sort) {
    this._sort = sort;
    this._resort();
  },

  /**
   */

  _resort: function () {
    if (!this._sort) return;

    var frag = this._views.source().sort(this._sort).map(function (view) {
      return view.section.toFragment();
    });

    this.section.append(this.application.nodeFactory.createFragment(frag));
  },

  /**
   */

  _onFilterChange: function (filter) {
    this._filter = filter;

    if (this._source && filter) {
      this._refilter(this._source.source());
    }
  },

  /**
   */

  _refilter: function (models) {

    if (!this._filter) return;

    var i, model, useModel, modelIndex;

    for (i = models.length; i--;) {
      model       = models[i];
      useModel    = !!this._filter(model, this);
      modelIndex  = this._views.searchIndex({ _id: model.__context._id });

      if (useModel === !!~modelIndex) {
        continue;
      }

      if (useModel) {
        this._onInsertModel(model);
      } else {
        this._onRemoveModel(model, undefined, modelIndex);
      }
    }

  }

});

module.exports = ListView;<|endoftext|>


<commit_before>// Grab links from Google.
var Horseman = require("node-horseman");

var horseman = new Horseman();

var links = [];

function getLinks(){
	return horseman.evaluate( function(){
		// This code is executed in the browser.
		var links = [];
		$("div.g h3.r a").each(function( item ){
			var link = {
				title : $(this).text(),
				url : $(this).attr("href")
			};
			links.push(link);
		});
		return links;
	});
}

function hasNextPage(){
	return horseman.exists("#pnnext");
}

function scrape(){

	return new Promise( function( resolve, reject ){
		return getLinks()
		.then(function(newLinks){

			links = links.concat(newLinks);

			if ( links.length < 30 ){
				return hasNextPage()
				.then(function(hasNext){
					if (hasNext){
						return horseman
							.click("#pnnext")
							.wait(1000)
							.then( scrape );
					}
				});
			}
		})
		.then( resolve );
	});
}

horseman
	.userAgent("Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0")
	.open("http://www.google.com")
	.type("input[name='q']","horseman")
	.click("button:contains('Google Search')")
	.keyboardEvent("keypress",16777221)
	.waitForSelector("div.g")
	.then( scrape )
	.finally(function(){
		console.log(links.length)
		horseman.close();
	});<commit_msg>Fix links.js example<commit_after>// Grab links from Google.
var Horseman = require("node-horseman");

var horseman = new Horseman();

var links = [];

function getLinks(){
	return horseman.evaluate( function(){
		// This code is executed in the browser.
		var links = [];
		$("div.g h3.r a").each(function( item ){
			var link = {
				title : $(this).text(),
				url : $(this).attr("href")
			};
			links.push(link);
		});
		return links;
	});
}

function hasNextPage(){
	return horseman.exists("#pnnext");
}

function scrape(){

	return new Promise( function( resolve, reject ){
		return getLinks()
		.then(function(newLinks){

			links = links.concat(newLinks);

			if ( links.length < 30 ){
				return hasNextPage()
				.then(function(hasNext){
					if (hasNext){
						return horseman
							.click("#pnnext")
							.wait(1000)
							.then( scrape );
					}
				});
			}
		})
		.then( resolve );
	});
}

horseman
	.userAgent("Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0")
	.open("http://www.google.com")
	.type("input[name='q']","horseman")
	.click("input[value='Google Search']")
	.keyboardEvent("keypress",16777221)
	.waitForSelector("div.g")
	.then( scrape )
	.finally(function(){
		console.log(links.length)
		horseman.close();
	});
<|endoftext|>


<commit_before>process.on('uncaughtException', function (err) {
  process.send({
    error: err.message,
    errorStack: err.stack
  })

  process.exit()
})

var cb

function callback () {
  cb = arguments[arguments.length - 1]
  var args = Array.prototype.slice.call(arguments)
  args.pop()
  process.send({ action: 'callback', pid: process.pid, params: args.sort() })
}

function sendAndExit (m) {
  process.send(m, undefined, undefined, function () {
    process.exit()
  })
}

process.on('message', function (m) {
  if (m.action === 'callback-response') {
    if (m.params.length) {
      if (m.params[0]) {
        m.params[0] = new Error(m.params[0])
      }
    }

    return cb.apply(this, m.params)
  }

  require(m.options.execModulePath)(m.inputs, callback, function (err, val) {
    if (err) {
      sendAndExit({
        error: err.message,
        errorStack: err.stack
      })
    } else {
      sendAndExit({
        action: 'process-response',
        value: val
      })
    }
  })
})
<commit_msg>ensure process is killed in older versions of node<commit_after>process.on('uncaughtException', function (err) {
  process.send({
    error: err.message,
    errorStack: err.stack
  })

  process.exit()
})

var cb

function callback () {
  cb = arguments[arguments.length - 1]
  var args = Array.prototype.slice.call(arguments)
  args.pop()
  process.send({ action: 'callback', pid: process.pid, params: args.sort() })
}

function sendAndExit (m) {
  // we check for the amount of arguments that `process.send` supports
  // to provide support for older versions (<=4.x.x) of node that doesn't support a callback
  if (process.send.length <= 2) {
    process.send(m)

    setTimeout(function () {
      process.exit()
    }, 5000)
  } else {
    // since other arguments in `process.send` are optional a call with two arguments
    // works in the rest of versions
    process.send(m, function () {
      process.exit()
    })
  }
}

process.on('message', function (m) {
  if (m.action === 'callback-response') {
    if (m.params.length) {
      if (m.params[0]) {
        m.params[0] = new Error(m.params[0])
      }
    }

    return cb.apply(this, m.params)
  }

  require(m.options.execModulePath)(m.inputs, callback, function (err, val) {
    if (err) {
      sendAndExit({
        error: err.message,
        errorStack: err.stack
      })
    } else {
      sendAndExit({
        action: 'process-response',
        value: val
      })
    }
  })
})
<|endoftext|>


<commit_before>

var ready = (function(){

    var readyList,
        DOMContentLoaded,
        class2type = {};
        class2type["[object Boolean]"] = "boolean";
        class2type["[object Number]"] = "number";
        class2type["[object String]"] = "string";
        class2type["[object Function]"] = "function";
        class2type["[object Array]"] = "array";
        class2type["[object Date]"] = "date";
        class2type["[object RegExp]"] = "regexp";
        class2type["[object Object]"] = "object";

    var ReadyObj = {
        // Is the DOM ready to be used? Set to true once it occurs.
        isReady: false,
        // A counter to track how many items to wait for before
        // the ready event fires. See #6781
        readyWait: 1,
        // Hold (or release) the ready event
        holdReady: function( hold ) {
            if ( hold ) {
                ReadyObj.readyWait++;
            } else {
                ReadyObj.ready( true );
            }
        },
        // Handle when the DOM is ready
        ready: function( wait ) {
            // Either a released hold or an DOMready/load event and not yet ready
            if ( (wait === true && !--ReadyObj.readyWait) || (wait !== true && !ReadyObj.isReady) ) {
                // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
                if ( !document.body ) {
                    return setTimeout( ReadyObj.ready, 1 );
                }

                // Remember that the DOM is ready
                ReadyObj.isReady = true;
                // If a normal DOM Ready event fired, decrement, and wait if need be
                if ( wait !== true && --ReadyObj.readyWait > 0 ) {
                    return;
                }
                // If there are functions bound, to execute
                readyList.resolveWith( document, [ ReadyObj ] );

                // Trigger any bound ready events
                //if ( ReadyObj.fn.trigger ) {
                //  ReadyObj( document ).trigger( "ready" ).unbind( "ready" );
                //}
            }
        },
        bindReady: function() {
            if ( readyList ) {
                return;
            }
            readyList = ReadyObj._Deferred();

            // Catch cases where $(document).ready() is called after the
            // browser event has already occurred.
            if ( document.readyState === "complete" ) {
                // Handle it asynchronously to allow scripts the opportunity to delay ready
                return setTimeout( ReadyObj.ready, 1 );
            }

            // Mozilla, Opera and webkit nightlies currently support this event
            if ( document.addEventListener ) {
                // Use the handy event callback
                document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
                // A fallback to window.onload, that will always work
                window.addEventListener( "load", ReadyObj.ready, false );

            // If IE event model is used
            } else if ( document.attachEvent ) {
                // ensure firing before onload,
                // maybe late but safe also for iframes
                document.attachEvent( "onreadystatechange", DOMContentLoaded );

                // A fallback to window.onload, that will always work
                window.attachEvent( "onload", ReadyObj.ready );

                // If IE and not a frame
                // continually check to see if the document is ready
                var toplevel = false;

                try {
                    toplevel = window.frameElement == null;
                } catch(e) {}

                if ( document.documentElement.doScroll && toplevel ) {
                    doScrollCheck();
                }
            }
        },
        _Deferred: function() {
            var // callbacks list
                callbacks = [],
                // stored [ context , args ]
                fired,
                // to avoid firing when already doing so
                firing,
                // flag to know if the deferred has been cancelled
                cancelled,
                // the deferred itself
                deferred  = {

                    // done( f1, f2, ...)
                    done: function() {
                        if ( !cancelled ) {
                            var args = arguments,
                                i,
                                length,
                                elem,
                                type,
                                _fired;
                            if ( fired ) {
                                _fired = fired;
                                fired = 0;
                            }
                            for ( i = 0, length = args.length; i < length; i++ ) {
                                elem = args[ i ];
                                type = ReadyObj.type( elem );
                                if ( type === "array" ) {
                                    deferred.done.apply( deferred, elem );
                                } else if ( type === "function" ) {
                                    callbacks.push( elem );
                                }
                            }
                            if ( _fired ) {
                                deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
                            }
                        }
                        return this;
                    },

                    // resolve with given context and args
                    resolveWith: function( context, args ) {
                        if ( !cancelled && !fired && !firing ) {
                            // make sure args are available (#8421)
                            args = args || [];
                            firing = 1;
                            try {
                                while( callbacks[ 0 ] ) {
                                    callbacks.shift().apply( context, args );//shifts a callback, and applies it to document
                                }
                            }
                            finally {
                                fired = [ context, args ];
                                firing = 0;
                            }
                        }
                        return this;
                    },

                    // resolve with this as context and given arguments
                    resolve: function() {
                        deferred.resolveWith( this, arguments );
                        return this;
                    },

                    // Has this deferred been resolved?
                    isResolved: function() {
                        return !!( firing || fired );
                    },

                    // Cancel
                    cancel: function() {
                        cancelled = 1;
                        callbacks = [];
                        return this;
                    }
                };

            return deferred;
        },
        type: function( obj ) {
            return obj == null ?
                String( obj ) :
                class2type[ Object.prototype.toString.call(obj) ] || "object";
        }
    }
    // The DOM ready check for Internet Explorer
    function doScrollCheck() {
        if ( ReadyObj.isReady ) {
            return;
        }

        try {
            // If IE is used, use the trick by Diego Perini
            // http://javascript.nwbox.com/IEContentLoaded/
            document.documentElement.doScroll("left");
        } catch(e) {
            setTimeout( doScrollCheck, 1 );
            return;
        }

        // and execute any waiting functions
        ReadyObj.ready();
    }
    // Cleanup functions for the document ready method
    if ( document.addEventListener ) {
        DOMContentLoaded = function() {
            document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
            ReadyObj.ready();
        };

    } else if ( document.attachEvent ) {
        DOMContentLoaded = function() {
            // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
            if ( document.readyState === "complete" ) {
                document.detachEvent( "onreadystatechange", DOMContentLoaded );
                ReadyObj.ready();
            }
        };
    }
    function ready( fn ) {
        // Attach the listeners
        ReadyObj.bindReady();

        var type = ReadyObj.type( fn );

        // Add the callback
        readyList.done( fn );//readyList is result of _Deferred()
    }
    return ready;
})();

function stringStartsWith (string, prefix) {
    return string.slice(0, prefix.length) == prefix;
}

function setCodeMirrorOption(optionname , optionvalue) {
  myCodeMirror.setOption(optionname, optionvalue);
}

      var toolbox = '<xml id="toolbox"  style="display: none"></xml>';

//<xml xmlns="http://www.w3.org/1999/xhtml">
//    <block type="appshare_ui_component" x="70" y="-90">
//        <statement name="main div element">
//             <block type="appshare_element_text">
//                 <field name="VALUE">Type text here</field>
//                 <next>
//                     <block type="appshare_element_box"></block>
//                 </next>
//             </block>
//         </statement>
//    </block>
//</xml>
      function findLastChild(el)
      {
        var blocks = el.getElementsByTagName("next");
        if (blocks.length == 0) {
          return el;
        }
        else {
          return findLastChild(blocks[0].children[0]);
        }
      }

      function rearrangeDom(dom)
      {
        var mainCustomComponents = document.createElement("custcomponents");

        var mainProg = document.createElement("block");
        mainProg.setAttribute("type","appshare_ui_component");
        var mainStatement = document.createElement("statement");
        mainStatement.setAttribute("name","main div element");
        mainProg.appendChild(mainStatement);

        lastblock = null;
        var blocks = dom.children;
        console.log("Block count: " + blocks.length);
        bc = blocks.length;
        var foundFirstMainUiBlock = false;
        for (i = 0; i  < bc; i++) {
          blocks = dom.children;
          block = blocks[0];
          console.log("next block is: " + i + " : " + block.getAttribute('type'));

          if (block.getAttribute('type') == 'appshare_custom_component') {
            mainCustomComponents.appendChild(block);
          }
          else if (block.getAttribute('type') == 'appshare_ui_component') {
            block.parentElement.removeChild(block);
          }
          else {
            if (foundFirstMainUiBlock == false) {
              mainStatement.appendChild(block);
            }
            else {
              var nextelement = document.createElement("next");
              lastblock.appendChild(nextelement);
              nextelement.appendChild(block);
            }
            foundFirstMainUiBlock = true;
            lastblock = findLastChild(block);
          }
        };

        var customBlocks = mainCustomComponents.children;
        customBlocksLength = customBlocks.length;
        for (i = 0; i  < customBlocksLength; i++) {
          customBlocks = mainCustomComponents.children;
          cblock = customBlocks[0];
          dom.appendChild(cblock);
        }
        dom.appendChild(mainProg);
      }

      function getBlocklyValue()
      {

        var dom = Blockly.Xml.workspaceToDom(workspace);
        var headlessWorkspace = new Blockly.Workspace();
        rearrangeDom(dom);
        Blockly.Xml.domToWorkspace(dom, headlessWorkspace);

        var inline = Blockly.ClojureScript.workspaceToCode(headlessWorkspace);
        headlessWorkspace.dispose();
        var code = inline;

        return code;
      }

      lastEval = -1;
      function myUpdateFunction(event) {
        if (event.type == 'ui') {return;}
        inEval = myappshare.mainapp.inEval();
        if (inEval) {return;}

        calcEvals = myappshare.mainapp.calcEvals();
        if (calcEvals == lastEval) {return;}

        lastEval = calcEvals;

        var code = getBlocklyValue();

        document.getElementById('blocklyCode').innerHTML = code;
        console.log("Event.type= " + event.type + " : " + calcEvals);
        document.getElementById('numberOfEvals').innerHTML = '' + calcEvals;
        //uuuttt(toolbox);
        myappshare.mainapp.refreshapp();
      }

      function getBlocklyXml()
      {
        var xml = Blockly.Xml.workspaceToDom(workspace);
        var code = Blockly.Xml.domToText(xml);
        //var code = Blockly.Xml.domToPrettyText(xml);
        return code;
      }

      function getBlocklyXml2()
      {

        var dom = Blockly.Xml.workspaceToDom(workspace);
        var headlessWorkspace = new Blockly.Workspace();
        rearrangeDom(dom);
        Blockly.Xml.domToWorkspace(dom, headlessWorkspace);

        var inline = Blockly.ClojureScript.workspaceToCode(headlessWorkspace);
        var dom = Blockly.Xml.workspaceToDom(headlessWorkspace);
        headlessWorkspace.dispose();
        var code = Blockly.Xml.domToText(dom);
        //var code = Blockly.Xml.domToPrettyText(xml);
        return code;
      }

      function setBlocklyXml(xml_text)
      {
        Blockly.mainWorkspace.clear();
        var xml = Blockly.Xml.textToDom(xml_text);
        Blockly.Xml.domToWorkspace(xml, workspace);
        centerBlocks();
      }

      function initBlockly() {

        workspace = Blockly.inject('blocklyDiv',
                                   {toolbox: toolbox,
                                   scrollbars: true,
                                    zoom:
         {controls: true,
          wheel: true,
          startScale: 1.0,
          maxScale: 3,
          minScale: 0.3,
          scaleSpeed: 1.2},
                                    grid:
                                    {spacing: 20,
                                     length: 3,
                                     colour: '#ccc',
                                     snap: true},
                                   css: true});
        workspace.addChangeListener(myUpdateFunction);
        Blockly.fireUiEvent(window, 'resize')
        workspace.updateToolbox(toolbox);

        //headlessWorkspace = new Blockly.Workspace();

      }

      function uuuttt(ttt) {
        workspace.updateToolbox(ttt);
      }

      function refreshBlockly() {
        var xml = Blockly.Xml.workspaceToDom(workspace);
        Blockly.mainWorkspace.clear();
        Blockly.Xml.domToWorkspace(workspace, xml);
      }

      function refreshCodeMirror() {
        myCodeMirror.refresh();
      }

      function clearBlockly() {
        Blockly.mainWorkspace.clear();
      }

      function centerBlocks() {
        Blockly.mainWorkspace.scrollX =  250;
        Blockly.mainWorkspace.scrollY =  0;
        refreshBlockly();
         //Blockly.mainWorkspace.scrollbar.set(20,550);
      }
<commit_msg>Remove all blockly attributes on rearrange<commit_after>

var ready = (function(){

    var readyList,
        DOMContentLoaded,
        class2type = {};
        class2type["[object Boolean]"] = "boolean";
        class2type["[object Number]"] = "number";
        class2type["[object String]"] = "string";
        class2type["[object Function]"] = "function";
        class2type["[object Array]"] = "array";
        class2type["[object Date]"] = "date";
        class2type["[object RegExp]"] = "regexp";
        class2type["[object Object]"] = "object";

    var ReadyObj = {
        // Is the DOM ready to be used? Set to true once it occurs.
        isReady: false,
        // A counter to track how many items to wait for before
        // the ready event fires. See #6781
        readyWait: 1,
        // Hold (or release) the ready event
        holdReady: function( hold ) {
            if ( hold ) {
                ReadyObj.readyWait++;
            } else {
                ReadyObj.ready( true );
            }
        },
        // Handle when the DOM is ready
        ready: function( wait ) {
            // Either a released hold or an DOMready/load event and not yet ready
            if ( (wait === true && !--ReadyObj.readyWait) || (wait !== true && !ReadyObj.isReady) ) {
                // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
                if ( !document.body ) {
                    return setTimeout( ReadyObj.ready, 1 );
                }

                // Remember that the DOM is ready
                ReadyObj.isReady = true;
                // If a normal DOM Ready event fired, decrement, and wait if need be
                if ( wait !== true && --ReadyObj.readyWait > 0 ) {
                    return;
                }
                // If there are functions bound, to execute
                readyList.resolveWith( document, [ ReadyObj ] );

                // Trigger any bound ready events
                //if ( ReadyObj.fn.trigger ) {
                //  ReadyObj( document ).trigger( "ready" ).unbind( "ready" );
                //}
            }
        },
        bindReady: function() {
            if ( readyList ) {
                return;
            }
            readyList = ReadyObj._Deferred();

            // Catch cases where $(document).ready() is called after the
            // browser event has already occurred.
            if ( document.readyState === "complete" ) {
                // Handle it asynchronously to allow scripts the opportunity to delay ready
                return setTimeout( ReadyObj.ready, 1 );
            }

            // Mozilla, Opera and webkit nightlies currently support this event
            if ( document.addEventListener ) {
                // Use the handy event callback
                document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
                // A fallback to window.onload, that will always work
                window.addEventListener( "load", ReadyObj.ready, false );

            // If IE event model is used
            } else if ( document.attachEvent ) {
                // ensure firing before onload,
                // maybe late but safe also for iframes
                document.attachEvent( "onreadystatechange", DOMContentLoaded );

                // A fallback to window.onload, that will always work
                window.attachEvent( "onload", ReadyObj.ready );

                // If IE and not a frame
                // continually check to see if the document is ready
                var toplevel = false;

                try {
                    toplevel = window.frameElement == null;
                } catch(e) {}

                if ( document.documentElement.doScroll && toplevel ) {
                    doScrollCheck();
                }
            }
        },
        _Deferred: function() {
            var // callbacks list
                callbacks = [],
                // stored [ context , args ]
                fired,
                // to avoid firing when already doing so
                firing,
                // flag to know if the deferred has been cancelled
                cancelled,
                // the deferred itself
                deferred  = {

                    // done( f1, f2, ...)
                    done: function() {
                        if ( !cancelled ) {
                            var args = arguments,
                                i,
                                length,
                                elem,
                                type,
                                _fired;
                            if ( fired ) {
                                _fired = fired;
                                fired = 0;
                            }
                            for ( i = 0, length = args.length; i < length; i++ ) {
                                elem = args[ i ];
                                type = ReadyObj.type( elem );
                                if ( type === "array" ) {
                                    deferred.done.apply( deferred, elem );
                                } else if ( type === "function" ) {
                                    callbacks.push( elem );
                                }
                            }
                            if ( _fired ) {
                                deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
                            }
                        }
                        return this;
                    },

                    // resolve with given context and args
                    resolveWith: function( context, args ) {
                        if ( !cancelled && !fired && !firing ) {
                            // make sure args are available (#8421)
                            args = args || [];
                            firing = 1;
                            try {
                                while( callbacks[ 0 ] ) {
                                    callbacks.shift().apply( context, args );//shifts a callback, and applies it to document
                                }
                            }
                            finally {
                                fired = [ context, args ];
                                firing = 0;
                            }
                        }
                        return this;
                    },

                    // resolve with this as context and given arguments
                    resolve: function() {
                        deferred.resolveWith( this, arguments );
                        return this;
                    },

                    // Has this deferred been resolved?
                    isResolved: function() {
                        return !!( firing || fired );
                    },

                    // Cancel
                    cancel: function() {
                        cancelled = 1;
                        callbacks = [];
                        return this;
                    }
                };

            return deferred;
        },
        type: function( obj ) {
            return obj == null ?
                String( obj ) :
                class2type[ Object.prototype.toString.call(obj) ] || "object";
        }
    }
    // The DOM ready check for Internet Explorer
    function doScrollCheck() {
        if ( ReadyObj.isReady ) {
            return;
        }

        try {
            // If IE is used, use the trick by Diego Perini
            // http://javascript.nwbox.com/IEContentLoaded/
            document.documentElement.doScroll("left");
        } catch(e) {
            setTimeout( doScrollCheck, 1 );
            return;
        }

        // and execute any waiting functions
        ReadyObj.ready();
    }
    // Cleanup functions for the document ready method
    if ( document.addEventListener ) {
        DOMContentLoaded = function() {
            document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
            ReadyObj.ready();
        };

    } else if ( document.attachEvent ) {
        DOMContentLoaded = function() {
            // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
            if ( document.readyState === "complete" ) {
                document.detachEvent( "onreadystatechange", DOMContentLoaded );
                ReadyObj.ready();
            }
        };
    }
    function ready( fn ) {
        // Attach the listeners
        ReadyObj.bindReady();

        var type = ReadyObj.type( fn );

        // Add the callback
        readyList.done( fn );//readyList is result of _Deferred()
    }
    return ready;
})();

function stringStartsWith (string, prefix) {
    return string.slice(0, prefix.length) == prefix;
}

function setCodeMirrorOption(optionname , optionvalue) {
  myCodeMirror.setOption(optionname, optionvalue);
}

      var toolbox = '<xml id="toolbox"  style="display: none"></xml>';

//<xml xmlns="http://www.w3.org/1999/xhtml">
//    <block type="appshare_ui_component" x="70" y="-90">
//        <statement name="main div element">
//             <block type="appshare_element_text">
//                 <field name="VALUE">Type text here</field>
//                 <next>
//                     <block type="appshare_element_box"></block>
//                 </next>
//             </block>
//         </statement>
//    </block>
//</xml>
      function findLastChild(el)
      {
        var blocks = el.getElementsByTagName("next");
        if (blocks.length == 0) {
          return el;
        }
        else {
          return findLastChild(blocks[0].children[0]);
        }
      }

      function rearrangeDom(dom)
      {
        var mainCustomComponents = document.createElement("custcomponents");

        var mainProg = document.createElement("block");
        mainProg.setAttribute("type","appshare_ui_component");
        var mainStatement = document.createElement("statement");
        mainStatement.setAttribute("name","main div element");
        mainProg.appendChild(mainStatement);

        lastblock = null;
        var blocks = dom.children;
        console.log("Block count: " + blocks.length);
        bc = blocks.length;
        var foundFirstMainUiBlock = false;
        for (i = 0; i  < bc; i++) {
          blocks = dom.children;
          block = blocks[0];
          block.removeAttribute('x');
          block.removeAttribute('y');
          console.log("next block is: " + i + " : " + block.getAttribute('type'));

          if (block.getAttribute('type') == 'appshare_custom_component') {
            mainCustomComponents.appendChild(block);
          }
          else if (block.getAttribute('type') == 'appshare_ui_component') {
            block.parentElement.removeChild(block);
          }
          else {
            if (foundFirstMainUiBlock == false) {
              mainStatement.appendChild(block);
            }
            else {
              var nextelement = document.createElement("next");
              lastblock.appendChild(nextelement);
              nextelement.appendChild(block);
            }
            foundFirstMainUiBlock = true;
            lastblock = findLastChild(block);
          }
        };

        var customBlocks = mainCustomComponents.children;
        customBlocksLength = customBlocks.length;
        for (i = 0; i  < customBlocksLength; i++) {
          customBlocks = mainCustomComponents.children;
          cblock = customBlocks[0];
          cblock.removeAttribute('x');
          cblock.removeAttribute('y');
          dom.appendChild(cblock);
        }
        dom.appendChild(mainProg);
      }

      function getBlocklyValue()
      {

        var dom = Blockly.Xml.workspaceToDom(workspace);
        var headlessWorkspace = new Blockly.Workspace();
        rearrangeDom(dom);
        Blockly.Xml.domToWorkspace(dom, headlessWorkspace);

        var inline = Blockly.ClojureScript.workspaceToCode(headlessWorkspace);
        headlessWorkspace.dispose();
        var code = inline;

        return code;
      }

      lastEval = -1;
      function myUpdateFunction(event) {
        if (event.type == 'ui') {return;}
        inEval = myappshare.mainapp.inEval();
        if (inEval) {return;}

        calcEvals = myappshare.mainapp.calcEvals();
        if (calcEvals == lastEval) {return;}

        lastEval = calcEvals;

        var code = getBlocklyValue();

        document.getElementById('blocklyCode').innerHTML = code;
        console.log("Event.type= " + event.type + " : " + calcEvals);
        document.getElementById('numberOfEvals').innerHTML = '' + calcEvals;
        //uuuttt(toolbox);
        myappshare.mainapp.refreshapp();
      }

      function getBlocklyXml()
      {
        var xml = Blockly.Xml.workspaceToDom(workspace);
        var code = Blockly.Xml.domToText(xml);
        //var code = Blockly.Xml.domToPrettyText(xml);
        return code;
      }

      function getBlocklyXml2()
      {

        var dom = Blockly.Xml.workspaceToDom(workspace);
        var headlessWorkspace = new Blockly.Workspace();
        rearrangeDom(dom);
        return dom;
      }

      function getBlocklyXml3()
      {

        var dom = Blockly.Xml.workspaceToDom(workspace);
        var headlessWorkspace = new Blockly.Workspace();
        rearrangeDom(dom);
        Blockly.Xml.domToWorkspace(dom, headlessWorkspace);

        var inline = Blockly.ClojureScript.workspaceToCode(headlessWorkspace);
        var dom = Blockly.Xml.workspaceToDom(headlessWorkspace);
        headlessWorkspace.dispose();
        var code = Blockly.Xml.domToText(dom);
        //var code = Blockly.Xml.domToPrettyText(xml);
        return code;
      }

      function setBlocklyXml(xml_text)
      {
        Blockly.mainWorkspace.clear();
        var xml = Blockly.Xml.textToDom(xml_text);
        Blockly.Xml.domToWorkspace(xml, workspace);
        centerBlocks();
      }

      function initBlockly() {

        workspace = Blockly.inject('blocklyDiv',
                                   {toolbox: toolbox,
                                   scrollbars: true,
                                    zoom:
         {controls: true,
          wheel: true,
          startScale: 1.0,
          maxScale: 3,
          minScale: 0.3,
          scaleSpeed: 1.2},
                                    grid:
                                    {spacing: 20,
                                     length: 3,
                                     colour: '#ccc',
                                     snap: true},
                                   css: true});
        workspace.addChangeListener(myUpdateFunction);
        Blockly.fireUiEvent(window, 'resize')
        workspace.updateToolbox(toolbox);

        //headlessWorkspace = new Blockly.Workspace();

      }

      function uuuttt(ttt) {
        workspace.updateToolbox(ttt);
      }

      function refreshBlockly() {
        var xml = Blockly.Xml.workspaceToDom(workspace);
        Blockly.mainWorkspace.clear();
        Blockly.Xml.domToWorkspace(workspace, xml);
      }

      function refreshCodeMirror() {
        myCodeMirror.refresh();
      }

      function clearBlockly() {
        Blockly.mainWorkspace.clear();
      }

      function centerBlocks() {
        Blockly.mainWorkspace.scrollX =  250;
        Blockly.mainWorkspace.scrollY =  0;
        refreshBlockly();
         //Blockly.mainWorkspace.scrollbar.set(20,550);
      }
<|endoftext|>