<commit_before>const path = require('path');

module.exports = async ({ config }) => ({
  ...config,
  module: {
    ...config.module,
    rules: [
      ...config.module.rules.slice(1),
      {
        test: /\.(mjs|jsx?|tsx?)$/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              cacheDirectory: `.cache/storybook`,
              presets: [
                ['@babel/preset-env', { shippedProposals: true, useBuiltIns: 'usage', corejs: 3 }],
                '@babel/preset-typescript',
                ['babel-preset-minify', { builtIns: false, mangle: false }],
                '@babel/preset-react',
                '@babel/preset-flow',
              ],
              plugins: [
                '@babel/plugin-proposal-object-rest-spread',
                '@babel/plugin-proposal-class-properties',
                '@babel/plugin-syntax-dynamic-import',
                ['babel-plugin-emotion', { sourceMap: true, autoLabel: true }],
                'babel-plugin-macros',
                '@babel/plugin-transform-react-constant-elements',
                'babel-plugin-add-react-displayname',
                [
                  'babel-plugin-react-docgen',
                  { DOC_GEN_COLLECTION_NAME: 'STORYBOOK_REACT_CLASSES' },
                ],
              ],
            },
          },
        ],
        exclude: [/node_modules/, /dist/],
      },
    ],
  },
  resolve: {
    ...config.resolve,
    extensions: [...(config.resolve.extensions || []), '.ts', '.tsx'],
  },
});
<commit_msg>Official examples: apply babel-preset-minify only in production mode<commit_after>const path = require('path');

module.exports = async ({ config, mode }) => ({
  ...config,
  module: {
    ...config.module,
    rules: [
      ...config.module.rules.slice(1),
      {
        test: /\.(mjs|jsx?|tsx?)$/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              cacheDirectory: `.cache/storybook`,
              presets: [
                ['@babel/preset-env', { shippedProposals: true, useBuiltIns: 'usage', corejs: 3 }],
                '@babel/preset-typescript',
                mode === 'PRODUCTION' && [
                  'babel-preset-minify',
                  { builtIns: false, mangle: false },
                ],
                '@babel/preset-react',
                '@babel/preset-flow',
              ].filter(Boolean),
              plugins: [
                '@babel/plugin-proposal-object-rest-spread',
                '@babel/plugin-proposal-class-properties',
                '@babel/plugin-syntax-dynamic-import',
                ['babel-plugin-emotion', { sourceMap: true, autoLabel: true }],
                'babel-plugin-macros',
                '@babel/plugin-transform-react-constant-elements',
                'babel-plugin-add-react-displayname',
                [
                  'babel-plugin-react-docgen',
                  { DOC_GEN_COLLECTION_NAME: 'STORYBOOK_REACT_CLASSES' },
                ],
              ],
            },
          },
        ],
        exclude: [/node_modules/, /dist/],
      },
    ],
  },
  resolve: {
    ...config.resolve,
    extensions: [...(config.resolve.extensions || []), '.ts', '.tsx'],
  },
});
<|endoftext|>


<commit_before>import PluginComponent from '../plugin.component';
import {Command} from '@grid/core/command';
import {clone, noop, flatten} from '@grid/core/utility';
import {getFactory as valueFactory} from '@grid/core/services/value';
import {getFactory as labelFactory} from '@grid/core/services/label';
import * as columnService from '@grid/core/column/column.service';

const Plugin = PluginComponent('column-filter-panel', {inject: ['vscroll', '$filter', 'qgrid']});
class ColumnFilterPanel extends Plugin {
	constructor() {
		super(...arguments);

		this.by = new Set();
		this.items = [];
		this.entries = new Map();

		this.toggle = new Command({
			execute: (item) => {
				if (this.by.has(item)) {
					this.by.delete(item);
				}
				else {
					this.by.add(item);
				}
			}
		});

		this.toggleAll = new Command({
			execute: () => {
				const state = !this.stateAll();
				if (state) {
					for (let item of this.items) {
						this.by.add(item);
					}
				}
				else {
					this.by.clear();
				}
			}
		});

		this.submit = new Command({
			execute: () => {
				const filter = this.model.filter;
				const by = clone(filter().by);
				const entries = this.entries;
				const items = flatten(Array.from(this.by).map(x => entries.get(x)));
				if (items.length) {
					by[this.key] = {items: items};
				}
				else {
					delete by[this.key];
				}

				filter({by: by});

				this.onSubmit();
			}
		});

		this.cancel = new Command({
			execute: () => this.onCancel()
		});

		this.reset = new Command({
			execute: () => {
				this.by = new Set([]);
				this.onReset();
			}
		});

		this.resetItems = new Command({
			execute: () => {
				this.items = [];
				this.vscrollContext.container.reset();
			}
		});

		this.vscrollContext = this.vscroll({
			fetch: (skip, take, d) => {
				if (!this.isReady()) {
					d.resolve(0);
					return;
				}

				const model = this.model;
				const filterState = model.filter();
				const service = this.qgrid.service(model);
				if (filterState.fetch !== noop) {
					const cancelBusy = service.busy();
					filterState
						.fetch(this.key, {
							value: this.getValue.bind(this),
							skip: skip,
							take: take,
							filter: this.filter
						})
						.then(items => {
							items.forEach(x => {
								this.items.push(x);
								this.entries.set(x, [x]);
							});

							d.resolve(this.items.length + take);
							cancelBusy();
						})
						.catch(cancelBusy);
				}
				else {
					const cancelBusy = service.busy();
					try {
						if (!this.items.length) {
							const source = model[model.columnFilter().source];
							const getValue = this.getValue;
							const getLabel = this.getLabel;
							const entries = this.entries;
							entries.clear();

							let uniqItems = [];
							source().rows.map(row => {
								const label = getLabel(row);
								let values;
								if (entries.has(label)) {
									values = entries.get(label);
								}
								else {
									values = [];
									entries.set(label, values);
									uniqItems.push(label);
								}

								const value = getValue(row);
								values.push(value);
							});

							const filter = this.$filter('filter');
							const filteredItems = filter(uniqItems, this.filter);
							filteredItems.sort();

							this.items = filteredItems;
						}

						d.resolve(this.items.length);
					}
					finally {
						cancelBusy();
					}
				}
			}
		});
	}

	onInit() {
		this.column = columnService.find(this.model.data().columns, this.key);
		this.getValue = valueFactory(this.column);
		this.getLabel = labelFactory(this.column);

		const filterBy = this.model.filter().by[this.key];
		this.by = new Set((filterBy && filterBy.items) || []);

		this.vscrollContext.settings.threshold = this.model.columnFilter().threshold;
		this.resetItems.execute();
	}

	state(item) {
		return this.by.has(item);
	}

	stateAll() {
		return this.items.every(this.state.bind(this));
	}

	isIndeterminate() {
		return !this.stateAll() && this.items.some(this.state.bind(this));
	}

	onReset() {
	}
}

export default ColumnFilterPanel.component({
	controller: ColumnFilterPanel,
	controllerAs: '$columnFilterPanel',
	bindings: {
		'onSubmit': '&',
		'onCancel': '&',
		'key': '<'
	}
});<commit_msg>restore values on column chooser open<commit_after>import PluginComponent from '../plugin.component';
import {Command} from '@grid/core/command';
import {clone, noop, flatten} from '@grid/core/utility';
import {getFactory as valueFactory} from '@grid/core/services/value';
import {getFactory as labelFactory} from '@grid/core/services/label';
import * as columnService from '@grid/core/column/column.service';

const Plugin = PluginComponent('column-filter-panel', {inject: ['vscroll', '$filter', 'qgrid']});
class ColumnFilterPanel extends Plugin {
	constructor() {
		super(...arguments);

		this.by = new Set();
		this.items = [];
		this.entries = new Map();

		this.toggle = new Command({
			execute: (item) => {
				if (this.by.has(item)) {
					this.by.delete(item);
				}
				else {
					this.by.add(item);
				}
			}
		});

		this.toggleAll = new Command({
			execute: () => {
				const state = !this.stateAll();
				if (state) {
					for (let item of this.items) {
						this.by.add(item);
					}
				}
				else {
					this.by.clear();
				}
			}
		});

		this.submit = new Command({
			execute: () => {
				const filter = this.model.filter;
				const by = clone(filter().by);
				const entries = this.entries;
				const items = flatten(Array.from(this.by).map(x => entries.get(x)));
				if (items.length) {
					by[this.key] = {items: items};
				}
				else {
					delete by[this.key];
				}

				filter({by: by});

				this.onSubmit();
			}
		});

		this.cancel = new Command({
			execute: () => this.onCancel()
		});

		this.reset = new Command({
			execute: () => {
				this.by = new Set([]);
				this.onReset();
			}
		});

		this.resetItems = new Command({
			execute: () => {
				this.items = [];
				this.vscrollContext.container.reset();
			}
		});

		this.vscrollContext = this.vscroll({
			fetch: (skip, take, d) => {
				if (!this.isReady()) {
					d.resolve(0);
					return;
				}

				const model = this.model;
				const filterState = model.filter();
				const service = this.qgrid.service(model);
				const filterBy = this.model.filter().by[this.key];
				const filterItems = (filterBy && filterBy.items) || [];
				const by = new Set(filterItems);
				if (filterState.fetch !== noop) {
					this.by = by;

					const cancelBusy = service.busy();
					filterState
						.fetch(this.key, {
							value: this.getValue.bind(this),
							skip: skip,
							take: take,
							filter: this.filter
						})
						.then(items => {
							items.forEach(x => {
								this.items.push(x);
								this.entries.set(x, [x]);
							});

							d.resolve(this.items.length + take);
							cancelBusy();
						})
						.catch(cancelBusy);
				}
				else {
					const cancelBusy = service.busy();
					try {
						if (!this.items.length) {
							const source = model[model.columnFilter().source];
							const getValue = this.getValue;
							const getLabel = this.getLabel;
							const entries = this.entries;
							entries.clear();

							const byItems = new Set();
							let uniqItems = [];
							source().rows.map(row => {
								const label = getLabel(row);
								let values;
								if (entries.has(label)) {
									values = entries.get(label);
								}
								else {
									values = [];
									entries.set(label, values);
									uniqItems.push(label);
								}

								const value = getValue(row);
								if (by.has(value)) {
									byItems.add(label);
								}

								values.push(value);
							});

							const filter = this.$filter('filter');
							const filteredItems = filter(uniqItems, this.filter);
							filteredItems.sort();

							this.items = filteredItems;
							this.by = byItems;
						}

						d.resolve(this.items.length);
					}
					finally {
						cancelBusy();
					}
				}
			}
		});
	}

	onInit() {
		this.column = columnService.find(this.model.data().columns, this.key);
		this.getValue = valueFactory(this.column);
		this.getLabel = labelFactory(this.column);

		this.vscrollContext.settings.threshold = this.model.columnFilter().threshold;
		this.resetItems.execute();
	}

	state(item) {
		return this.by.has(item);
	}

	stateAll() {
		return this.items.every(this.state.bind(this));
	}

	isIndeterminate() {
		return !this.stateAll() && this.items.some(this.state.bind(this));
	}

	onReset() {
	}
}

export default ColumnFilterPanel.component({
	controller: ColumnFilterPanel,
	controllerAs: '$columnFilterPanel',
	bindings: {
		'onSubmit': '&',
		'onCancel': '&',
		'key': '<'
	}
});<|endoftext|>


<commit_before>/**
 * jsPsych plugin for showing animations
 * Josh de Leeuw
 * updated January 2014
 *
 * shows a sequence of images at a fixed frame rate.
 * subject can respond with keys if desired.
 * entire animation sequence is recorded as JSON encoded string.
 * responses are tagged with rt and image that was onscreen.
 *
 * parameters:
 *      stimuli: array of arrays. inner arrays should consist of all the frames of the animation sequence. each inner array
 *                  corresponds to a single trial
 *      frame_time: how long to display each frame in ms.
 *      frame_isi: length of gap between successive frames.
 *      repetitions: how many times to show the animation sequence.
 *      choices: array of valid key responses during animation.
 *      timing_post_trial: how long to show a blank screen after the trial in ms.
 *      prompt: optional HTML string to display while the animation is playing
 *      data: optional data object
 *
 */

(function($) {
    jsPsych.animation = (function() {

        var plugin = {};

        plugin.create = function(params) {

            var trials = new Array(params.stimuli.length);
            for (var i = 0; i < trials.length; i++) {
                trials[i] = {};
                trials[i].type = "animation";
                trials[i].stims = params.stimuli[i];
                trials[i].frame_time = params.frame_time || 250;
                trials[i].frame_isi = params.frame_isi || 0;
                trials[i].repetitions = params.repetitions || 1;
                trials[i].choices = params.choices || [];
                trials[i].timing_post_trial = params.timing_post_trial || 1000;
                trials[i].prompt = (typeof params.prompt === 'undefined') ? "" : params.prompt;
                trials[i].data = (typeof params.data === 'undefined') ? {} : params.data[i];
            }
            return trials;
        };

        plugin.trial = function(display_element, block, trial, part) {
            var interval_time = trial.frame_time + trial.frame_isi;
            var animate_frame = -1;
            var reps = 0;
            var startTime = (new Date()).getTime();
            var animation_sequence = [];
            var responses = [];
            var current_stim = "";

            var animate_interval = setInterval(function() {
                var showImage = true;
                display_element.html(""); // clear everything
                animate_frame++;
                if (animate_frame == trial.stims.length) {
                    animate_frame = 0;
                    reps++;
                    if (reps >= trial.repetitions) {
                        endTrial();
                        clearInterval(animate_interval);
                        showImage = false;
                    }
                }
                if (showImage) {
                    show_next_frame();
                }
            }, interval_time);

            function show_next_frame() {
                // show image
                display_element.append($('<img>', {
                    "src": trial.stims[animate_frame],
                    "id": 'jspsych-animation-image'
                }));

                current_stim = trial.stims[animate_frame];

                // record when image was shown
                animation_sequence.push({
                    "stimulus": current_stim,
                    "time": (new Date()).getTime() - startTime
                });

                if (trial.prompt !== "") {
                    display_element.append(trial.prompt);
                }

                if (trial.frame_isi > 0) {
                    setTimeout(function() {
                        $('#jspsych-animation-image').css('visibility', 'hidden');
                        current_stim = 'blank';
                        // record when blank image was shown
                        animation_sequence.push({
                            "stimulus": 'blank',
                            "time": (new Date()).getTime() - startTime
                        });
                    }, trial.frame_time);
                }
            }

            var resp_func = function(e) {
                var flag = false;
                // check if the key is any of the options, or if it is an accidental keystroke
                for (var i = 0; i < trial.choices.length; i++) {
                    if (e.which == trial.choices[i]) {
                        flag = true;
                    }
                }
                if (flag) {
                    var key_press = e.which;

                    // record rt
                    var endTime = (new Date()).getTime();

                    responses.push({
                        "key_press": key_press,
                        "rt": endTime - startTime,
                        "stimulus": current_stim
                    });

                    // after a valid response, the stimulus will have the CSS class 'responded'
                    // which can be used to provide visual feedback that a response was recorded
                    $("#jspsych-animation-image").addClass('responded');
                }
            };

            $(document).keydown(resp_func);

            function endTrial() {
                 $(document).unbind('keydown', resp_func);

                block.writeData($.extend({}, {
                    "trial_type": "animation",
                    "trial_index": block.trial_idx,
                    "animation_sequence": JSON.stringify(animation_sequence),
                    "responses": JSON.stringify(responses)
                }, trial.data));

                setTimeout(function() {
                    block.next();
                }, trial.timing_post_trial);
            }
        };

        return plugin;
    })();
})(jQuery);
<commit_msg>fixing issues with 0 as timing parameter (#15)<commit_after>/**
 * jsPsych plugin for showing animations
 * Josh de Leeuw
 * updated January 2014
 *
 * shows a sequence of images at a fixed frame rate.
 * subject can respond with keys if desired.
 * entire animation sequence is recorded as JSON encoded string.
 * responses are tagged with rt and image that was onscreen.
 *
 * parameters:
 *      stimuli: array of arrays. inner arrays should consist of all the frames of the animation sequence. each inner array
 *                  corresponds to a single trial
 *      frame_time: how long to display each frame in ms.
 *      frame_isi: length of gap between successive frames.
 *      repetitions: how many times to show the animation sequence.
 *      choices: array of valid key responses during animation.
 *      timing_post_trial: how long to show a blank screen after the trial in ms.
 *      prompt: optional HTML string to display while the animation is playing
 *      data: optional data object
 *
 */

(function($) {
    jsPsych.animation = (function() {

        var plugin = {};

        plugin.create = function(params) {

            var trials = new Array(params.stimuli.length);
            for (var i = 0; i < trials.length; i++) {
                trials[i] = {};
                trials[i].type = "animation";
                trials[i].stims = params.stimuli[i];
                trials[i].frame_time = params.frame_time || 250;
                trials[i].frame_isi = params.frame_isi || 0;
                trials[i].repetitions = params.repetitions || 1;
                trials[i].choices = params.choices || [];
                trials[i].timing_post_trial = (typeof params.timing_post_trial === 'undefined') ? 1000 : params.timing_post_trial;
                trials[i].prompt = (typeof params.prompt === 'undefined') ? "" : params.prompt;
                trials[i].data = (typeof params.data === 'undefined') ? {} : params.data[i];
            }
            return trials;
        };

        plugin.trial = function(display_element, block, trial, part) {
            var interval_time = trial.frame_time + trial.frame_isi;
            var animate_frame = -1;
            var reps = 0;
            var startTime = (new Date()).getTime();
            var animation_sequence = [];
            var responses = [];
            var current_stim = "";

            var animate_interval = setInterval(function() {
                var showImage = true;
                display_element.html(""); // clear everything
                animate_frame++;
                if (animate_frame == trial.stims.length) {
                    animate_frame = 0;
                    reps++;
                    if (reps >= trial.repetitions) {
                        endTrial();
                        clearInterval(animate_interval);
                        showImage = false;
                    }
                }
                if (showImage) {
                    show_next_frame();
                }
            }, interval_time);

            function show_next_frame() {
                // show image
                display_element.append($('<img>', {
                    "src": trial.stims[animate_frame],
                    "id": 'jspsych-animation-image'
                }));

                current_stim = trial.stims[animate_frame];

                // record when image was shown
                animation_sequence.push({
                    "stimulus": current_stim,
                    "time": (new Date()).getTime() - startTime
                });

                if (trial.prompt !== "") {
                    display_element.append(trial.prompt);
                }

                if (trial.frame_isi > 0) {
                    setTimeout(function() {
                        $('#jspsych-animation-image').css('visibility', 'hidden');
                        current_stim = 'blank';
                        // record when blank image was shown
                        animation_sequence.push({
                            "stimulus": 'blank',
                            "time": (new Date()).getTime() - startTime
                        });
                    }, trial.frame_time);
                }
            }

            var resp_func = function(e) {
                var flag = false;
                // check if the key is any of the options, or if it is an accidental keystroke
                for (var i = 0; i < trial.choices.length; i++) {
                    if (e.which == trial.choices[i]) {
                        flag = true;
                    }
                }
                if (flag) {
                    var key_press = e.which;

                    // record rt
                    var endTime = (new Date()).getTime();

                    responses.push({
                        "key_press": key_press,
                        "rt": endTime - startTime,
                        "stimulus": current_stim
                    });

                    // after a valid response, the stimulus will have the CSS class 'responded'
                    // which can be used to provide visual feedback that a response was recorded
                    $("#jspsych-animation-image").addClass('responded');
                }
            };

            $(document).keydown(resp_func);

            function endTrial() {
                 $(document).unbind('keydown', resp_func);

                block.writeData($.extend({}, {
                    "trial_type": "animation",
                    "trial_index": block.trial_idx,
                    "animation_sequence": JSON.stringify(animation_sequence),
                    "responses": JSON.stringify(responses)
                }, trial.data));

                if(trial.timing_post_trial > 0){
                    setTimeout(function() {
                        block.next();
                    }, trial.timing_post_trial);
                } else {
                    block.next();
                }
            }
        };

        return plugin;
    })();
})(jQuery);
<|endoftext|>


<commit_before>function dataRequest(collumn, Gid){
    this.Gid = Gid || "none";
    this.collumn  = collumn || "none";
    this.request = new XMLHttpRequest();

    if(this.Gid == "none" && this.collumn == "none"){

        this.dataRequestID = "getDB.php"

    }else if(this.Gid != "none"){

        this.dataRequestID = "getDB.php?id=" + this.Gid;

    }else if(this.Gid == "none" && this.collumn != "none"){

        this.dataRequestID = "getDB.php?collumn=" + this.collumn;

    }else if(this.Gid != "none" && this.collumn != "none"){

        this.dataRequestID = "getDB.php?id=" + this.Gid + "&collumn=" + this.collumn;

    }
    this.request.open("GET",this.dataRequestID, true)

    this.request.addEventListener("load", function(){
        console.log(this.responseText);
    });

    this.request.send();

    console.log(this.dataRequestID);

    this.requestResponse = this.request.responseText;
}

var getUsers = new dataRequest("firstname");

    console.log(getUsers.requestResponse);

<commit_msg>fixed dataReq<commit_after>function dataRequest(collumn, Gid, callback){
    this.Gid = Gid || "none";
    this.collumn  = collumn || "none";
    this.request = new XMLHttpRequest();

    if(this.Gid == "none" && this.collumn == "none"){

        this.dataRequestID = "getDB.php"

    }else if(this.Gid != "none"){

        this.dataRequestID = "getDB.php?id=" + this.Gid;

    }else if(this.Gid == "none" && this.collumn != "none"){

        this.dataRequestID = "getDB.php?collumn=" + this.collumn;

    }else if(this.Gid != "none" && this.collumn != "none"){

        this.dataRequestID = "getDB.php?id=" + this.Gid + "&collumn=" + this.collumn;

    }
    this.request.open("GET",this.dataRequestID, true)

    this.request.addEventListener("load", function(){
        if(callback){
            callback(this.responseText);
        }
    });

    this.request.send();

    console.log(this.dataRequestID);

}

var getUsers = new dataRequest("firstname","" ,function(args){
    console.log(args)

});
    console.log(getUsers.requestResponse);

<|endoftext|>


<commit_before>import declare from 'dojo/_base/declare';
import array from 'dojo/_base/array';
import lang from 'dojo/_base/lang';
import aspect from 'dojo/aspect';
import GroupUtility from '../GroupUtility';
import _RightDrawerBaseMixin from './_RightDrawerBaseMixin';
import LookupField from 'argos/Fields/LookupField';
import getResource from 'argos/I18n';
import $ from 'jquery';

const resource = getResource('rightDrawerListMixin');

/**
 * @class crm.Views._RightDrawerListMixin
 *
 * List mixin for right drawers.
 *
 * @since 3.0
 * @mixins crm.Views._RightDrawerBaseMixin
 *
 */
const __class = declare('crm.Views._RightDrawerListMixin', [_RightDrawerBaseMixin], {
  // Localization
  hashTagsSectionText: resource.hashTagsSectionText,
  groupsSectionText: resource.groupsSectionText,
  kpiSectionText: resource.kpiSectionText,
  configureGroupsText: resource.configureGroupsText,
  refreshGroupsText: resource.refreshGroupsText,
  layoutsText: resource.layoutsText,

  _hasChangedKPIPrefs: false, // Dirty flag so we know when to reload the widgets
  _hashTagClicked: false,
  groupList: null,
  DRAWER_PAGESIZE: 100,
  groupLookupId: 'groups_configure',
  hasSettings: true,

  setupRightDrawer: function setupRightDrawer() {
    const drawer = App.getView('right_drawer');
    if (drawer) {
      drawer.pageSize = this.DRAWER_PAGESIZE;
      this.groupList = GroupUtility.getGroupPreferences(this.entityName);
      this._finishSetup(drawer);
    }
  },
  refreshRightDrawer: function refreshRightDrawer() {
    const drawer = App.getView('right_drawer');
    if (drawer) {
      drawer.clear();
      drawer.layout = null;
      drawer.setLayout(this.createRightDrawerLayout());
      drawer.refresh();
    }
  },
  _finishSetup: function _finishSetup(drawer) {
    lang.mixin(drawer, this._createActions());
    drawer.setLayout(this.createRightDrawerLayout());
    drawer.getGroupForEntry = function getGroupForEntry(entry) {
      return this.getGroupForRightDrawerEntry(entry);
    }.bind(this);

    if (this.rebuildWidgets) {
      App.viewSettingsModal.element.on('close', () => {
        if (this._hasChangedKPIPrefs) {
          this.destroyWidgets();

          // HACK: Don't rebuild widgets if a hashtag was clicked,
          // because the widget mixin will rebuild on a data refresh anyways.
          // TODO: Fix multiple calls to rebuildWidets() at the same time.
          if (!this._hashTagClicked) {
            this.rebuildWidgets();
          }
          this._hasChangedKPIPrefs = false;
        }

        // Reset state
        this._hashTagClicked = false;
      });
    }
  },
  unloadRightDrawer: function unloadRightDrawer() {
    const drawer = App.getView('right_drawer');
    if (drawer) {
      drawer.setLayout([]);
      drawer.getGroupForEntry = function getGroupForEntry() {};
      App.viewSettingsModal.element.off('close');
    }
  },
  _onSearchExpression: function _onSearchExpression() {
    // TODO: Don't extend this private function - connect to the search widget onSearchExpression instead
    if (this.groupsMode) {
      this._clearGroupMode();
    }

    this.inherited(arguments);
  },
  openSettings: function openSettings() {
    App.viewSettingsModal.open();
  },
  _createActions: function _createActions() {
    // These actions will get mixed into the right drawer view.
    const actions = {
      hashTagClicked: function hashTagClicked(params) {
        const { hashtag } = params;

        if (this.groupsMode) {
          this._clearGroupMode();
        }

        if (hashtag && typeof hashtag === 'string') {
          this._hashTagClicked = true;
          if (hashtag.startsWith('#')) {
            this.setSearchTerm(hashtag);
          } else {
            this.setSearchTerm(`#${hashtag}`);
          }

          this.search();
          App.viewSettingsModal.close();
        }
      }.bind(this),
      kpiClicked: function kpiClicked(params) {
        const metrics = App.getMetricsByResourceKind(this.resourceKind);
        let results;

        if (metrics.length > 0) {
          results = array.filter(metrics, (metric) => {
            return metric.title === unescape(params.title);
          });
        }

        if (results.length > 0) {
          const enabled = !!results[0].enabled;
          results[0].enabled = !enabled;
          App.persistPreferences();
          this._hasChangedKPIPrefs = true;

          $(params.$source).attr('data-enabled', (!enabled).toString());
        }
      }.bind(this),
      groupConfigureClicked: function groupConfigureClicked() {
        this._selectGroups();
        App.viewSettingsModal.close();
      }.bind(this),
      groupClicked: function groupClicked(params) {
        this._startGroupMode();
        const groupId = params.$key;

        const group = array.filter(this.groupList, (item) => {
          return item.$key === groupId;
        })[0];

        if (!group) {
          throw new Error('Expected a group.');
        }
        this.setCurrentGroup(group);
        this.refresh();
        App.viewSettingsModal.close();
      }.bind(this),
      layoutSelectedClicked: function layoutSelectedClicked(params) {
        const name = params.name;
        GroupUtility.setSelectedGroupLayoutTemplate(this.entityName, name);
        this._groupInitialized = false;
        this.refresh();
        App.viewSettingsModal.close();
      }.bind(this),

    };

    return actions;
  },
  _selectGroups: function _selectGroups() {
    const view = App.getView(this.groupLookupId);
    view.family = this.entityName;
    view.set('store', null);
    view.clear();
    view.refreshRequired = true;

    const field = new LookupField({
      owner: this,
      view,
      singleSelect: false,
      previousSelections: array.map(this.groupList, (group) => {
        return group.$key;
      }),
    });

    const handle = aspect.after(field, 'complete', function afterComplete() {
      const self = this;
      const list = this.owner;
      const items = [];

      // We will get an object back where the property names are the keys (groupId's)
      // Extract them out, and save the entry, which is the data property on the extracted object
      for (const groupId in self.currentValue) {
        if (self.currentValue.hasOwnProperty(groupId)) {
          const entry = self.currentValue[groupId].data;
          if (entry) {
            items.push(entry);
          }
        }
      }

      const hasDefaultGroup = list.hasDefaultGroup;
      GroupUtility.addToGroupPreferences(items, list.entityName, true);
      const currentGroup = GroupUtility.getDefaultGroup(list.entityName);
      if (currentGroup) {
        list.setCurrentGroup(currentGroup);
      }

      handle.remove();
      self.destroy();

      if (hasDefaultGroup) {
        // We will transition back to the list, pop back open the right drawer so the user is back where they started
        const processDataHandle = aspect.after(list, 'processData', function postProcessData() {
          App.viewSettingsModal.close();
          processDataHandle.remove();
          if (this.transitionHandle) {
            this.transitionHandle.remove();
          }
        }.bind(list));
      } else {
        // Since there was no previous default group, just refresh the list (no need to toggle the right drawer)
        this.transitionHandle = aspect.after(list, 'onTransitionTo', function postOnTransitionTo() {
          this.refreshRequired = true;
          this.clear();
          this.refresh();
          if (this.transitionHandle) {
            this.transitionHandle.remove();
          }
        }.bind(list));
      }
    }.bind(field));

    field.navigateToListView();
  },
  getGroupForRightDrawerEntry: function getGroupForRightDrawerEntry(entry) {
    if (entry.dataProps && entry.dataProps.hashtag && this._hasHashTags() && App.enableHashTags) {
      return {
        tag: 'view',
        title: resource.hashTagsSectionText,
      };
    }

    if ((entry.action === 'groupClicked' || entry.action === 'groupConfigureClicked') && this.groupsEnabled) {
      return {
        tag: 'group',
        title: resource.groupsSectionText,
      };
    }
    if ((entry.action === 'layoutSelectedClicked') && this.groupsEnabled) {
      return {
        tag: 'layoutTemplates',
        title: resource.layoutsText,
      };
    }
    return {
      tag: 'kpi',
      title: resource.kpiSectionText,
    };
  },
  createRightDrawerLayout: function createRightDrawerLayout() {
    const layout = [];

    if (this.groupsEnabled) {
      const groupsSection = {
        id: 'actions',
        children: [],
      };

      groupsSection.children.push({
        name: 'configureGroups',
        action: 'groupConfigureClicked',
        title: resource.configureGroupsText,
        cls: 'group-configuration',
        iconCls: 'fa fa-cog fa-fw ',
      });

      if (this.groupList && this.groupList.length > 0) {
        array.forEach(this.groupList, (group) => {
          groupsSection.children.push({
            name: group.name,
            action: 'groupClicked',
            title: group.displayName,
            dataProps: {
              $key: group.$key,
              title: group.displayName,
            },
          });
        });
      }
      const layoutSection = {
        id: 'actions',
        children: [],
      };
      if (this.groupTemplateLayouts && this.groupTemplateLayouts.length > 0) {
        array.forEach(this.groupTemplateLayouts, (theLayout) => {
          layoutSection.children.push({
            name: theLayout.name,
            action: 'layoutSelectedClicked',
            title: theLayout.displayName,
            dataProps: {
              name: theLayout.name,
              title: theLayout.displayName,
            },
          });
        });
      }

      if (this.entityName) {
        layout.push(groupsSection);
        layout.push(layoutSection);
      }
    }

    if (App.enableHashTags) {
      const hashTagsSection = {
        id: 'actions',
        children: [],
      };

      if (this._hasHashTags()) {
        const len = this.searchWidget.hashTagQueries.length;
        for (let i = 0; i < len; i++) {
          const hashTag = this.searchWidget.hashTagQueries[i];
          hashTagsSection.children.push({
            name: hashTag.key,
            action: 'hashTagClicked',
            title: hashTag.tag,
            dataProps: {
              hashtag: hashTag.tag,
            },
          });
        }
      }

      layout.push(hashTagsSection);
    }

    if (this.createMetricWidgetsLayout) {
      const metrics = App.getMetricsByResourceKind(this.resourceKind);

      const kpiSection = {
        id: 'kpi',
        children: [],
      };

      if (metrics.length > 0) {
        array.forEach(metrics, (metric, i) => {
          if (metric.title) {
            kpiSection.children.push({
              name: `KPI${i}`,
              action: 'kpiClicked',
              title: metric.title,
              dataProps: {
                title: escape(metric.title),
                enabled: !!metric.enabled,
              },
            });
          }
        });

        layout.push(kpiSection);
      }
    }

    return layout;
  },
  _hasHashTags: function _hasHashTags() {
    return this.searchWidget && this.searchWidget.hashTagQueries && this.searchWidget.hashTagQueries.length > 0;
  },
});

lang.setObject('Mobile.SalesLogix.Views._RightDrawerListMixin', __class);
export default __class;
<commit_msg>Add enabled attribute to selected group on list settings<commit_after>import declare from 'dojo/_base/declare';
import array from 'dojo/_base/array';
import lang from 'dojo/_base/lang';
import aspect from 'dojo/aspect';
import GroupUtility from '../GroupUtility';
import _RightDrawerBaseMixin from './_RightDrawerBaseMixin';
import LookupField from 'argos/Fields/LookupField';
import getResource from 'argos/I18n';
import $ from 'jquery';

const resource = getResource('rightDrawerListMixin');

/**
 * @class crm.Views._RightDrawerListMixin
 *
 * List mixin for right drawers.
 *
 * @since 3.0
 * @mixins crm.Views._RightDrawerBaseMixin
 *
 */
const __class = declare('crm.Views._RightDrawerListMixin', [_RightDrawerBaseMixin], {
  // Localization
  hashTagsSectionText: resource.hashTagsSectionText,
  groupsSectionText: resource.groupsSectionText,
  kpiSectionText: resource.kpiSectionText,
  configureGroupsText: resource.configureGroupsText,
  refreshGroupsText: resource.refreshGroupsText,
  layoutsText: resource.layoutsText,

  _hasChangedKPIPrefs: false, // Dirty flag so we know when to reload the widgets
  _hashTagClicked: false,
  groupList: null,
  DRAWER_PAGESIZE: 100,
  groupLookupId: 'groups_configure',
  hasSettings: true,

  setupRightDrawer: function setupRightDrawer() {
    const drawer = App.getView('right_drawer');
    if (drawer) {
      drawer.pageSize = this.DRAWER_PAGESIZE;
      this.groupList = GroupUtility.getGroupPreferences(this.entityName);
      this._finishSetup(drawer);
    }
  },
  refreshRightDrawer: function refreshRightDrawer() {
    const drawer = App.getView('right_drawer');
    if (drawer) {
      drawer.clear();
      drawer.layout = null;
      drawer.setLayout(this.createRightDrawerLayout());
      drawer.refresh();
    }
  },
  _finishSetup: function _finishSetup(drawer) {
    lang.mixin(drawer, this._createActions());
    drawer.setLayout(this.createRightDrawerLayout());
    drawer.getGroupForEntry = function getGroupForEntry(entry) {
      return this.getGroupForRightDrawerEntry(entry);
    }.bind(this);

    if (this.rebuildWidgets) {
      App.viewSettingsModal.element.on('close', () => {
        if (this._hasChangedKPIPrefs) {
          this.destroyWidgets();

          // HACK: Don't rebuild widgets if a hashtag was clicked,
          // because the widget mixin will rebuild on a data refresh anyways.
          // TODO: Fix multiple calls to rebuildWidets() at the same time.
          if (!this._hashTagClicked) {
            this.rebuildWidgets();
          }
          this._hasChangedKPIPrefs = false;
        }

        // Reset state
        this._hashTagClicked = false;
      });
    }
  },
  unloadRightDrawer: function unloadRightDrawer() {
    const drawer = App.getView('right_drawer');
    if (drawer) {
      drawer.setLayout([]);
      drawer.getGroupForEntry = function getGroupForEntry() {};
      App.viewSettingsModal.element.off('close');
    }
  },
  _onSearchExpression: function _onSearchExpression() {
    // TODO: Don't extend this private function - connect to the search widget onSearchExpression instead
    if (this.groupsMode) {
      this._clearGroupMode();
    }

    this.inherited(arguments);
  },
  openSettings: function openSettings() {
    App.viewSettingsModal.open();
  },
  _createActions: function _createActions() {
    // These actions will get mixed into the right drawer view.
    const actions = {
      hashTagClicked: function hashTagClicked(params) {
        const { hashtag } = params;

        if (this.groupsMode) {
          this._clearGroupMode();
        }

        if (hashtag && typeof hashtag === 'string') {
          this._hashTagClicked = true;
          if (hashtag.startsWith('#')) {
            this.setSearchTerm(hashtag);
          } else {
            this.setSearchTerm(`#${hashtag}`);
          }

          this.search();
          App.viewSettingsModal.close();
        }
      }.bind(this),
      kpiClicked: function kpiClicked(params) {
        const metrics = App.getMetricsByResourceKind(this.resourceKind);
        let results;

        if (metrics.length > 0) {
          results = array.filter(metrics, (metric) => {
            return metric.title === unescape(params.title);
          });
        }

        if (results.length > 0) {
          const enabled = !!results[0].enabled;
          results[0].enabled = !enabled;
          App.persistPreferences();
          this._hasChangedKPIPrefs = true;

          $(params.$source).attr('data-enabled', (!enabled).toString());
        }
      }.bind(this),
      groupConfigureClicked: function groupConfigureClicked() {
        this._selectGroups();
        App.viewSettingsModal.close();
      }.bind(this),
      groupClicked: function groupClicked(params) {
        this._startGroupMode();
        const groupId = params.$key;

        const group = array.filter(this.groupList, (item) => {
          return item.$key === groupId;
        })[0];

        if (!group) {
          throw new Error('Expected a group.');
        }
        this.setCurrentGroup(group);
        this.refresh();
        App.viewSettingsModal.close();
      }.bind(this),
      layoutSelectedClicked: function layoutSelectedClicked(params) {
        const name = params.name;
        $(params.$source.parentElement.parentElement).find('a').each((i, a) => {
          $(a).attr('data-enabled', (($(a).attr('data-name') === name)).toString());
        });

        GroupUtility.setSelectedGroupLayoutTemplate(this.entityName, name);
        this._groupInitialized = false;
        this.refresh();
        App.viewSettingsModal.close();
      }.bind(this),

    };

    return actions;
  },
  _selectGroups: function _selectGroups() {
    const view = App.getView(this.groupLookupId);
    view.family = this.entityName;
    view.set('store', null);
    view.clear();
    view.refreshRequired = true;

    const field = new LookupField({
      owner: this,
      view,
      singleSelect: false,
      previousSelections: array.map(this.groupList, (group) => {
        return group.$key;
      }),
    });

    const handle = aspect.after(field, 'complete', function afterComplete() {
      const self = this;
      const list = this.owner;
      const items = [];

      // We will get an object back where the property names are the keys (groupId's)
      // Extract them out, and save the entry, which is the data property on the extracted object
      for (const groupId in self.currentValue) {
        if (self.currentValue.hasOwnProperty(groupId)) {
          const entry = self.currentValue[groupId].data;
          if (entry) {
            items.push(entry);
          }
        }
      }

      const hasDefaultGroup = list.hasDefaultGroup;
      GroupUtility.addToGroupPreferences(items, list.entityName, true);
      const currentGroup = GroupUtility.getDefaultGroup(list.entityName);
      if (currentGroup) {
        list.setCurrentGroup(currentGroup);
      }

      handle.remove();
      self.destroy();

      if (hasDefaultGroup) {
        // We will transition back to the list, pop back open the right drawer so the user is back where they started
        const processDataHandle = aspect.after(list, 'processData', function postProcessData() {
          App.viewSettingsModal.close();
          processDataHandle.remove();
          if (this.transitionHandle) {
            this.transitionHandle.remove();
          }
        }.bind(list));
      } else {
        // Since there was no previous default group, just refresh the list (no need to toggle the right drawer)
        this.transitionHandle = aspect.after(list, 'onTransitionTo', function postOnTransitionTo() {
          this.refreshRequired = true;
          this.clear();
          this.refresh();
          if (this.transitionHandle) {
            this.transitionHandle.remove();
          }
        }.bind(list));
      }
    }.bind(field));

    field.navigateToListView();
  },
  getGroupForRightDrawerEntry: function getGroupForRightDrawerEntry(entry) {
    if (entry.dataProps && entry.dataProps.hashtag && this._hasHashTags() && App.enableHashTags) {
      return {
        tag: 'view',
        title: resource.hashTagsSectionText,
      };
    }

    if ((entry.action === 'groupClicked' || entry.action === 'groupConfigureClicked') && this.groupsEnabled) {
      return {
        tag: 'group',
        title: resource.groupsSectionText,
      };
    }
    if ((entry.action === 'layoutSelectedClicked') && this.groupsEnabled) {
      return {
        tag: 'layoutTemplates',
        title: resource.layoutsText,
      };
    }
    return {
      tag: 'kpi',
      title: resource.kpiSectionText,
    };
  },
  createRightDrawerLayout: function createRightDrawerLayout() {
    const layout = [];

    if (this.groupsEnabled) {
      const groupsSection = {
        id: 'actions',
        children: [],
      };

      groupsSection.children.push({
        name: 'configureGroups',
        action: 'groupConfigureClicked',
        title: resource.configureGroupsText,
        cls: 'group-configuration',
        iconCls: 'fa fa-cog fa-fw ',
      });

      if (this.groupList && this.groupList.length > 0) {
        array.forEach(this.groupList, (group) => {
          groupsSection.children.push({
            name: group.name,
            action: 'groupClicked',
            title: group.displayName,
            dataProps: {
              $key: group.$key,
              title: group.displayName,
            },
          });
        });
      }
      const layoutSection = {
        id: 'actions',
        children: [],
      };
      if (this.groupTemplateLayouts && this.groupTemplateLayouts.length > 0) {
        array.forEach(this.groupTemplateLayouts, (theLayout) => {
          layoutSection.children.push({
            name: theLayout.name,
            action: 'layoutSelectedClicked',
            title: theLayout.displayName,
            dataProps: {
              name: theLayout.name,
              title: theLayout.displayName,
              enabled: theLayout.name === App.preferences[`groups-selected-template-name${this.entityName}`],
            },
          });
        });
      }

      if (this.entityName) {
        layout.push(groupsSection);
        layout.push(layoutSection);
      }
    }

    if (App.enableHashTags) {
      const hashTagsSection = {
        id: 'actions',
        children: [],
      };

      if (this._hasHashTags()) {
        const len = this.searchWidget.hashTagQueries.length;
        for (let i = 0; i < len; i++) {
          const hashTag = this.searchWidget.hashTagQueries[i];
          hashTagsSection.children.push({
            name: hashTag.key,
            action: 'hashTagClicked',
            title: hashTag.tag,
            dataProps: {
              hashtag: hashTag.tag,
            },
          });
        }
      }

      layout.push(hashTagsSection);
    }

    if (this.createMetricWidgetsLayout) {
      const metrics = App.getMetricsByResourceKind(this.resourceKind);

      const kpiSection = {
        id: 'kpi',
        children: [],
      };

      if (metrics.length > 0) {
        array.forEach(metrics, (metric, i) => {
          if (metric.title) {
            kpiSection.children.push({
              name: `KPI${i}`,
              action: 'kpiClicked',
              title: metric.title,
              dataProps: {
                title: escape(metric.title),
                enabled: !!metric.enabled,
              },
            });
          }
        });

        layout.push(kpiSection);
      }
    }

    return layout;
  },
  _hasHashTags: function _hasHashTags() {
    return this.searchWidget && this.searchWidget.hashTagQueries && this.searchWidget.hashTagQueries.length > 0;
  },
});

lang.setObject('Mobile.SalesLogix.Views._RightDrawerListMixin', __class);
export default __class;
<|endoftext|>


<commit_before>mf.include("block_finder.js");
mf.include("navigator.js");
mf.include("auto_respawn.js");
mf.include("items.js");
mf.include("chat_commands.js");
mf.include("navigator_3d.js");
function() {
    var get_it;

    function go() {
        if (get_it === undefined) {
            return;
        }
        // FIND CAKE
        mf.chat("looking for " + get_it.name);
        var cake_pos_arr = block_finder.findNearest(mf.self().position.floored(), get_it.id, 64, 1);
        if (cake_pos_arr.length === 0) {
            mf.chat("can't find " + get_it.name);
        } else {
            // STAND ON THE CAKE
            var cake_pos = cake_pos_arr[0];
            navigator.navigateTo(cake_pos.offset(0, 1, 0), {
                "end_radius": 1,
                "arrived_func": function() {
                    // PUNCH THE CAKE
                    mf.onStoppedDigging(function got_it() {
                        mf.removeHandler(mf.onStoppedDigging, got_it);
                        mf.chat("take THAT "+ get_it.name + "!!");
                        go();
                    });
                    mf.startDigging(cake_pos);
                },
            });
        }
    }

    chat_commands.registerCommand("punch", function(username, args, responder_func) {
        get_it = items.findItemTypeUnambiguously(args[0]);
        if (get_it === undefined) {
            return;
        }
        go();
    }, 1);
    chat_commands.registerCommand("stop", function() {
        get_it = undefined;
        mf.stopDigging();
    });
}();
<commit_msg>Fixed cake_puncher<commit_after>mf.include("block_finder.js");
mf.include("navigator.js");
mf.include("auto_respawn.js");
mf.include("items.js");
mf.include("chat_commands.js");
mf.include("navigator_3d.js");
(function() {
    var get_it;

    function go() {
        if (get_it === undefined) {
            return;
        }
        // FIND CAKE
        mf.chat("looking for " + get_it.name);
        var cake_pos_arr = block_finder.findNearest(mf.self().position.floored(), get_it.id, 64, 1);
        if (cake_pos_arr.length === 0) {
            mf.chat("can't find " + get_it.name);
        } else {
            // STAND ON THE CAKE
            var cake_pos = cake_pos_arr[0];
            navigator.navigateTo(cake_pos.offset(0, 1, 0), {
                "end_radius": 1,
                "arrived_func": function() {
                    // PUNCH THE CAKE
                    mf.onStoppedDigging(function got_it() {
                        mf.removeHandler(mf.onStoppedDigging, got_it);
                        mf.chat("take THAT "+ get_it.name + "!!");
                        go();
                    });
                    mf.startDigging(cake_pos);
                },
            });
        }
    }

    chat_commands.registerCommand("punch", function(username, args, responder_func) {
        get_it = items.findItemTypeUnambiguously(args[0]);
        if (get_it === undefined) {
            return;
        }
        go();
    }, 1);
    chat_commands.registerCommand("stop", function() {
        get_it = undefined;
        mf.stopDigging();
    });
})();
<|endoftext|>


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

const minimum_character_length = 25;

// Variable to store user preferences
let userPreferences,
// A div that shows feedback of detected language:
    feedbackDiv = document.createElement("div"),
    // In this variable we keep a reference to the input element which the addon operates on currently
    currentInputElement,
    ignoreSignature;

// Initialize the feedback div. It has our unique id
feedbackDiv.id = "danielnaber-firefox-dict-switcher-tooltip";

// Listen to a message from the main script containing user preferences
self.port.on("config", function (prefs)
{
    // We require the presence of user preferences just to know the languages for which the user chosen "Don't
    // detect this language" option so that we disable spell checking if we encountered text in these languages
    userPreferences = prefs;
    ignoreSignature = userPreferences["ignoreSignature"];
});

// The main script sends this message after it receives the detected language code, and found the language dialect
// (ie. the dictionary) that will be used, or found that there's no dictionary for the detected language
// See the changeDictionary function in main.js
self.port.on("feedback", function (feedback)
{
    showFeedback(currentInputElement, feedback.language, feedback.message, feedback.isWarning);
});

function detectAndSetLanguage(targetElement, text)
{
    // If spell checking was disabled by the page developer, we honor the setting and don't set the value of
    // the spellcheck attribute to true, but we still try to detect the language and keep the ordinary operation
    // of the addon because the user can manually enable spell checking from the context menu, and the spellcheck
    // attribute stays false.
    // I set the developerDisabledSpellChecking to indicate this case
    // (see how the firefoxDictSwitcherDisabledSpellCheck flag is set later)
    // I use === because I'm not sure if this attribute accepts only booleans
    const developerDisabledSpellChecking = targetElement.spellcheck === false &&
                                          !targetElement.dataset.firefoxDictSwitcherDisabledSpellCheck;

    // text is an optional parameter used when handling the paste event only. Otherwise, we read the text from
    // the element itself
    text = text || targetElement.value || targetElement.textContent;

    if(ignoreSignature)
    {
        let signatureDelimiterPos = text.indexOf("-- \n");

        if(signatureDelimiterPos >= 0)
        {
            // cut off signature: it may be written in a different language than
            // the main text and would thus decrease language detection quality:
            text = text.substring(0, signatureDelimiterPos);
        }
    }

    // we are only going to check language if there is some amount of text available as
    // that will increase our chances of detecting language correctly.
    if(text.length > minimum_character_length)
    {
        //const startTime = performance.now();

        // Looks like we have enough text to reliably detect the language.
        guessLanguage.detect(text, function (language)
        {
            // The index of the dash character (-) in the language code (ex for en-US this will be 2)
            const dashIndex = language.indexOf("-"),
                languageOnlyCode = dashIndex < 0 ? language : language.substr(0, dashIndex);

            //console.log(`Detected language code is (${language}) in ${performance.now() - startTime} ms`);

            // If the language wasn't successfully identified
            if(language == "unknown")
                showFeedback(targetElement, "...", "Need more characters to detect language");
            // If the user chose to ignore the detected language (see the configs in package.json)
            else if(userPreferences[languageOnlyCode] == "-")
                showFeedback(targetElement, "--", "Detected " + languageOnlyCode + " but it's disabled in configuration");
            else
            {
                // We won't show the feedback tooltip until the main script sends us the language dialect that
                // will be used, and whether or not it found a dictionary for this dialect, so, keep a reference
                // for the input element the user currently edits so that we can show the feedback tooltip on it
                // later.
                // Notice that we are either passed targetElement as a parameter or use the current activeElement
                // (in case of paste events only)
                currentInputElement = targetElement || document.activeElement;

                // If the language was detected successfully enable spell checking and send its code to the main script
                if(!developerDisabledSpellChecking)
                {
                    // We enable spell checking only if the attribute wasn't already set to false be the page developer
                    targetElement.spellcheck = true;
                }

                self.port.emit("changeDictionary", language);

                return;
            }

            // Disable spell checking...
            targetElement.spellcheck = false;

            // ...send null to indicate to the main script that either we failed to detect or the language is disabled...
            //self.port.emit("changeDictionary", null);

            // ...and set a flag to indicate that it's our code who disabled spell checking not the page developer's
            // We do so only if the attribute wasn't already set to false be the page developer
            if(!developerDisabledSpellChecking)
                targetElement.dataset.firefoxDictSwitcherDisabledSpellCheck = "1";
        });
    }
    else
    {
        showFeedback(targetElement, "...", "Need more characters to detect language");

        // Because we can't detect the language, disable spell checking
        targetElement.spellcheck = false;

        // Sending null to the main script also indicates that the input text is too short to detect the language
        self.port.emit("changeDictionary", null);

        // And set a flag to indicate that it's our code who disabled spell checking not the page developer's
        // We do so only if the attribute wasn't already set to false be the page developer
        if(!developerDisabledSpellChecking)
            targetElement.dataset.firefoxDictSwitcherDisabledSpellCheck = "1";
    }
}

function showFeedback(element, feedbackText, feedbackTitle, isWarning)
{
    // Detach the feedback div from the document if it were previously attached
    if(feedbackDiv.parentElement)
        feedbackDiv.parentElement.removeChild(feedbackDiv);

    const parentElement = element.offsetParent;

    // offsetParent is null if the element itself is hidden. If the element is hidden we exit as, of course,
    // we won't show feedback on a hidden element
    if(!parentElement)
        return;

    currentInputElement = element;

    feedbackDiv.title = feedbackTitle;
    feedbackDiv.textContent = feedbackText;

    if(isWarning)
        feedbackDiv.classList.add("firefox-dict-switcher-warning");
    else
        feedbackDiv.classList.remove("firefox-dict-switcher-warning");

    parentElement.appendChild(feedbackDiv);

    // Initialize the positioning loop
    requestAnimationFrame(positionFeedbackDiv);
}

// This function keeps the feedback div always positioned properly relative to
function positionFeedbackDiv()
{
    const parentElement = feedbackDiv.parentElement;

    if(!parentElement)
        return;

    const leftPos = currentInputElement.offsetLeft + currentInputElement.offsetWidth - feedbackDiv.offsetWidth - 18,
          topPos = currentInputElement.offsetTop + currentInputElement.offsetHeight - feedbackDiv.offsetHeight - 5;

    feedbackDiv.style.left = leftPos + "px";
    feedbackDiv.style.top = topPos + "px";

    // Keep the loop going
    requestAnimationFrame(positionFeedbackDiv);
}

function isEligible(element)
{
    // The addon operates only on textarea elements or elements with the contenteditable attribute set
    return element.tagName == "TEXTAREA" ||
           element.contentEditable === 'true';   // TODO: this can be 'inherit', we need the real value
}

// Note from Ashraf: I commented the old code that initially iterates over all TEXTAREA elements and instead
// used event delegation by attaching event handlers only to the root element. This is better for performance
// and covers the elements that are later appended to the DOM
document.documentElement.addEventListener("keydown", function (evt)
{
    if(isEligible(evt.target))
    {
        var key = evt.keyCode || evt.charCode;

        // check if user has finished entering a word
        if(key == 32/*space*/ || key == 188/*comma*/ || key == 190/*dot*/)
        {
            detectAndSetLanguage(evt.target);
        }
    }
});

// HACK: The focus event doesn't bubble, so I set the useCapture parameter of addEventListener to true.
// We should use the focusin event which bubbles but it's not supported on Firefox as of the date I wrote this.
// See the note on this article https://developer.mozilla.org/en-US/docs/Web/Events/focusin
document.documentElement.addEventListener("focus", function (evt)
{
    // Set correct language when we set the focus to already filled textarea
    if(isEligible(evt.target))
        detectAndSetLanguage(evt.target);
}, true);

// HACK: The blur event doesn't bubble, so I set the useCapture parameter of addEventListener to true.
// We should use the focusout event which bubbles but it's not supported on Firefox as of the date I wrote this.
// See the note on this article https://developer.mozilla.org/en-US/docs/Web/Events/focusout
document.documentElement.addEventListener("blur", function (evt)
{
    // When the focus gets out of an element, detach the feedback div from the document
    if(feedbackDiv.parentElement)
        feedbackDiv.parentElement.removeChild(feedbackDiv);
}, true);

document.documentElement.addEventListener("paste", function (e)
{
    // We act only when data is pasted on a TEXTAREA element
    if(isEligible(e.target))
    {
        // We try to detect only if the pasted data is available in plain text format
        const text = e.clipboardData.getData("text/plain");

        if(text)
            detectAndSetLanguage(e.target, text);
    }
});<commit_msg>remove incorrect TODO (if the contentEditable value is just inherited, we get 'true' automatically)<commit_after>//   Automatic Dictionary Switcher Add-on for Firefox
//   Copyright 2015 Daniel Naber
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

const minimum_character_length = 25;

// Variable to store user preferences
let userPreferences,
// A div that shows feedback of detected language:
    feedbackDiv = document.createElement("div"),
    // In this variable we keep a reference to the input element which the addon operates on currently
    currentInputElement,
    ignoreSignature;

// Initialize the feedback div. It has our unique id
feedbackDiv.id = "danielnaber-firefox-dict-switcher-tooltip";

// Listen to a message from the main script containing user preferences
self.port.on("config", function (prefs)
{
    // We require the presence of user preferences just to know the languages for which the user chosen "Don't
    // detect this language" option so that we disable spell checking if we encountered text in these languages
    userPreferences = prefs;
    ignoreSignature = userPreferences["ignoreSignature"];
});

// The main script sends this message after it receives the detected language code, and found the language dialect
// (ie. the dictionary) that will be used, or found that there's no dictionary for the detected language
// See the changeDictionary function in main.js
self.port.on("feedback", function (feedback)
{
    showFeedback(currentInputElement, feedback.language, feedback.message, feedback.isWarning);
});

function detectAndSetLanguage(targetElement, text)
{
    // If spell checking was disabled by the page developer, we honor the setting and don't set the value of
    // the spellcheck attribute to true, but we still try to detect the language and keep the ordinary operation
    // of the addon because the user can manually enable spell checking from the context menu, and the spellcheck
    // attribute stays false.
    // I set the developerDisabledSpellChecking to indicate this case
    // (see how the firefoxDictSwitcherDisabledSpellCheck flag is set later)
    // I use === because I'm not sure if this attribute accepts only booleans
    const developerDisabledSpellChecking = targetElement.spellcheck === false &&
                                          !targetElement.dataset.firefoxDictSwitcherDisabledSpellCheck;

    // text is an optional parameter used when handling the paste event only. Otherwise, we read the text from
    // the element itself
    text = text || targetElement.value || targetElement.textContent;

    if(ignoreSignature)
    {
        let signatureDelimiterPos = text.indexOf("-- \n");

        if(signatureDelimiterPos >= 0)
        {
            // cut off signature: it may be written in a different language than
            // the main text and would thus decrease language detection quality:
            text = text.substring(0, signatureDelimiterPos);
        }
    }

    // we are only going to check language if there is some amount of text available as
    // that will increase our chances of detecting language correctly.
    if(text.length > minimum_character_length)
    {
        //const startTime = performance.now();

        // Looks like we have enough text to reliably detect the language.
        guessLanguage.detect(text, function (language)
        {
            // The index of the dash character (-) in the language code (ex for en-US this will be 2)
            const dashIndex = language.indexOf("-"),
                languageOnlyCode = dashIndex < 0 ? language : language.substr(0, dashIndex);

            //console.log(`Detected language code is (${language}) in ${performance.now() - startTime} ms`);

            // If the language wasn't successfully identified
            if(language == "unknown")
                showFeedback(targetElement, "...", "Need more characters to detect language");
            // If the user chose to ignore the detected language (see the configs in package.json)
            else if(userPreferences[languageOnlyCode] == "-")
                showFeedback(targetElement, "--", "Detected " + languageOnlyCode + " but it's disabled in configuration");
            else
            {
                // We won't show the feedback tooltip until the main script sends us the language dialect that
                // will be used, and whether or not it found a dictionary for this dialect, so, keep a reference
                // for the input element the user currently edits so that we can show the feedback tooltip on it
                // later.
                // Notice that we are either passed targetElement as a parameter or use the current activeElement
                // (in case of paste events only)
                currentInputElement = targetElement || document.activeElement;

                // If the language was detected successfully enable spell checking and send its code to the main script
                if(!developerDisabledSpellChecking)
                {
                    // We enable spell checking only if the attribute wasn't already set to false be the page developer
                    targetElement.spellcheck = true;
                }

                self.port.emit("changeDictionary", language);

                return;
            }

            // Disable spell checking...
            targetElement.spellcheck = false;

            // ...send null to indicate to the main script that either we failed to detect or the language is disabled...
            //self.port.emit("changeDictionary", null);

            // ...and set a flag to indicate that it's our code who disabled spell checking not the page developer's
            // We do so only if the attribute wasn't already set to false be the page developer
            if(!developerDisabledSpellChecking)
                targetElement.dataset.firefoxDictSwitcherDisabledSpellCheck = "1";
        });
    }
    else
    {
        showFeedback(targetElement, "...", "Need more characters to detect language");

        // Because we can't detect the language, disable spell checking
        targetElement.spellcheck = false;

        // Sending null to the main script also indicates that the input text is too short to detect the language
        self.port.emit("changeDictionary", null);

        // And set a flag to indicate that it's our code who disabled spell checking not the page developer's
        // We do so only if the attribute wasn't already set to false be the page developer
        if(!developerDisabledSpellChecking)
            targetElement.dataset.firefoxDictSwitcherDisabledSpellCheck = "1";
    }
}

function showFeedback(element, feedbackText, feedbackTitle, isWarning)
{
    // Detach the feedback div from the document if it were previously attached
    if(feedbackDiv.parentElement)
        feedbackDiv.parentElement.removeChild(feedbackDiv);

    const parentElement = element.offsetParent;

    // offsetParent is null if the element itself is hidden. If the element is hidden we exit as, of course,
    // we won't show feedback on a hidden element
    if(!parentElement)
        return;

    currentInputElement = element;

    feedbackDiv.title = feedbackTitle;
    feedbackDiv.textContent = feedbackText;

    if(isWarning)
        feedbackDiv.classList.add("firefox-dict-switcher-warning");
    else
        feedbackDiv.classList.remove("firefox-dict-switcher-warning");

    parentElement.appendChild(feedbackDiv);

    // Initialize the positioning loop
    requestAnimationFrame(positionFeedbackDiv);
}

// This function keeps the feedback div always positioned properly relative to
function positionFeedbackDiv()
{
    const parentElement = feedbackDiv.parentElement;

    if(!parentElement)
        return;

    const leftPos = currentInputElement.offsetLeft + currentInputElement.offsetWidth - feedbackDiv.offsetWidth - 18,
          topPos = currentInputElement.offsetTop + currentInputElement.offsetHeight - feedbackDiv.offsetHeight - 5;

    feedbackDiv.style.left = leftPos + "px";
    feedbackDiv.style.top = topPos + "px";

    // Keep the loop going
    requestAnimationFrame(positionFeedbackDiv);
}

function isEligible(element)
{
    // The addon operates only on textarea elements or elements with the contenteditable attribute set
    return element.tagName == "TEXTAREA" ||
           element.contentEditable === 'true';
}

// Note from Ashraf: I commented the old code that initially iterates over all TEXTAREA elements and instead
// used event delegation by attaching event handlers only to the root element. This is better for performance
// and covers the elements that are later appended to the DOM
document.documentElement.addEventListener("keydown", function (evt)
{
    if(isEligible(evt.target))
    {
        var key = evt.keyCode || evt.charCode;

        // check if user has finished entering a word
        if(key == 32/*space*/ || key == 188/*comma*/ || key == 190/*dot*/)
        {
            detectAndSetLanguage(evt.target);
        }
    }
});

// HACK: The focus event doesn't bubble, so I set the useCapture parameter of addEventListener to true.
// We should use the focusin event which bubbles but it's not supported on Firefox as of the date I wrote this.
// See the note on this article https://developer.mozilla.org/en-US/docs/Web/Events/focusin
document.documentElement.addEventListener("focus", function (evt)
{
    // Set correct language when we set the focus to already filled textarea
    if(isEligible(evt.target))
        detectAndSetLanguage(evt.target);
}, true);

// HACK: The blur event doesn't bubble, so I set the useCapture parameter of addEventListener to true.
// We should use the focusout event which bubbles but it's not supported on Firefox as of the date I wrote this.
// See the note on this article https://developer.mozilla.org/en-US/docs/Web/Events/focusout
document.documentElement.addEventListener("blur", function (evt)
{
    // When the focus gets out of an element, detach the feedback div from the document
    if(feedbackDiv.parentElement)
        feedbackDiv.parentElement.removeChild(feedbackDiv);
}, true);

document.documentElement.addEventListener("paste", function (e)
{
    // We act only when data is pasted on a TEXTAREA element
    if(isEligible(e.target))
    {
        // We try to detect only if the pasted data is available in plain text format
        const text = e.clipboardData.getData("text/plain");

        if(text)
            detectAndSetLanguage(e.target, text);
    }
});<|endoftext|>


<commit_before>define(function (require) {
  require("jquery");
  var Utils = require("core/Utils");
  var Locale = require("core/Locale");
  var Inherits = require("core/Inherits");
  var Class = require("core/Class");
  var Primitive = require("core/Primitive");
  var Storage = require("core/Storage");
  var Dialog = require("core/Dialog");
  var Menu = require("core/Control/Menu");
  var Grid= require("core/Control/Grid");
  var List = require("core/Control/List");
  var DivButton = require("core/Control/DivButton");
  var Field = require("core/Control/Field/Field");

  function save_as_draft(self, list) {
    var data = {};
    list.data().forEach(function (item) {
      data[item.locale] = item.value;
    });
    self._draft = data;
    self.refresh();
  }

  function show_languages_dialog(self, locale, locales, columns, caption, src_items) {
    if (!self._draft) {
      self._draft = !self._value ? {} : self._value;
    }
    var items = Object.keys(self._draft).map(function(locale_id) { return { "id" : locale_id, "locale": locale_id, "value" : self._draft[locale_id] }; });
    var menu_items = null;
    var list = new List();
    var dialog = new Dialog();
    dialog.init(function(contents_id) {
      return list.init("#" + contents_id, { class_id : self.detail_id(), embedded : true, width : null, height : null});
    })
    .then(function () {
      return Menu.convert(src_items, list).done(function(dst_items) { menu_items = dst_items; });
    })
    .then(function () {
      list.items(menu_items);
      list.data(items);
      list.edit(true);
      list.refresh();
    })
    .then(function () {
      dialog.title(caption);
      dialog.buttons([
        { text: "OK",    click:function (event) { save_as_draft(self, list); dialog.close(); } },
        { text:"Cancel", click:function (event) { dialog.close(); }}
      ]);
      dialog.size(400, 300);
      dialog.open();
    });
  }

  function Text() {
    Field.call(this, "core/Control/Field", "Text");
    this._input = null;
    this._value = null;
    this._draft = null;
    this._properties = null;
    this._button = null;
  };
  Inherits(Text, Field);

  Text.prototype.template = function() {
    return '
<input style="color:black;"/>

';
  };

  Text.prototype.create_form = function(root, field_name) {
    this._input = root.find('input');
    this._input.attr("name", field_name);
    this._input.css("width", this._properties.width);
    this._input.w2field("text");
  };

  Text.DEFAULT_PROPERTIES = { "width" : 200, "is_require" : false, "default" : "", "multi_lingualization" : false };
  Text.prototype.default_properties = function() {
    return Text.DEFAULT_PROPERTIES;
  };

  Text.prototype.detail_id = function() {
    return Class.TEXT_MULTILINGUALIZATION_ID;
  };

  Text.prototype.init = function(selector, field) {
    var dfd = new $.Deferred;

    var root = $(selector);
    root.append(this.template());

    // properties
    this._properties = Utils.get_as_json(
      this.default_properties(),
      function() { return field.datatype.properties; },
      false);
    var self = this;

    // Input
    this.create_form(root, field.name);

    // If *NOT* multi-lingualize, do not create Button
    if (!self._properties.multi_lingualization) {
      dfd.resolve();
      return dfd.promise();
    }

    // Get Locale data
    var locale = null;
    var locales = null;
    var field_map = null;
    var columns = null;
    var src_actions = null;
    var class_ = null;
    $.when(
      Storage.read(Class.CLASS_ID, Class.LOCALE_ID).done(function(data) { locale = data; }),
      Storage.read(Class.LOCALE_ID).then(function(objects) { locales = objects; }),
      Storage.read(Primitive.ID, field.datatype.id).done(function(object) { class_ = object; })
    )
    .then(function () {
      return Class.field_map(locale).then(function (field_map_) { field_map = field_map_; });
    })
    .then(function () {
      columns = Grid.columns(locale, field_map);
    })
    .then(function () {
      var prop_array = Utils.get_as_json(
        [],
        function() { return class_.static_properties; },
        false);
      var prop_map = {};
      prop_array.forEach(function (prop) { prop_map[prop.name] = prop; });
      //class_.static_properties.forEach(function (prop) { prop_map[prop.name] = prop; });
      var actions_field = prop_map["multi_lingualization_actions"];
      if (!actions_field) {
        return;
      }
      src_items = actions_field.datatype.properties.toolbar_items;
      return;
    })
    .then(function () {
      // Button
      var button_selector = selector + " > div > div[name='button']";
      self._button = new DivButton();
      return self._button.init(button_selector, '', function (event) {
        show_languages_dialog(self, locale, locales, columns, Locale.translate(field.label), src_items);
      });
    })
    .then(function () {
      self._button.visible(false);
      dfd.resolve();
    });

    return dfd.promise();
  };

  Text.prototype.backup = function() {
    return this._value;
  };

  Text.prototype.commit = function() {
    if (!this._properties.multi_lingualization) {
      this._value = this._input.val();
      return;
    }
    this._value = !this._draft ? {} : this._draft;
  };

  Text.prototype.restore = function() {
    if (!this._properties.multi_lingualization) {
      this._input.val(this._value);
      return;
    }
    this._draft = this._value;
  };

  Text.prototype.edit = function(on) {
    if (!this._button) {
      this._input.attr("readonly", !on);
      return;
    } else {
      this._input.attr("readonly", !on);
      this._button.visible(on);
    }
  };

  Text.prototype.data = function(value) {
    var multi = this._properties.multi_lingualization;
    // getter
    if (arguments.length == 0) {
      // Not Multi Lingualized
      if (!multi) {
        return this._input.val();
      }
      // Multi Lingualized
      var draft = !this._draft ? {} : this._draft;
      var lang = Locale.language();
      if (lang != "") {
        draft[lang] = this._input.val();
      }
      var default_value = draft[""];
      if (!default_value || default_value == "") {
        draft[""] = this._input.val();
      }
      return draft;
    }
    // setter
    if (!multi) {
      this._value = is_object(value) ? value[""] : value;
    } else {
      this._value = is_object(value) ? value : { "" : value };
    }
    this._draft = this._value;
    this._input.val(!multi ? this._value : Locale.translate(this._value));
  };

  Text.prototype.refresh = function() {
    var multi = this._properties.multi_lingualization;
    if (!multi) {
      return;
    }
    this._input.val(Locale.translate(this._draft));
  };

  Text.generate_renderer = function(default_properties, field) {
    var props = Utils.get_as_json(default_properties, function() { return field.datatype.properties; });

    var dfd = new $.Deferred;
    var renderer = function(record, index, column_index) {
      var value = record[field.name];
      if (is_object(value) && props.multi_lingualization) {
        return Locale.translate(value);
      } else {
        return value;
      }
    };
    dfd.resolve(renderer);
    return dfd.promise();
  };

  Text.renderer = function(field) {
    return Text.generate_renderer(Text.DEFAULT_PROPERTIES, field);
  };

  Text.comparer = function(field) {
    function compare(rec1, rec2) {
      var value1 = Locale.translate(rec1[field.name]);
      var value2 = Locale.translate(rec2[field.name]);
      if (value1 === value2) {
        return 0;
      }
      return value1 < value2 ? -1 : 1;
    }
    var dfd = new $.Deferred;
    dfd.resolve(compare);
    return dfd.promise();
  };
  return Text;
});
<commit_msg>Modified property name from "locale" to "language".<commit_after>define(function (require) {
  require("jquery");
  var Utils = require("core/Utils");
  var Locale = require("core/Locale");
  var Inherits = require("core/Inherits");
  var Class = require("core/Class");
  var Primitive = require("core/Primitive");
  var Storage = require("core/Storage");
  var Dialog = require("core/Dialog");
  var Menu = require("core/Control/Menu");
  var Grid= require("core/Control/Grid");
  var List = require("core/Control/List");
  var DivButton = require("core/Control/DivButton");
  var Field = require("core/Control/Field/Field");

  function save_as_draft(self, list) {
    var data = {};
    list.data().forEach(function (item) {
      data[item.language] = item.value;
    });
    self._draft = data;
    self.refresh();
  }

  function show_languages_dialog(self, locale, locales, columns, caption, src_items) {
    if (!self._draft) {
      self._draft = !self._value ? {} : self._value;
    }
    var items = Object.keys(self._draft).map(function(language_code) { return { "id" : language_code, "language": language_code, "value" : self._draft[language_code] }; });
    var menu_items = null;
    var list = new List();
    var dialog = new Dialog();
    dialog.init(function(contents_id) {
      return list.init("#" + contents_id, { class_id : self.detail_id(), embedded : true, width : null, height : null});
    })
    .then(function () {
      return Menu.convert(src_items, list).done(function(dst_items) { menu_items = dst_items; });
    })
    .then(function () {
      list.items(menu_items);
      list.data(items);
      list.edit(true);
      list.refresh();
    })
    .then(function () {
      dialog.title(caption);
      dialog.buttons([
        { text: "OK",    click:function (event) { save_as_draft(self, list); dialog.close(); } },
        { text:"Cancel", click:function (event) { dialog.close(); }}
      ]);
      dialog.size(400, 300);
      dialog.open();
    });
  }

  function Text() {
    Field.call(this, "core/Control/Field", "Text");
    this._input = null;
    this._value = null;
    this._draft = null;
    this._properties = null;
    this._button = null;
  };
  Inherits(Text, Field);

  Text.prototype.template = function() {
    return '
<input style="color:black;"/>

';
  };

  Text.prototype.create_form = function(root, field_name) {
    this._input = root.find('input');
    this._input.attr("name", field_name);
    this._input.css("width", this._properties.width);
    this._input.w2field("text");
  };

  Text.DEFAULT_PROPERTIES = { "width" : 200, "is_require" : false, "default" : "", "multi_lingualization" : false };
  Text.prototype.default_properties = function() {
    return Text.DEFAULT_PROPERTIES;
  };

  Text.prototype.detail_id = function() {
    return Class.TEXT_MULTILINGUALIZATION_ID;
  };

  Text.prototype.init = function(selector, field) {
    var dfd = new $.Deferred;

    var root = $(selector);
    root.append(this.template());

    // properties
    this._properties = Utils.get_as_json(
      this.default_properties(),
      function() { return field.datatype.properties; },
      false);
    var self = this;

    // Input
    this.create_form(root, field.name);

    // If *NOT* multi-lingualize, do not create Button
    if (!self._properties.multi_lingualization) {
      dfd.resolve();
      return dfd.promise();
    }

    // Get Locale data
    var locale = null;
    var locales = null;
    var field_map = null;
    var columns = null;
    var src_actions = null;
    var class_ = null;
    $.when(
      Storage.read(Class.CLASS_ID, Class.LOCALE_ID).done(function(data) { locale = data; }),
      Storage.read(Class.LOCALE_ID).then(function(objects) { locales = objects; }),
      Storage.read(Primitive.ID, field.datatype.id).done(function(object) { class_ = object; })
    )
    .then(function () {
      return Class.field_map(locale).then(function (field_map_) { field_map = field_map_; });
    })
    .then(function () {
      columns = Grid.columns(locale, field_map);
    })
    .then(function () {
      var prop_array = Utils.get_as_json(
        [],
        function() { return class_.static_properties; },
        false);
      var prop_map = {};
      prop_array.forEach(function (prop) { prop_map[prop.name] = prop; });
      //class_.static_properties.forEach(function (prop) { prop_map[prop.name] = prop; });
      var actions_field = prop_map["multi_lingualization_actions"];
      if (!actions_field) {
        return;
      }
      src_items = actions_field.datatype.properties.toolbar_items;
      return;
    })
    .then(function () {
      // Button
      var button_selector = selector + " > div > div[name='button']";
      self._button = new DivButton();
      return self._button.init(button_selector, '', function (event) {
        show_languages_dialog(self, locale, locales, columns, Locale.translate(field.label), src_items);
      });
    })
    .then(function () {
      self._button.visible(false);
      dfd.resolve();
    });

    return dfd.promise();
  };

  Text.prototype.backup = function() {
    return this._value;
  };

  Text.prototype.commit = function() {
    if (!this._properties.multi_lingualization) {
      this._value = this._input.val();
      return;
    }
    this._value = !this._draft ? {} : this._draft;
  };

  Text.prototype.restore = function() {
    if (!this._properties.multi_lingualization) {
      this._input.val(this._value);
      return;
    }
    this._draft = this._value;
  };

  Text.prototype.edit = function(on) {
    if (!this._button) {
      this._input.attr("readonly", !on);
      return;
    } else {
      this._input.attr("readonly", !on);
      this._button.visible(on);
    }
  };

  Text.prototype.data = function(value) {
    var multi = this._properties.multi_lingualization;
    // getter
    if (arguments.length == 0) {
      // Not Multi Lingualized
      if (!multi) {
        return this._input.val();
      }
      // Multi Lingualized
      var draft = !this._draft ? {} : this._draft;
      var lang = Locale.language();
      if (lang != "") {
        draft[lang] = this._input.val();
      }
      var default_value = draft[""];
      if (!default_value || default_value == "") {
        draft[""] = this._input.val();
      }
      return draft;
    }
    // setter
    if (!multi) {
      this._value = is_object(value) ? value[""] : value;
    } else {
      this._value = is_object(value) ? value : { "" : value };
    }
    this._draft = this._value;
    this._input.val(!multi ? this._value : Locale.translate(this._value));
  };

  Text.prototype.refresh = function() {
    var multi = this._properties.multi_lingualization;
    if (!multi) {
      return;
    }
    this._input.val(Locale.translate(this._draft));
  };

  Text.generate_renderer = function(default_properties, field) {
    var props = Utils.get_as_json(default_properties, function() { return field.datatype.properties; });

    var dfd = new $.Deferred;
    var renderer = function(record, index, column_index) {
      var value = record[field.name];
      if (is_object(value) && props.multi_lingualization) {
        return Locale.translate(value);
      } else {
        return value;
      }
    };
    dfd.resolve(renderer);
    return dfd.promise();
  };

  Text.renderer = function(field) {
    return Text.generate_renderer(Text.DEFAULT_PROPERTIES, field);
  };

  Text.comparer = function(field) {
    function compare(rec1, rec2) {
      var value1 = Locale.translate(rec1[field.name]);
      var value2 = Locale.translate(rec2[field.name]);
      if (value1 === value2) {
        return 0;
      }
      return value1 < value2 ? -1 : 1;
    }
    var dfd = new $.Deferred;
    dfd.resolve(compare);
    return dfd.promise();
  };
  return Text;
});
<|endoftext|>


<commit_before>/* global ODSA, ClickHandler */
(function ($) {
  "use strict";
  var arraySize = 10,
    initialArray,
    initialTempArray,
    barArray,
    tempArray,
    $arrayLabel,
    $tempLabel,
    pseudo,
    interpret,
    clickHandler,
    config = ODSA.UTILS.loadLangData({'av_container': 'jsavcontainer'}),
    av = new JSAV($("#jsavcontainer"));

  av.recorded(); // we are not recording an AV with an algorithm

  // set title and instructions in the chosen language
// ODSA.AV.setTitleAndInstructions(av.container, config.language);

  // create interpreter function
  interpret = config.interpreter;

  function initialize() {

    // show the code
    if (!pseudo && config.code) {
      pseudo = av.code($.extend({after: {element: $(".instructions")}, visible: true}, config.code));
      pseudo.highlight(config.code.tags.highlight);
    }

    // initialize click handler
    if (typeof clickHandler === "undefined") {
      clickHandler = new ClickHandler(av, exercise, {
        selectedClass: "selected",
        effect: "copy"
      });
    }
    clickHandler.reset();

    // remove old elements
    if (barArray) {
      clickHandler.remove(barArray);
      barArray.clear();
    }
    if (tempArray) {
      clickHandler.remove(tempArray);
      tempArray.clear();
    }

    // initialize the bar array
    initialArray = [];
    for (var i = 0; i < arraySize; i++) {
      initialArray[i] = Math.floor(Math.random() * 100) + 10;
    }
    barArray = av.ds.array(initialArray, {indexed: true, layout: "bar"});
    clickHandler.addArray(barArray);

    // initialize temp variable
    initialTempArray = [];
    initialTempArray[0] = Math.floor(Math.random() * 100) + 10;
    tempArray = av.ds.array(initialTempArray, {indexed: false});
    clickHandler.addArray(tempArray);

    // create labels
    $tempLabel = $("
" + interpret("temp_label") + "
")
      .insertBefore(tempArray.element);
    $arrayLabel = $("
" + interpret("array_label") + "
")
      .insertBefore(barArray.element);

    $tempLabel.add($arrayLabel)
      .css("text-align", "center")
      .css("font-weight", "bold")
      .css("margin-bottom", -10);

    return [barArray, tempArray];
  }

  function modelSolution(jsav) {
    var jsavI = jsav.variable(1, {label: "i:", visible: true, left: 10});
    var jsavJ = jsav.variable(0, {label: "j:", visible: true, left: 10, top: 60});

    var modelArray = jsav.ds.array(initialArray, {indexed: true, layout: "bar"});
    var modelTempArray = jsav.ds.array(initialTempArray);

    jsav._undo = [];
    modelArray.layout();

    var msCode;
    if (config.code) {
      msCode = jsav.code(config.code).show();
    }

    jsav.displayInit();

    var j = 0;
    for (var i = 1; i < arraySize; i++) {
      jsavI.value(i);
      jsav.effects.copyValue(modelArray, i, modelTempArray, 0);
      jsav.umsg(interpret("ms_copy"), {fill: {arr_at_i: modelArray.value(i)}});
      if (config.code) {
        msCode.setCurrentLine(config.code.tags.copy_to_tmp);
      }
      jsav.stepOption("grade", true);
      jsav.step();
      j = i;
      jsavJ.value(j);
      while (j > 0 && modelArray.value(j - 1) > modelTempArray.value(0)) {
        jsav.effects.copyValue(modelArray, j - 1, modelArray, j);
        modelArray.layout();
        jsav.umsg(interpret("ms_shift"), {fill: {temp: modelTempArray.value(0), i: i}});
        if (config.code) {
          msCode.setCurrentLine(config.code.tags.shift);
        }
        jsav.stepOption("grade", true);
        jsav.step();
        j--;
        jsavJ.value(j);
      }
      jsav.effects.copyValue(modelTempArray, 0, modelArray, j);
      modelArray.layout();
      jsav.umsg(interpret("ms_copy_back"), {fill: {temp: modelTempArray.value(0), i: i}});
      if (config.code) {
        msCode.setCurrentLine(config.code.tags.copy_back);
      }
      jsav.stepOption("grade", true);
      jsav.step();
    }

    return [modelArray, modelTempArray];
  }

  var exercise = av.exercise(modelSolution, initialize, {feedback: "atend"});
  exercise.reset();

}(jQuery));<commit_msg>Removed obsolete reference to setTitleAndInstructions()<commit_after>/* global ODSA, ClickHandler */
(function ($) {
  "use strict";
  var arraySize = 10,
    initialArray,
    initialTempArray,
    barArray,
    tempArray,
    $arrayLabel,
    $tempLabel,
    pseudo,
    interpret,
    clickHandler,
    config = ODSA.UTILS.loadLangData({'av_container': 'jsavcontainer'}),
    av = new JSAV($("#jsavcontainer"));

  av.recorded(); // we are not recording an AV with an algorithm

  // create interpreter function
  interpret = config.interpreter;

  function initialize() {

    // show the code
    if (!pseudo && config.code) {
      pseudo = av.code($.extend({after: {element: $(".instructions")}, visible: true}, config.code));
      pseudo.highlight(config.code.tags.highlight);
    }

    // initialize click handler
    if (typeof clickHandler === "undefined") {
      clickHandler = new ClickHandler(av, exercise, {
        selectedClass: "selected",
        effect: "copy"
      });
    }
    clickHandler.reset();

    // remove old elements
    if (barArray) {
      clickHandler.remove(barArray);
      barArray.clear();
    }
    if (tempArray) {
      clickHandler.remove(tempArray);
      tempArray.clear();
    }

    // initialize the bar array
    initialArray = [];
    for (var i = 0; i < arraySize; i++) {
      initialArray[i] = Math.floor(Math.random() * 100) + 10;
    }
    barArray = av.ds.array(initialArray, {indexed: true, layout: "bar"});
    clickHandler.addArray(barArray);

    // initialize temp variable
    initialTempArray = [];
    initialTempArray[0] = Math.floor(Math.random() * 100) + 10;
    tempArray = av.ds.array(initialTempArray, {indexed: false});
    clickHandler.addArray(tempArray);

    // create labels
    $tempLabel = $("
" + interpret("temp_label") + "
")
      .insertBefore(tempArray.element);
    $arrayLabel = $("
" + interpret("array_label") + "
")
      .insertBefore(barArray.element);

    $tempLabel.add($arrayLabel)
      .css("text-align", "center")
      .css("font-weight", "bold")
      .css("margin-bottom", -10);

    return [barArray, tempArray];
  }

  function modelSolution(jsav) {
    var jsavI = jsav.variable(1, {label: "i:", visible: true, left: 10});
    var jsavJ = jsav.variable(0, {label: "j:", visible: true, left: 10, top: 60});

    var modelArray = jsav.ds.array(initialArray, {indexed: true, layout: "bar"});
    var modelTempArray = jsav.ds.array(initialTempArray);

    jsav._undo = [];
    modelArray.layout();

    var msCode;
    if (config.code) {
      msCode = jsav.code(config.code).show();
    }

    jsav.displayInit();

    var j = 0;
    for (var i = 1; i < arraySize; i++) {
      jsavI.value(i);
      jsav.effects.copyValue(modelArray, i, modelTempArray, 0);
      jsav.umsg(interpret("ms_copy"), {fill: {arr_at_i: modelArray.value(i)}});
      if (config.code) {
        msCode.setCurrentLine(config.code.tags.copy_to_tmp);
      }
      jsav.stepOption("grade", true);
      jsav.step();
      j = i;
      jsavJ.value(j);
      while (j > 0 && modelArray.value(j - 1) > modelTempArray.value(0)) {
        jsav.effects.copyValue(modelArray, j - 1, modelArray, j);
        modelArray.layout();
        jsav.umsg(interpret("ms_shift"), {fill: {temp: modelTempArray.value(0), i: i}});
        if (config.code) {
          msCode.setCurrentLine(config.code.tags.shift);
        }
        jsav.stepOption("grade", true);
        jsav.step();
        j--;
        jsavJ.value(j);
      }
      jsav.effects.copyValue(modelTempArray, 0, modelArray, j);
      modelArray.layout();
      jsav.umsg(interpret("ms_copy_back"), {fill: {temp: modelTempArray.value(0), i: i}});
      if (config.code) {
        msCode.setCurrentLine(config.code.tags.copy_back);
      }
      jsav.stepOption("grade", true);
      jsav.step();
    }

    return [modelArray, modelTempArray];
  }

  var exercise = av.exercise(modelSolution, initialize, {feedback: "atend"});
  exercise.reset();

}(jQuery));
<|endoftext|>