1
0
mirror of https://github.com/psychopy/psychojs.git synced 2025-05-11 16:18:10 +00:00

Merge branch 'master' of github.com:apitiot/psychojs

This commit is contained in:
Alain Pitiot 2021-06-01 11:04:53 +02:00
commit 0bac3ee235
25 changed files with 3427 additions and 8800 deletions

3
.gitignore vendored
View File

@ -1,2 +1,3 @@
dist
node_modules
out
node_modules

11737
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -8,69 +8,42 @@
"name": "Alain Pitiot"
},
"type": "module",
"main": "src/index.js",
"exports": {
".": "./src/index.js",
"./css": "./src/index.css",
"./package": "./package.json"
},
"main": "./src/index.js",
"scripts": {
"build": "npm run build:js && npm run build:css && npm run build:docs",
"build:css": "npx cross-var postcss -o dist/psychojs-$npm_package_version.css src/index.css",
"build:css": "node ./scripts/build.css.cjs",
"build:docs": "jsdoc src -r -d docs",
"build:js": "rollup -c",
"build:js": "node ./scripts/build.js.cjs",
"lint": "npm run lint:js && npm run lint:css",
"lint:css": "stylelint src/**/*.css",
"lint:js": "eslint rollup.config.js src/**/*.js",
"lint:css": "csslint src",
"lint:js": "eslint src",
"lint:scripts": "eslint scripts --ext .cjs",
"start": "npm run build"
},
"babel": {
"presets": [
[
"@babel/preset-env",
{
"modules": false,
"targets": {
"ie": 11
},
"spec": true,
"forceAllTransforms": true,
"debug": true
}
]
]
},
"browserslist": [
"last 2 versions"
],
"stylelint": {
"extends": "stylelint-config-standard",
"rules": {
"no-descending-specificity": [
true,
{
"severity": "warning"
}
]
}
"dependencies": {
"howler": "^2.2.1",
"log4javascript": "github:Ritzlgrmft/log4javascript",
"moment": "^2.29.1",
"pako": "^1.0.10",
"pixi.js-legacy": "^6.0.4",
"preload-js": "^0.6.3",
"seedrandom": "^3.0.5",
"tone": "^14.7.77",
"xlsx": "^0.17.0"
},
"devDependencies": {
"@babel/core": "^7.12.3",
"@babel/preset-env": "^7.12.1",
"@rollup/plugin-babel": "^5.2.1",
"cross-var": "^1.1.0",
"cssnano": "^4.1.10",
"eslint": "^7.24.0",
"jsdoc": "^3.6.6",
"postcss": "^8.1.3",
"postcss-cli": "^8.1.0",
"postcss-preset-env": "^6.7.0",
"rollup": "^2.32.1",
"stylelint": "^13.7.2",
"stylelint-config-standard": "^20.0.0",
"terser": "^5.3.8"
"csslint": "^1.0.5",
"esbuild": "^0.12.1",
"eslint": "^7.26.0",
"jsdoc": "^3.6.7"
},
"postcss": {
"plugins": {
"postcss-preset-env": {},
"cssnano": {
"autoprefixer": false
}
}
"engines": {
"node": ">=14.15.0",
"npm": ">=6.14.8"
}
}

View File

@ -1,212 +0,0 @@
// ES native imports courtesy of using type module in 'package.json'
import path from 'path';
import fs from 'fs';
import { minify } from 'terser';
import babel from '@rollup/plugin-babel';
import pkg from './package.json';
// Manually set default version here for easier
// diffing when comparing to original build script output
const { VERSION: version = pkg.version } = process.env;
// Enabled in the original, even though
// source maps missing for sample provided
const sourcemap = false;
// Might be 'build' or similar
const destination = './dist';
// Could be 'src' or 'lib'
const source = './src';
// Start fresh
try {
if (fs.existsSync(destination)) {
// Clear out JS files before rebuilding
const contents = fs.readdirSync(destination).filter(item => item.endsWith('js'));
for (const item of contents) {
const target = path.join(destination, item);
const stat = fs.statSync(target);
// Delete
fs.unlinkSync(target);
}
} else {
// Create 'dist' if missing
fs.mkdirSync(destination);
}
} catch (error) {
console.error(error);
}
// For sorting legacy/IE11 bundle components
const orderOfAppearance = [ 'util', 'data', 'core', 'visual', 'sound' ];
const last = [ ...orderOfAppearance ].pop();
const footer = `
// Add a few top level variables for convenience, this makes it
// possible to eg. use "return Scheduler.Event.NEXT;" instead of "util.Scheduler.Event.NEXT;"
PsychoJS = core.PsychoJS;
TrialHandler = data.TrialHandler;
Scheduler = util.Scheduler;`;
const plugins = [
babel({
babelHelpers: 'bundled',
exclude: 'node_modules/**',
include: `${destination}/*.iife.js`
}),
minifier({
compress: false,
mangle: false,
output: {
beautify: true
},
sourceMap: false,
toplevel: false
})
];
// List source directory contents
const components = fs.readdirSync(source)
// Need subdirectories only
.filter((item) => {
const target = path.join(source, item);
const stat = fs.statSync(target);
return stat.isDirectory();
})
// Put in order
.sort((a, b) => orderOfAppearance.indexOf(a) - orderOfAppearance.indexOf(b))
// Prepare an output object for each component module
.map((component, _, contents) => ({
// So I don't have to specify full paths
external: (id) => {
// Decompose current component path
const segments = id.split('/');
// Mark as external if contents within source
// directory tree, excluding the current component
return contents
.filter(item => item !== component)
.some(item => segments.includes(item));
},
input: `${source}/${component}/index.js`,
// Disable circular dependency warnings
onwarn,
output: [
{
file: `${destination}/${component}-${version}.js`,
format: 'module',
globals: {
performance: 'performance'
},
// Find which module the import points to
// and fix path in place
paths: (id) => {
const name = findName(id, contents);
return `./${name}-${version}.js`;
},
sourcemap,
},
{
esModule: false,
file: `${destination}/${component}-${version}.iife.js`,
format: 'iife',
globals: id => findName(id, contents),
name: component,
paths: (id) => {
const name = findName(id, contents);
return `./${name}-${version}.iife.js`;
},
sourcemap,
plugins: [
appender({
target: `${destination}/psychojs-${version}.js`,
// Mirrors rollup's 'outputOptions' hook
outputOptions: (options) => {
if (options.file.includes(last)) {
options.footer = footer;
}
return options;
}
})
]
}
],
plugins
})
);
export default [
...components,
{
// Add a UMD build for Thomas
input: `${source}/index.js`,
onwarn,
output: {
file: `${destination}/psychojs-${version}.umd.js`,
format: 'umd',
name: 'psychojs'
},
plugins
}
];
// https://rollupjs.org/guide/en/#onwarn
function onwarn(message, warn) {
// Skip circular dependency warnings
if (message.code === 'CIRCULAR_DEPENDENCY') {
return;
}
warn(message);
}
// Helper for extracting module name from contents array by rollup id (path to file)
function findName(id, contents) {
return id.split(path.sep).find(item => contents.includes(item));
}
// Minimal terser plugin
function minifier(options) {
return {
name: 'minifier',
async renderChunk(code) {
try {
// Includes code and map keys
const result = await minify(code, options);
return result;
} catch (error) {
throw error;
}
}
};
}
// Custom plugin for cancatenating IIFE's sans cat(1)
function appender({ target = '', outputOptions = () => {} } = {}) {
return {
name: 'appender',
outputOptions: (options) => outputOptions(options),
async generateBundle(options, bundle) {
const { file } = options;
const id = file.split('/').pop();
const { code } = bundle[id];
// Should be expected to throw if `target` missing
fs.appendFile(target, code, (error) => {
if (error) {
throw error;
}
});
// Prevent write out
delete bundle[id];
}
};
}

13
scripts/build.css.cjs Normal file
View File

@ -0,0 +1,13 @@
const { buildSync } = require('esbuild');
const pkg = require('psychojs/package');
const versionMaybe = process.env.npm_config_outver;
const dirMaybe = process.env.npm_config_outdir;
const [,,, dir = dirMaybe || 'out', version = versionMaybe || pkg.version] = process.argv;
buildSync({
bundle: true,
entryPoints: ['src/index.css'],
minify: true,
outfile: `./${dir}/psychojs-${version}.css`
});

14
scripts/build.js.cjs Normal file
View File

@ -0,0 +1,14 @@
const { buildSync } = require('esbuild');
const pkg = require('psychojs/package');
const versionMaybe = process.env.npm_config_outver;
const dirMaybe = process.env.npm_config_outdir;
const [,,, dir = dirMaybe || 'out', version = versionMaybe || pkg.version] = process.argv;
buildSync({
bundle: true,
entryPoints: ['src/index.js'],
format: 'esm',
minify: true,
outfile: `./${dir}/psychojs-${version}.js`
});

View File

@ -8,7 +8,7 @@
* @license Distributed under the terms of the MIT License
*/
import * as Tone from 'tone';
import {PsychoJS} from './PsychoJS';
import {ServerManager} from './ServerManager';
import {Scheduler} from '../util/Scheduler';
@ -113,7 +113,9 @@ export class GUI
}
// prepare jquery UI dialog box:
let htmlCode = '<div id="expDialog" title="' + title + '">';
let htmlCode =
'<div id="expDialog" title="' + title + '">' +
'<p class="validateTips">Fields marked with an asterisk (*) are required.</p>';
// uncomment for older version of the library:
// htmlCode += '<p style="font-size: 0.8em; padding: 0.5em; margin-bottom: 0.5em; color: #FFAA00; border: 1px solid #FFAA00;">&#9888; This experiment uses a deprecated version of the PsychoJS library. Consider updating to a newer version (e.g. by updating PsychoPy and re-exporting the experiment).</p>'+
@ -181,7 +183,7 @@ export class GUI
}
htmlCode += '</select>';
$('#' + keyId).selectmenu({classes: {}});
jQuery('#' + keyId).selectmenu({classes: {}});
}
// otherwise we use a single string input:
@ -209,7 +211,7 @@ export class GUI
// the dialog box:
if (typeof logoUrl === 'string')
{
$("#dialog-logo").on('load', () =>
jQuery("#dialog-logo").on('load', () =>
{
self._onDialogOpen('#expDialog')();
});
@ -231,7 +233,7 @@ export class GUI
self._dialogComponent.button = 'Cancel';
self._estimateDialogScalingFactor();
const dialogSize = self._getDialogSize();
$("#expDialog").dialog({
jQuery("#expDialog").dialog({
width: dialogSize[0],
maxHeight: dialogSize[1],
@ -248,7 +250,7 @@ export class GUI
click: function ()
{
self._dialogComponent.button = 'Cancel';
$("#expDialog").dialog('close');
jQuery("#expDialog").dialog('close');
}
},
{
@ -270,7 +272,7 @@ export class GUI
self._dialogComponent.button = 'OK';
$("#expDialog").dialog('close');
jQuery("#expDialog").dialog('close');
// Tackle browser demands on having user action initiate audio context
Tone.start();
@ -290,8 +292,8 @@ export class GUI
// close is called by both buttons and when the user clicks on the cross:
close: function ()
{
//$.unblockUI();
$(this).dialog('destroy').remove();
//jQuery.unblockUI();
jQuery(this).dialog('destroy').remove();
self._dialogComponent.status = PsychoJS.Status.FINISHED;
}
@ -310,11 +312,11 @@ export class GUI
// block UI until user has pressed dialog button:
// note: block UI does not allow for text to be entered in the dialog form boxes, alas!
//$.blockUI({ message: "", baseZ: 1});
//jQuery.blockUI({ message: "", baseZ: 1});
// show dialog box:
$("#progressbar").progressbar({value: self._progressBarCurrentValue});
$("#progressbar").progressbar("option", "max", self._progressBarMax);
jQuery("#progressbar").progressbar({value: self._progressBarCurrentValue});
jQuery("#progressbar").progressbar("option", "max", self._progressBarMax);
}
if (self._dialogComponent.status === PsychoJS.Status.FINISHED)
@ -357,12 +359,12 @@ export class GUI
{
// close the previously opened dialog box, if there is one:
const expDialog = $("#expDialog");
const expDialog = jQuery("#expDialog");
if (expDialog.length)
{
expDialog.dialog("destroy").remove();
}
const msgDialog = $("#msgDialog");
const msgDialog = jQuery("#msgDialog");
if (msgDialog.length)
{
msgDialog.dialog("destroy").remove();
@ -459,7 +461,7 @@ export class GUI
this._estimateDialogScalingFactor();
const dialogSize = this._getDialogSize();
const self = this;
$("#msgDialog").dialog({
jQuery("#msgDialog").dialog({
dialogClass: 'no-close',
width: dialogSize[0],
@ -476,7 +478,7 @@ export class GUI
text: "Ok",
click: function ()
{
$(this).dialog("destroy").remove();
jQuery(this).dialog("destroy").remove();
// execute callback function:
if (typeof onOK !== 'undefined')
@ -514,10 +516,10 @@ export class GUI
return () =>
{
const windowSize = [$(window).width(), $(window).height()];
const windowSize = [jQuery(window).width(), jQuery(window).height()];
// note: $(dialogId) is the dialog-content, $(dialogId).parent() is the actual widget
const parent = $(dialogId).parent();
// note: jQuery(dialogId) is the dialog-content, jQuery(dialogId).parent() is the actual widget
const parent = jQuery(dialogId).parent();
parent.css({
position: 'absolute',
left: Math.max(0, (windowSize[0] - parent.outerWidth()) / 2.0),
@ -526,8 +528,8 @@ export class GUI
// record width and height difference between dialog content and dialog:
self._contentDelta = [
parent.css('width').slice(0, -2) - $(dialogId).css('width').slice(0, -2),
parent.css('height').slice(0, -2) - $(dialogId).css('height').slice(0, -2)];
parent.css('width').slice(0, -2) - jQuery(dialogId).css('width').slice(0, -2),
parent.css('height').slice(0, -2) - jQuery(dialogId).css('height').slice(0, -2)];
};
}
@ -544,10 +546,10 @@ export class GUI
{
const self = this;
$(window).resize(function ()
jQuery(window).resize(function ()
{
const parent = $(dialogId).parent();
const windowSize = [$(window).width(), $(window).height()];
const parent = jQuery(dialogId).parent();
const windowSize = [jQuery(window).width(), jQuery(window).height()];
// size (we need to redimension both the dialog and the dialog content):
const dialogSize = self._getDialogSize();
@ -559,7 +561,7 @@ export class GUI
const isDifferent = self._estimateDialogScalingFactor();
if (!isDifferent)
{
$(dialogId).css({
jQuery(dialogId).css({
width: dialogSize[0] - self._contentDelta[0],
maxHeight: dialogSize[1] - self._contentDelta[1]
});
@ -592,7 +594,7 @@ export class GUI
{
// for each resource, we have a 'downloading resource' and a 'resource downloaded' message:
this._progressBarMax = signal.count * 2;
$("#progressbar").progressbar("option", "max", this._progressBarMax);
jQuery("#progressbar").progressbar("option", "max", this._progressBarMax);
this._progressBarCurrentValue = 0;
}
@ -601,7 +603,7 @@ export class GUI
else if (signal.message === ServerManager.Event.DOWNLOAD_COMPLETED)
{
this._allResourcesDownloaded = true;
$("#progressMsg").text('all resources downloaded.');
jQuery("#progressMsg").text('all resources downloaded.');
this._updateOkButtonStatus();
}
@ -617,20 +619,20 @@ export class GUI
if (signal.message === ServerManager.Event.RESOURCE_DOWNLOADED)
{
$("#progressMsg").text('downloaded ' + (this._progressBarCurrentValue / 2) + ' / ' + (this._progressBarMax / 2));
jQuery("#progressMsg").text('downloaded ' + (this._progressBarCurrentValue / 2) + ' / ' + (this._progressBarMax / 2));
}
else
{
$("#progressMsg").text('downloading ' + (this._progressBarCurrentValue / 2) + ' / ' + (this._progressBarMax / 2));
jQuery("#progressMsg").text('downloading ' + (this._progressBarCurrentValue / 2) + ' / ' + (this._progressBarMax / 2));
}
// $("#progressMsg").text(signal.resource + ': downloaded.');
$("#progressbar").progressbar("option", "value", this._progressBarCurrentValue);
jQuery("#progressbar").progressbar("option", "value", this._progressBarCurrentValue);
}
// unknown message: we just display it
else
{
$("#progressMsg").text(signal.message);
jQuery("#progressMsg").text(signal.message);
}
}
@ -649,23 +651,23 @@ export class GUI
{
if (changeFocus)
{
$("#buttonOk").button("option", "disabled", false).focus();
jQuery("#buttonOk").button("option", "disabled", false).focus();
}
else
{
$("#buttonOk").button("option", "disabled", false);
jQuery("#buttonOk").button("option", "disabled", false);
}
}
else
{
$("#buttonOk").button("option", "disabled", true);
jQuery("#buttonOk").button("option", "disabled", true);
}
// strangely, changing the disabled option sometimes fails to update the ui,
// so we need to hide it and show it again:
$("#buttonOk").hide(0, () =>
jQuery("#buttonOk").hide(0, () =>
{
$("#buttonOk").show();
jQuery("#buttonOk").show();
});
}
@ -680,7 +682,7 @@ export class GUI
*/
_estimateDialogScalingFactor()
{
const windowSize = [$(window).width(), $(window).height()];
const windowSize = [jQuery(window).width(), jQuery(window).height()];
// desktop:
let dialogScalingFactor = 1.0;
@ -715,7 +717,7 @@ export class GUI
*/
_getDialogSize()
{
const windowSize = [$(window).width(), $(window).height()];
const windowSize = [jQuery(window).width(), jQuery(window).height()];
this._estimateDialogScalingFactor();
return [

View File

@ -8,11 +8,12 @@
*/
import log4javascript from 'log4javascript';
import pako from 'pako';
import * as util from '../util/Util';
import {MonotonicClock} from '../util/Clock';
import {ExperimentHandler} from '../data/ExperimentHandler';
/**
* <p>This class handles a variety of loggers, e.g. a browser console one (mostly for debugging),
* a remote one, etc.</p>

View File

@ -8,7 +8,7 @@
* @license Distributed under the terms of the MIT License
*/
import log4javascript from 'log4javascript';
import {Scheduler} from '../util/Scheduler';
import {ServerManager} from './ServerManager';
import {ExperimentHandler} from '../data/ExperimentHandler';
@ -182,7 +182,7 @@ export class PsychoJS
this.logger.info('[PsychoJS] @version 2021.1.4');
// Hide #root::after
$('#root').addClass('is-ready');
jQuery('#root').addClass('is-ready');
}
@ -697,7 +697,7 @@ export class PsychoJS
this._IP = {};
try
{
const geoResponse = await $.get('http://www.geoplugin.net/json.gp');
const geoResponse = await jQuery.get('http://www.geoplugin.net/json.gp');
const geoData = JSON.parse(geoResponse);
this._IP = {
IP: geoData.geoplugin_request,

View File

@ -7,15 +7,14 @@
* @license Distributed under the terms of the MIT License
*/
import createjs from 'preload-js';
import { Howl } from 'howler';
import {PsychoJS} from './PsychoJS';
import {PsychObject} from '../util/PsychObject';
import * as util from '../util/Util';
import {ExperimentHandler} from "../data/ExperimentHandler";
import {MonotonicClock} from "../util/Clock";
// import { Howl } from 'howler';
/**
* <p>This manager handles all communications between the experiment running in the participant's browser and the [pavlovia.org]{@link http://pavlovia.org} server, <em>in an asynchronous manner</em>.</p>
@ -87,7 +86,7 @@ export class ServerManager extends PsychObject
const self = this;
return new Promise((resolve, reject) =>
{
$.get(configURL, 'json')
jQuery.get(configURL, 'json')
.done((config, textStatus) =>
{
// resolve({ ...response, config });
@ -144,7 +143,7 @@ export class ServerManager extends PsychObject
return new Promise((resolve, reject) =>
{
const url = this._psychoJS.config.pavlovia.URL + '/api/v2/experiments/' + encodeURIComponent(self._psychoJS.config.experiment.fullpath) + '/sessions';
$.post(url, data, null, 'json')
jQuery.post(url, data, null, 'json')
.done((data, textStatus) =>
{
if (!('token' in data))
@ -256,7 +255,7 @@ export class ServerManager extends PsychObject
const self = this;
return new Promise((resolve, reject) =>
{
$.ajax({
jQuery.ajax({
url,
type: 'delete',
data: {isCompleted},
@ -679,7 +678,7 @@ export class ServerManager extends PsychObject
value
};
$.post(url, data, null, 'json')
jQuery.post(url, data, null, 'json')
.done((serverData, textStatus) =>
{
self.setStatus(ServerManager.Status.READY);
@ -741,7 +740,7 @@ export class ServerManager extends PsychObject
'/sessions/' + self._psychoJS.config.session.token +
'/logs';
$.post(url, data, null, 'json')
jQuery.post(url, data, null, 'json')
.done((serverData, textStatus) =>
{
self.setStatus(ServerManager.Status.READY);
@ -870,7 +869,7 @@ export class ServerManager extends PsychObject
'/api/v2/experiments/' + encodeURIComponent(this._psychoJS.config.experiment.fullpath) +
'/resources';
$.get(url, data, null, 'json')
jQuery.get(url, data, null, 'json')
.done((data, textStatus) =>
{
if (!('resources' in data))

View File

@ -7,6 +7,7 @@
* @license Distributed under the terms of the MIT License
*/
import * as PIXI from 'pixi.js-legacy';
import {Color} from '../util/Color';
import {PsychObject} from '../util/PsychObject';
import {MonotonicClock} from '../util/Clock';

View File

@ -8,6 +8,7 @@
*/
import * as XLSX from 'xlsx';
import {PsychObject} from '../util/PsychObject';
import {MonotonicClock} from '../util/Clock';
import * as util from '../util/Util';

View File

@ -10,10 +10,11 @@
*/
import seedrandom from 'seedrandom';
import * as XLSX from 'xlsx';
import {PsychObject} from '../util/PsychObject';
import * as util from '../util/Util';
/**
* <p>A Trial Handler handles the importing and sequencing of conditions.</p>
*
@ -618,11 +619,11 @@ export class TrialHandler extends PsychObject
// seed the random number generator:
if (typeof (this.seed) !== 'undefined')
{
Math.seedrandom(this.seed);
seedrandom(this.seed);
}
else
{
Math.seedrandom();
seedrandom();
}
if (this.method === TrialHandler.Method.SEQUENTIAL)

View File

@ -7,6 +7,7 @@
* @license Distributed under the terms of the MIT License
*/
import * as Tone from 'tone';
import {SoundPlayer} from './SoundPlayer';
@ -243,7 +244,7 @@ export class TonePlayer extends SoundPlayer
playToneCallback,
this.duration_s,
Tone.now(),
Tone.Infinity
Infinity
);
}
else

View File

@ -7,6 +7,8 @@
* @license Distributed under the terms of the MIT License
*/
import moment from 'moment';
/**
* <p>MonotonicClock offers a convenient way to keep track of time during experiments. An experiment can have as many independent clocks as needed, e.g. one to time responses, another one to keep track of stimuli, etc.</p>

View File

@ -7,6 +7,8 @@
* @license Distributed under the terms of the MIT License
*/
import * as PIXI from 'pixi.js-legacy';
/**
* Syntactic sugar for Mixins

View File

@ -8,6 +8,7 @@
*/
import * as PIXI from 'pixi.js-legacy';
import {Color} from '../util/Color';
import {ColorMixin} from '../util/ColorMixin';
import * as util from '../util/Util';
@ -42,6 +43,7 @@ import {Slider} from './Slider';
* @param {number[]} [options.items= []] - the array of labels
* @param {number} [options.itemPadding= 0.05] - the granularity
*
* @param {string} [options.font= 'Arial'] - the text font
* @param {string} [options.fontFamily= 'Helvetica'] - the text font
* @param {boolean} [options.bold= true] - whether or not the font of the labels is bold
* @param {boolean} [options.italic= false] - whether or not the font of the labels is italic
@ -55,7 +57,7 @@ import {Slider} from './Slider';
*/
export class Form extends util.mix(VisualStim).with(ColorMixin)
{
constructor({name, win, pos, size, units, borderColor, fillColor, itemColor, markerColor, responseColor, color, contrast, opacity, depth, items, randomize, itemPadding, fontFamily, bold, italic, fontSize, clipMask, autoDraw, autoLog} = {})
constructor({name, win, pos, size, units, borderColor, fillColor, itemColor, markerColor, responseColor, color, contrast, opacity, depth, items, randomize, itemPadding, font, fontFamily, bold, italic, fontSize, clipMask, autoDraw, autoLog} = {})
{
super({name, win, units, opacity, depth, pos, size, clipMask, autoDraw, autoLog});
@ -118,6 +120,13 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
);
// fonts:
this._addAttribute(
'font',
font,
'Arial',
this._onChange(true, true)
);
// Not in use at present
this._addAttribute(
'fontFamily',
fontFamily,
@ -725,7 +734,7 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
const textStimOption = {
win: this._win,
name: 'item text',
font: 'Arial',
font: this.font,
units: this._units,
alignHoriz: 'left',
alignVert: 'top',
@ -741,7 +750,10 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
name: 'choice response',
units: this._units,
flip: false,
fontFamily: 'Arial',
// Not part of Slider options as things stand
fontFamily: this.fontFamily,
// As found in Slider options
font: this.font,
bold: false,
italic: false,
fontSize: this._fontSize * this._responseTextHeightRatio,
@ -760,7 +772,7 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
flip: false,
opacity: 1,
depth: this._depth + 1,
font: 'Arial',
font: this.font,
letterHeight: this._fontSize * this._responseTextHeightRatio,
bold: false,
italic: false,

View File

@ -8,6 +8,7 @@
*/
import * as PIXI from 'pixi.js-legacy';
import {VisualStim} from './VisualStim';
import {Color} from '../util/Color';
import {ColorMixin} from '../util/ColorMixin';

View File

@ -8,6 +8,7 @@
*/
import * as PIXI from 'pixi.js-legacy';
import {VisualStim} from './VisualStim';
import {Color} from '../util/Color';
import {ColorMixin} from '../util/ColorMixin';

View File

@ -9,6 +9,7 @@
*/
import * as PIXI from 'pixi.js-legacy';
import {VisualStim} from './VisualStim';
import {Color} from '../util/Color';
import {ColorMixin} from '../util/ColorMixin';

View File

@ -8,6 +8,7 @@
*/
import * as PIXI from 'pixi.js-legacy';
import {VisualStim} from './VisualStim';
import {Color} from '../util/Color';
import {ColorMixin} from '../util/ColorMixin';
@ -44,7 +45,7 @@ import {PsychoJS} from "../core/PsychoJS";
* and labels with respect to the central bar
* @param {boolean} [options.readOnly= false] - whether or not the slider is read only
*
* @param {string} [options.fontFamily= 'Helvetica'] - the text font
* @param {string} [options.font= 'Arial'] - the text font
* @param {boolean} [options.bold= true] - whether or not the font of the labels is bold
* @param {boolean} [options.italic= false] - whether or not the font of the labels is italic
* @param {number} [options.fontSize] - the font size of the labels (in pixels), the default fontSize depends on the
@ -130,7 +131,7 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
this._addAttribute(
'font',
font,
'Helvetica',
'Arial',
this._onChange(true, true)
);
this._addAttribute(

View File

@ -8,6 +8,7 @@
*/
import * as PIXI from 'pixi.js-legacy';
import {VisualStim} from './VisualStim';
import {Color} from '../util/Color';
import {ColorMixin} from '../util/ColorMixin';
@ -59,6 +60,12 @@ export class TextBox extends util.mix(VisualStim).with(ColorMixin)
'',
this._onChange(true, true)
);
this._addAttribute(
'placeholder',
text,
'',
this._onChange(true, true)
);
this._addAttribute(
'anchor',
anchor,
@ -404,6 +411,9 @@ export class TextBox extends util.mix(VisualStim).with(ColorMixin)
{
this._pixi.destroy(true);
}
// Get the currently entered text
let enteredText = this._pixi !== undefined? this._pixi.text: '';
// Create new TextInput
this._pixi = new TextInput(this._getTextInputOptions());
// listeners required for regular textboxes, but may cause problems with button stimuli
@ -425,7 +435,8 @@ export class TextBox extends util.mix(VisualStim).with(ColorMixin)
}
if (this._editable)
{
this._pixi.placeholder = this._text;
this.text = enteredText;
this._pixi.placeholder = this._placeholder;
}
else
{

View File

@ -9,6 +9,8 @@
* We are currently using it almost as is but will be making modification in the near future.
*/
import * as PIXI from 'pixi.js-legacy';
export class TextInput extends PIXI.Container
{
constructor(styles)

View File

@ -8,6 +8,7 @@
*/
import * as PIXI from 'pixi.js-legacy';
import {VisualStim} from './VisualStim';
import {Color} from '../util/Color';
import {ColorMixin} from '../util/ColorMixin';

View File

@ -8,6 +8,7 @@
*/
import * as PIXI from 'pixi.js-legacy';
import {MinimalStim} from '../core/MinimalStim';
import {WindowMixin} from '../core/WindowMixin';
import * as util from '../util/Util';