<commit_before>/**
 * Worker manager with support for custom callbacks and loop counts.
 *
 * @author	Alexander Ebert
 * @copyright	2001-2017 WoltLab GmbH
 * @license	GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 * @module	WoltLabSuite/Core/Acp/Ui/Worker
 */
define(['Ajax', 'Core', 'Language', 'Ui/Dialog'], function(Ajax, Core, Language, UiDialog) {
	"use strict";

	/**
	 * Creates a new worker instance.
	 *
	 * @param       {Object}        options         configuration options
	 * @constructor
	 */
	function AcpUiWorker(options) { this.init(options); }
	AcpUiWorker.prototype = {
		/**
		 * Creates a new worker instance.
		 *
		 * @param       {Object}        options         configuration options
		 */
		init: function (options) {
			this._aborted = false;
			this._options = Core.extend({
				// dialog
				dialogId: '',
				dialogTitle: '',

				// ajax
				className: '',
				loopCount: -1,
				parameters: {},

				// callbacks
				callbackAbort: null,
				callbackFailure: null,
				callbackSuccess: null
			}, options);
			this._options.dialogId += 'Worker';

			this._request = Ajax.api(this);
		},

		_ajaxSuccess: function (data) {
			if (this._aborted) return;

			if (typeof data.template === 'string') {
				UiDialog.open(this, data.template);
			}

			var content = UiDialog.getDialog(this).content;

			// update progress
			var progress = elBySel('progress', content);
			progress.value = data.progress;
			progress.nextElementSibling.textContent = data.progress + '%';

			// worker is still busy
			if (data.progress < 100) {
				Ajax.api(this, {
					loopCount: data.loopCount,
					parameters: data.parameters
				});
			}
			else {
				var spinner = elBySel('.fa-spinner', content);
				spinner.classList.remove('fa-spinner');
				spinner.classList.add('fa-check');
				spinner.classList.add('green');

				var formSubmit = elCreate('div');
				formSubmit.className = 'formSubmit';
				formSubmit.innerHTML = '<button class="buttonPrimary">' + Language.get('wcf.global.button.next') + '</button>';

				content.appendChild(formSubmit);
				UiDialog.rebuild(this);

				var button = formSubmit.children[0];
				button.addEventListener(WCF_CLICK_EVENT, (function(event) {
					event.preventDefault();

					if (typeof this._options.callbackSuccess === 'function') {
						this._options.callbackSuccess(data);

						UiDialog.close(this);
					}
					else {
						window.location = data.proceedURL;
					}
				}).bind(this));
			}
		},

		_ajaxFailure: function () {
			var dialog = UiDialog.getDialog(this);
			if (dialog !== null) {
				var spinner = elBySel('.fa-spinner', dialog.content);
				spinner.classList.remove('fa-spinner');
				spinner.classList.add('fa-times');
				spinner.classList.add('red');
			}
		},

		_ajaxSetup: function () {
			return {
				data: {
					className: this._options.className,
					loopCount: this._options.loopCount,
					parameters: this._options.parameters
				},
				silent: true,
				url: 'index.php?worker-proxy/&t=' + SECURITY_TOKEN
			};
		},

		_dialogSetup: function () {
			return {
				id: this._options.dialogId,
				onClose: (function () {
					this._aborted = true;
					this._request.abortPrevious();

					if (typeof this._options.callbackAbort === 'function') {
						this._options.callbackAbort();
					}
					else {
						window.location.reload();
					}
				}).bind(this),
				options: {
					backdropCloseOnClick: false,
					title: this._options.dialogTitle
				},
				source: null
			}
		}
	};

	return AcpUiWorker;
});
<commit_msg>Fix failed workers without dialog<commit_after>/**
 * Worker manager with support for custom callbacks and loop counts.
 *
 * @author	Alexander Ebert
 * @copyright	2001-2017 WoltLab GmbH
 * @license	GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 * @module	WoltLabSuite/Core/Acp/Ui/Worker
 */
define(['Ajax', 'Core', 'Language', 'Ui/Dialog'], function(Ajax, Core, Language, UiDialog) {
	"use strict";

	/**
	 * Creates a new worker instance.
	 *
	 * @param       {Object}        options         configuration options
	 * @constructor
	 */
	function AcpUiWorker(options) { this.init(options); }
	AcpUiWorker.prototype = {
		/**
		 * Creates a new worker instance.
		 *
		 * @param       {Object}        options         configuration options
		 */
		init: function (options) {
			this._aborted = false;
			this._options = Core.extend({
				// dialog
				dialogId: '',
				dialogTitle: '',

				// ajax
				className: '',
				loopCount: -1,
				parameters: {},

				// callbacks
				callbackAbort: null,
				callbackFailure: null,
				callbackSuccess: null
			}, options);
			this._options.dialogId += 'Worker';

			this._request = Ajax.api(this);
		},

		_ajaxSuccess: function (data) {
			if (this._aborted) return;

			if (typeof data.template === 'string') {
				UiDialog.open(this, data.template);
			}

			var content = UiDialog.getDialog(this).content;

			// update progress
			var progress = elBySel('progress', content);
			progress.value = data.progress;
			progress.nextElementSibling.textContent = data.progress + '%';

			// worker is still busy
			if (data.progress < 100) {
				Ajax.api(this, {
					loopCount: data.loopCount,
					parameters: data.parameters
				});
			}
			else {
				var spinner = elBySel('.fa-spinner', content);
				spinner.classList.remove('fa-spinner');
				spinner.classList.add('fa-check');
				spinner.classList.add('green');

				var formSubmit = elCreate('div');
				formSubmit.className = 'formSubmit';
				formSubmit.innerHTML = '<button class="buttonPrimary">' + Language.get('wcf.global.button.next') + '</button>';

				content.appendChild(formSubmit);
				UiDialog.rebuild(this);

				var button = formSubmit.children[0];
				button.addEventListener(WCF_CLICK_EVENT, (function(event) {
					event.preventDefault();

					if (typeof this._options.callbackSuccess === 'function') {
						this._options.callbackSuccess(data);

						UiDialog.close(this);
					}
					else {
						window.location = data.proceedURL;
					}
				}).bind(this));
			}
		},

		_ajaxFailure: function () {
			var dialog = UiDialog.getDialog(this);
			if (dialog !== undefined) {
				var spinner = elBySel('.fa-spinner', dialog.content);
				spinner.classList.remove('fa-spinner');
				spinner.classList.add('fa-times');
				spinner.classList.add('red');
			}
		},

		_ajaxSetup: function () {
			return {
				data: {
					className: this._options.className,
					loopCount: this._options.loopCount,
					parameters: this._options.parameters
				},
				silent: true,
				url: 'index.php?worker-proxy/&t=' + SECURITY_TOKEN
			};
		},

		_dialogSetup: function () {
			return {
				id: this._options.dialogId,
				onClose: (function () {
					this._aborted = true;
					this._request.abortPrevious();

					if (typeof this._options.callbackAbort === 'function') {
						this._options.callbackAbort();
					}
					else {
						window.location.reload();
					}
				}).bind(this),
				options: {
					backdropCloseOnClick: false,
					title: this._options.dialogTitle
				},
				source: null
			}
		}
	};

	return AcpUiWorker;
});
<|endoftext|>


<commit_before>/**
 * Worker manager with support for custom callbacks and loop counts.
 *
 * @author	Alexander Ebert
 * @copyright	2001-2017 WoltLab GmbH
 * @license	GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 * @module	WoltLabSuite/Core/Acp/Ui/Worker
 */
define(['Ajax', 'Core', 'Language', 'Ui/Dialog'], function(Ajax, Core, Language, UiDialog) {
	"use strict";

	/**
	 * Creates a new worker instance.
	 *
	 * @param       {Object}        options         configuration options
	 * @constructor
	 */
	function AcpUiWorker(options) { this.init(options); }
	AcpUiWorker.prototype = {
		/**
		 * Creates a new worker instance.
		 *
		 * @param       {Object}        options         configuration options
		 */
		init: function (options) {
			this._aborted = false;
			this._options = Core.extend({
				// dialog
				dialogId: '',
				dialogTitle: '',

				// ajax
				className: '',
				loopCount: -1,
				parameters: {},

				// callbacks
				callbackAbort: null,
				callbackFailure: null,
				callbackSuccess: null
			}, options);
			this._options.dialogId += 'Worker';

			this._request = Ajax.api(this);
		},

		_ajaxSuccess: function (data) {
			if (this._aborted) return;

			if (typeof data.template === 'string') {
				UiDialog.open(this, data.template);
			}

			var content = UiDialog.getDialog(this).content;

			// update progress
			var progress = elBySel('progress', content);
			progress.value = data.progress;
			progress.nextElementSibling.textContent = data.progress + '%';

			// worker is still busy
			if (data.progress < 100) {
				Ajax.api(this, {
					loopCount: data.loopCount,
					parameters: data.parameters
				});
			}
			else {
				var spinner = elBySel('.fa-spinner', content);
				spinner.classList.remove('fa-spinner');
				spinner.classList.add('fa-check');
				spinner.classList.add('green');

				var formSubmit = elCreate('div');
				formSubmit.className = 'formSubmit';
				formSubmit.innerHTML = '<button class="buttonPrimary">' + Language.get('wcf.global.button.next') + '</button>';

				content.appendChild(formSubmit);
				UiDialog.rebuild(this);

				var button = formSubmit.children[0];
				button.addEventListener(WCF_CLICK_EVENT, (function(event) {
					event.preventDefault();

					if (typeof this._options.callbackSuccess === 'function') {
						this._options.callbackSuccess(data);

						UiDialog.close(this);
					}
					else {
						window.location = data.proceedURL;
					}
				}).bind(this));
			}
		},

		_ajaxFailure: function () {
			var dialog = UiDialog.getDialog(this);
			if (dialog !== undefined) {
				var spinner = elBySel('.fa-spinner', dialog.content);
				spinner.classList.remove('fa-spinner');
				spinner.classList.add('fa-times');
				spinner.classList.add('red');
			}
		},

		_ajaxSetup: function () {
			return {
				data: {
					className: this._options.className,
					loopCount: this._options.loopCount,
					parameters: this._options.parameters
				},
				silent: true,
				url: 'index.php?worker-proxy/&t=' + SECURITY_TOKEN
			};
		},

		_dialogSetup: function () {
			return {
				id: this._options.dialogId,
				onClose: (function () {
					this._aborted = true;
					this._request.abortPrevious();

					if (typeof this._options.callbackAbort === 'function') {
						this._options.callbackAbort();
					}
					else {
						window.location.reload();
					}
				}).bind(this),
				options: {
					backdropCloseOnClick: false,
					title: this._options.dialogTitle
				},
				source: null
			}
		}
	};

	return AcpUiWorker;
});
<commit_msg>Fixed dialog title when executing multiple workers<commit_after>/**
 * Worker manager with support for custom callbacks and loop counts.
 *
 * @author	Alexander Ebert
 * @copyright	2001-2017 WoltLab GmbH
 * @license	GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 * @module	WoltLabSuite/Core/Acp/Ui/Worker
 */
define(['Ajax', 'Core', 'Language', 'Ui/Dialog'], function(Ajax, Core, Language, UiDialog) {
	"use strict";

	/**
	 * Creates a new worker instance.
	 *
	 * @param       {Object}        options         configuration options
	 * @constructor
	 */
	function AcpUiWorker(options) { this.init(options); }
	AcpUiWorker.prototype = {
		/**
		 * Creates a new worker instance.
		 *
		 * @param       {Object}        options         configuration options
		 */
		init: function (options) {
			this._aborted = false;
			this._options = Core.extend({
				// dialog
				dialogId: '',
				dialogTitle: '',

				// ajax
				className: '',
				loopCount: -1,
				parameters: {},

				// callbacks
				callbackAbort: null,
				callbackFailure: null,
				callbackSuccess: null
			}, options);
			this._options.dialogId += 'Worker';

			// update title
			if (UiDialog.getDialog(this._options.dialogId) !== undefined) {
				UiDialog.setTitle(this._options.dialogId, this._options.dialogTitle);
			}

			this._request = Ajax.api(this);
		},

		_ajaxSuccess: function (data) {
			if (this._aborted) return;

			if (typeof data.template === 'string') {
				UiDialog.open(this, data.template);
			}

			var content = UiDialog.getDialog(this).content;

			// update progress
			var progress = elBySel('progress', content);
			progress.value = data.progress;
			progress.nextElementSibling.textContent = data.progress + '%';

			// worker is still busy
			if (data.progress < 100) {
				Ajax.api(this, {
					loopCount: data.loopCount,
					parameters: data.parameters
				});
			}
			else {
				var spinner = elBySel('.fa-spinner', content);
				spinner.classList.remove('fa-spinner');
				spinner.classList.add('fa-check');
				spinner.classList.add('green');

				var formSubmit = elCreate('div');
				formSubmit.className = 'formSubmit';
				formSubmit.innerHTML = '<button class="buttonPrimary">' + Language.get('wcf.global.button.next') + '</button>';

				content.appendChild(formSubmit);
				UiDialog.rebuild(this);

				var button = formSubmit.children[0];
				button.addEventListener(WCF_CLICK_EVENT, (function(event) {
					event.preventDefault();

					if (typeof this._options.callbackSuccess === 'function') {
						this._options.callbackSuccess(data);

						UiDialog.close(this);
					}
					else {
						window.location = data.proceedURL;
					}
				}).bind(this));
			}
		},

		_ajaxFailure: function () {
			var dialog = UiDialog.getDialog(this);
			if (dialog !== undefined) {
				var spinner = elBySel('.fa-spinner', dialog.content);
				spinner.classList.remove('fa-spinner');
				spinner.classList.add('fa-times');
				spinner.classList.add('red');
			}
		},

		_ajaxSetup: function () {
			return {
				data: {
					className: this._options.className,
					loopCount: this._options.loopCount,
					parameters: this._options.parameters
				},
				silent: true,
				url: 'index.php?worker-proxy/&t=' + SECURITY_TOKEN
			};
		},

		_dialogSetup: function () {
			return {
				id: this._options.dialogId,
				onClose: (function () {
					this._aborted = true;
					this._request.abortPrevious();

					if (typeof this._options.callbackAbort === 'function') {
						this._options.callbackAbort();
					}
					else {
						window.location.reload();
					}
				}).bind(this),
				options: {
					backdropCloseOnClick: false,
					title: this._options.dialogTitle
				},
				source: null
			}
		}
	};

	return AcpUiWorker;
});
<|endoftext|>


<commit_before>$(function() {

    // Header.
    $('#toggle-nav').sidr({
        name : 'mobile-header',
        renaming : false,
        source : '#desktop-header'
    });

    $('.header-bar-close').on('click',function() {
        $.sidr('close','mobile-header');
    });

    if ($.isTouchCapable()) {
        $('#mobile-header').on('swipeleft',function() {
            $.sidr('close','mobile-header');
        });
    }

    $(window).on('resize',function() {
        $.sidr('close','mobile-header');
    });

    // Auto-display vertical scrollbar.
    $('.autoscroll').css('overflow','hidden');

    $('.autoscroll').on('mouseover',function() {
        $(this).css('overflow','auto');
    }).on('mouseout',function() {
        $(this).css('overflow','hidden');
    });

    // Sidebar.
    $('.toggle-sidebar').sidr({
        name : 'sidebar',
        renaming : false,
        source : '#sidebar',
        side : 'right',
        displace : false
    });

    $('#sidebar .title .close').on('click',function() {
        $.sidr('close','sidebar');
    });

    // Editor.
    $('#editor-markdown .editor-panel-content').prop('contenteditable',true);

    $('body').on('click','#editor-controls ul button',function() {
        var b = $(this);
        var i = $('#editor-controls ul button').index(b);
        $('.editor-panel').css('z-index','1');
        $('.editor-panel').eq(i).css('z-index','2');
        $('#editor-controls ul button').removeClass('active');
        b.addClass('active');
    });

});<commit_msg>Eliminato _admin.js<commit_after><|endoftext|>


<commit_before>import {dialog} from 'electron';
import {isEmpty, first} from 'lodash';
import csv from 'fast-csv';
import fs from 'fs';
import {basename} from 'path';
import log from 'karmapa-log';
import sleep from 'sleep-promise';
import shortid from 'shortid';

import csvProcessor, {FIELD_PAGE_NUM} from './../../helpers/csvProcessor';
import pageNumToFloat from './../../helpers/pageNumToFloat';
import FRACTION_LENGTH from './../../constants/fractionLength';

const NUMBER_CONCURRNT_WRITE = 5000;

export default async function addFolderByCsv(event, data) {

  const {models, importEmitter, db} = this.params;
  const {Folder, Entry} = models;
  const {broadcast, resolve, reject} = this;
  const {writeDelay} = data;

  const options = {
    properties: ['openFile'],
    filters: [
      {name: 'Csv Files', extensions: ['csv']}
    ]
  };

  dialog.showOpenDialog(options, handleDialogOpen);

  function processCsv(csvFilePath) {

    let cancelImporting = false;
    importEmitter.removeAllListeners();

    importEmitter.once('cancel-importing', () => {
      cancelImporting = true;
    });

    const filename = basename(csvFilePath);
    const stream = fs.createReadStream(csvFilePath);
    const timeStart = +new Date();

    let completedLines = 0;
    let hasColumnRow = false;
    let folder = null;
    let fields = [];
    let currentEntry = null;

    async function handleData(data) {

      if (cancelImporting) {
        return Promise.reject('User stopped importing');
      }

      if (isEmpty(folder) && csvProcessor.isColumnRow(data)) {
        const columnData = csvProcessor.getColumnData(data);
        folder = await Folder.create({
          name: `${filename} - ${shortid.generate()}`,
          data: columnData
        });
        broadcast('csv-folder-created', {folderId: folder.id});
        fields = csvProcessor.getFields(data);
        hasColumnRow = true;
      }
      else if (folder) {

        const rowData = csvProcessor.getRowDataByFields(data, fields);
        const {sourceEntry} = rowData;
        const pageNum = pageNumToFloat(rowData[FIELD_PAGE_NUM], FRACTION_LENGTH) || '';

        if (sourceEntry) {

          delete rowData.sourceEntry;
          delete rowData[FIELD_PAGE_NUM];

          await sleep(writeDelay);
          currentEntry = await Entry.create({
            folderId: folder.id,
            sourceEntry,
            pageNum,
            data: rowData
          });
        }
        else if (currentEntry) {
          const newData = csvProcessor.appendData(data, currentEntry.data, fields);
          await sleep(writeDelay);
          const rowsAffected = await Entry.update({id: currentEntry.id}, {data: newData});

          if (rowsAffected) {
            currentEntry.data = newData;
          }
        }
      }
      ++completedLines;

      const seconds = parseInt((+new Date() - timeStart) / 1000, 10);
      const linesPerSecond = Math.floor(completedLines / seconds);
      broadcast('csv-processing-status', {completedLines, linesPerSecond});
    }

    csv.fromStream(stream)
      .validate((data, next) => {
        handleData(data)
          .then(() => next(null, true))
          .catch((err) => next(err));
      })
      .on('data', () => {})
      .on('error', (err) => {
        log.error(err);
        reject({message: `${err}`});
      })
      .on('end', () => {

        if (! hasColumnRow) {
          reject({messageId: 'no-column-row-detected', filename});
          return;
        }

        broadcast('csv-processing-status', {completedLines});
        broadcast('csv-processing-done', {filename});
        resolve({message: 'done'});
      });
  }

  function handleDialogOpen(paths) {

    if (isEmpty(paths)) {
      resolve({message: 'User did not choose csv file'});
      return;
    }
    broadcast('csv-processing-start');
    const csvFilePath = first(paths);
    processCsv(csvFilePath);
  }
}
<commit_msg>remove const Entry<commit_after>import {dialog} from 'electron';
import {isEmpty, first} from 'lodash';
import csv from 'fast-csv';
import fs from 'fs';
import {basename} from 'path';
import log from 'karmapa-log';
import sleep from 'sleep-promise';
import shortid from 'shortid';

import csvProcessor, {FIELD_PAGE_NUM} from './../../helpers/csvProcessor';
import pageNumToFloat from './../../helpers/pageNumToFloat';
import FRACTION_LENGTH from './../../constants/fractionLength';

const NUMBER_CONCURRNT_WRITE = 5000;

export default async function addFolderByCsv(event, data) {

  const {models, importEmitter, db} = this.params;
  const {Folder} = models;
  const {broadcast, resolve, reject} = this;
  const {writeDelay} = data;

  const options = {
    properties: ['openFile'],
    filters: [
      {name: 'Csv Files', extensions: ['csv']}
    ]
  };

  dialog.showOpenDialog(options, handleDialogOpen);

  function processCsv(csvFilePath) {

    let cancelImporting = false;
    importEmitter.removeAllListeners();

    importEmitter.once('cancel-importing', () => {
      cancelImporting = true;
    });

    const filename = basename(csvFilePath);
    const stream = fs.createReadStream(csvFilePath);
    const timeStart = +new Date();

    let completedLines = 0;
    let hasColumnRow = false;
    let folder = null;
    let fields = [];
    let currentEntry = null;

    async function handleData(data) {

      if (cancelImporting) {
        return Promise.reject('User stopped importing');
      }

      if (isEmpty(folder) && csvProcessor.isColumnRow(data)) {
        const columnData = csvProcessor.getColumnData(data);
        folder = await Folder.create({
          name: `${filename} - ${shortid.generate()}`,
          data: columnData
        });
        broadcast('csv-folder-created', {folderId: folder.id});
        fields = csvProcessor.getFields(data);
        hasColumnRow = true;
      }
      else if (folder) {

        const rowData = csvProcessor.getRowDataByFields(data, fields);
        const {sourceEntry} = rowData;
        const pageNum = pageNumToFloat(rowData[FIELD_PAGE_NUM], FRACTION_LENGTH) || '';

        if (sourceEntry) {

          delete rowData.sourceEntry;
          delete rowData[FIELD_PAGE_NUM];

          await sleep(writeDelay);
          currentEntry = await Entry.create({
            folderId: folder.id,
            sourceEntry,
            pageNum,
            data: rowData
          });
        }
        else if (currentEntry) {
          const newData = csvProcessor.appendData(data, currentEntry.data, fields);
          await sleep(writeDelay);
          const rowsAffected = await Entry.update({id: currentEntry.id}, {data: newData});

          if (rowsAffected) {
            currentEntry.data = newData;
          }
        }
      }
      ++completedLines;

      const seconds = parseInt((+new Date() - timeStart) / 1000, 10);
      const linesPerSecond = Math.floor(completedLines / seconds);
      broadcast('csv-processing-status', {completedLines, linesPerSecond});
    }

    csv.fromStream(stream)
      .validate((data, next) => {
        handleData(data)
          .then(() => next(null, true))
          .catch((err) => next(err));
      })
      .on('data', () => {})
      .on('error', (err) => {
        log.error(err);
        reject({message: `${err}`});
      })
      .on('end', () => {

        if (! hasColumnRow) {
          reject({messageId: 'no-column-row-detected', filename});
          return;
        }

        broadcast('csv-processing-status', {completedLines});
        broadcast('csv-processing-done', {filename});
        resolve({message: 'done'});
      });
  }

  function handleDialogOpen(paths) {

    if (isEmpty(paths)) {
      resolve({message: 'User did not choose csv file'});
      return;
    }
    broadcast('csv-processing-start');
    const csvFilePath = first(paths);
    processCsv(csvFilePath);
  }
}
<|endoftext|>


<commit_before>/**
 * jquery.citys.js 1.0
 * http://jquerywidget.com
 */
;(function (factory) {
    if (typeof define === "function" && (define.amd || define.cmd) && !jQuery) {
        // AMD或CMD
        define([ "jquery" ],factory);
    } else if (typeof module === 'object' && module.exports) {
        // Node/CommonJS
        module.exports = function( root, jQuery ) {
            if ( jQuery === undefined ) {
                if ( typeof window !== 'undefined' ) {
                    jQuery = require('jquery');
                } else {
                    jQuery = require('jquery')(root);
                }
            }
            factory(jQuery);
            return jQuery;
        };
    } else {
        //Browser globals
        factory(jQuery);
    }
}(function ($) {
    $.support.cors = true;
    $.fn.citys = function(parameter,getApi) {
        if(typeof parameter == 'function'){ //重载
            getApi = parameter;
            parameter = {};
        }else{
            parameter = parameter || {};
            getApi = getApi||function(){};
        }
        var defaults = {
            dataUrl:'http://passer-by.com/data_location/list.json',     //数据库地址
            dataType:'json',          //数据库类型:'json'或'jsonp'
            provinceField:'province', //省份字段名
            cityField:'city',         //城市字段名
            areaField:'area',         //地区字段名
            valueType:'code',         //下拉框值的类型,code行政区划代码,name地名
            code:0,                   //地区编码
            province:0,               //省份,可以为地区编码或者名称
            city:0,                   //城市,可以为地区编码或者名称
            area:0,                   //地区,可以为地区编码或者名称
            required: true,           //是否必须选一个
            nodata: 'hidden',         //当无数据时的表现形式:'hidden'隐藏,'disabled'禁用,为空不做任何处理
            onChange:function(){}     //地区切换时触发,回调函数传入地区数据
        };
        var options = $.extend({}, defaults, parameter);
        return this.each(function() {
            //对象定义
            var _api = {};
            var $this = $(this);
            var $province = $this.find('select[name="'+options.provinceField+'"]'),
                $city = $this.find('select[name="'+options.cityField+'"]'),
                $area = $this.find('select[name="'+options.areaField+'"]');
            $.ajax({
                url:options.dataUrl,
                type:'GET',
                crossDomain: true,
                dataType:options.dataType,
                jsonpCallback:'jsonp_location',
                success:function(data){
                    var province,city,area,hasCity;
                    if(options.code){   //如果设置地区编码，则忽略单独设置的信息
                        var c = options.code - options.code%1e4;
                        if(data[c]){
                            options.province = c;
                        }
                        c = options.code - (options.code%1e4 ? options.code%1e2 : options.code);
                        if(data[c]){
                            options.city = c;
                        }
                        c = options.code%1e2 ? options.code : 0;
                        if(data[c]){
                            options.area = c;
                        }
                    }
                    var updateData = function(){
                        province = {},city={},area={};
                        hasCity = false;       //判断是非有地级城市
                        for(var code in data){
                            if(!(code%1e4)){     //获取所有的省级行政单位
                                province[code]=data[code];
                                if(options.required&&!options.province){
                                    if(options.city&&!(options.city%1e4)){  //省未填，并判断为直辖市
                                        options.province = options.city;
                                    }else{
                                        options.province = code;
                                    }
                                }else if(data[code].indexOf(options.province)>-1){
                                    options.province = isNaN(options.province)?code:options.province;
                                }
                            }else{
                                var p = code - options.province;
                                if(options.province&&p>0&&p<1e4){    //同省的城市或地区
                                    if(!(code%100)){
                                        hasCity = true;
                                        city[code]=data[code];
                                        if(data[code].indexOf(options.city)>-1){
                                            options.city = isNaN(options.city)?code:options.city;
                                        }
                                    }else if(p>9000){                   //省直辖县级行政单位
                                        city[code] = data[code];
                                        if(data[code].indexOf(options.city)>-1){
                                            options.city = isNaN(options.city)?code:options.city;
                                        }
                                    }else if(hasCity){                  //非直辖市
                                        var c = code-options.city;
                                        if(options.city&&c>0&&c<100){     //同个城市的地区
                                            area[code]=data[code];
                                            if(data[code].indexOf(options.area)>-1){
                                                options.area = isNaN(options.area)?code:options.area;
                                            }
                                        }
                                    }else{
                                        city[code]=data[code];            //直辖市
                                        if(options.area){
                                            options.city = options.area;
                                            options.area = '';
                                        }
                                        if(data[code].indexOf(options.city)>-1){
                                            options.city = isNaN(options.city)?code:options.city;
                                        }
                                    }
                                }
                            }
                        }
                    };
                    var format = {
                        province:function(){
                            $province.empty();
                            if(!options.required){
                                $province.append('<option value=""> - 请选择 - </option>');
                            }
                            for(var i in province){
                                $province.append('<option value="'+(options.valueType=='code'?i:province[i])+'" data-code="'+i+'">'+province[i]+'</option>');
                            }
                            if(options.province){
                                var value = options.valueType=='code'?options.province:province[options.province];
                                $province.val(value);
                            }
                            this.city();
                        },
                        city:function(){
                            $city.empty();
                            if(!options.required){
                                $city.append('<option value=""> - 请选择 - </option>');
                            }
                            if(options.nodata=='disabled'){
                                $city.prop('disabled',$.isEmptyObject(city));
                            }else if(options.nodata=='hidden'){
                                $city.css('display',$.isEmptyObject(city)?'none':'');
                            }
                            for(var i in city){
                                $city.append('<option value="'+(options.valueType=='code'?i:city[i])+'" data-code="'+i+'">'+city[i]+'</option>');
                            }
                            if(options.city){
                                var value = options.valueType=='code'?options.city:city[options.city];
                                $city.val(value);
                            }else if(options.area){
                                var value = options.valueType=='code'?options.area:city[options.area];
                                $city.val(value);
                            }
                            this.area();
                        },
                        area:function(){
                            $area.empty();
                            if(!hasCity){
                                $area.css('display','none');
                            }else{
                                $area.css('display','');
                                if(!options.required){
                                    $area.append('<option value=""> - 请选择 - </option>');
                                }
                                if(options.nodata=='disabled'){
                                    $area.prop('disabled',$.isEmptyObject(area));
                                }else if(options.nodata=='hidden'){
                                    $area.css('display',$.isEmptyObject(area)?'none':'');
                                }
                                for(var i in area){
                                    $area.append('<option value="'+(options.valueType=='code'?i:area[i])+'" data-code="'+i+'">'+area[i]+'</option>');
                                }
                                if(options.area){
                                    var value = options.valueType=='code'?options.area:area[options.area];
                                    $area.val(value);
                                }
                            }
                        }
                    };
                    //获取当前地理信息
                    _api.getInfo = function(){
                        var status = {
                            direct:!hasCity,
                            province:data[options.province]||'',
                            city:data[options.city]||'',
                            area:data[options.area]||'',
                            code:options.area||options.city||options.province
                        };
                        return status;
                    };
                    //事件绑定
                    $province.on('change',function(){
                        options.province = $(this).find('option:selected').data('code')||0; //选中节点的区划代码
                        options.city = 0;
                        options.area = 0;
                        updateData();
                        format.city();
                        options.onChange(_api.getInfo());
                    });
                    $city.on('change',function(){
                        options.city = $(this).find('option:selected').data('code')||0; //选中节点的区划代码
                        options.area = 0;
                        updateData();
                        format.area();
                        options.onChange(_api.getInfo());
                    });
                    $area.on('change',function(){
                        options.area = $(this).find('option:selected').data('code')||0; //选中节点的区划代码
                        options.onChange(_api.getInfo());
                    });
                    //初始化
                    updateData();
                    format.province();
                    if(options.code){
                        options.onChange(_api.getInfo());
                    }
                    getApi(_api);
                }
            });
        });
    };
}));
<commit_msg>updated 直辖市由隐藏区级改成隐藏市级<commit_after>/**
 * jquery.citys.js 1.0
 * http://jquerywidget.com
 */
;(function (factory) {
    if (typeof define === "function" && (define.amd || define.cmd) && !jQuery) {
        // AMD或CMD
        define([ "jquery" ],factory);
    } else if (typeof module === 'object' && module.exports) {
        // Node/CommonJS
        module.exports = function( root, jQuery ) {
            if ( jQuery === undefined ) {
                if ( typeof window !== 'undefined' ) {
                    jQuery = require('jquery');
                } else {
                    jQuery = require('jquery')(root);
                }
            }
            factory(jQuery);
            return jQuery;
        };
    } else {
        //Browser globals
        factory(jQuery);
    }
}(function ($) {
    $.support.cors = true;
    $.fn.citys = function(parameter,getApi) {
        if(typeof parameter == 'function'){ //重载
            getApi = parameter;
            parameter = {};
        }else{
            parameter = parameter || {};
            getApi = getApi||function(){};
        }
        var defaults = {
            dataUrl:'http://passer-by.com/data_location/list.json',     //数据库地址
            dataType:'json',          //数据库类型:'json'或'jsonp'
            provinceField:'province', //省份字段名
            cityField:'city',         //城市字段名
            areaField:'area',         //地区字段名
            valueType:'code',         //下拉框值的类型,code行政区划代码,name地名
            code:0,                   //地区编码
            province:0,               //省份,可以为地区编码或者名称
            city:0,                   //城市,可以为地区编码或者名称
            area:0,                   //地区,可以为地区编码或者名称
            required: true,           //是否必须选一个
            nodata: 'hidden',         //当无数据时的表现形式:'hidden'隐藏,'disabled'禁用,为空不做任何处理
            onChange:function(){}     //地区切换时触发,回调函数传入地区数据
        };
        var options = $.extend({}, defaults, parameter);
        return this.each(function() {
            //对象定义
            var _api = {};
            var $this = $(this);
            var $province = $this.find('select[name="'+options.provinceField+'"]'),
                $city = $this.find('select[name="'+options.cityField+'"]'),
                $area = $this.find('select[name="'+options.areaField+'"]');
            $.ajax({
                url:options.dataUrl,
                type:'GET',
                crossDomain: true,
                dataType:options.dataType,
                jsonpCallback:'jsonp_location',
                success:function(data){
                    var province,city,area,hasCity;
                    if(options.code){   //如果设置地区编码，则忽略单独设置的信息
                        var c = options.code - options.code%1e4;
                        if(data[c]){
                            options.province = c;
                        }
                        c = options.code - (options.code%1e4 ? options.code%1e2 : options.code);
                        if(data[c]){
                            options.city = c;
                        }
                        c = options.code%1e2 ? options.code : 0;
                        if(data[c]){
                            options.area = c;
                        }
                    }
                    var updateData = function(){
                        province = {},city={},area={};
                        hasCity = false;       //判断是非有地级城市
                        for(var code in data){
                            if(!(code%1e4)){     //获取所有的省级行政单位
                                province[code]=data[code];
                                if(options.required&&!options.province){
                                    if(options.city&&!(options.city%1e4)){  //省未填，并判断为直辖市
                                        options.province = options.city;
                                    }else{
                                        options.province = code;
                                    }
                                }else if(data[code].indexOf(options.province)>-1){
                                    options.province = isNaN(options.province)?code:options.province;
                                }
                            }else{
                                var p = code - options.province;
                                if(options.province&&p>0&&p<1e4){    //同省的城市或地区
                                    if(!(code%100)){
                                        hasCity = true;
                                        city[code]=data[code];
                                        if(data[code].indexOf(options.city)>-1){
                                            options.city = isNaN(options.city)?code:options.city;
                                        }
                                    }else if(p>9000){                   //省直辖县级行政单位
                                        city[code] = data[code];
                                        if(data[code].indexOf(options.city)>-1){
                                            options.city = isNaN(options.city)?code:options.city;
                                        }
                                    }else if(hasCity){                  //非直辖市
                                        var c = code-options.city;
                                        if(options.city&&c>0&&c<100){     //同个城市的地区
                                            area[code]=data[code];
                                            if(data[code].indexOf(options.area)>-1){
                                                options.area = isNaN(options.area)?code:options.area;
                                            }
                                        }
                                    }else{
                                        area[code]=data[code];            //直辖市
                                        if(data[code].indexOf(options.area)>-1){
                                            options.area = isNaN(options.area)?code:options.area;
                                        }
                                    }
                                }
                            }
                        }
                    };
                    var format = {
                        province:function(){
                            $province.empty();
                            if(!options.required){
                                $province.append('<option value=""> - 请选择 - </option>');
                            }
                            for(var i in province){
                                $province.append('<option value="'+(options.valueType=='code'?i:province[i])+'" data-code="'+i+'">'+province[i]+'</option>');
                            }
                            if(options.province){
                                var value = options.valueType=='code'?options.province:province[options.province];
                                $province.val(value);
                            }
                            this.city();
                        },
                        city:function(){
                            $city.empty();
                            if(!hasCity){
                                $city.css('display','none');
                            }else{
                                $city.css('display','');
                                if(!options.required){
                                    $city.append('<option value=""> - 请选择 - </option>');
                                }
                                if(options.nodata=='disabled'){
                                    $city.prop('disabled',$.isEmptyObject(city));
                                }else if(options.nodata=='hidden'){
                                    $city.css('display',$.isEmptyObject(city)?'none':'');
                                }
                                for(var i in city){
                                    $city.append('<option value="'+(options.valueType=='code'?i:city[i])+'" data-code="'+i+'">'+city[i]+'</option>');
                                }
                                if(options.city){
                                    var value = options.valueType=='code'?options.city:city[options.city];
                                    $city.val(value);
                                }else if(options.area){
                                    var value = options.valueType=='code'?options.area:city[options.area];
                                    $city.val(value);
                                }
                            }
                            this.area();
                        },
                        area:function(){
                            $area.empty();
                            if(!options.required){
                                $area.append('<option value=""> - 请选择 - </option>');
                            }
                            if(options.nodata=='disabled'){
                                $area.prop('disabled',$.isEmptyObject(area));
                            }else if(options.nodata=='hidden'){
                                $area.css('display',$.isEmptyObject(area)?'none':'');
                            }
                            for(var i in area){
                                $area.append('<option value="'+(options.valueType=='code'?i:area[i])+'" data-code="'+i+'">'+area[i]+'</option>');
                            }
                            if(options.area){
                                var value = options.valueType=='code'?options.area:area[options.area];
                                $area.val(value);
                            }
                        }
                    };
                    //获取当前地理信息
                    _api.getInfo = function(){
                        var status = {
                            direct:!hasCity,
                            province:data[options.province]||'',
                            city:data[options.city]||'',
                            area:data[options.area]||'',
                            code:options.area||options.city||options.province
                        };
                        return status;
                    };
                    //事件绑定
                    $province.on('change',function(){
                        options.province = $(this).find('option:selected').data('code')||0; //选中节点的区划代码
                        options.city = 0;
                        options.area = 0;
                        updateData();
                        format.city();
                        options.onChange(_api.getInfo());
                    });
                    $city.on('change',function(){
                        options.city = $(this).find('option:selected').data('code')||0; //选中节点的区划代码
                        options.area = 0;
                        updateData();
                        format.area();
                        options.onChange(_api.getInfo());
                    });
                    $area.on('change',function(){
                        options.area = $(this).find('option:selected').data('code')||0; //选中节点的区划代码
                        options.onChange(_api.getInfo());
                    });
                    //初始化
                    updateData();
                    format.province();
                    if(options.code){
                        options.onChange(_api.getInfo());
                    }
                    getApi(_api);
                }
            });
        });
    };
}));
<|endoftext|>


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

/*
 * A command line script to produce mocked data output for the
 * CrowdCompass CSV input interfaces.
 *
 * Usage:
 *  gsvGen [#] [attendees/organizations/etc.]
*/

// reqs

var fake = require('faker')
var clear = require('clear')

// funcdtions

var printURL = function() { return ("http://www." + fake.internet.domainName() + "/" + fake.lorem.words(1)); }

// main

if (!process.argv[2]) {
  console.log("Usage: csvGen # [a/o/etc.]");
} else {
  input = +process.argv[2];
  console.log("Unique ID", "First Name", "Last Name", "Email", "Registration Code",
                "Show on Attendee List", "Company Name", "Job Title", "Brief Bio",
                "Work Phone", "Mobile Phone", "Other Phone", "Other Phone Type",
                "Address", "Address 2", "City", "State", "Zipcode", "Country",
                "Website", "Website 2", "Linkedin URL", "Twitter URL", "Facebook URL",
                "Group List (comma-separated)")
  for (i=0; i < input; i++) {
    console.log("A-" + i + ", " + fake.name.firstName() + ", " + fake.name.lastName()
               + ", " + fake.internet.email() + ", " + ", " + fake.lorem.sentence()
               + ", " + "FALSE, " + fake.lorem.sentence() + ", " + fake.lorem.sentence()
               + ", " + fake.lorem.sentence() + ", " + fake.phone.phoneNumber()
               + ", " + ", " + ", " + ", " + ", " + fake.address.city()
               + ", " + fake.lorem.sentence() + ", " + fake.address.zipCode()
               + ", " + fake.address.country() + ", " + printURL() + ", " + printURL()
               + ", " + ", " + ", " + ", ");
  }
}

/*

locales = ['bg_BG',
        'cs_CZ',
        'de_DE',
        'dk_DK',
        'el_GR',
        'en_CA',
        'en_GB',
        'en_US',
        'es_ES',
        'es_MX',
        'fa_IR',
        'fi_FI',
        'fr_FR',
        'hi_IN',
        'it_IT',
        'ko_KR',
        'lt_LT',
        'lv_LV',
        'nl_NL',
        'pl_PL',
        'pt_BR',
        'ru_RU',
        'sl_SI',
        'zh_CN',
        'zh_TW' ]

/*
 * ToDo:
 * [X] Functional: output onto the command line for > filename.csv
 * [ ] Output files. Create a directory to contain them
 * [ ] Localization. Drop files named by locale into the folder
 */
<commit_msg>csvGen.js version 1<commit_after>#!/usr/bin/env node

/*
 * A command line script to produce mocked data output for the
 * CrowdCompass CSV input interfaces.
 *
 * Usage: gsvGen [#]
*/

var fake = require('faker')
var printURL = function() { return ("http://www." + fake.internet.domainName() + "/" + fake.lorem.words(1)); }

if (!process.argv[2]) {
  console.log("Usage: csvGen #");
} else {
  input = +process.argv[2];
  console.log("Unique ID, First Name, Last Name, Email, Registration Code, Show on Attendee List, Company Name, Job Title, Brief Bio, Work Phone, Mobile Phone, Other Phone, Other Phone Type, Address, Address 2, City, State, Zipcode, Country, Website, Website 2, Linkedin URL, Twitter URL, Facebook URL, Group List (comma-separated)");
  for (var i=0; i < input; i++) {
    console.log("A-" + (i+1) + ", " + fake.name.firstName() + ", " + fake.name.lastName()
               + ", " + fake.internet.email() + ", " + ", " + fake.lorem.sentence()
               + ", " + "FALSE, " + fake.lorem.sentence() + ", " + fake.lorem.sentence()
               + ", " + fake.lorem.sentence() + ", " + fake.phone.phoneNumber()
               + ", " + ", " + ", " + ", " + ", " + fake.address.city()
               + ", " + fake.lorem.sentence() + ", " + fake.address.zipCode()
               + ", " + fake.address.country() + ", " + printURL() + ", " + printURL()
               + ", " + ", " + ", " + ", ");
  }
}

/*
de
de_AT
de_CH
en
en_AU
en_BORK
en_CA
en_GB
en_IND
en_US
en_au_ocker
es
fa
fr
it
ja
ko
nb_NO
nep
nl
pl
pt_BR
ru
sk
sv
vi
zh_CN
*/
<|endoftext|>


<commit_before>/* global GLVertexLayout */

import gl from './gl_constants'; // web workers don't have access to GL context, so import all GL constants

import log from 'loglevel';

// Describes a vertex layout that can be used with many different GL programs.
export default class GLVertexLayout {
    // Attribs are an array, in layout order, of: name, size, type, normalized
    // ex: { name: 'position', size: 3, type: gl.FLOAT, normalized: false }
    constructor (attribs) {
        this.attribs = attribs; // dictionary of attributes, specified as standard GL attrib options
        this.components = [];   // list of type and offset info about each attribute component
        this.index = {};        // linear buffer index of each attribute component, e.g. this.index.position.x

        // Calc vertex stride
        this.stride = 0;

        var count = 0;
        for (var attrib of this.attribs) {
            attrib.offset = this.stride;
            attrib.byte_size = attrib.size;
            var shift = 0;

            switch (attrib.type) {
                case gl.FLOAT:
                case gl.INT:
                case gl.UNSIGNED_INT:
                    attrib.byte_size *= 4;
                    shift = 2;
                    break;
                case gl.SHORT:
                case gl.UNSIGNED_SHORT:
                    attrib.byte_size *= 2;
                    shift = 1;
                    break;
            }

            // Force 4-byte alignment on attributes
            this.stride += attrib.byte_size;
            if (this.stride & 3) { // pad to multiple of 4 bytes
                this.stride += 4 - (this.stride & 3);
            }

            // Add info to list of attribute components
            // Used to build the vertex data, provides pointers and offsets into each typed array view
            // Each component is an array of:
            // [GL attrib type, pointer to typed array view, bits to shift right to determine buffer offset, additional buffer offset for the component]
            var offset_typed = attrib.offset >> shift;
            if (attrib.size > 1) {
                for (var a=0; a < attrib.size; a++) {
                    this.components.push([attrib.type, null, shift, offset_typed++]);
                }
            }
            else {
                this.components.push([attrib.type, null, shift, offset_typed]);
            }

            // Provide an index into the vertex data buffer for each attribute component
            this.index[attrib.name] = count;
            count += attrib.size;
        }
    }

    // Setup a vertex layout for a specific GL program
    // Assumes that the desired vertex buffer (VBO) is already bound
    // If a given program doesn't include all attributes, it can still use the vertex layout
    // to read those attribs that it does recognize, using the attrib offsets to skip others.
    enable (gl, program)
    {
        var attrib, location;

        // Enable all attributes for this layout
        for (var a=0; a < this.attribs.length; a++) {
            attrib = this.attribs[a];
            location = program.attribute(attrib.name).location;

            if (location !== -1) {
                gl.enableVertexAttribArray(location);
                gl.vertexAttribPointer(location, attrib.size, attrib.type, attrib.normalized, this.stride, attrib.offset);
                GLVertexLayout.enabled_attribs[location] = program;
            }
        }

        // Disable any previously bound attributes that aren't for this layout
        for (location in GLVertexLayout.enabled_attribs) {
            this.disableUnusedAttribute(gl, location, program);
        }
    }

    // Disable an attribute if it was not enabled for the specified program
    // NOTE: this was moved out of the inner loop in enable() to assist w/VM optimization
    disableUnusedAttribute (gl, location, program) {
        if (GLVertexLayout.enabled_attribs[location] !== program) {
            gl.disableVertexAttribArray(location);
            delete GLVertexLayout.enabled_attribs[location];
        }
    }

    createVertexData () {
        return new GLVertexData(this);
    }

}

// Track currently enabled attribs, by the program they are bound to
// Static class property to reflect global GL state
GLVertexLayout.enabled_attribs = {};

// An intermediary object that holds vertex data in typed arrays, according to a given vertex layout
// Used to construct a mesh/VBO for rendering
export class GLVertexData {

    constructor (vertex_layout) {
        this.vertex_layout = vertex_layout;
        this.block_size = 50000;     // block size in which to allocate
        this.block_num = 1;         // initial # of allocated blocks
        this.buffer_offset = 0;      // byte offset into currently allocated buffer
        this.buffer = new ArrayBuffer(this.vertex_layout.stride * this.block_size * this.block_num);
        // this.components = [for (component of this.vertex_layout.components) [...component]]; // TODO: turn on array comprehension in traceur?
        this.components = [];
        for (var component of this.vertex_layout.components) {
            this.components.push([...component]);
        }
        this.vertex_count = 0;
        this.setBufferViews();
    }

    // (Re-)allocate typed views into the main buffer - only create the types we need for this layout
    setBufferViews () {
        this.buffer_views = {};
        for (var attrib of this.vertex_layout.attribs) {
            // Need view for this type?
            if (this.buffer_views[attrib.type] == null) {
                var array_type = this.array_types[attrib.type];
                this.buffer_views[attrib.type] = new array_type(this.buffer);
            }
        }

        // Update component buffer pointers
        for (var component of this.components) {
            component[1] = this.buffer_views[component[0]];
        }
    }

    // Check allocated buffer size, expand/realloc buffer if needed
    // checkBufferSize (num = 1) {
    //     if ((this.buffer_offset + (num * this.vertex_layout.stride)) > this.buffer.byteLength) {
    //         this.block_num += Math.ceil(num / this.block_size);
    checkBufferSize () {
        if ((this.buffer_offset + this.vertex_layout.stride) > this.buffer.byteLength) {
            this.block_num++;
            var new_block = new ArrayBuffer(this.vertex_layout.stride * this.block_size * this.block_num);
            var new_view = new Uint8Array(new_block);
            new_view.set(new Uint8Array(this.buffer)); // copy existing data to new buffer

            this.buffer = new_block;
            this.setBufferViews();
            log.info(`GLVertexData: expanded vertex block to ${this.block_size * this.block_num} vertices`);
        }
    }

    // Add a vertex, copied from a plain JS array of elements matching the order of the vertex layout.
    // Note: uses pre-calculated info about each attribute, including pointer to appropriate typed array
    // view and offset into it. This was the fastest method profiled so far for filling a mixed-type
    // vertex layout (though still slower than the previous method that only supported Float32Array attributes).
    addVertex (vertex) {
        this.checkBufferSize();
        var i=0;

        // ES6-style destructuring and iteration - cool but noticeably slower (at least w/traceur compiled code)
        // for (var [, buffer, shift, offset] of this.components) {
        //     buffer[(this.buffer_offset >> shift) + offset] = vertex[i++];

        var clen = this.components.length;
        for (var c=0; c < clen; c++) {
            var component = this.components[c];
            component[1][(this.buffer_offset >> component[2]) + component[3]] = vertex[i++];
        }

        this.buffer_offset += this.vertex_layout.stride;
        this.vertex_count++;
    }

    // Finalize vertex buffer for use in constructing a mesh
    end () {
        // Clip the allocated block to free unused memory
        if (this.buffer_offset < this.buffer.byteLength) {
            var new_block = new ArrayBuffer(this.buffer_offset);
            var new_view = new Uint8Array(new_block);
            new_view.set(new Uint8Array(this.buffer, 0, this.buffer_offset));
            this.buffer = new_block;
        }
        return this;
    }

}

// Maps GL types to JS array types
GLVertexData.prototype.array_types = {
    [gl.FLOAT]: Float32Array,
    [gl.BYTE]: Int8Array,
    [gl.UNSIGNED_BYTE]: Uint8Array,
    [gl.INT]: Int32Array,
    [gl.UNSIGNED_INT]: Uint32Array,
    [gl.SHORT]: Int16Array,
    [gl.UNSIGNED_SHORT]: Uint16Array
};
<commit_msg>clear internal buffer state when VBO data is done<commit_after>/* global GLVertexLayout */

import gl from './gl_constants'; // web workers don't have access to GL context, so import all GL constants

import log from 'loglevel';

// Describes a vertex layout that can be used with many different GL programs.
export default class GLVertexLayout {
    // Attribs are an array, in layout order, of: name, size, type, normalized
    // ex: { name: 'position', size: 3, type: gl.FLOAT, normalized: false }
    constructor (attribs) {
        this.attribs = attribs; // dictionary of attributes, specified as standard GL attrib options
        this.components = [];   // list of type and offset info about each attribute component
        this.index = {};        // linear buffer index of each attribute component, e.g. this.index.position.x

        // Calc vertex stride
        this.stride = 0;

        var count = 0;
        for (var attrib of this.attribs) {
            attrib.offset = this.stride;
            attrib.byte_size = attrib.size;
            var shift = 0;

            switch (attrib.type) {
                case gl.FLOAT:
                case gl.INT:
                case gl.UNSIGNED_INT:
                    attrib.byte_size *= 4;
                    shift = 2;
                    break;
                case gl.SHORT:
                case gl.UNSIGNED_SHORT:
                    attrib.byte_size *= 2;
                    shift = 1;
                    break;
            }

            // Force 4-byte alignment on attributes
            this.stride += attrib.byte_size;
            if (this.stride & 3) { // pad to multiple of 4 bytes
                this.stride += 4 - (this.stride & 3);
            }

            // Add info to list of attribute components
            // Used to build the vertex data, provides pointers and offsets into each typed array view
            // Each component is an array of:
            // [GL attrib type, pointer to typed array view, bits to shift right to determine buffer offset, additional buffer offset for the component]
            var offset_typed = attrib.offset >> shift;
            if (attrib.size > 1) {
                for (var a=0; a < attrib.size; a++) {
                    this.components.push([attrib.type, null, shift, offset_typed++]);
                }
            }
            else {
                this.components.push([attrib.type, null, shift, offset_typed]);
            }

            // Provide an index into the vertex data buffer for each attribute component
            this.index[attrib.name] = count;
            count += attrib.size;
        }
    }

    // Setup a vertex layout for a specific GL program
    // Assumes that the desired vertex buffer (VBO) is already bound
    // If a given program doesn't include all attributes, it can still use the vertex layout
    // to read those attribs that it does recognize, using the attrib offsets to skip others.
    enable (gl, program)
    {
        var attrib, location;

        // Enable all attributes for this layout
        for (var a=0; a < this.attribs.length; a++) {
            attrib = this.attribs[a];
            location = program.attribute(attrib.name).location;

            if (location !== -1) {
                gl.enableVertexAttribArray(location);
                gl.vertexAttribPointer(location, attrib.size, attrib.type, attrib.normalized, this.stride, attrib.offset);
                GLVertexLayout.enabled_attribs[location] = program;
            }
        }

        // Disable any previously bound attributes that aren't for this layout
        for (location in GLVertexLayout.enabled_attribs) {
            this.disableUnusedAttribute(gl, location, program);
        }
    }

    // Disable an attribute if it was not enabled for the specified program
    // NOTE: this was moved out of the inner loop in enable() to assist w/VM optimization
    disableUnusedAttribute (gl, location, program) {
        if (GLVertexLayout.enabled_attribs[location] !== program) {
            gl.disableVertexAttribArray(location);
            delete GLVertexLayout.enabled_attribs[location];
        }
    }

    createVertexData () {
        return new GLVertexData(this);
    }

}

// Track currently enabled attribs, by the program they are bound to
// Static class property to reflect global GL state
GLVertexLayout.enabled_attribs = {};

// An intermediary object that holds vertex data in typed arrays, according to a given vertex layout
// Used to construct a mesh/VBO for rendering
export class GLVertexData {

    constructor (vertex_layout) {
        this.vertex_layout = vertex_layout;
        this.block_size = 50000;     // block size in which to allocate
        this.block_num = 1;         // initial # of allocated blocks
        this.buffer_offset = 0;      // byte offset into currently allocated buffer
        this.buffer = new ArrayBuffer(this.vertex_layout.stride * this.block_size * this.block_num);
        // this.components = [for (component of this.vertex_layout.components) [...component]]; // TODO: turn on array comprehension in traceur?
        this.components = [];
        for (var component of this.vertex_layout.components) {
            this.components.push([...component]);
        }
        this.vertex_count = 0;
        this.setBufferViews();
    }

    // (Re-)allocate typed views into the main buffer - only create the types we need for this layout
    setBufferViews () {
        this.buffer_views = {};
        for (var attrib of this.vertex_layout.attribs) {
            // Need view for this type?
            if (this.buffer_views[attrib.type] == null) {
                var array_type = this.array_types[attrib.type];
                this.buffer_views[attrib.type] = new array_type(this.buffer);
            }
        }

        // Update component buffer pointers
        for (var component of this.components) {
            component[1] = this.buffer_views[component[0]];
        }
    }

    // Check allocated buffer size, expand/realloc buffer if needed
    // checkBufferSize (num = 1) {
    //     if ((this.buffer_offset + (num * this.vertex_layout.stride)) > this.buffer.byteLength) {
    //         this.block_num += Math.ceil(num / this.block_size);
    checkBufferSize () {
        if ((this.buffer_offset + this.vertex_layout.stride) > this.buffer.byteLength) {
            this.block_num++;
            var new_block = new ArrayBuffer(this.vertex_layout.stride * this.block_size * this.block_num);
            var new_view = new Uint8Array(new_block);
            new_view.set(new Uint8Array(this.buffer)); // copy existing data to new buffer

            this.buffer = new_block;
            this.setBufferViews();
            log.info(`GLVertexData: expanded vertex block to ${this.block_size * this.block_num} vertices`);
        }
    }

    // Add a vertex, copied from a plain JS array of elements matching the order of the vertex layout.
    // Note: uses pre-calculated info about each attribute, including pointer to appropriate typed array
    // view and offset into it. This was the fastest method profiled so far for filling a mixed-type
    // vertex layout (though still slower than the previous method that only supported Float32Array attributes).
    addVertex (vertex) {
        this.checkBufferSize();
        var i=0;

        // ES6-style destructuring and iteration - cool but noticeably slower (at least w/traceur compiled code)
        // for (var [, buffer, shift, offset] of this.components) {
        //     buffer[(this.buffer_offset >> shift) + offset] = vertex[i++];

        var clen = this.components.length;
        for (var c=0; c < clen; c++) {
            var component = this.components[c];
            component[1][(this.buffer_offset >> component[2]) + component[3]] = vertex[i++];
        }

        this.buffer_offset += this.vertex_layout.stride;
        this.vertex_count++;
    }

    // Finalize vertex buffer for use in constructing a mesh
    end () {
        // Clip the allocated block to free unused memory
        if (this.buffer_offset < this.buffer.byteLength) {
            var new_block = new ArrayBuffer(this.buffer_offset);
            var new_view = new Uint8Array(new_block);
            new_view.set(new Uint8Array(this.buffer, 0, this.buffer_offset));
            this.buffer = new_block;
            this.buffer_views = null;
            this.components = null;
        }
        return this;
    }

}

// Maps GL types to JS array types
GLVertexData.prototype.array_types = {
    [gl.FLOAT]: Float32Array,
    [gl.BYTE]: Int8Array,
    [gl.UNSIGNED_BYTE]: Uint8Array,
    [gl.INT]: Int32Array,
    [gl.UNSIGNED_INT]: Uint32Array,
    [gl.SHORT]: Int16Array,
    [gl.UNSIGNED_SHORT]: Uint16Array
};
<|endoftext|>


<commit_before>'use strict'

const BaseOptionsOutput=require('crnx-base/options-output')
const Option=require('./option-classes')

class GraphOptionsOutput extends BaseOptionsOutput {
	setOptionClassWriters(optionClassWriters) {
		// intentionally not calling super here
		// TODO
	}
}

class GraphOptionOutput {
	constructor(option,writeOption,i18n,generateId) {
		const gridSize=32
		const graphHeight=15
		const nodeWidth=6
		const $lines=$("<svg xmlns='http://www.w3.org/2000/svg' version='1.1'></svg>")
		const $nodes=$("
") // TODO populate with default/imported entries
		let maxZIndex=0
		const writeConnectionLine=(gx1,gy1,gx2,gy2)=>{
			const writeLine=(x1,y1,x2,y2)=>$(
				document.createElementNS("http://www.w3.org/2000/svg","line")
			).attr({stroke:'#000',x1,y1,x2,y2})
			return writeLine(
				(gx1+nodeWidth)*gridSize,
				(gy1+1.5)*gridSize,
				gx2*gridSize,
				(gy2+1.5)*gridSize
			)
		}
		const updateConnectionLine=($line,$node1,$node2)=>{
			const pos1=$node1.position()
			const pos2=$node2.position()
			$line.attr({
				x1: pos1.left+$node1.width(),
				y1: pos1.top+gridSize*1.5,
				x2: pos2.left,
				y2: pos2.top+gridSize*1.5
			})
		}
		const addNode=(nodeOption,gx0,gy0)=>{
			const id=generateId()
			const number=$nodes.children().length
			let dragAnimationId=null
			let snapAnimationId=null
			const writePort=(thisDirection,thatDirection)=>$(`<div class='node-port node-port-${thisDirection}'>`).append(
				$("
").append(
					`<span>${thisDirection} connected to:</span>`, // TODO i18n
					$("
"),
					// TODO <select> with all nodes
					$(`<button title='connect ${thisDirection} to ${thatDirection}'>`).append( // TODO i18n
						"Connect"
					)
				)
			)
			const $node=$(`<fieldset id='${id}' class='node'>`).append(
				$("<legend class='node-section'>").append(
					i18n('options.'+nodeOption.fullName),
					" ",
					`<span class='number-mark'>#<span class='number'>${number}</span></span>`
				),
				$("
").append(
					// TODO top-left burger button for keyboard movement
					$("<button class='delete' title='"+i18n('options-output.delete.tip')+"'>").append(
						""+i18n('options-output.delete')+""
					).mousedown(function(ev){
						ev.stopPropagation() // prevent $node.mousedown()
					}).click(function(){
						cancelAnimationFrame(dragAnimationId)
						cancelAnimationFrame(snapAnimationId)
						$node.remove()
						// TODO update option.nodes
					})
				),
				$("
").append(
					'audio signal ', // TODO i18n
					writePort('input','output'),
					writePort('output','input')
				)
			).css({
				left: gx0*gridSize,
				top: gy0*gridSize,
			}).mousedown(function(ev){
				cancelAnimationFrame(snapAnimationId)
				let dragX1=ev.pageX
				let dragY1=ev.pageY
				const handlers={
					mouseup() { // IE doesn't receive this event when the button is released outside the window
						cancelAnimationFrame(dragAnimationId)
						dragAnimationId=null
						$(document).off(handlers)
						const pos=$node.position()
						const snapX1=pos.left
						const snapY1=pos.top
						let gx=Math.round(snapX1/gridSize)
						if (gx<0) gx=0
						let gy=Math.round(snapY1/gridSize)
						if (gy<0) gy=0
						if (gy>graphHeight-2) gy=graphHeight-2
						// TODO store new grid positions, update options
						const snapX2=gx*gridSize
						const snapY2=gy*gridSize
						const snapDuration=150
						const snapStartTime=performance.now()
						const snapAnimationHandler=time=>{
							const t=time-snapStartTime
							if (t>=snapDuration) {
								$node.css({
									left: snapX2,
									top:  snapY2,
								})
								snapAnimationId=null
							} else {
								$node.css({
									left: snapX1+(snapX2-snapX1)*t/snapDuration,
									top:  snapY1+(snapY2-snapY1)*t/snapDuration,
								})
								snapAnimationId=requestAnimationFrame(snapAnimationHandler)
							}
						}
						snapAnimationId=requestAnimationFrame(snapAnimationHandler)
					},
					mousemove(ev) {
						const dragX2=ev.pageX
						const dragY2=ev.pageY
						if (dragAnimationId==null) {
							dragAnimationId=requestAnimationFrame(()=>{
								const pos=$node.position()
								$node.css({
									left: pos.left+dragX2-dragX1,
									top: pos.top+dragY2-dragY1,
								})
								dragX1=dragX2
								dragY1=dragY2
								dragAnimationId=null
							})
						}
					},
				}
				if ($node.css('z-index')<maxZIndex) {
					$node.css('z-index',++maxZIndex)
				}
				$(document).on(handlers)
				ev.preventDefault() // prevent text selection
			}).css('z-index',++maxZIndex)
			$nodes.append($node)
			// TODO update option.nodes
		}
		// { copypasted from array-option-output
		const $buttons=$("
")
		option.availableTypes.forEach((type,i)=>{
			if (i) $buttons.append(" ")
			$buttons.append(
				$("<button type='button'>").html(
					i18n('options.'+option.fullName+'.'+type+'.add')
				).click(()=>{
					const nodeOption=option.makeEntry(type)
					addNode(nodeOption,1,1)
				})
			)
		})
		// }
		this.$output=option.$=$("<fieldset>").append(
			"<legend>"+i18n('options.'+option.fullName)+"</legend>",
			$buttons, // TODO reorder/renumber buttons
			$("
").height(gridSize*graphHeight).append(
				$lines,$nodes
			)
		)
		//$lines.append($line=writeConnectionLine(2,5,12,6))
	}
	// make clone button work
	/*
	writeDraggableSubOption(subOption,writeOption,i18n) {
		const $subOutput=super.writeDraggableSubOption(subOption,writeOption,i18n)
		const This=this
		if (subOption instanceof Option.BiquadFilter) {
			$subOutput.find('button.clone').click(function(){
				const $button=$(this)
				const coefs=$button.data('coefs')
				if (coefs) {
					const entry=This.option.makeEntry('iir',coefs)
					This.$entries.append(
						This.writeDraggableSubOption(entry,writeOption,i18n)
					)
					This.updateArrayEntries()
				}
			})
		}
		return $subOutput
	}
	*/
}

module.exports=GraphOptionOutput
<commit_msg>graph editor: update node numbers on add/delete<commit_after>'use strict'

const BaseOptionsOutput=require('crnx-base/options-output')
const Option=require('./option-classes')

class GraphOptionsOutput extends BaseOptionsOutput {
	setOptionClassWriters(optionClassWriters) {
		// intentionally not calling super here
		// TODO
	}
}

class GraphOptionOutput {
	constructor(option,writeOption,i18n,generateId) {
		const gridSize=32
		const graphHeight=15
		const nodeWidth=6
		const $lines=$("<svg xmlns='http://www.w3.org/2000/svg' version='1.1'></svg>")
		const $nodes=$("
") // TODO populate with default/imported entries
		let maxZIndex=0
		const writeConnectionLine=(gx1,gy1,gx2,gy2)=>{
			const writeLine=(x1,y1,x2,y2)=>$(
				document.createElementNS("http://www.w3.org/2000/svg","line")
			).attr({stroke:'#000',x1,y1,x2,y2})
			return writeLine(
				(gx1+nodeWidth)*gridSize,
				(gy1+1.5)*gridSize,
				gx2*gridSize,
				(gy2+1.5)*gridSize
			)
		}
		const updateConnectionLine=($line,$node1,$node2)=>{
			const pos1=$node1.position()
			const pos2=$node2.position()
			$line.attr({
				x1: pos1.left+$node1.width(),
				y1: pos1.top+gridSize*1.5,
				x2: pos2.left,
				y2: pos2.top+gridSize*1.5
			})
		}
		const updateNodeSequence=()=>{
			$nodes.children().each(function(i){
				const $node=$(this)
				$node.find('.number').text(i)
			})
			// TODO update option.nodes
		}
		const addNode=(nodeOption,gx0,gy0)=>{
			const id=generateId()
			let dragAnimationId=null
			let snapAnimationId=null
			const writePort=(thisDirection,thatDirection)=>$(`<div class='node-port node-port-${thisDirection}'>`).append(
				$("
").append(
					`<span>${thisDirection} connected to:</span>`, // TODO i18n
					$("
"),
					// TODO <select> with all nodes
					$(`<button title='connect ${thisDirection} to ${thatDirection}'>`).append( // TODO i18n
						"Connect"
					)
				)
			)
			const $node=$(`<fieldset id='${id}' class='node'>`).append(
				$("<legend class='node-section'>").append(
					i18n('options.'+nodeOption.fullName),
					" ",
					`<span class='number-mark'>#<span class='number'></span></span>`
				),
				$("
").append(
					// TODO top-left burger button for keyboard movement
					$("<button class='delete' title='"+i18n('options-output.delete.tip')+"'>").append(
						""+i18n('options-output.delete')+""
					).mousedown(function(ev){
						ev.stopPropagation() // prevent $node.mousedown()
					}).click(function(){
						cancelAnimationFrame(dragAnimationId)
						cancelAnimationFrame(snapAnimationId)
						$node.remove()
						updateNodeSequence()
					})
				),
				$("
").append(
					'audio signal ', // TODO i18n
					writePort('input','output'),
					writePort('output','input')
				)
			).css({
				left: gx0*gridSize,
				top: gy0*gridSize,
			}).mousedown(function(ev){
				cancelAnimationFrame(snapAnimationId)
				let dragX1=ev.pageX
				let dragY1=ev.pageY
				const handlers={
					mouseup() { // IE doesn't receive this event when the button is released outside the window
						cancelAnimationFrame(dragAnimationId)
						dragAnimationId=null
						$(document).off(handlers)
						const pos=$node.position()
						const snapX1=pos.left
						const snapY1=pos.top
						let gx=Math.round(snapX1/gridSize)
						if (gx<0) gx=0
						let gy=Math.round(snapY1/gridSize)
						if (gy<0) gy=0
						if (gy>graphHeight-2) gy=graphHeight-2
						// TODO store new grid positions, update options
						const snapX2=gx*gridSize
						const snapY2=gy*gridSize
						const snapDuration=150
						const snapStartTime=performance.now()
						const snapAnimationHandler=time=>{
							const t=time-snapStartTime
							if (t>=snapDuration) {
								$node.css({
									left: snapX2,
									top:  snapY2,
								})
								snapAnimationId=null
							} else {
								$node.css({
									left: snapX1+(snapX2-snapX1)*t/snapDuration,
									top:  snapY1+(snapY2-snapY1)*t/snapDuration,
								})
								snapAnimationId=requestAnimationFrame(snapAnimationHandler)
							}
						}
						snapAnimationId=requestAnimationFrame(snapAnimationHandler)
					},
					mousemove(ev) {
						const dragX2=ev.pageX
						const dragY2=ev.pageY
						if (dragAnimationId==null) {
							dragAnimationId=requestAnimationFrame(()=>{
								const pos=$node.position()
								$node.css({
									left: pos.left+dragX2-dragX1,
									top: pos.top+dragY2-dragY1,
								})
								dragX1=dragX2
								dragY1=dragY2
								dragAnimationId=null
							})
						}
					},
				}
				if ($node.css('z-index')<maxZIndex) {
					$node.css('z-index',++maxZIndex)
				}
				$(document).on(handlers)
				ev.preventDefault() // prevent text selection
			}).css('z-index',++maxZIndex)
			$nodes.append($node)
			updateNodeSequence()
		}
		// { copypasted from array-option-output
		const $buttons=$("
")
		option.availableTypes.forEach((type,i)=>{
			if (i) $buttons.append(" ")
			$buttons.append(
				$("<button type='button'>").html(
					i18n('options.'+option.fullName+'.'+type+'.add')
				).click(()=>{
					const nodeOption=option.makeEntry(type)
					addNode(nodeOption,1,1)
				})
			)
		})
		// }
		this.$output=option.$=$("<fieldset>").append(
			"<legend>"+i18n('options.'+option.fullName)+"</legend>",
			$buttons, // TODO reorder/renumber buttons
			$("
").height(gridSize*graphHeight).append(
				$lines,$nodes
			)
		)
		//$lines.append($line=writeConnectionLine(2,5,12,6))
	}
	// make clone button work
	/*
	writeDraggableSubOption(subOption,writeOption,i18n) {
		const $subOutput=super.writeDraggableSubOption(subOption,writeOption,i18n)
		const This=this
		if (subOption instanceof Option.BiquadFilter) {
			$subOutput.find('button.clone').click(function(){
				const $button=$(this)
				const coefs=$button.data('coefs')
				if (coefs) {
					const entry=This.option.makeEntry('iir',coefs)
					This.$entries.append(
						This.writeDraggableSubOption(entry,writeOption,i18n)
					)
					This.updateArrayEntries()
				}
			})
		}
		return $subOutput
	}
	*/
}

module.exports=GraphOptionOutput
<|endoftext|>


<commit_before>import {removePackage} from '../../packages/packages.js';

export default Vue.extend({
  props: {
    modules: Array,
    date: Date
  },
  template: `

          {{date | formatDate 'dddd'}}
          {{date | formatDate 'MMMM Do'}}

                {{module.name}}

            {{module.downloads.toLocaleString()}}

  `,
  methods: {
    removePackage
  }
});<commit_msg>order legend by downloads descending<commit_after>import {removePackage} from '../../packages/packages.js';

export default Vue.extend({
  props: {
    modules: Array,
    date: Date
  },
  template: `

          {{date | formatDate 'dddd'}}
          {{date | formatDate 'MMMM Do'}}

                {{module.name}}

            {{module.downloads.toLocaleString()}}

  `,
  methods: {
    removePackage
  }
});<|endoftext|>