├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── NOTICE
├── config-overrides.js
├── lib
├── domReady.js
├── humane.js
├── mustache.js
├── picoModal.js
├── require.js
├── sugar-web
│ ├── LICENSE
│ ├── README.md
│ ├── activity
│ │ ├── activity.js
│ │ └── shortcut.js
│ ├── bus.js
│ ├── bus
│ │ ├── sugarizer.js
│ │ └── sugaros.js
│ ├── datastore.js
│ ├── datastore
│ │ ├── sugarizer.js
│ │ └── sugaros.js
│ ├── dictstore.js
│ ├── env.js
│ ├── graphics
│ │ ├── README.md
│ │ ├── activitypalette.html
│ │ ├── activitypalette.js
│ │ ├── css
│ │ │ ├── sugar-200dpi.css
│ │ │ ├── sugar-200dpi.less
│ │ │ ├── sugar-96dpi.css
│ │ │ ├── sugar-96dpi.less
│ │ │ └── sugar.less
│ │ ├── grid.js
│ │ ├── icon.js
│ │ ├── icons
│ │ │ ├── actions
│ │ │ │ ├── activity-abecedarium.svg
│ │ │ │ ├── activity-journal.svg
│ │ │ │ ├── activity-stop.svg
│ │ │ │ ├── checkbox-checked-selected.svg
│ │ │ │ ├── checkbox-checked.svg
│ │ │ │ ├── checkbox-unchecked-selected.svg
│ │ │ │ ├── checkbox-unchecked.svg
│ │ │ │ ├── dialog-cancel-active.svg
│ │ │ │ ├── dialog-cancel.svg
│ │ │ │ ├── dialog-ok-active.svg
│ │ │ │ ├── dialog-ok.svg
│ │ │ │ ├── entry-cancel-active.svg
│ │ │ │ ├── entry-cancel-disabled.svg
│ │ │ │ ├── entry-cancel.svg
│ │ │ │ ├── photo.svg
│ │ │ │ ├── radio-active-selected.svg
│ │ │ │ ├── radio-active.svg
│ │ │ │ ├── radio-selected.svg
│ │ │ │ ├── radio.svg
│ │ │ │ ├── zoom-groups.svg
│ │ │ │ ├── zoom-home.svg
│ │ │ │ └── zoom-neighborhood.svg
│ │ │ └── emblems
│ │ │ │ ├── arrow-down.svg
│ │ │ │ ├── arrow-up.svg
│ │ │ │ └── favorite.svg
│ │ ├── journalchooser.js
│ │ ├── menupalette.html
│ │ ├── menupalette.js
│ │ ├── palette.js
│ │ ├── presencepalette.js
│ │ ├── radiobuttonsgroup.js
│ │ └── xocolor.js
│ ├── package.json
│ ├── presence.js
│ └── test
│ │ ├── functional
│ │ ├── datastoreSpec.js
│ │ └── toolkitContractSpec.js
│ │ ├── graphics
│ │ ├── iconSpec.js
│ │ ├── menupaletteSpec.js
│ │ ├── paletteSpec.js
│ │ └── radiobuttonsgroupSpec.js
│ │ ├── karma-shared.conf.js
│ │ ├── karma-unit.conf.js
│ │ ├── karma.conf.js
│ │ ├── loader.js
│ │ └── unit
│ │ ├── busSpec.js
│ │ ├── datastoreSpec.js
│ │ ├── dictstoreSpec.js
│ │ └── envSpec.js
├── text.js
└── webL10n.js
├── package-lock.json
├── package.json
├── public
├── activity
│ ├── activity-icon.svg
│ └── activity.info
├── index.html
├── lib
│ ├── domReady.js
│ ├── humane.js
│ ├── mustache.js
│ ├── picoModal.js
│ ├── require.js
│ ├── sugar-web
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── activity
│ │ │ ├── activity.js
│ │ │ └── shortcut.js
│ │ ├── bus.js
│ │ ├── bus
│ │ │ ├── sugarizer.js
│ │ │ └── sugaros.js
│ │ ├── datastore.js
│ │ ├── datastore
│ │ │ ├── sugarizer.js
│ │ │ └── sugaros.js
│ │ ├── dictstore.js
│ │ ├── env.js
│ │ ├── graphics
│ │ │ ├── README.md
│ │ │ ├── activitypalette.html
│ │ │ ├── activitypalette.js
│ │ │ ├── css
│ │ │ │ ├── sugar-200dpi.css
│ │ │ │ ├── sugar-200dpi.less
│ │ │ │ ├── sugar-96dpi.css
│ │ │ │ ├── sugar-96dpi.less
│ │ │ │ └── sugar.less
│ │ │ ├── evaluationpalette.js
│ │ │ ├── grid.js
│ │ │ ├── icon.js
│ │ │ ├── icons
│ │ │ │ ├── actions
│ │ │ │ │ ├── activity-abecedarium.svg
│ │ │ │ │ ├── activity-journal.svg
│ │ │ │ │ ├── activity-stop.svg
│ │ │ │ │ ├── checkbox-checked-selected.svg
│ │ │ │ │ ├── checkbox-checked.svg
│ │ │ │ │ ├── checkbox-unchecked-selected.svg
│ │ │ │ │ ├── checkbox-unchecked.svg
│ │ │ │ │ ├── dialog-cancel-active.svg
│ │ │ │ │ ├── dialog-cancel.svg
│ │ │ │ │ ├── dialog-ok-active.svg
│ │ │ │ │ ├── dialog-ok.svg
│ │ │ │ │ ├── entry-cancel-active.svg
│ │ │ │ │ ├── entry-cancel-disabled.svg
│ │ │ │ │ ├── entry-cancel.svg
│ │ │ │ │ ├── photo.svg
│ │ │ │ │ ├── radio-active-selected.svg
│ │ │ │ │ ├── radio-active.svg
│ │ │ │ │ ├── radio-selected.svg
│ │ │ │ │ ├── radio.svg
│ │ │ │ │ ├── zoom-groups.svg
│ │ │ │ │ ├── zoom-home.svg
│ │ │ │ │ └── zoom-neighborhood.svg
│ │ │ │ └── emblems
│ │ │ │ │ ├── arrow-down.svg
│ │ │ │ │ ├── arrow-up.svg
│ │ │ │ │ └── favorite.svg
│ │ │ ├── journalchooser.js
│ │ │ ├── menupalette.html
│ │ │ ├── menupalette.js
│ │ │ ├── palette.js
│ │ │ ├── presencepalette.js
│ │ │ ├── radiobuttonsgroup.js
│ │ │ └── xocolor.js
│ │ ├── package.json
│ │ ├── presence.js
│ │ └── test
│ │ │ ├── functional
│ │ │ ├── datastoreSpec.js
│ │ │ └── toolkitContractSpec.js
│ │ │ ├── graphics
│ │ │ ├── iconSpec.js
│ │ │ ├── menupaletteSpec.js
│ │ │ ├── paletteSpec.js
│ │ │ └── radiobuttonsgroupSpec.js
│ │ │ ├── karma-shared.conf.js
│ │ │ ├── karma-unit.conf.js
│ │ │ ├── karma.conf.js
│ │ │ ├── loader.js
│ │ │ └── unit
│ │ │ ├── busSpec.js
│ │ │ ├── datastoreSpec.js
│ │ │ ├── dictstoreSpec.js
│ │ │ └── envSpec.js
│ ├── text.js
│ └── webL10n.js
└── manifest.json
├── readme.md
├── screenshots
├── CLOZE_Player.png
├── Detailed_Results.png
├── FREETEXT_Player.png
├── GROUP_Player.png
├── Home_Screen.png
├── Image_Editor.png
├── MATCH_Player.png
├── MCQPlayer.png
├── MCQ_FORM.png
├── Presence.png
├── REORDER_Form.png
├── REORER_Player.png
├── Scores_Screen.png
├── Template_Screen.png
├── Tutorial.png
└── screenshots.gif
└── src
├── components
├── DragList.js
├── Exercise.js
├── ExerciseListItem.js
├── ImageEditor.js
├── MainToolbar.js
├── MultimediaJSX.js
├── Navbar.js
├── Tutorial.js
├── UserIcon.js
├── UserList.js
└── WithMultimedia.js
├── containers
├── App.js
├── Builders
│ ├── CLOZEForm.js
│ ├── FreeTextInputForm.js
│ ├── GroupAssignmentForm.js
│ ├── MCQForm.js
│ ├── MatchingForm.js
│ ├── REORDERForm.js
│ ├── Template.js
│ └── WordPuzzleForm.js
├── ExerciseList.js
├── Players
│ ├── CLOZEPlayer.js
│ ├── FreeTextInputPlayer.js
│ ├── GroupAssignmentPlayer.js
│ ├── MCQPlayer.js
│ ├── MatchingPlayer.js
│ ├── REORDERPlayer.js
│ └── WordPuzzlePlayer.js
├── Router.js
├── Scores
│ ├── PresenceScores.js
│ ├── ScoreHoc.js
│ └── Scores.js
├── Sugarizer.js
└── translation.js
├── css
├── CLOZEForm.css
├── CLOZEPlayer.css
├── DragList.css
├── Evaluation.css
├── Exercise.css
├── ExerciseDragList.css
├── ExerciseList.css
├── FreeTextInputForm.css
├── FreeTextInputPlayer.css
├── GroupAssignmentForm.css
├── GroupAssignmentPlayer.css
├── ImageEditor.css
├── MCQForm.css
├── MCQPlayer.css
├── MatchingForm.css
├── MatchingPlayer.css
├── Navbar.css
├── NewExerciseTemplate.css
├── PresenceScores.css
├── REORDERForm.css
├── REORDERPlayer.css
├── Scores.css
├── Tutorial.css
├── UserList.css
├── WordPuzzleForm.css
├── WordPuzzlePlayer.css
├── index.css
└── libnotify.css
├── default_activities.json
├── icons
├── exercise
│ ├── ArrowSmall.cur
│ ├── audio.svg
│ ├── clock.svg
│ ├── cog.svg
│ ├── correct.png
│ ├── delete.svg
│ ├── details.png
│ ├── dialog-cancel.svg
│ ├── dialog-ok.svg
│ ├── down.svg
│ ├── edit.svg
│ ├── eval-mode.svg
│ ├── go-left.svg
│ ├── go-right.svg
│ ├── help.svg
│ ├── insert-image.svg
│ ├── left.svg
│ ├── owner-icon.svg
│ ├── percent.svg
│ ├── photo.svg
│ ├── play-button.svg
│ ├── redo.svg
│ ├── reorder-drag.png
│ ├── reorder-drag.svg2
│ ├── result.svg
│ ├── right.svg
│ ├── sound_off_black.png
│ ├── sound_off_white.png
│ ├── sound_on_black.png
│ ├── sound_on_white.png
│ ├── speak.svg
│ ├── sub.svg
│ ├── up.svg
│ ├── user.svg
│ ├── video.svg
│ └── wrong.png
└── navbar
│ ├── activity-icon.svg
│ ├── add.svg
│ ├── async-mode.svg
│ ├── cog.svg
│ ├── eval-mode.svg
│ ├── export-eval.svg
│ ├── fullscreen.svg
│ ├── home.svg
│ ├── play.svg
│ ├── shareAll.svg
│ ├── unfullscreen.svg
│ ├── zoom-home.svg
│ └── zoom-neighborhood.svg
├── index.js
├── media
├── defaultExerciseThumbnail
│ ├── images
│ │ ├── README.md
│ │ ├── animal.png
│ │ ├── bark.png
│ │ ├── canoe.png
│ │ ├── car.png
│ │ ├── cat.png
│ │ ├── conjugate.jpg
│ │ ├── cow.png
│ │ ├── discount.png
│ │ ├── dog.png
│ │ ├── numerals.jpg
│ │ ├── plane.png
│ │ ├── puzzle.png
│ │ ├── sail.png
│ │ ├── sheep.png
│ │ └── world.png
│ ├── sounds
│ │ ├── README.md
│ │ ├── cat.mp3
│ │ ├── cow.mp3
│ │ ├── dog.mp3
│ │ ├── sheep.mp3
│ │ └── train.mp3
│ └── videos
│ │ └── README.md
└── template
│ ├── cloze_image.svg
│ ├── freetext_input_image.svg
│ ├── group_image.svg
│ ├── list_reorder_image.svg
│ ├── matching_pair_image.svg
│ ├── mcq_image.svg
│ └── word_puzzle_image.svg
├── mespeak_config.json
├── registerServiceWorker.js
├── store
├── actionTypes.js
├── actions
│ ├── evaluation.js
│ ├── exercises.js
│ ├── increment_counter.js
│ ├── presence.js
│ └── sugarizer.js
├── index.js
└── reducers
│ ├── current_user.js
│ ├── evaluation_exercise.js
│ ├── evaluation_mode.js
│ ├── exercise_counter.js
│ ├── exercises.js
│ ├── index.js
│ ├── presence
│ ├── isHost.js
│ ├── isShared.js
│ ├── shareAll.js
│ ├── sharedExercises.js
│ └── users.js
│ ├── run_all.js
│ └── run_all_exercise_index.js
├── translations
├── en.json
├── es.json
├── fr.json
└── lang.js
├── tutorialSteps.js
└── utils.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 | .idea/
3 |
4 | build/
5 |
6 | # dependencies
7 | /node_modules
8 |
9 | # testing
10 | /coverage
11 |
12 | # production
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | As with all Open Source software, contributions to Exerciser are welcome.
2 |
3 | An excellent way to contribute is testing and trying Exerciser to find some issues. If you find one, don't be shy; submit your issue [here](https://github.com/llaske/Exerciser/issues) by giving the maximum information on it and precisely detailed steps to reproduce it. We will check your issue and ask you for more information if needed.
4 |
5 | If you're a developer, the best way is to first [setup Exerciser](https://github.com/llaske/ExerciserReact#steps-to-run-project) and then also [setup Sugarizer](https://github.com/llaske/sugarizer/blob/dev/docs/tutorial/VanillaJS/step0.md). Testing the functionality requires using Sugarizer features like `Sharing the Exercise,` `Using Journals,` and many more need Exerciser to be deployed on Sugarizer.
6 |
7 | When you think you're ready, you could try to fix some current issues [here](https://github.com/llaske/Exerciser/issues). If you find a fix, send a Pull Request, and we will be pleased to review it.
8 |
9 |
10 | So to send your Pull Request:
11 |
12 | * [ ] Clone this repository,
13 | * [ ] Fork the **master** branch of your new repository,
14 | * [ ] Update this new branch with your contribution and commit your changes,
15 | * [ ] Send a pull request from your new branch to the dev branch of this repository.
16 |
17 | Few rules to respect when you fix an issue:
18 |
19 | * [ ] Ensure your pull request contains only updates related to the fix,
20 | * [ ] Respect indentation of the original file,
21 | * [ ] Mention the issue number in the pull request but not in the commit message
22 |
23 |
24 | Please note there is no need to ask permission to work on an issue. You should check for pull requests linked to an issue you are addressing; if there are none, assume nobody has done anything. Begin to fix the problem, test, make your commits, push your commits, then make a pull request. These practices allow the competition of ideas and give priority to meritocracy.
25 |
26 | Thanks in advance for your contribution, and become a member of the Exerciser community!
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | Copyright 2018 Mankirat Singh and Avinash Agarwal
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
--------------------------------------------------------------------------------
/config-overrides.js:
--------------------------------------------------------------------------------
1 | const CopyWebpackPlugin = require('copy-webpack-plugin');
2 |
3 | module.exports = function override(config, env) {
4 | let resolvePlugin = (config.resolveLoader ? config.resolveLoader : {});
5 | resolvePlugin['alias'] = {
6 | 'text': 'text-loader'
7 | };
8 | config['resolveLoader'] = resolvePlugin;
9 |
10 | let resolvePath = config.resolve.alias;
11 | resolvePath['webL10n'] = 'lib/webL10n';
12 | resolvePath['sugar-web'] = 'lib/sugar-web';
13 | resolvePath['mustache'] = 'lib/mustache';
14 | resolvePath['picoModal'] = 'lib/picoModal';
15 | config.resolve.alias = resolvePath;
16 |
17 | return config;
18 | }
--------------------------------------------------------------------------------
/lib/sugar-web/README.md:
--------------------------------------------------------------------------------
1 | Sugar Web
2 | =========
3 |
4 | These are the tools that a developer can use to make a web
5 | activity.
6 |
7 | For details see: http://developer.sugarlabs.org/
8 |
--------------------------------------------------------------------------------
/lib/sugar-web/activity/shortcut.js:
--------------------------------------------------------------------------------
1 | define(function () {
2 |
3 | 'use strict';
4 |
5 | var shortcut = {};
6 |
7 | shortcut._allShortcuts = [];
8 |
9 | shortcut.add = function (modifiersString, key, callback) {
10 | // Parse the modifiers. For example "Ctrl+Alt" will become
11 | // {'ctrlKey': true, 'altKey': true, 'shiftKey': false}
12 | var modifiersList = modifiersString.toLowerCase().split("+");
13 | var modifiers = {
14 | 'ctrlKey': modifiersList.indexOf('ctrl') >= 0,
15 | 'altKey': modifiersList.indexOf('alt') >= 0,
16 | 'shiftKey': modifiersList.indexOf('shift') >= 0
17 | };
18 |
19 | this._allShortcuts.push({
20 | 'modifiers': modifiers,
21 | 'key': key.toLowerCase(),
22 | 'callback': callback
23 | });
24 | };
25 |
26 | document.onkeypress = function (e) {
27 | e = e || window.event;
28 |
29 | var modifiers = {
30 | 'ctrlKey': e.ctrlKey,
31 | 'altKey': e.altKey,
32 | 'shiftKey': e.shiftKey
33 | };
34 |
35 | // Obtain the key
36 | var charCode;
37 | if (typeof e.which == "number") {
38 | charCode = e.which;
39 | } else {
40 | charCode = e.keyCode;
41 | }
42 | var key = String.fromCharCode(charCode).toLowerCase();
43 |
44 | // Search for a matching shortcut
45 | for (var i = 0; i < shortcut._allShortcuts.length; i += 1) {
46 | var currentShortcut = shortcut._allShortcuts[i];
47 |
48 | var match = currentShortcut.key == key &&
49 | currentShortcut.modifiers.ctrlKey == modifiers.ctrlKey &&
50 | currentShortcut.modifiers.altKey == modifiers.altKey &&
51 | currentShortcut.modifiers.shiftKey == modifiers.shiftKey;
52 | if (match) {
53 | currentShortcut.callback();
54 | return;
55 | }
56 | }
57 | };
58 |
59 | return shortcut;
60 | });
61 |
--------------------------------------------------------------------------------
/lib/sugar-web/bus.js:
--------------------------------------------------------------------------------
1 | define(["sugar-web/env", "sugar-web/bus/sugarizer", "sugar-web/bus/sugaros"], function(env, sugarizer, sugaros) {
2 |
3 | 'use strict';
4 |
5 | var bus;
6 |
7 | if (env.isSugarizer()) {
8 | bus = sugarizer;
9 | } else {
10 | bus = sugaros;
11 | }
12 |
13 | return bus;
14 | });
15 |
--------------------------------------------------------------------------------
/lib/sugar-web/bus/sugarizer.js:
--------------------------------------------------------------------------------
1 | define(["sugar-web/env"], function (env) {
2 |
3 | 'use strict';
4 |
5 | var bus = {};
6 |
7 | function WebSocketClient(environment) {
8 | }
9 |
10 | WebSocketClient.prototype.send = function (data) {
11 | };
12 |
13 | WebSocketClient.prototype.close = function () {
14 | };
15 |
16 | function InputStream() {
17 | }
18 |
19 | InputStream.prototype.open = function (callback) {
20 | };
21 |
22 | InputStream.prototype.read = function (count, callback) {
23 | };
24 |
25 | InputStream.prototype.gotData = function (buffer) {
26 | };
27 |
28 | InputStream.prototype.close = function (callback) {
29 | };
30 |
31 | function OutputStream() {
32 | }
33 |
34 | OutputStream.prototype.open = function (callback) {
35 | };
36 |
37 | OutputStream.prototype.write = function (data) {
38 | };
39 |
40 | OutputStream.prototype.close = function (callback) {
41 | };
42 |
43 | bus.createInputStream = function (callback) {
44 | };
45 |
46 | bus.createOutputStream = function (callback) {
47 | };
48 |
49 | bus.sendMessage = function (method, params, callback) {
50 | if (method == "activity.close") {
51 | window.location = "../../index.html";
52 | } else if (method == "activity.get_xo_color") {
53 | var color = {stroke: "#FF2B34", fill: "#005FE4"};
54 | if (typeof chrome != 'undefined' && chrome.app && chrome.app.runtime) {
55 | chrome.storage.local.get("sugar_settings", function(values) {
56 | color = JSON.parse(values.sugar_settings).colorvalue;
57 | callback(null, [[color.stroke, color.fill]]);
58 | });
59 | } else if (typeof(Storage)!=="undefined" && typeof(window.localStorage)!=="undefined") {
60 | try {
61 | color = JSON.parse(window.localStorage.getItem("sugar_settings")).colorvalue;
62 | } catch(err) {}
63 | }
64 | callback(null, [[color.stroke, color.fill]]);
65 | }
66 | return;
67 | };
68 |
69 | bus.onNotification = function (method, callback) {
70 | };
71 |
72 | bus.sendBinary = function (buffer, callback) {
73 | };
74 |
75 | bus.listen = function (customClient) {
76 | };
77 |
78 | bus.close = function () {
79 | };
80 |
81 | return bus;
82 | });
83 |
--------------------------------------------------------------------------------
/lib/sugar-web/datastore.js:
--------------------------------------------------------------------------------
1 | define(["sugar-web/env", "sugar-web/datastore/sugarizer", "sugar-web/datastore/sugaros"], function(env, sugarizer, sugaros) {
2 |
3 | 'use strict';
4 |
5 | var datastore ;
6 |
7 | if (env.isSugarizer()) {
8 | datastore = sugarizer;
9 | } else {
10 | datastore = sugaros;
11 | }
12 |
13 | return datastore;
14 | });
15 |
--------------------------------------------------------------------------------
/lib/sugar-web/dictstore.js:
--------------------------------------------------------------------------------
1 | define(["sugar-web/activity/activity", "sugar-web/env"], function (activity, env) {
2 |
3 | 'use strict';
4 |
5 | // This is a helper module that allows to persist key/value data
6 | // using the standard localStorage object.
7 | //
8 | // Usage:
9 | // ------
10 | //
11 | // // 1. Setup:
12 | //
13 | // dictstore.init(onReadyCallback);
14 | //
15 | // // 2. Use localStorage directly, and then call save():
16 | //
17 | // var value = localStorage['key'];
18 | // localStorage['key'] = newValue;
19 | // dictstore.save(onSavedCallback);
20 | //
21 | var dictstore = {};
22 |
23 | dictstore.init = function (callback) {
24 |
25 | if (env.isStandalone()) {
26 | // In standalone mode, use localStorage as is.
27 | callback();
28 |
29 | } else {
30 | // In Sugar, set localStorage from the datastore.
31 | localStorage.clear();
32 |
33 | var onLoaded = function (error, metadata, jsonData) {
34 | var data = JSON.parse(jsonData);
35 | for (var i in data) {
36 | localStorage[i] = data[i];
37 | }
38 |
39 | callback();
40 |
41 | };
42 | activity.getDatastoreObject().loadAsText(onLoaded);
43 | }
44 | };
45 |
46 | // Internally, the key/values are stored as text in the Sugar
47 | // datastore, using the JSON format.
48 | dictstore.save = function (callback) {
49 | if (callback === undefined) {
50 | callback = function () {};
51 | }
52 |
53 | if (env.isStandalone()) {
54 | // In standalone mode, use localStorage as is.
55 | callback();
56 | } else {
57 | var datastoreObject = activity.getDatastoreObject();
58 | var jsonData = JSON.stringify(localStorage);
59 | datastoreObject.setDataAsText(jsonData);
60 | datastoreObject.save(function (error) {
61 | callback(error);
62 | });
63 | }
64 | };
65 |
66 | return dictstore;
67 |
68 | });
69 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/README.md:
--------------------------------------------------------------------------------
1 | Sugar Graphics
2 | ==============
3 |
4 | Sugar widgets and graphics, implementing the [Sugar Interface
5 | Guidelines](http://wiki.sugarlabs.org/go/Human_Interface_Guidelines).
6 |
7 | Modifying the CSS
8 | -----------------
9 |
10 | We use [LESS](http://lesscss.org) and then compile the CSS files.
11 | This is to be able to use calculations and variables for colors and
12 | measures. And to be able to output different CSS files for different
13 | screen resolutions.
14 |
15 | To compile the CSS files do:
16 |
17 | lessc graphics/css/sugar-96dpi.less graphics/css/sugar-96dpi.css
18 | lessc graphics/css/sugar-200dpi.less graphics/css/sugar-200dpi.css
19 |
20 | Be sure to compile them before commit.
21 |
22 | The grid helper
23 | ---------------
24 |
25 | The grid is a visual debug tool that allows you to check if the
26 | elements have the correct size. To activate the grid, open the
27 | inspector console and paste the following.
28 |
29 | If RequireJS is not in the page head (ie. in the sugar-web-samples),
30 | load it:
31 |
32 | var script = document.createElement('script');
33 | script.src = 'lib/require.js';
34 | document.head.appendChild(script);
35 |
36 | requirejs.config({ baseUrl: "lib" });
37 |
38 | Then do:
39 |
40 | require(["sugar-web/graphics/grid"], function (grid) { grid.addGrid(11) });
41 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/activitypalette.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/activitypalette.js:
--------------------------------------------------------------------------------
1 | define(["sugar-web/graphics/palette",
2 | "text!sugar-web/graphics/activitypalette.html"], function (palette, template) {
3 |
4 | 'use strict';
5 |
6 | var activitypalette = {};
7 |
8 | activitypalette.ActivityPalette = function (activityButton,
9 | datastoreObject) {
10 |
11 | palette.Palette.call(this, activityButton);
12 |
13 | var activityTitle;
14 | var descriptionLabel;
15 | var descriptionBox;
16 |
17 | this.getPalette().id = "activity-palette";
18 |
19 | var containerElem = document.createElement('div');
20 | containerElem.innerHTML = template;
21 | this.setContent([containerElem]);
22 |
23 | this.titleElem = containerElem.querySelector('#title');
24 | this.descriptionElem = containerElem.querySelector('#description');
25 |
26 | this.titleElem.onblur = function () {
27 | datastoreObject.setMetadata({
28 | "title": this.value,
29 | "title_set_by_user": "1"
30 | });
31 | datastoreObject.save();
32 | };
33 |
34 | this.descriptionElem.onblur = function () {
35 | datastoreObject.setMetadata({
36 | "description": this.value
37 | });
38 | datastoreObject.save();
39 | };
40 | };
41 |
42 | // Fill the text inputs with the received metadata.
43 | var setTitleDescription = function (metadata) {
44 | this.titleElem.value = metadata.title;
45 |
46 | if (metadata.description !== undefined) {
47 | this.descriptionElem.value = metadata.description;
48 | }
49 | };
50 |
51 | activitypalette.ActivityPalette.prototype =
52 | Object.create(palette.Palette.prototype, {
53 | setTitleDescription: {
54 | value: setTitleDescription,
55 | enumerable: true,
56 | configurable: true,
57 | writable: true
58 | }
59 | });
60 |
61 | return activitypalette;
62 | });
63 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/css/sugar-200dpi.less:
--------------------------------------------------------------------------------
1 | @subcell-size: 15px;
2 | @import "sugar.less";
3 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/css/sugar-96dpi.less:
--------------------------------------------------------------------------------
1 | @subcell-size: 11px;
2 | @import "sugar.less";
3 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/grid.js:
--------------------------------------------------------------------------------
1 | define(function () {
2 |
3 | 'use strict';
4 |
5 | var grid = {};
6 |
7 | // Add a grid overlay with lines spaced by subcellSize, for visual
8 | // debugging. This is useful while doing the activity layout or
9 | // while developing widgets.
10 | grid.addGrid = function (subcellSize) {
11 | var canvas = document.createElement('canvas');
12 | canvas.className = "grid";
13 | document.body.appendChild(canvas);
14 |
15 | var updateGrid = function () {
16 | canvas.width = window.innerWidth;
17 | canvas.height = window.innerHeight;
18 |
19 | var ctx = canvas.getContext("2d");
20 | ctx.strokeStyle = "#00FFFF";
21 |
22 | var subcellsVertical = window.innerHeight / subcellSize;
23 | for (i = 0; i < subcellsVertical; i++) {
24 | if ((i + 1) % 5 === 0) {
25 | ctx.lineWidth = 1;
26 | } else {
27 | ctx.lineWidth = 0.5;
28 | }
29 | ctx.beginPath();
30 | ctx.moveTo(0, subcellSize * (i + 1));
31 | ctx.lineTo(canvas.width, subcellSize * (i + 1));
32 | ctx.stroke();
33 | }
34 |
35 | var subcellsHorizontal = window.innerWidth / subcellSize;
36 | for (i = 0; i < subcellsHorizontal; i++) {
37 | if ((i + 1) % 5 === 0) {
38 | ctx.lineWidth = 1;
39 | } else {
40 | ctx.lineWidth = 0.5;
41 | }
42 | ctx.beginPath();
43 | ctx.moveTo(subcellSize * (i + 1), 0);
44 | ctx.lineTo(subcellSize * (i + 1), canvas.height);
45 | ctx.stroke();
46 | }
47 | };
48 |
49 | updateGrid();
50 |
51 | window.onresize = function (event) {
52 | updateGrid();
53 | };
54 | };
55 |
56 | return grid;
57 | });
58 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/icons/actions/activity-journal.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/icons/actions/activity-stop.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/icons/actions/checkbox-checked-selected.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ]>
6 |
28 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/icons/actions/checkbox-checked.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ]>
6 |
28 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/icons/actions/checkbox-unchecked-selected.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 | ]>
5 |
23 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/icons/actions/checkbox-unchecked.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 | ]>
5 |
23 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/icons/actions/dialog-cancel-active.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
7 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/icons/actions/dialog-cancel.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/icons/actions/dialog-ok-active.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
7 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/icons/actions/dialog-ok.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/icons/actions/entry-cancel-active.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ]>
6 |
24 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/icons/actions/entry-cancel-disabled.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ]>
6 |
22 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/icons/actions/entry-cancel.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ]>
6 |
22 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/icons/actions/radio-active-selected.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ]>
6 |
32 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/icons/actions/radio-active.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ]>
6 |
32 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/icons/actions/radio-selected.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ]>
6 |
27 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/icons/actions/radio.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ]>
6 |
27 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/icons/actions/zoom-groups.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/icons/actions/zoom-home.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/icons/actions/zoom-neighborhood.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/icons/emblems/arrow-down.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ]>
6 |
21 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/icons/emblems/arrow-up.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ]>
6 |
21 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/icons/emblems/favorite.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/menupalette.html:
--------------------------------------------------------------------------------
1 | {{#.}}
2 |
3 |
7 |
8 | {{/.}}
9 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/menupalette.js:
--------------------------------------------------------------------------------
1 | define(["sugar-web/graphics/palette",
2 | "text!sugar-web/graphics/menupalette.html", "mustache"], function (palette, template, mustache) {
3 |
4 | 'use strict';
5 |
6 | var menupalette = {};
7 |
8 | menupalette.MenuPalette = function (invoker, primaryText, menuData) {
9 | palette.Palette.call(this, invoker, primaryText);
10 |
11 | this.selectItemEvent = document.createEvent("CustomEvent");
12 | this.selectItemEvent.initCustomEvent('selectItem', true, true, {
13 | 'item': undefined
14 | });
15 |
16 | var menuElem = document.createElement('ul');
17 | menuElem.className = "menu";
18 | menuElem.innerHTML = mustache.render(template, menuData);
19 | this.setContent([menuElem]);
20 |
21 | // Pop-down the palette when a item in the menu is clicked.
22 |
23 | this.buttons = menuElem.querySelectorAll('button');
24 |
25 | var that = this;
26 |
27 | function popDownOnButtonClick(event) {
28 | that.selectItemEvent.detail.target = event.target;
29 | that.getPalette().dispatchEvent(that.selectItemEvent);
30 | that.popDown();
31 | }
32 |
33 | for (var i = 0; i < this.buttons.length; i++) {
34 | this.buttons[i].addEventListener('click', popDownOnButtonClick);
35 | }
36 | };
37 |
38 | var addEventListener = function (type, listener, useCapture) {
39 | return this.getPalette().addEventListener(type, listener, useCapture);
40 | };
41 |
42 | menupalette.MenuPalette.prototype =
43 | Object.create(palette.Palette.prototype, {
44 | addEventListener: {
45 | value: addEventListener,
46 | enumerable: true,
47 | configurable: true,
48 | writable: true
49 | }
50 | });
51 |
52 | return menupalette;
53 | });
54 |
--------------------------------------------------------------------------------
/lib/sugar-web/graphics/radiobuttonsgroup.js:
--------------------------------------------------------------------------------
1 | define(function () {
2 |
3 | 'use strict';
4 |
5 | var radioButtonsGroup = {};
6 |
7 | // ## RadioButtonsGroup
8 | //
9 | // A group of elements where only one can be active at the same
10 | // time.
11 | //
12 | // When an element is clicked, it becomes the active one. The
13 | // active element gains the 'active' CSS class.
14 | //
15 | // Parameters:
16 | //
17 | // * **elems** Array of elements of the group.
18 | radioButtonsGroup.RadioButtonsGroup = function (elems) {
19 | this.elems = elems;
20 | var active;
21 |
22 | for (var i = 0; i < elems.length; i++) {
23 | var elem = elems[i];
24 | elem.addEventListener("click", clickHandler);
25 |
26 | // The first element that has 'active' CSS class is made
27 | // the active of the group on startup.
28 | if (active === undefined && elem.classList.contains('active')) {
29 | active = elem;
30 | }
31 | }
32 |
33 | // If no element has 'active' CSS class, the first element of
34 | // the array is made the active.
35 | if (active === undefined) {
36 | active = elems[0];
37 | updateClasses();
38 | }
39 |
40 | function clickHandler(evt) {
41 | active = evt.target;
42 | updateClasses();
43 | }
44 |
45 | function updateClasses() {
46 | for (i = 0; i < elems.length; i++) {
47 | var elem = elems[i];
48 | elem.classList.remove('active');
49 | }
50 | active.classList.add('active');
51 | }
52 |
53 | // Get the active element.
54 | this.getActive = function () {
55 | return active;
56 | };
57 |
58 | };
59 |
60 | return radioButtonsGroup;
61 |
62 | });
63 |
--------------------------------------------------------------------------------
/lib/sugar-web/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "volo": {
3 | "baseUrl": "lib",
4 | "dependencies": {
5 | "webL10n": "github:sugarlabs/webL10n",
6 | "mustache": "github:janl/mustache.js/0.7.2",
7 | "text": "github:requirejs/text"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/lib/sugar-web/test/functional/toolkitContractSpec.js:
--------------------------------------------------------------------------------
1 | define(["sugar-web/env"], function (env) {
2 |
3 | 'use strict';
4 |
5 | describe("Environment object", function () {
6 |
7 | it("should have valid properties", function () {
8 | //FIXME: we shouldn't stub this here.
9 | //current implementation of isStandalone fails with sugar-web-test
10 | spyOn(env, 'isStandalone').andReturn(false);
11 |
12 | var expectedEnv;
13 |
14 | runs(function () {
15 | env.getEnvironment(function (error, environment) {
16 | expectedEnv = environment;
17 | });
18 | });
19 |
20 | waitsFor(function () {
21 | return expectedEnv !== undefined;
22 | }, "should get sugar environment");
23 |
24 | runs(function () {
25 | expect(expectedEnv.bundleId).not.toBeUndefined();
26 | expect(expectedEnv.activityId).not.toBeUndefined();
27 | expect(expectedEnv.activityName).not.toBeUndefined();
28 | });
29 | });
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/lib/sugar-web/test/graphics/iconSpec.js:
--------------------------------------------------------------------------------
1 | define(["sugar-web/graphics/icon"], function (icon) {
2 |
3 | 'use strict';
4 |
5 | describe("icon", function () {
6 | var wasLoaded;
7 | var iconUrlResult;
8 |
9 | it("should be able to change icon more than once", function () {
10 | var elem = document.createElement('div');
11 | var iconUrl;
12 |
13 | function callback(url) {
14 | iconUrlResult = url;
15 | wasLoaded = true;
16 | }
17 |
18 | runs(function () {
19 | wasLoaded = false;
20 | iconUrl = "/base/graphics/icons/actions/dialog-ok-active.svg";
21 | var iconInfo = {
22 | "uri": iconUrl,
23 | "strokeColor": '#B20008',
24 | "fillColor": '#FF2B34'
25 | };
26 | icon.load(iconInfo, callback);
27 | });
28 |
29 | waitsFor(function () {
30 | return wasLoaded;
31 | }, "icon loaded");
32 |
33 | runs(function () {
34 | expect(iconUrlResult).not.toBe(iconUrl);
35 | });
36 |
37 | runs(function () {
38 | wasLoaded = false;
39 | iconUrl = iconUrlResult;
40 | var iconInfo = {
41 | "uri": iconUrl,
42 | "strokeColor": '#FF2B34',
43 | "fillColor": '#B20008'
44 | };
45 | icon.load(iconInfo, callback);
46 | });
47 |
48 | waitsFor(function () {
49 | return wasLoaded;
50 | }, "icon loaded");
51 |
52 | runs(function () {
53 | expect(iconUrlResult).not.toBe(iconUrl);
54 | });
55 |
56 | });
57 | });
58 |
59 | });
60 |
--------------------------------------------------------------------------------
/lib/sugar-web/test/graphics/paletteSpec.js:
--------------------------------------------------------------------------------
1 | define(["sugar-web/graphics/palette"], function (palette) {
2 |
3 | 'use strict';
4 |
5 | describe("palette", function () {
6 | it("should start down", function () {
7 | var invoker = document.createElement('button');
8 | var myPalette = new palette.Palette(invoker);
9 | expect(myPalette.isDown()).toBe(true);
10 | });
11 |
12 | it("should toggle", function () {
13 | var invoker = document.createElement('button');
14 | var myPalette = new palette.Palette(invoker);
15 | myPalette.toggle();
16 | expect(myPalette.isDown()).toBe(false);
17 | myPalette.toggle();
18 | expect(myPalette.isDown()).toBe(true);
19 | });
20 |
21 | it("if one palette in a group popups, the others popdown", function () {
22 | var invokerA = document.createElement('button');
23 | var invokerB = document.createElement('button');
24 | var myPaletteA = new palette.Palette(invokerA);
25 | var myPaletteB = new palette.Palette(invokerB);
26 | myPaletteA.toggle();
27 | expect(myPaletteA.isDown()).toBe(false);
28 | expect(myPaletteB.isDown()).toBe(true);
29 | myPaletteB.toggle();
30 | expect(myPaletteA.isDown()).toBe(true);
31 | expect(myPaletteB.isDown()).toBe(false);
32 | });
33 |
34 | });
35 |
36 | });
37 |
--------------------------------------------------------------------------------
/lib/sugar-web/test/karma-shared.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 | // Generated on Mon May 13 2013 10:01:17 GMT-0300 (ART)
3 |
4 |
5 | // list of files / patterns to load in the browser
6 | module.exports = function (config) {
7 | config.set({
8 | frameworks: ['jasmine', 'requirejs'],
9 |
10 |
11 | // base path, that will be used to resolve files and exclude
12 | basePath: '..',
13 |
14 |
15 | files: [
16 | 'test/loader.js',
17 | {
18 | pattern: 'lib/**/*.js',
19 | included: false
20 | }, {
21 | pattern: '*.js',
22 | included: false
23 | }, {
24 | pattern: 'activity/**/*.js',
25 | included: false
26 | }, {
27 | pattern: 'graphics/**/*',
28 | included: false
29 | }
30 | ],
31 |
32 |
33 | // list of files to exclude
34 | exclude: [],
35 |
36 |
37 | // test results reporter to use
38 | // possible values: 'dots', 'progress', 'junit'
39 | reporters: ['progress'],
40 |
41 |
42 | // web server port
43 | port: 9876,
44 |
45 |
46 | // cli runner port
47 | runnerPort: 9100,
48 |
49 |
50 | // enable / disable colors in the output (reporters and logs)
51 | colors: true,
52 |
53 |
54 | // level of logging
55 | // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO ||
56 | // LOG_DEBUG
57 | logLevel: config.LOG_INFO,
58 |
59 |
60 | // enable / disable watching file and executing tests whenever any file
61 | // changes
62 | autoWatch: true,
63 |
64 |
65 | // If browser does not capture in given timeout [ms], kill it
66 | captureTimeout: 60000,
67 |
68 |
69 | // Continuous Integration mode
70 | // if true, it capture browsers, run tests and exit
71 | singleRun: false,
72 |
73 | preprocessors: {}
74 | });
75 | };
76 |
--------------------------------------------------------------------------------
/lib/sugar-web/test/karma-unit.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration for unit tests
2 |
3 | sharedConfig = require("./karma-shared.conf.js");
4 |
5 | module.exports = function (config) {
6 | var testFiles = [
7 | {
8 | pattern: 'test/unit/*Spec.js',
9 | included: false
10 | }, {
11 | pattern: 'test/graphics/*Spec.js',
12 | included: false
13 | },
14 | ];
15 |
16 | sharedConfig(config);
17 |
18 | config.files = config.files.concat(testFiles);
19 | };
20 |
--------------------------------------------------------------------------------
/lib/sugar-web/test/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration for all the tests
2 |
3 | sharedConfig = require("./karma-shared.conf.js");
4 |
5 | module.exports = function (config) {
6 | var testFiles = [
7 | {
8 | pattern: 'test/**/*Spec.js',
9 | included: false
10 | }
11 | ];
12 |
13 | sharedConfig(config);
14 |
15 | config.files = config.files.concat(testFiles);
16 | };
17 |
--------------------------------------------------------------------------------
/lib/sugar-web/test/loader.js:
--------------------------------------------------------------------------------
1 | var tests = Object.keys(window.__karma__.files).filter(function (file) {
2 | return (/Spec\.js$/).test(file);
3 | });
4 |
5 | requirejs.config({
6 | // Karma serves files from '/base'
7 | baseUrl: "/base",
8 |
9 | paths: {
10 | "sugar-web": ".",
11 | "mustache": "lib/mustache",
12 | "text": "lib/text",
13 | "webL10n": "lib/webL10n"
14 | },
15 |
16 | // ask Require.js to load these files (all our tests)
17 | deps: tests,
18 |
19 | // start test run, once Require.js is done
20 | callback: window.__karma__.start
21 | });
22 |
--------------------------------------------------------------------------------
/lib/sugar-web/test/unit/datastoreSpec.js:
--------------------------------------------------------------------------------
1 | define(["sugar-web/env", "sugar-web/datastore"], function (env, datastore) {
2 |
3 | 'use strict';
4 |
5 | describe("Ensure the datastore object has an objectId", function () {
6 |
7 | // FIXME does not work in standalone mode
8 | it("should have objectId", function () {
9 | var objectId = "objectId";
10 | spyOn(env, "getObjectId").andCallFake(function (callback) {
11 | setTimeout(function () {
12 | callback(objectId);
13 | }, 0);
14 | });
15 | var callback = jasmine.createSpy();
16 |
17 | var datastoreObject = new datastore.DatastoreObject();
18 |
19 | runs(function () {
20 | datastoreObject.ensureObjectId(callback);
21 | });
22 |
23 | waitsFor(function () {
24 | return datastoreObject.objectId !== undefined;
25 | }, "should have objectId received from the environment");
26 |
27 | runs(function () {
28 | expect(callback).toHaveBeenCalled();
29 | });
30 | });
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/lib/sugar-web/test/unit/dictstoreSpec.js:
--------------------------------------------------------------------------------
1 | define(["sugar-web/dictstore", "sugar-web/env"], function (dictstore, env) {
2 |
3 | 'use strict';
4 |
5 | describe("dictstore on standalone mode", function () {
6 |
7 | beforeEach(function () {
8 | spyOn(env, 'isStandalone').andReturn(true);
9 | });
10 |
11 | describe("init method", function () {
12 |
13 | it("should execute callback", function () {
14 | var callback = jasmine.createSpy();
15 |
16 | dictstore.init(callback);
17 | expect(callback).toHaveBeenCalled();
18 | });
19 |
20 | it("should maintain localStorage", function () {
21 | localStorage.testKey = "test";
22 |
23 | dictstore.init(function () {});
24 | expect(localStorage.testKey).toBe("test");
25 | });
26 | });
27 |
28 | describe("save method", function () {
29 |
30 | it("should just execute the callback", function () {
31 | var callbackExecuted;
32 |
33 | localStorage.test_key = "test";
34 |
35 | runs(function () {
36 | callbackExecuted = false;
37 |
38 | dictstore.save(function () {
39 | callbackExecuted = true;
40 | });
41 | });
42 |
43 | waitsFor(function () {
44 | return callbackExecuted === true;
45 | }, "The callback should executed");
46 |
47 | runs(function () {
48 | expect(localStorage.test_key).toBe("test");
49 | });
50 | });
51 | });
52 |
53 | });
54 | });
55 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "exerciser",
3 | "version": "0.1.0",
4 | "private": true,
5 | "homepage": ".",
6 | "dependencies": {
7 | "ajv": "^8.11.0",
8 | "bootstrap": "^4.1.1",
9 | "chart.js": "^2.9.4",
10 | "copy-webpack-plugin": "^11.0.0",
11 | "cropper": "^4.1.0",
12 | "font-awesome": "^4.7.0",
13 | "interactjs": "^1.10.14",
14 | "intro.js": "5.1.0",
15 | "intro.js-react": "^0.7.1",
16 | "jquery": "^3.6.0",
17 | "jsplumb": "^2.15.6",
18 | "lz-string": "^1.4.4",
19 | "mespeak": "^2.0.2",
20 | "picomodal": "^3.0.0",
21 | "popper.js": "^1.14.3",
22 | "react": "^17.0.2",
23 | "react-app-rewired": "^2.1.3",
24 | "react-beautiful-dnd": "^8.0.5",
25 | "react-burger-menu": "^3.0.8",
26 | "react-chartjs-2": "^2.11.2",
27 | "react-dom": "^17.0.2",
28 | "react-intl": "^2.9.0",
29 | "react-modal": "^3.15.1",
30 | "react-redux": "^5.1.2",
31 | "react-router-dom": "^4.3.1",
32 | "react-scripts": "^1.1.4",
33 | "react-select": "^1.2.1",
34 | "react-tooltip": "^4.2.21",
35 | "react-use-dimensions": "^1.2.1",
36 | "redux": "^4.2.0",
37 | "source-map-explorer": "^2.5.2",
38 | "styled-components": "^5.3.5",
39 | "text-loader": "0.0.1"
40 | },
41 | "scripts": {
42 | "analyze": "source-map-explorer 'build/static/js/*.js'",
43 | "start": "react-app-rewired start --scripts-version react-scripts",
44 | "build": "react-app-rewired build --scripts-version react-scripts",
45 | "test": "react-app-rewired test --env=jsdom --scripts-version react-scripts",
46 | "eject": "react-scripts eject"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/public/activity/activity.info:
--------------------------------------------------------------------------------
1 | [Activity]
2 | name = Exerciser
3 | activity_version = 1
4 | bundle_id = org.sugarlabs.Exerciser
5 | exec = sugar-activity-web
6 | icon = activity-icon
7 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Exerciser Activity
6 |
7 |
9 |
11 |
12 |
13 |
14 |
17 |
18 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/README.md:
--------------------------------------------------------------------------------
1 | Sugar Web
2 | =========
3 |
4 | These are the tools that a developer can use to make a web
5 | activity.
6 |
7 | For details see: http://developer.sugarlabs.org/
8 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/activity/shortcut.js:
--------------------------------------------------------------------------------
1 | define(function () {
2 |
3 | 'use strict';
4 |
5 | var shortcut = {};
6 |
7 | shortcut._allShortcuts = [];
8 |
9 | shortcut.add = function (modifiersString, key, callback) {
10 | // Parse the modifiers. For example "Ctrl+Alt" will become
11 | // {'ctrlKey': true, 'altKey': true, 'shiftKey': false}
12 | var modifiersList = modifiersString.toLowerCase().split("+");
13 | var modifiers = {
14 | 'ctrlKey': modifiersList.indexOf('ctrl') >= 0,
15 | 'altKey': modifiersList.indexOf('alt') >= 0,
16 | 'shiftKey': modifiersList.indexOf('shift') >= 0
17 | };
18 |
19 | this._allShortcuts.push({
20 | 'modifiers': modifiers,
21 | 'key': key.toLowerCase(),
22 | 'callback': callback
23 | });
24 | };
25 |
26 | document.onkeypress = function (e) {
27 | e = e || window.event;
28 |
29 | var modifiers = {
30 | 'ctrlKey': e.ctrlKey,
31 | 'altKey': e.altKey,
32 | 'shiftKey': e.shiftKey
33 | };
34 |
35 | // Obtain the key
36 | var charCode;
37 | if (typeof e.which == "number") {
38 | charCode = e.which;
39 | } else {
40 | charCode = e.keyCode;
41 | }
42 | var key = String.fromCharCode(charCode).toLowerCase();
43 |
44 | // Search for a matching shortcut
45 | for (var i = 0; i < shortcut._allShortcuts.length; i += 1) {
46 | var currentShortcut = shortcut._allShortcuts[i];
47 |
48 | var match = currentShortcut.key == key &&
49 | currentShortcut.modifiers.ctrlKey == modifiers.ctrlKey &&
50 | currentShortcut.modifiers.altKey == modifiers.altKey &&
51 | currentShortcut.modifiers.shiftKey == modifiers.shiftKey;
52 | if (match) {
53 | currentShortcut.callback();
54 | return;
55 | }
56 | }
57 | };
58 |
59 | return shortcut;
60 | });
61 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/bus.js:
--------------------------------------------------------------------------------
1 | define(["sugar-web/env", "sugar-web/bus/sugarizer", "sugar-web/bus/sugaros"], function(env, sugarizer, sugaros) {
2 |
3 | 'use strict';
4 |
5 | var bus;
6 |
7 | if (env.isSugarizer()) {
8 | bus = sugarizer;
9 | } else {
10 | bus = sugaros;
11 | }
12 |
13 | return bus;
14 | });
15 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/bus/sugarizer.js:
--------------------------------------------------------------------------------
1 | define(["sugar-web/env"], function (env) {
2 |
3 | 'use strict';
4 |
5 | var bus = {};
6 |
7 | function WebSocketClient(environment) {
8 | }
9 |
10 | WebSocketClient.prototype.send = function (data) {
11 | };
12 |
13 | WebSocketClient.prototype.close = function () {
14 | };
15 |
16 | function InputStream() {
17 | }
18 |
19 | InputStream.prototype.open = function (callback) {
20 | };
21 |
22 | InputStream.prototype.read = function (count, callback) {
23 | };
24 |
25 | InputStream.prototype.gotData = function (buffer) {
26 | };
27 |
28 | InputStream.prototype.close = function (callback) {
29 | };
30 |
31 | function OutputStream() {
32 | }
33 |
34 | OutputStream.prototype.open = function (callback) {
35 | };
36 |
37 | OutputStream.prototype.write = function (data) {
38 | };
39 |
40 | OutputStream.prototype.close = function (callback) {
41 | };
42 |
43 | bus.createInputStream = function (callback) {
44 | };
45 |
46 | bus.createOutputStream = function (callback) {
47 | };
48 |
49 | bus.sendMessage = function (method, params, callback) {
50 | if (method == "activity.close") {
51 | window.location = "../../index.html";
52 | } else if (method == "activity.get_xo_color") {
53 | var color = {stroke: "#FF2B34", fill: "#005FE4"};
54 | if (typeof chrome != 'undefined' && chrome.app && chrome.app.runtime) {
55 | chrome.storage.local.get("sugar_settings", function(values) {
56 | color = JSON.parse(values.sugar_settings).colorvalue;
57 | callback(null, [[color.stroke, color.fill]]);
58 | });
59 | } else if (typeof(Storage)!=="undefined" && typeof(window.localStorage)!=="undefined") {
60 | try {
61 | color = JSON.parse(window.localStorage.getItem("sugar_settings")).colorvalue;
62 | } catch(err) {}
63 | }
64 | callback(null, [[color.stroke, color.fill]]);
65 | }
66 | return;
67 | };
68 |
69 | bus.onNotification = function (method, callback) {
70 | };
71 |
72 | bus.sendBinary = function (buffer, callback) {
73 | };
74 |
75 | bus.listen = function (customClient) {
76 | };
77 |
78 | bus.close = function () {
79 | };
80 |
81 | return bus;
82 | });
83 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/datastore.js:
--------------------------------------------------------------------------------
1 | define(["sugar-web/env", "sugar-web/datastore/sugarizer", "sugar-web/datastore/sugaros"], function(env, sugarizer, sugaros) {
2 |
3 | 'use strict';
4 |
5 | var datastore ;
6 |
7 | if (env.isSugarizer()) {
8 | datastore = sugarizer;
9 | } else {
10 | datastore = sugaros;
11 | }
12 |
13 | return datastore;
14 | });
15 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/dictstore.js:
--------------------------------------------------------------------------------
1 | define(["sugar-web/activity/activity", "sugar-web/env"], function (activity, env) {
2 |
3 | 'use strict';
4 |
5 | // This is a helper module that allows to persist key/value data
6 | // using the standard localStorage object.
7 | //
8 | // Usage:
9 | // ------
10 | //
11 | // // 1. Setup:
12 | //
13 | // dictstore.init(onReadyCallback);
14 | //
15 | // // 2. Use localStorage directly, and then call save():
16 | //
17 | // var value = localStorage['key'];
18 | // localStorage['key'] = newValue;
19 | // dictstore.save(onSavedCallback);
20 | //
21 | var dictstore = {};
22 |
23 | dictstore.init = function (callback) {
24 |
25 | if (env.isStandalone()) {
26 | // In standalone mode, use localStorage as is.
27 | callback();
28 |
29 | } else {
30 | // In Sugar, set localStorage from the datastore.
31 | localStorage.clear();
32 |
33 | var onLoaded = function (error, metadata, jsonData) {
34 | var data = JSON.parse(jsonData);
35 | for (var i in data) {
36 | localStorage[i] = data[i];
37 | }
38 |
39 | callback();
40 |
41 | };
42 | activity.getDatastoreObject().loadAsText(onLoaded);
43 | }
44 | };
45 |
46 | // Internally, the key/values are stored as text in the Sugar
47 | // datastore, using the JSON format.
48 | dictstore.save = function (callback) {
49 | if (callback === undefined) {
50 | callback = function () {};
51 | }
52 |
53 | if (env.isStandalone()) {
54 | // In standalone mode, use localStorage as is.
55 | callback();
56 | } else {
57 | var datastoreObject = activity.getDatastoreObject();
58 | var jsonData = JSON.stringify(localStorage);
59 | datastoreObject.setDataAsText(jsonData);
60 | datastoreObject.save(function (error) {
61 | callback(error);
62 | });
63 | }
64 | };
65 |
66 | return dictstore;
67 |
68 | });
69 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/README.md:
--------------------------------------------------------------------------------
1 | Sugar Graphics
2 | ==============
3 |
4 | Sugar widgets and graphics, implementing the [Sugar Interface
5 | Guidelines](http://wiki.sugarlabs.org/go/Human_Interface_Guidelines).
6 |
7 | Modifying the CSS
8 | -----------------
9 |
10 | We use [LESS](http://lesscss.org) and then compile the CSS files.
11 | This is to be able to use calculations and variables for colors and
12 | measures. And to be able to output different CSS files for different
13 | screen resolutions.
14 |
15 | To compile the CSS files do:
16 |
17 | lessc graphics/css/sugar-96dpi.less graphics/css/sugar-96dpi.css
18 | lessc graphics/css/sugar-200dpi.less graphics/css/sugar-200dpi.css
19 |
20 | Be sure to compile them before commit.
21 |
22 | The grid helper
23 | ---------------
24 |
25 | The grid is a visual debug tool that allows you to check if the
26 | elements have the correct size. To activate the grid, open the
27 | inspector console and paste the following.
28 |
29 | If RequireJS is not in the page head (ie. in the sugar-web-samples),
30 | load it:
31 |
32 | var script = document.createElement('script');
33 | script.src = 'lib/require.js';
34 | document.head.appendChild(script);
35 |
36 | requirejs.config({ baseUrl: "lib" });
37 |
38 | Then do:
39 |
40 | require(["sugar-web/graphics/grid"], function (grid) { grid.addGrid(11) });
41 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/activitypalette.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/activitypalette.js:
--------------------------------------------------------------------------------
1 | define(["sugar-web/graphics/palette",
2 | "text!sugar-web/graphics/activitypalette.html"], function (palette, template) {
3 |
4 | 'use strict';
5 |
6 | var activitypalette = {};
7 |
8 | activitypalette.ActivityPalette = function (activityButton,
9 | datastoreObject) {
10 |
11 | palette.Palette.call(this, activityButton);
12 |
13 | var activityTitle;
14 | var descriptionLabel;
15 | var descriptionBox;
16 |
17 | this.getPalette().id = "activity-palette";
18 |
19 | var containerElem = document.createElement('div');
20 | containerElem.innerHTML = template;
21 | this.setContent([containerElem]);
22 |
23 | this.titleElem = containerElem.querySelector('#title');
24 | this.descriptionElem = containerElem.querySelector('#description');
25 |
26 | this.titleElem.onblur = function () {
27 | datastoreObject.setMetadata({
28 | "title": this.value,
29 | "title_set_by_user": "1"
30 | });
31 | datastoreObject.save();
32 | };
33 |
34 | this.descriptionElem.onblur = function () {
35 | datastoreObject.setMetadata({
36 | "description": this.value
37 | });
38 | datastoreObject.save();
39 | };
40 | };
41 |
42 | // Fill the text inputs with the received metadata.
43 | var setTitleDescription = function (metadata) {
44 | this.titleElem.value = metadata.title;
45 |
46 | if (metadata.description !== undefined) {
47 | this.descriptionElem.value = metadata.description;
48 | }
49 | };
50 |
51 | activitypalette.ActivityPalette.prototype =
52 | Object.create(palette.Palette.prototype, {
53 | setTitleDescription: {
54 | value: setTitleDescription,
55 | enumerable: true,
56 | configurable: true,
57 | writable: true
58 | }
59 | });
60 |
61 | return activitypalette;
62 | });
63 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/css/sugar-200dpi.less:
--------------------------------------------------------------------------------
1 | @subcell-size: 15px;
2 | @import "sugar.less";
3 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/css/sugar-96dpi.less:
--------------------------------------------------------------------------------
1 | @subcell-size: 11px;
2 | @import "sugar.less";
3 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/evaluationpalette.js:
--------------------------------------------------------------------------------
1 | define(["sugar-web/graphics/palette"], function (palette) {
2 | "use strict";
3 |
4 | var evaluationpalette = {};
5 |
6 | evaluationpalette.EvaluationPalette = function (invoker, primaryText) {
7 | palette.Palette.call(this, invoker, primaryText);
8 |
9 | var template = "Hello palette!";
10 | var containerElem = document.createElement("div");
11 | containerElem.innerHTML = template;
12 | this.setContent([containerElem]);
13 | };
14 |
15 | var addEventListener = function (type, listener, useCapture) {
16 | return this.getPalette().addEventListener(type, listener, useCapture);
17 | };
18 |
19 | evaluationpalette.EvaluationPalette.prototype = Object.create(
20 | palette.Palette.prototype,
21 | {
22 | addEventListener: {
23 | value: addEventListener,
24 | enumerable: true,
25 | configurable: true,
26 | writable: true,
27 | },
28 | }
29 | );
30 |
31 | return evaluationpalette;
32 | });
33 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/grid.js:
--------------------------------------------------------------------------------
1 | define(function () {
2 |
3 | 'use strict';
4 |
5 | var grid = {};
6 |
7 | // Add a grid overlay with lines spaced by subcellSize, for visual
8 | // debugging. This is useful while doing the activity layout or
9 | // while developing widgets.
10 | grid.addGrid = function (subcellSize) {
11 | var canvas = document.createElement('canvas');
12 | canvas.className = "grid";
13 | document.body.appendChild(canvas);
14 |
15 | var updateGrid = function () {
16 | canvas.width = window.innerWidth;
17 | canvas.height = window.innerHeight;
18 |
19 | var ctx = canvas.getContext("2d");
20 | ctx.strokeStyle = "#00FFFF";
21 |
22 | var subcellsVertical = window.innerHeight / subcellSize;
23 | for (i = 0; i < subcellsVertical; i++) {
24 | if ((i + 1) % 5 === 0) {
25 | ctx.lineWidth = 1;
26 | } else {
27 | ctx.lineWidth = 0.5;
28 | }
29 | ctx.beginPath();
30 | ctx.moveTo(0, subcellSize * (i + 1));
31 | ctx.lineTo(canvas.width, subcellSize * (i + 1));
32 | ctx.stroke();
33 | }
34 |
35 | var subcellsHorizontal = window.innerWidth / subcellSize;
36 | for (i = 0; i < subcellsHorizontal; i++) {
37 | if ((i + 1) % 5 === 0) {
38 | ctx.lineWidth = 1;
39 | } else {
40 | ctx.lineWidth = 0.5;
41 | }
42 | ctx.beginPath();
43 | ctx.moveTo(subcellSize * (i + 1), 0);
44 | ctx.lineTo(subcellSize * (i + 1), canvas.height);
45 | ctx.stroke();
46 | }
47 | };
48 |
49 | updateGrid();
50 |
51 | window.onresize = function (event) {
52 | updateGrid();
53 | };
54 | };
55 |
56 | return grid;
57 | });
58 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/icons/actions/activity-journal.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/icons/actions/activity-stop.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/icons/actions/checkbox-checked-selected.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ]>
6 |
28 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/icons/actions/checkbox-checked.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ]>
6 |
28 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/icons/actions/checkbox-unchecked-selected.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 | ]>
5 |
23 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/icons/actions/checkbox-unchecked.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 | ]>
5 |
23 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/icons/actions/dialog-cancel-active.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
7 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/icons/actions/dialog-cancel.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/icons/actions/dialog-ok-active.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
7 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/icons/actions/dialog-ok.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/icons/actions/entry-cancel-active.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ]>
6 |
24 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/icons/actions/entry-cancel-disabled.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ]>
6 |
22 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/icons/actions/entry-cancel.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ]>
6 |
22 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/icons/actions/radio-active-selected.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ]>
6 |
32 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/icons/actions/radio-active.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ]>
6 |
32 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/icons/actions/radio-selected.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ]>
6 |
27 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/icons/actions/radio.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ]>
6 |
27 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/icons/actions/zoom-groups.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/icons/actions/zoom-home.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/icons/actions/zoom-neighborhood.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/icons/emblems/arrow-down.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ]>
6 |
21 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/icons/emblems/arrow-up.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | ]>
6 |
21 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/icons/emblems/favorite.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/menupalette.html:
--------------------------------------------------------------------------------
1 | {{#.}}
2 |
3 |
7 |
8 | {{/.}}
9 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/menupalette.js:
--------------------------------------------------------------------------------
1 | define(["sugar-web/graphics/palette",
2 | "text!sugar-web/graphics/menupalette.html", "mustache"], function (palette, template, mustache) {
3 |
4 | 'use strict';
5 |
6 | var menupalette = {};
7 |
8 | menupalette.MenuPalette = function (invoker, primaryText, menuData) {
9 | palette.Palette.call(this, invoker, primaryText);
10 |
11 | this.selectItemEvent = document.createEvent("CustomEvent");
12 | this.selectItemEvent.initCustomEvent('selectItem', true, true, {
13 | 'item': undefined
14 | });
15 |
16 | var menuElem = document.createElement('ul');
17 | menuElem.className = "menu";
18 | menuElem.innerHTML = mustache.render(template, menuData);
19 | this.setContent([menuElem]);
20 |
21 | // Pop-down the palette when a item in the menu is clicked.
22 |
23 | this.buttons = menuElem.querySelectorAll('button');
24 |
25 | var that = this;
26 |
27 | function popDownOnButtonClick(event) {
28 | that.selectItemEvent.detail.target = event.target;
29 | that.getPalette().dispatchEvent(that.selectItemEvent);
30 | that.popDown();
31 | }
32 |
33 | for (var i = 0; i < this.buttons.length; i++) {
34 | this.buttons[i].addEventListener('click', popDownOnButtonClick);
35 | }
36 | };
37 |
38 | var addEventListener = function (type, listener, useCapture) {
39 | return this.getPalette().addEventListener(type, listener, useCapture);
40 | };
41 |
42 | menupalette.MenuPalette.prototype =
43 | Object.create(palette.Palette.prototype, {
44 | addEventListener: {
45 | value: addEventListener,
46 | enumerable: true,
47 | configurable: true,
48 | writable: true
49 | }
50 | });
51 |
52 | return menupalette;
53 | });
54 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/graphics/radiobuttonsgroup.js:
--------------------------------------------------------------------------------
1 | define(function () {
2 |
3 | 'use strict';
4 |
5 | var radioButtonsGroup = {};
6 |
7 | // ## RadioButtonsGroup
8 | //
9 | // A group of elements where only one can be active at the same
10 | // time.
11 | //
12 | // When an element is clicked, it becomes the active one. The
13 | // active element gains the 'active' CSS class.
14 | //
15 | // Parameters:
16 | //
17 | // * **elems** Array of elements of the group.
18 | radioButtonsGroup.RadioButtonsGroup = function (elems) {
19 | this.elems = elems;
20 | var active;
21 |
22 | for (var i = 0; i < elems.length; i++) {
23 | var elem = elems[i];
24 | elem.addEventListener("click", clickHandler);
25 |
26 | // The first element that has 'active' CSS class is made
27 | // the active of the group on startup.
28 | if (active === undefined && elem.classList.contains('active')) {
29 | active = elem;
30 | }
31 | }
32 |
33 | // If no element has 'active' CSS class, the first element of
34 | // the array is made the active.
35 | if (active === undefined) {
36 | active = elems[0];
37 | updateClasses();
38 | }
39 |
40 | function clickHandler(evt) {
41 | active = evt.target;
42 | updateClasses();
43 | }
44 |
45 | function updateClasses() {
46 | for (i = 0; i < elems.length; i++) {
47 | var elem = elems[i];
48 | elem.classList.remove('active');
49 | }
50 | active.classList.add('active');
51 | }
52 |
53 | // Get the active element.
54 | this.getActive = function () {
55 | return active;
56 | };
57 |
58 | };
59 |
60 | return radioButtonsGroup;
61 |
62 | });
63 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "volo": {
3 | "baseUrl": "lib",
4 | "dependencies": {
5 | "webL10n": "github:sugarlabs/webL10n",
6 | "mustache": "github:janl/mustache.js/0.7.2",
7 | "text": "github:requirejs/text"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/test/functional/toolkitContractSpec.js:
--------------------------------------------------------------------------------
1 | define(["sugar-web/env"], function (env) {
2 |
3 | 'use strict';
4 |
5 | describe("Environment object", function () {
6 |
7 | it("should have valid properties", function () {
8 | //FIXME: we shouldn't stub this here.
9 | //current implementation of isStandalone fails with sugar-web-test
10 | spyOn(env, 'isStandalone').andReturn(false);
11 |
12 | var expectedEnv;
13 |
14 | runs(function () {
15 | env.getEnvironment(function (error, environment) {
16 | expectedEnv = environment;
17 | });
18 | });
19 |
20 | waitsFor(function () {
21 | return expectedEnv !== undefined;
22 | }, "should get sugar environment");
23 |
24 | runs(function () {
25 | expect(expectedEnv.bundleId).not.toBeUndefined();
26 | expect(expectedEnv.activityId).not.toBeUndefined();
27 | expect(expectedEnv.activityName).not.toBeUndefined();
28 | });
29 | });
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/test/graphics/iconSpec.js:
--------------------------------------------------------------------------------
1 | define(["sugar-web/graphics/icon"], function (icon) {
2 |
3 | 'use strict';
4 |
5 | describe("icon", function () {
6 | var wasLoaded;
7 | var iconUrlResult;
8 |
9 | it("should be able to change icon more than once", function () {
10 | var elem = document.createElement('div');
11 | var iconUrl;
12 |
13 | function callback(url) {
14 | iconUrlResult = url;
15 | wasLoaded = true;
16 | }
17 |
18 | runs(function () {
19 | wasLoaded = false;
20 | iconUrl = "/base/graphics/icons/actions/dialog-ok-active.svg";
21 | var iconInfo = {
22 | "uri": iconUrl,
23 | "strokeColor": '#B20008',
24 | "fillColor": '#FF2B34'
25 | };
26 | icon.load(iconInfo, callback);
27 | });
28 |
29 | waitsFor(function () {
30 | return wasLoaded;
31 | }, "icon loaded");
32 |
33 | runs(function () {
34 | expect(iconUrlResult).not.toBe(iconUrl);
35 | });
36 |
37 | runs(function () {
38 | wasLoaded = false;
39 | iconUrl = iconUrlResult;
40 | var iconInfo = {
41 | "uri": iconUrl,
42 | "strokeColor": '#FF2B34',
43 | "fillColor": '#B20008'
44 | };
45 | icon.load(iconInfo, callback);
46 | });
47 |
48 | waitsFor(function () {
49 | return wasLoaded;
50 | }, "icon loaded");
51 |
52 | runs(function () {
53 | expect(iconUrlResult).not.toBe(iconUrl);
54 | });
55 |
56 | });
57 | });
58 |
59 | });
60 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/test/graphics/paletteSpec.js:
--------------------------------------------------------------------------------
1 | define(["sugar-web/graphics/palette"], function (palette) {
2 |
3 | 'use strict';
4 |
5 | describe("palette", function () {
6 | it("should start down", function () {
7 | var invoker = document.createElement('button');
8 | var myPalette = new palette.Palette(invoker);
9 | expect(myPalette.isDown()).toBe(true);
10 | });
11 |
12 | it("should toggle", function () {
13 | var invoker = document.createElement('button');
14 | var myPalette = new palette.Palette(invoker);
15 | myPalette.toggle();
16 | expect(myPalette.isDown()).toBe(false);
17 | myPalette.toggle();
18 | expect(myPalette.isDown()).toBe(true);
19 | });
20 |
21 | it("if one palette in a group popups, the others popdown", function () {
22 | var invokerA = document.createElement('button');
23 | var invokerB = document.createElement('button');
24 | var myPaletteA = new palette.Palette(invokerA);
25 | var myPaletteB = new palette.Palette(invokerB);
26 | myPaletteA.toggle();
27 | expect(myPaletteA.isDown()).toBe(false);
28 | expect(myPaletteB.isDown()).toBe(true);
29 | myPaletteB.toggle();
30 | expect(myPaletteA.isDown()).toBe(true);
31 | expect(myPaletteB.isDown()).toBe(false);
32 | });
33 |
34 | });
35 |
36 | });
37 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/test/karma-shared.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 | // Generated on Mon May 13 2013 10:01:17 GMT-0300 (ART)
3 |
4 |
5 | // list of files / patterns to load in the browser
6 | module.exports = function (config) {
7 | config.set({
8 | frameworks: ['jasmine', 'requirejs'],
9 |
10 |
11 | // base path, that will be used to resolve files and exclude
12 | basePath: '..',
13 |
14 |
15 | files: [
16 | 'test/loader.js',
17 | {
18 | pattern: 'lib/**/*.js',
19 | included: false
20 | }, {
21 | pattern: '*.js',
22 | included: false
23 | }, {
24 | pattern: 'activity/**/*.js',
25 | included: false
26 | }, {
27 | pattern: 'graphics/**/*',
28 | included: false
29 | }
30 | ],
31 |
32 |
33 | // list of files to exclude
34 | exclude: [],
35 |
36 |
37 | // test results reporter to use
38 | // possible values: 'dots', 'progress', 'junit'
39 | reporters: ['progress'],
40 |
41 |
42 | // web server port
43 | port: 9876,
44 |
45 |
46 | // cli runner port
47 | runnerPort: 9100,
48 |
49 |
50 | // enable / disable colors in the output (reporters and logs)
51 | colors: true,
52 |
53 |
54 | // level of logging
55 | // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO ||
56 | // LOG_DEBUG
57 | logLevel: config.LOG_INFO,
58 |
59 |
60 | // enable / disable watching file and executing tests whenever any file
61 | // changes
62 | autoWatch: true,
63 |
64 |
65 | // If browser does not capture in given timeout [ms], kill it
66 | captureTimeout: 60000,
67 |
68 |
69 | // Continuous Integration mode
70 | // if true, it capture browsers, run tests and exit
71 | singleRun: false,
72 |
73 | preprocessors: {}
74 | });
75 | };
76 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/test/karma-unit.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration for unit tests
2 |
3 | sharedConfig = require("./karma-shared.conf.js");
4 |
5 | module.exports = function (config) {
6 | var testFiles = [
7 | {
8 | pattern: 'test/unit/*Spec.js',
9 | included: false
10 | }, {
11 | pattern: 'test/graphics/*Spec.js',
12 | included: false
13 | },
14 | ];
15 |
16 | sharedConfig(config);
17 |
18 | config.files = config.files.concat(testFiles);
19 | };
20 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/test/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration for all the tests
2 |
3 | sharedConfig = require("./karma-shared.conf.js");
4 |
5 | module.exports = function (config) {
6 | var testFiles = [
7 | {
8 | pattern: 'test/**/*Spec.js',
9 | included: false
10 | }
11 | ];
12 |
13 | sharedConfig(config);
14 |
15 | config.files = config.files.concat(testFiles);
16 | };
17 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/test/loader.js:
--------------------------------------------------------------------------------
1 | var tests = Object.keys(window.__karma__.files).filter(function (file) {
2 | return (/Spec\.js$/).test(file);
3 | });
4 |
5 | requirejs.config({
6 | // Karma serves files from '/base'
7 | baseUrl: "/base",
8 |
9 | paths: {
10 | "sugar-web": ".",
11 | "mustache": "lib/mustache",
12 | "text": "lib/text",
13 | "webL10n": "lib/webL10n"
14 | },
15 |
16 | // ask Require.js to load these files (all our tests)
17 | deps: tests,
18 |
19 | // start test run, once Require.js is done
20 | callback: window.__karma__.start
21 | });
22 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/test/unit/datastoreSpec.js:
--------------------------------------------------------------------------------
1 | define(["sugar-web/env", "sugar-web/datastore"], function (env, datastore) {
2 |
3 | 'use strict';
4 |
5 | describe("Ensure the datastore object has an objectId", function () {
6 |
7 | // FIXME does not work in standalone mode
8 | it("should have objectId", function () {
9 | var objectId = "objectId";
10 | spyOn(env, "getObjectId").andCallFake(function (callback) {
11 | setTimeout(function () {
12 | callback(objectId);
13 | }, 0);
14 | });
15 | var callback = jasmine.createSpy();
16 |
17 | var datastoreObject = new datastore.DatastoreObject();
18 |
19 | runs(function () {
20 | datastoreObject.ensureObjectId(callback);
21 | });
22 |
23 | waitsFor(function () {
24 | return datastoreObject.objectId !== undefined;
25 | }, "should have objectId received from the environment");
26 |
27 | runs(function () {
28 | expect(callback).toHaveBeenCalled();
29 | });
30 | });
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/public/lib/sugar-web/test/unit/dictstoreSpec.js:
--------------------------------------------------------------------------------
1 | define(["sugar-web/dictstore", "sugar-web/env"], function (dictstore, env) {
2 |
3 | 'use strict';
4 |
5 | describe("dictstore on standalone mode", function () {
6 |
7 | beforeEach(function () {
8 | spyOn(env, 'isStandalone').andReturn(true);
9 | });
10 |
11 | describe("init method", function () {
12 |
13 | it("should execute callback", function () {
14 | var callback = jasmine.createSpy();
15 |
16 | dictstore.init(callback);
17 | expect(callback).toHaveBeenCalled();
18 | });
19 |
20 | it("should maintain localStorage", function () {
21 | localStorage.testKey = "test";
22 |
23 | dictstore.init(function () {});
24 | expect(localStorage.testKey).toBe("test");
25 | });
26 | });
27 |
28 | describe("save method", function () {
29 |
30 | it("should just execute the callback", function () {
31 | var callbackExecuted;
32 |
33 | localStorage.test_key = "test";
34 |
35 | runs(function () {
36 | callbackExecuted = false;
37 |
38 | dictstore.save(function () {
39 | callbackExecuted = true;
40 | });
41 | });
42 |
43 | waitsFor(function () {
44 | return callbackExecuted === true;
45 | }, "The callback should executed");
46 |
47 | runs(function () {
48 | expect(localStorage.test_key).toBe("test");
49 | });
50 | });
51 | });
52 |
53 | });
54 | });
55 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Exersizer",
3 | "name": "Exerciser Activity",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/screenshots/CLOZE_Player.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/screenshots/CLOZE_Player.png
--------------------------------------------------------------------------------
/screenshots/Detailed_Results.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/screenshots/Detailed_Results.png
--------------------------------------------------------------------------------
/screenshots/FREETEXT_Player.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/screenshots/FREETEXT_Player.png
--------------------------------------------------------------------------------
/screenshots/GROUP_Player.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/screenshots/GROUP_Player.png
--------------------------------------------------------------------------------
/screenshots/Home_Screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/screenshots/Home_Screen.png
--------------------------------------------------------------------------------
/screenshots/Image_Editor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/screenshots/Image_Editor.png
--------------------------------------------------------------------------------
/screenshots/MATCH_Player.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/screenshots/MATCH_Player.png
--------------------------------------------------------------------------------
/screenshots/MCQPlayer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/screenshots/MCQPlayer.png
--------------------------------------------------------------------------------
/screenshots/MCQ_FORM.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/screenshots/MCQ_FORM.png
--------------------------------------------------------------------------------
/screenshots/Presence.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/screenshots/Presence.png
--------------------------------------------------------------------------------
/screenshots/REORDER_Form.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/screenshots/REORDER_Form.png
--------------------------------------------------------------------------------
/screenshots/REORER_Player.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/screenshots/REORER_Player.png
--------------------------------------------------------------------------------
/screenshots/Scores_Screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/screenshots/Scores_Screen.png
--------------------------------------------------------------------------------
/screenshots/Template_Screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/screenshots/Template_Screen.png
--------------------------------------------------------------------------------
/screenshots/Tutorial.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/screenshots/Tutorial.png
--------------------------------------------------------------------------------
/screenshots/screenshots.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/screenshots/screenshots.gif
--------------------------------------------------------------------------------
/src/components/Tutorial.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { tutorialSteps } from "../tutorialSteps";
3 | import { injectIntl } from "react-intl";
4 | import { NEXT_SHORT, PREV, END } from "../containers/translation";
5 | import "../css/Tutorial.css";
6 | import 'intro.js/introjs.css';
7 | import { Steps } from 'intro.js-react';
8 |
9 | class Tutorial extends Component {
10 | isSingleStepTutorial = tutorialSteps(this.props.pathname, this.props.intl).some(step => !Object.keys(step).length);
11 | render() {
12 | return (
13 | {this.props.unmount();}}
26 | onBeforeChange={(stepIntex)=>{
27 | if (!this.isSingleStepTutorial || stepIntex >=0 && Object.keys(tutorialSteps(this.props.pathname, this.props.intl)[stepIntex+1]).length) return true;
28 | document.querySelector(".introjs-nextbutton") ? document.querySelector(".introjs-nextbutton").classList.add("introjs-disabled"): "";
29 | return false;
30 | }}
31 | />
32 | );
33 | }
34 | }
35 |
36 | export default injectIntl(Tutorial);
37 |
--------------------------------------------------------------------------------
/src/components/UserIcon.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 |
4 | class UserIcon extends Component {
5 | render() {
6 | const { stroke_color, fill_color, width, height } = this.props;
7 |
8 | return (
9 |
53 | )
54 | }
55 | }
56 |
57 | export default UserIcon;
--------------------------------------------------------------------------------
/src/components/UserList.js:
--------------------------------------------------------------------------------
1 | import { slide as Menu } from 'react-burger-menu'
2 | import React from 'react';
3 | import "../css/UserList.css"
4 |
5 | function UserList(props) {
6 | const { userList, stroke, isOpen } = props;
7 |
8 | let styles = {
9 | bmCrossButton: {
10 | height: '30px',
11 | width: '30px'
12 | },
13 | bmCross: {
14 | background: stroke
15 | },
16 | bmMenu: {
17 | background: '#808080',
18 | }
19 | };
20 |
21 | return (
22 |
30 | );
31 | }
32 |
33 | export default UserList;
34 |
--------------------------------------------------------------------------------
/src/containers/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Provider } from "react-redux";
3 | import { configureStore } from "../store";
4 | // import { DndProvider } from "react-dnd";
5 | // import { HTML5Backend } from "react-dnd-html5-backend"
6 |
7 | import Sugarizer from "./Sugarizer";
8 |
9 | import "../css/index.css";
10 |
11 | const store = configureStore();
12 |
13 | class App extends Component {
14 | render() {
15 | return (
16 |
17 | {/*
*/}
18 |
19 |
20 |
21 | {/* */}
22 |
23 | );
24 | }
25 | }
26 |
27 | export default App;
28 |
--------------------------------------------------------------------------------
/src/css/CLOZEPlayer.css:
--------------------------------------------------------------------------------
1 | .input-ans{
2 | display: block;
3 | font-size: 15px;
4 | max-height: 30px!important;
5 | border-radius: 10px;
6 | border-width: 0;
7 | min-width: 180px;
8 | margin-bottom: 5px;
9 | }
10 |
11 | .checked-ans{
12 | font-size: 15px;
13 | max-height: 30px!important;
14 | border-radius: 10px;
15 | border-width: 0;
16 | min-width: 180px;
17 | }
18 |
19 | .Select-placeholder{
20 | border-radius: 15px!important;
21 | }
22 |
23 | .Select{
24 | padding: 0!important;
25 | }
26 |
27 |
28 | .wrong{
29 | padding: 4px 8px;
30 | border-radius: 10px;
31 | background-color: orangered;
32 | }
33 |
34 | .right{
35 | padding: 4px 8px;
36 | border-radius: 10px;
37 | background-color: lime;
38 | }
39 |
40 | .cloze-span{
41 | display: inline-block;
42 | margin-bottom: 15px;
43 | }
44 |
45 | div{
46 | line-height: 1.5;
47 | }
48 |
49 | #cloze-container{
50 | margin-top: 5%;
51 | margin-bottom: 5%;
52 | }
53 |
54 |
55 | .jumbotron {
56 | background-color: #dfdfdf !important;
57 | }
58 |
59 | .lead {
60 | font-weight: bold !important;
61 | }
62 |
--------------------------------------------------------------------------------
/src/css/DragList.css:
--------------------------------------------------------------------------------
1 | * {
2 | padding: 0;
3 | margin: 0;
4 | -webkit-user-select: none;
5 | -moz-user-select: none;
6 | user-select: none;
7 | }
8 | body {
9 | /*cursor: url('cursor.png') 39 39, auto;*/
10 | }
11 | .demo8-outer {
12 | background-color: #EEE;
13 | color: #FFF;
14 | position: absolute;
15 | width: 100%;
16 | height: 100%;
17 | font: 28px/1em "Helvetica";
18 | display: flex;
19 | justify-content: center;
20 | align-items: center;
21 | display: -webkit-flex;
22 | -webkit-justify-content: center;
23 | -webkit-align-items: center;
24 | }
25 | .demo8 {
26 | width: 320px;
27 | height: 400px;
28 | }
29 | .demo8-item {
30 | position: absolute;
31 | width: 320px;
32 | height: 90px;
33 | overflow: visible;
34 | pointer-events: auto;
35 | transform-origin: 50% 50% 0px;
36 | border-radius: 4px;
37 | color: rgb(153, 153, 153);
38 | line-height: 96px;
39 | padding-left: 32px;
40 | font-size: 24px;
41 | font-weight: 400;
42 | background-color: rgb(255, 255, 255);
43 | box-sizing: border-box;
44 | -webkit-box-sizing: border-box;
45 | }
46 | .link {
47 | position: absolute;
48 | color: rgb(76, 76, 76);
49 | text-decoration: none;
50 | font: 14px/1em "Helvetica";
51 | padding: 10px;
52 | top: 0;
53 | left: 0;
54 | }
--------------------------------------------------------------------------------
/src/css/Evaluation.css:
--------------------------------------------------------------------------------
1 | #evaluation-container{
2 | margin-top: 1rem;
3 | }
4 |
5 | #evaluation-heading{
6 | font-size: 2rem;
7 | justify-content: center;
8 | color: #6F6F6F;
9 | font-weight: 600;
10 | margin: 1rem;
11 | }
--------------------------------------------------------------------------------
/src/css/ExerciseDragList.css:
--------------------------------------------------------------------------------
1 | .drag-exercise{
2 | flex-basis: 50% !important;
3 | display: flex;
4 | align-items: flex-start !important;
5 | margin-bottom: 2rem !important;
6 | }
7 | .draggable-card{
8 | margin-top: 0;
9 | }
10 | .draggable-exercise{
11 | padding-left: 0 !important;
12 | }
13 | .drag-handler{
14 | margin-top: 0.5rem;
15 | }
--------------------------------------------------------------------------------
/src/css/ExerciseList.css:
--------------------------------------------------------------------------------
1 | .exercise-div{
2 | display: inline-block;
3 | }
4 |
5 |
6 | .user:hover{
7 | background-color: transparent!important;
8 | border-color: transparent!important;
9 | }
10 |
11 | .user-icon{
12 | max-width: 50px;
13 | padding: 0!important;
14 | max-height: 50px;
15 | }
16 |
17 | .user-container{
18 | position: absolute;
19 | top: 100px;
20 | right: 50px;
21 | z-index: 1000;
22 | }
23 |
24 | .evaluation-container{
25 | position: absolute;
26 | top: 160px;
27 | right: 68px;
28 | z-index: 1000;
29 | }
30 |
31 | .user-text{
32 | min-height: 40px!important;
33 | margin-bottom: 10px;
34 | font-size: 20px;
35 | vertical-align: center;
36 | }
37 |
38 | .tooltip-react{
39 | max-width: 200px;
40 | padding-left: 0;
41 | padding-right: 0;
42 | }
43 |
44 | .badge-notify{
45 | background:red;
46 | position:relative;
47 | color: white;
48 | font-size: 15px!important;
49 | top: -45px!important;
50 | left: -25px!important;
51 | }
52 |
53 | .user-list{
54 | font-size: 14px;
55 | text-align: center;
56 | max-height: 50px;
57 | line-height: 50px;
58 | height: 100%;
59 | }
60 |
61 | .exercise-list-container{
62 | margin: 0!important;
63 | padding: 3%;
64 | height: 100%;
65 | }
66 |
67 | .total-score{
68 | width: fit-content;
69 | padding: 0.5rem;
70 | margin: auto;
71 | border: 2px solid;
72 | border-radius: 8px;
73 | font-size: 1.5rem;
74 | }
75 |
76 | .user-list-button{
77 | width: 50px!important;
78 | height: 50px!important;
79 | background-image: url("../icons/navbar/zoom-neighborhood.svg");
80 | background-repeat: no-repeat;
81 | background-size: contain;
82 | border-radius: 25px;
83 | background-color: black!important;
84 | }
85 |
86 | .realtime-evaluation-button{
87 | width: 50px!important;
88 | height: 50px!important;
89 | background-image: url("../icons/navbar/eval-mode.svg");
90 | background-repeat: no-repeat;
91 | background-size: contain;
92 | border-radius: 25px;
93 | background-color: black;
94 | }
95 |
96 | .home-container{
97 | height: auto;
98 | min-height: 100%;
99 | }
100 |
101 | .Exercise-List-NoPadding{
102 | padding: 0px !important;
103 | }
--------------------------------------------------------------------------------
/src/css/MCQPlayer.css:
--------------------------------------------------------------------------------
1 | .form-group{
2 | /*margin-top: 20px;*/
3 | }
4 |
5 | .choices-but{
6 | width: 85%;
7 | margin-right: 0px!important;
8 | }
9 |
10 | .choices-button:focus, .choices-button:active{
11 | box-shadow: none!important;
12 | border: 2px solid #808080!important;
13 | }
14 |
15 | .choices{
16 | display: inline-block!important;
17 | margin: 10px 0px;
18 | }
19 |
20 | .choices-container{
21 | display: flex;
22 | flex-direction: column;
23 | align-items: center;
24 | }
25 |
26 | @media (min-width: 576px) {
27 | .jumbotron {
28 | padding: 2rem 1rem!important;
29 | }
30 | }
31 |
32 | .jumbotron{
33 | margin-bottom: 1rem!important;
34 | background-color: #dfdfdf!important;
35 | }
36 |
37 | .d-flex{
38 | margin-top: 1rem;
39 | }
40 |
41 | .next-button{
42 | width: 180px;
43 | text-align: center;
44 | align-self: center;
45 | border-radius: 20px!important;
46 | font-size: 15px!important;
47 | background-color: #808080!important;
48 | margin-bottom: 10px;
49 | }
50 |
51 | #mcq-container{
52 | margin-top: 5%;
53 | margin-bottom: 5%;
54 | }
55 |
56 | .lead {
57 | font-weight: bold !important;
58 | }
59 |
60 | .btn-outline-secondary {
61 | color: #6c757d!important;
62 | border-color: #6c757d!important;
63 | }
64 |
65 | .btn-selected{
66 | color: #6c757d!important;
67 | border: 2px solid #808080!important;
68 | }
69 |
70 | .button-on{
71 | content: url(../icons/exercise/sound_on_black.png);
72 | vertical-align: middle;
73 | }
74 |
75 | .button-off{
76 | content: url(../icons/exercise/sound_off_black.png);
77 | vertical-align: middle;
78 | }
79 |
80 | .options-radio{
81 | margin-right: 5px!important;
82 | background: #6c757d;
83 | border-radius: 15px;
84 | border: 4px solid #dfdfdf;
85 | }
86 |
87 | .options-radio:hover{
88 | border: 4px solid #808080;
89 | }
90 |
91 |
92 | input[type=radio]:checked{
93 | background: #6c757d;
94 | border-radius: 15px;
95 | border: 4px solid #dfdfdf;
96 | }
97 |
98 | .audio-option{
99 | max-width: -webkit-fill-available;
100 | }
--------------------------------------------------------------------------------
/src/css/PresenceScores.css:
--------------------------------------------------------------------------------
1 | .score-button{
2 | width: 40px;
3 | height: 40px;
4 | background-image: url("../icons/exercise/percent.svg");
5 | background-repeat: no-repeat;
6 | background-size: contain;
7 | border-radius: 20px;
8 | margin-top: 10px;
9 | }
10 |
11 | .score-button:hover{
12 | background-color: lightskyblue!important;
13 | border: 2px solid transparent!important;
14 | }
15 |
16 | .time-button{
17 | width: 40px;
18 | height: 40px;
19 | background-image: url("../icons/exercise/clock.svg");
20 | background-repeat: no-repeat;
21 | background-size: contain;
22 | border-radius: 20px;
23 | margin-top: 10px;
24 | }
25 |
26 | .time-button:hover{
27 | background-color: lightskyblue!important;
28 | border: 2px solid transparent!important;
29 | }
30 |
31 | .detail-button{
32 | width: 40px;
33 | height: 40px;
34 | background-image: url("../icons/exercise/details.png");
35 | background-repeat: no-repeat;
36 | background-size: cover;
37 | border-radius: 20px;
38 | margin-top: 10px;
39 | }
40 |
41 | .detail-button:hover{
42 | background-color: lightskyblue!important;
43 | border: 2px solid transparent!important;
44 | }
45 |
46 | .active{
47 | background-color: deepskyblue;
48 | }
49 |
50 | th, td {
51 | padding: 15px;
52 | text-align: center !important;
53 | border-bottom: 1px solid #ddd;
54 | display: table-cell!important;
55 | }
56 |
57 | .td-userans {
58 | display: flex!important;
59 | align-items: center;
60 | }
61 |
62 | .shared-results-user-selected :hover {
63 | background-color: #cccccc;
64 | }
--------------------------------------------------------------------------------
/src/css/REORDERForm.css:
--------------------------------------------------------------------------------
1 | .button-choices-add .button-choices-sub {
2 | background-color: gray!important;
3 | }
4 |
5 | #reorder-form{
6 | margin-top: 5%;
7 | margin-bottom: 5%;
8 | }
9 |
10 | .button-thumbnail {
11 | background-image: url(../icons/exercise/insert-image.svg);
12 | background-repeat: no-repeat;
13 | background-size: contain;
14 | float: right;
15 | width: 30px;
16 | height: 30px;
17 | margin-bottom: 5px;
18 | margin-right: 0px!important;
19 | }
20 |
21 | .button-cancel{
22 | background-image: url(../icons/exercise/sub.svg);
23 | background-repeat: no-repeat;
24 | background-size: contain;
25 | background-position: center;
26 | position: absolute;
27 | right: 0;
28 | background-color: gray!important;
29 | height: 30px;
30 | width: 30px;
31 | border-radius: 16px!important;
32 | margin-top: 5px;
33 | }
34 |
35 | .thumbnail {
36 | background-color: #e5e5e5;
37 | text-align: center;
38 | margin-bottom: 10px;
39 | }
40 |
--------------------------------------------------------------------------------
/src/css/REORDERPlayer.css:
--------------------------------------------------------------------------------
1 | #reorder-player{
2 | margin-top: 40px;
3 | margin-bottom: 40px;
4 | }
5 |
6 | .container{
7 | margin-bottom: 50px;
8 | }
9 |
10 | .list-item{
11 | user-select: none;
12 | padding: 16px;
13 | margin: 0 0 8px 0;
14 | border-radius:10px;
15 | text-align:center;
16 | }
17 |
18 | .jumbotron {
19 | background-color: #dfdfdf !important;
20 | }
21 | .lead {
22 | font-weight: bold !important;
23 | }
24 | .btn-normal{
25 | background-color: white;
26 | }
--------------------------------------------------------------------------------
/src/css/Scores.css:
--------------------------------------------------------------------------------
1 | #scores{
2 | margin-top: 5%;
3 | margin-bottom: 5%;
4 | }
5 |
6 | .button-redo{
7 | width: 60px;
8 | height: 60px;
9 | background-image: url("../icons/exercise/redo.svg");
10 | background-repeat: no-repeat;
11 | background-size: contain;
12 | border-radius: 30px;
13 | }
14 |
15 | .button-redo:hover{
16 | background-color: limegreen!important;
17 | border: 2px solid transparent!important;
18 | }
19 |
20 | button{
21 | margin-right: 10px!important;
22 | background-color: #808080;
23 | color: white!important;
24 | border: 2px solid transparent;
25 | border-radius: 22px;
26 | line-height: 22px;
27 | padding: 2px 4px;
28 | -moz-user-select: none;
29 | -webkit-user-select: none;
30 | }
31 |
32 | .button-container{
33 | display: flex;
34 | flex-direction: row;
35 | float: right;
36 | }
37 |
38 | th, td {
39 | padding: 15px;
40 | text-align: center !important;
41 | border-bottom: 1px solid #ddd;
42 | display: table-cell!important;
43 | }
44 |
45 | .td-userans {
46 | display: flex!important;
47 | align-items: center;
48 | }
--------------------------------------------------------------------------------
/src/css/UserList.css:
--------------------------------------------------------------------------------
1 | /* Position and sizing of burger button */
2 | .bm-burger-button {
3 | position: fixed;
4 | width: 36px;
5 | height: 30px;
6 | right: 50px;
7 | top: 100px;
8 | }
9 |
10 | /* Color/shape of burger icon bars */
11 | .bm-burger-bars {
12 | background: #373a47;
13 | }
14 |
15 | /* General sidebar styles */
16 | .bm-menu {
17 | padding: 2.5em 1.5em 0;
18 | font-size: 1.15em;
19 | }
20 |
21 | /* Wrapper for item list */
22 | .bm-item-list {
23 | color: #b8b7ad;
24 | padding: 0.8em;
25 | }
26 |
27 | /* Individual item */
28 | .bm-item {
29 | display: inline-block;
30 | }
31 |
32 | /* Styling of overlay */
33 | .bm-overlay {
34 | width: 100%;
35 | height: 100%;
36 | }
37 |
38 | .user{
39 | width: 70px;
40 | height: 70px;
41 | background-repeat: no-repeat;
42 | border-radius: 30px;
43 | background-color: transparent;
44 | }
45 |
46 | .user:hover{
47 | background-color: transparent!important;
48 | border-color: transparent!important;
49 | }
50 |
51 | .user-icon{
52 | max-width: 50px;
53 | padding: 0!important;
54 | max-height: 50px;
55 | display: inline-block;
56 | }
57 |
58 | .user-container{
59 | position: absolute;
60 | top: 100px;
61 | right: 50px;
62 | z-index: 1000;
63 | }
64 |
65 | .user-text{
66 | min-height: 40px!important;
67 | margin-bottom: 10px;
68 | display: inline-block;
69 | text-align: center;
70 | vertical-align: middle;
71 | font-size: 25px
72 | }
73 |
74 | .badge-notify{
75 | background:red;
76 | position:relative;
77 | color: white;
78 | font-size: 15px!important;
79 | top: -50px;
80 | left: -30px;
81 | }
82 |
83 | .user-list{
84 | font-size: 14px;
85 | text-align: center;
86 | max-height: 50px;
87 | line-height: 50px;
88 | height: 100%;
89 | }
--------------------------------------------------------------------------------
/src/css/WordPuzzleForm.css:
--------------------------------------------------------------------------------
1 | /* Form uses some styles from MCQForm.css */
2 | #wp-form {
3 | margin-block: 40px;
4 | }
5 | #wp-form .media-background {
6 | border-radius: 13px;
7 | }
8 |
9 | #wp-form .title,
10 | .wp-title,
11 | .wp-question,
12 | .wp-answer,
13 | .wp-add-question span {
14 | font-weight: bold;
15 | color: #282828;
16 | }
17 |
18 | .wp-add-question {
19 | width: fit-content !important;
20 | background: #e6e6e6;
21 | padding-right: 15px;
22 | border-radius: 15px;
23 | }
24 | .wp-add-question span {
25 | display: inline-block;
26 | vertical-align: middle;
27 | }
28 |
--------------------------------------------------------------------------------
/src/css/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | width: 100%;
3 | height: 100vh;
4 | margin: 0;
5 | padding: 0;
6 | font-family: sans-serif;
7 | overflow: hidden;
8 | }
9 |
10 | #root{
11 | width: 100%;
12 | height: 100%;
13 | margin: 0;
14 | padding: 0;
15 | font-family: sans-serif;
16 | }
17 |
18 | .App{
19 | width: 100%;
20 | height: 100%;
21 | margin: 0;
22 | padding: 0;
23 | font-family: sans-serif;
24 | }
25 |
26 | .App-container{
27 | width: 100%;
28 | height: 100%;
29 | margin: 0;
30 | padding: 0;
31 | font-family: sans-serif;
32 | overflow: hidden;
33 | display: flex;
34 | flex-direction: column;
35 | }
36 |
37 | .main-container{
38 | overflow-y: auto;
39 | flex-grow: 1;
40 | }
41 |
42 | .fullScreenMargin, .fullScreenPaddingMargin{
43 | margin-top: 4px !important;
44 | margin-bottom: 4px !important;
45 | }
46 |
47 | .fullScreenPadding, .fullScreenPaddingMargin{
48 | padding-left: 0px !important;
49 | padding-right: 0px !important;
50 | }
51 | input[type='text'].expand {
52 | width: 100%;
53 | }
54 | .wrapper > .container {
55 | width: 100%;
56 | margin-right: auto;
57 | margin-left: auto;
58 | padding: 0px;
59 | padding-bottom: 3px;
60 | }
61 |
62 | textarea.expand {
63 | width: 100%;
64 | }
--------------------------------------------------------------------------------
/src/icons/exercise/ArrowSmall.cur:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/icons/exercise/ArrowSmall.cur
--------------------------------------------------------------------------------
/src/icons/exercise/clock.svg:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/src/icons/exercise/correct.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/icons/exercise/correct.png
--------------------------------------------------------------------------------
/src/icons/exercise/delete.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/src/icons/exercise/details.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/icons/exercise/details.png
--------------------------------------------------------------------------------
/src/icons/exercise/dialog-cancel.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/src/icons/exercise/dialog-ok.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/src/icons/exercise/down.svg:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/src/icons/exercise/edit.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/src/icons/exercise/go-left.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/src/icons/exercise/go-right.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/icons/exercise/help.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
10 |
--------------------------------------------------------------------------------
/src/icons/exercise/left.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/src/icons/exercise/percent.svg:
--------------------------------------------------------------------------------
1 |
2 |
15 |
--------------------------------------------------------------------------------
/src/icons/exercise/play-button.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/icons/exercise/redo.svg:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/src/icons/exercise/reorder-drag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/icons/exercise/reorder-drag.png
--------------------------------------------------------------------------------
/src/icons/exercise/reorder-drag.svg2:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/exercise/result.svg:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/src/icons/exercise/right.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/src/icons/exercise/sound_off_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/icons/exercise/sound_off_black.png
--------------------------------------------------------------------------------
/src/icons/exercise/sound_off_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/icons/exercise/sound_off_white.png
--------------------------------------------------------------------------------
/src/icons/exercise/sound_on_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/icons/exercise/sound_on_black.png
--------------------------------------------------------------------------------
/src/icons/exercise/sound_on_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/icons/exercise/sound_on_white.png
--------------------------------------------------------------------------------
/src/icons/exercise/speak.svg:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | ]>
7 |
14 |
15 |
--------------------------------------------------------------------------------
/src/icons/exercise/sub.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/icons/exercise/up.svg:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/src/icons/exercise/wrong.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/icons/exercise/wrong.png
--------------------------------------------------------------------------------
/src/icons/navbar/add.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/src/icons/navbar/async-mode.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/src/icons/navbar/fullscreen.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/src/icons/navbar/home.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
45 |
--------------------------------------------------------------------------------
/src/icons/navbar/play.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/icons/navbar/shareAll.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/icons/navbar/zoom-home.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/src/icons/navbar/zoom-neighborhood.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 | ]>
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './containers/App';
4 | import { unregister } from './registerServiceWorker';
5 | import 'bootstrap/dist/css/bootstrap.min.css';
6 | import './css/index.css';
7 | import Modal from 'react-modal';
8 |
9 | Modal.setAppElement('#root');
10 | ReactDOM.render(, document.getElementById('root'));
11 | // registerServiceWorker();
12 | unregister();
13 |
--------------------------------------------------------------------------------
/src/media/defaultExerciseThumbnail/images/README.md:
--------------------------------------------------------------------------------
1 | ## Guidelines
2 | This folder contains images used in default exercises. The supported formats are - png, jpeg, jpg.
--------------------------------------------------------------------------------
/src/media/defaultExerciseThumbnail/images/animal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/media/defaultExerciseThumbnail/images/animal.png
--------------------------------------------------------------------------------
/src/media/defaultExerciseThumbnail/images/bark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/media/defaultExerciseThumbnail/images/bark.png
--------------------------------------------------------------------------------
/src/media/defaultExerciseThumbnail/images/canoe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/media/defaultExerciseThumbnail/images/canoe.png
--------------------------------------------------------------------------------
/src/media/defaultExerciseThumbnail/images/car.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/media/defaultExerciseThumbnail/images/car.png
--------------------------------------------------------------------------------
/src/media/defaultExerciseThumbnail/images/cat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/media/defaultExerciseThumbnail/images/cat.png
--------------------------------------------------------------------------------
/src/media/defaultExerciseThumbnail/images/conjugate.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/media/defaultExerciseThumbnail/images/conjugate.jpg
--------------------------------------------------------------------------------
/src/media/defaultExerciseThumbnail/images/cow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/media/defaultExerciseThumbnail/images/cow.png
--------------------------------------------------------------------------------
/src/media/defaultExerciseThumbnail/images/discount.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/media/defaultExerciseThumbnail/images/discount.png
--------------------------------------------------------------------------------
/src/media/defaultExerciseThumbnail/images/dog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/media/defaultExerciseThumbnail/images/dog.png
--------------------------------------------------------------------------------
/src/media/defaultExerciseThumbnail/images/numerals.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/media/defaultExerciseThumbnail/images/numerals.jpg
--------------------------------------------------------------------------------
/src/media/defaultExerciseThumbnail/images/plane.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/media/defaultExerciseThumbnail/images/plane.png
--------------------------------------------------------------------------------
/src/media/defaultExerciseThumbnail/images/puzzle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/media/defaultExerciseThumbnail/images/puzzle.png
--------------------------------------------------------------------------------
/src/media/defaultExerciseThumbnail/images/sail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/media/defaultExerciseThumbnail/images/sail.png
--------------------------------------------------------------------------------
/src/media/defaultExerciseThumbnail/images/sheep.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/media/defaultExerciseThumbnail/images/sheep.png
--------------------------------------------------------------------------------
/src/media/defaultExerciseThumbnail/images/world.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/media/defaultExerciseThumbnail/images/world.png
--------------------------------------------------------------------------------
/src/media/defaultExerciseThumbnail/sounds/README.md:
--------------------------------------------------------------------------------
1 | ## Guidelines
2 | This folder contains audios used in default exercises. The supported formats are - mpeg, wav, mp3.
--------------------------------------------------------------------------------
/src/media/defaultExerciseThumbnail/sounds/cat.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/media/defaultExerciseThumbnail/sounds/cat.mp3
--------------------------------------------------------------------------------
/src/media/defaultExerciseThumbnail/sounds/cow.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/media/defaultExerciseThumbnail/sounds/cow.mp3
--------------------------------------------------------------------------------
/src/media/defaultExerciseThumbnail/sounds/dog.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/media/defaultExerciseThumbnail/sounds/dog.mp3
--------------------------------------------------------------------------------
/src/media/defaultExerciseThumbnail/sounds/sheep.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/media/defaultExerciseThumbnail/sounds/sheep.mp3
--------------------------------------------------------------------------------
/src/media/defaultExerciseThumbnail/sounds/train.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/llaske/ExerciserReact/2e2b8104273efd7c8a642d71647a748f4c5974da/src/media/defaultExerciseThumbnail/sounds/train.mp3
--------------------------------------------------------------------------------
/src/media/defaultExerciseThumbnail/videos/README.md:
--------------------------------------------------------------------------------
1 | ## Guidelines
2 | This folder contains videos used in default exercises. The supported formats are - webm, mp4.
--------------------------------------------------------------------------------
/src/store/actionTypes.js:
--------------------------------------------------------------------------------
1 | // new exercise object
2 | export const ADD_NEW_EXERCISE_TYPE = "ADD_NEW_EXERCISE_TYPE";
3 | export const ADD_NEW_EXERCISE_QUES = "ADD_NEW_EXERCISE_QUES";
4 | export const ADD_NEW_EXERCISE_ID = "ADD_NEW_EXERCISE_ID";
5 |
6 | // exercises array
7 | export const ADD_NEW_EXERCISE = "ADD_NEW_EXERCISE";
8 | export const ADD_SCORE_TIME = "ADD_SCORE_TIME";
9 | export const EDIT_EXERCISE = "EDIT_EXERCISE";
10 | export const SET_ALL_EXERCISES = "SET_ALL_EXERCISES";
11 | export const REMOVE_EXERCISE = "REMOVE_EXERCISE";
12 | export const INCREMENT_ID = "INCREMENT_ID";
13 | export const SET_COUNTER = "SET_COUNTER";
14 |
15 | // isHost
16 | export const IS_HOST = "IS_HOST";
17 | export const IS_SHARED = "IS_SHARED";
18 | export const ADD_SHARED_EXERCISE = "ADD_SHARED_EXERCISE";
19 | export const GET_SHARED_EXERCISES = "GET_SHARED_EXERCISE";
20 | export const REMOVE_SHARED_EXERCISE = "REMOVE_SHARED_EXERCISE";
21 | export const ADD_USER = "ADD_USER";
22 | export const REMOVE_USER = "REMOVE_USER";
23 | export const ADD_SHARED_RESULT = "ADD_SHARED_RESULT";
24 | export const SHARE_ALL_EXERCISES = "SHARE_ALL_EXERCISES";
25 |
26 | // Sugarizer
27 | export const SET_USER = "SET_USER";
28 |
29 | // Run All Exercises
30 | export const SET_RUN_ALL_EXERCISE = "SET RUN ALL EXERCISE";
31 | export const SET_EXERCISE_INDEX = "SET EXERCISE INDEX";
32 |
33 | // Evaluation Mode
34 | export const SET_EVALUATION_MODE = "SET EVALUATION MODE";
35 | export const SET_EVALUATION_EXERCISE = "SET EVALUATION EXERCISE";
36 | export const ADD_EVALUATION_EXERCISE = "ADD EVALUATION EXERCISE";
37 | export const UPDATE_EVALUATED_EXERCISE = "UPDATE EVALUATED EXERCISE";
38 | export const PRESENCE_ADD_EVALUATION_EXERCISES =
39 | "PRESENCE ADD EVALUATION EXERCISES";
40 |
--------------------------------------------------------------------------------
/src/store/actions/evaluation.js:
--------------------------------------------------------------------------------
1 | import {
2 | ADD_EVALUATION_EXERCISE,
3 | PRESENCE_ADD_EVALUATION_EXERCISES,
4 | SET_EVALUATION_EXERCISE,
5 | SET_EVALUATION_MODE,
6 | UPDATE_EVALUATED_EXERCISE,
7 | } from "../actionTypes";
8 |
9 | export const setEvaluationMode = (mode) => {
10 | return {
11 | type: SET_EVALUATION_MODE,
12 | mode,
13 | };
14 | };
15 |
16 | export const setEvaluationExercise = (exercises) => {
17 | return {
18 | type: SET_EVALUATION_EXERCISE,
19 | exercises,
20 | };
21 | };
22 |
23 | export const addEvaluationExercise = (exercise) => {
24 | return {
25 | type: ADD_EVALUATION_EXERCISE,
26 | exercise: { ...exercise, shared: false },
27 | };
28 | };
29 |
30 | export const updateEvaluatedExercise = (id, evaluation) => {
31 | return {
32 | type: UPDATE_EVALUATED_EXERCISE,
33 | id,
34 | evaluation,
35 | };
36 | };
37 |
38 | export const addEvaluationExercisesPresence = (exercises) => {
39 | return {
40 | type: PRESENCE_ADD_EVALUATION_EXERCISES,
41 | exercises,
42 | };
43 | };
44 |
--------------------------------------------------------------------------------
/src/store/actions/exercises.js:
--------------------------------------------------------------------------------
1 | import { SET_ALL_EXERCISES, REMOVE_EXERCISE, ADD_NEW_EXERCISE, EDIT_EXERCISE, ADD_SCORE_TIME } from "../actionTypes";
2 |
3 | export const setExercises = (exercises) => {
4 | return {
5 | type: SET_ALL_EXERCISES,
6 | exercises
7 | }
8 | };
9 |
10 | export const removeExercises = (id) => ({
11 | type: REMOVE_EXERCISE,
12 | id
13 | });
14 |
15 | export const addNewExercise = (exercise) => ({
16 | type: ADD_NEW_EXERCISE,
17 | exercise: { ...exercise, shared: false }
18 | });
19 |
20 | export const editExercise = (exercise) => ({
21 | type: EDIT_EXERCISE,
22 | exercise
23 | });
24 |
25 | export const addScoreTime = (id, score, time) => ({
26 | type: ADD_SCORE_TIME,
27 | id,
28 | score,
29 | time
30 | });
--------------------------------------------------------------------------------
/src/store/actions/increment_counter.js:
--------------------------------------------------------------------------------
1 | import { INCREMENT_ID, SET_COUNTER } from "../actionTypes";
2 |
3 | export const incrementExerciseCounter = () => ({
4 | type: INCREMENT_ID
5 | });
6 |
7 | export const setExerciseCounter = (counter) => ({
8 | type: SET_COUNTER,
9 | counter
10 | });
--------------------------------------------------------------------------------
/src/store/actions/presence.js:
--------------------------------------------------------------------------------
1 | import {
2 | IS_HOST,
3 | IS_SHARED,
4 | GET_SHARED_EXERCISES,
5 | ADD_SHARED_EXERCISE,
6 | REMOVE_SHARED_EXERCISE,
7 | ADD_USER,
8 | REMOVE_USER,
9 | ADD_SHARED_RESULT,
10 | SHARE_ALL_EXERCISES,
11 | } from "../actionTypes";
12 |
13 | export const setIsHost = () => ({
14 | type: IS_HOST,
15 | });
16 |
17 | export const setIsShared = () => ({
18 | type: IS_SHARED,
19 | });
20 |
21 | export const getSharedExercises = () => ({
22 | type: GET_SHARED_EXERCISES,
23 | });
24 |
25 | export const addSharedExercise = (exercise) => ({
26 | type: ADD_SHARED_EXERCISE,
27 | exercise,
28 | });
29 |
30 | export const addSharedResult = (result) => ({
31 | type: ADD_SHARED_RESULT,
32 | result,
33 | });
34 |
35 | export const removeSharedExercise = (id) => ({
36 | type: REMOVE_SHARED_EXERCISE,
37 | id,
38 | });
39 |
40 | export const addUser = (user) => ({
41 | type: ADD_USER,
42 | user,
43 | });
44 |
45 | export const removeUser = (user) => ({
46 | type: REMOVE_USER,
47 | user,
48 | });
49 |
50 | export const shareAllExercise = (shared_exercises) => ({
51 | type: SHARE_ALL_EXERCISES,
52 | shared_exercises,
53 | });
54 |
--------------------------------------------------------------------------------
/src/store/actions/sugarizer.js:
--------------------------------------------------------------------------------
1 | import {
2 | SET_EXERCISE_INDEX,
3 | SET_RUN_ALL_EXERCISE,
4 | SET_USER,
5 | } from "../actionTypes";
6 |
7 | export const setUser = (user) => ({
8 | type: SET_USER,
9 | user,
10 | });
11 |
12 | export const setRunAllExercise = (runAll) => ({
13 | type: SET_RUN_ALL_EXERCISE,
14 | runAll,
15 | });
16 |
17 | export const setExerciseIndex = (index) => ({
18 | type: SET_EXERCISE_INDEX,
19 | index,
20 | });
21 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import rootReducer from "./reducers";
2 | import { createStore } from "redux";
3 |
4 | export function configureStore() {
5 | const store = createStore(rootReducer);
6 | return store;
7 | }
--------------------------------------------------------------------------------
/src/store/reducers/current_user.js:
--------------------------------------------------------------------------------
1 | import { SET_USER } from "../actionTypes";
2 |
3 | const current_user = (state = {}, action) => {
4 | switch (action.type) {
5 | case SET_USER:
6 | return action.user;
7 | default:
8 | return state
9 | }
10 | };
11 |
12 | export default current_user;
--------------------------------------------------------------------------------
/src/store/reducers/evaluation_exercise.js:
--------------------------------------------------------------------------------
1 | import {
2 | ADD_EVALUATION_EXERCISE,
3 | PRESENCE_ADD_EVALUATION_EXERCISES,
4 | SET_EVALUATION_EXERCISE,
5 | UPDATE_EVALUATED_EXERCISE,
6 | } from "../actionTypes";
7 |
8 | const DEFAULT_STATE = [];
9 |
10 | const evaluation_exercise = (state = DEFAULT_STATE, action) => {
11 | switch (action.type) {
12 | case SET_EVALUATION_EXERCISE:
13 | return [...action.exercises];
14 | case ADD_EVALUATION_EXERCISE:
15 | return [...state, action.exercise];
16 | case UPDATE_EVALUATED_EXERCISE:
17 | let exercises = [];
18 | state.forEach((exercise) => {
19 | if (exercise.id === action.id) {
20 | exercises.push({ ...exercise, evaluation: action.evaluation });
21 | } else {
22 | exercises.push(exercise);
23 | }
24 | });
25 | state = exercises;
26 | return state;
27 | case PRESENCE_ADD_EVALUATION_EXERCISES:
28 | let temp = state;
29 | action.exercises.forEach((exercise) => {
30 | if (!temp.find((x) => x.id === exercise.id)) {
31 | temp.push(exercise);
32 | }
33 | });
34 | state = temp;
35 | return state;
36 | default:
37 | return state;
38 | }
39 | };
40 |
41 | export default evaluation_exercise;
42 |
--------------------------------------------------------------------------------
/src/store/reducers/evaluation_mode.js:
--------------------------------------------------------------------------------
1 | import { SET_EVALUATION_MODE } from "../actionTypes";
2 |
3 | const evaluationMode = (state = "", action) => {
4 | switch (action.type) {
5 | case SET_EVALUATION_MODE:
6 | return action.mode;
7 | default:
8 | return state;
9 | }
10 | };
11 |
12 | export default evaluationMode;
13 |
--------------------------------------------------------------------------------
/src/store/reducers/exercise_counter.js:
--------------------------------------------------------------------------------
1 | import { INCREMENT_ID, SET_COUNTER } from "../actionTypes";
2 |
3 | const exercise_counter = (state = 1, action) => {
4 | switch (action.type) {
5 | case INCREMENT_ID:
6 | return state + 1;
7 | case SET_COUNTER:
8 | return action.counter;
9 | default:
10 | return state
11 | }
12 | };
13 |
14 | export default exercise_counter;
--------------------------------------------------------------------------------
/src/store/reducers/exercises.js:
--------------------------------------------------------------------------------
1 | import {
2 | SET_ALL_EXERCISES,
3 | REMOVE_EXERCISE,
4 | ADD_NEW_EXERCISE,
5 | EDIT_EXERCISE,
6 | ADD_SCORE_TIME,
7 | } from "../actionTypes";
8 |
9 | const DEFAULT_STATE = [];
10 |
11 | const exercises = (state = DEFAULT_STATE, actions) => {
12 | switch (actions.type) {
13 | case SET_ALL_EXERCISES:
14 | return [...actions.exercises];
15 | case ADD_NEW_EXERCISE:
16 | return [...state, actions.exercise];
17 | case EDIT_EXERCISE:
18 | return state.map((exercise, i) => {
19 | return exercise.id === actions.exercise.id
20 | ? actions.exercise
21 | : exercise;
22 | });
23 | case REMOVE_EXERCISE:
24 | return state.filter((exercise) => exercise.id !== actions.id);
25 | case ADD_SCORE_TIME:
26 | return state.map((exercise, i) => {
27 | if (exercise.id === actions.id) {
28 | let temp = exercise;
29 | temp.scores.push(actions.score);
30 | temp.times.push(actions.time);
31 | return temp;
32 | }
33 | return exercise;
34 | });
35 | default:
36 | return state;
37 | }
38 | };
39 |
40 | export default exercises;
41 |
--------------------------------------------------------------------------------
/src/store/reducers/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from "redux";
2 | import exercises from "./exercises";
3 | import exercise_counter from "./exercise_counter";
4 | import isHost from "./presence/isHost";
5 | import isShared from "./presence/isShared";
6 | import sharedExercises from "./presence/sharedExercises";
7 | import users from "./presence/users";
8 | import sharedAllExercises from "./presence/shareAll";
9 | import current_user from "./current_user";
10 | import run_all from "./run_all";
11 | import run_all_exercise from "./run_all_exercise_index";
12 | import evaluationMode from "./evaluation_mode";
13 | import evaluation_exercise from "./evaluation_exercise";
14 |
15 | const rootReducer = combineReducers({
16 | exercises,
17 | exercise_counter,
18 | isHost: isHost,
19 | isShared: isShared,
20 | shared_exercises: sharedExercises,
21 | users: users,
22 | current_user: current_user,
23 | isRunAll: run_all,
24 | exerciseRunning: run_all_exercise,
25 | shared_all_exercises: sharedAllExercises,
26 | evaluation_mode: evaluationMode,
27 | evaluation_exercise: evaluation_exercise,
28 | });
29 |
30 | export default rootReducer;
31 |
--------------------------------------------------------------------------------
/src/store/reducers/presence/isHost.js:
--------------------------------------------------------------------------------
1 | import { IS_HOST } from "../../actionTypes";
2 |
3 | const isHost = (state = false, action) => {
4 | switch (action.type) {
5 | case IS_HOST:
6 | return true;
7 | default:
8 | return state
9 | }
10 | };
11 |
12 | export default isHost;
--------------------------------------------------------------------------------
/src/store/reducers/presence/isShared.js:
--------------------------------------------------------------------------------
1 | import { IS_SHARED } from "../../actionTypes";
2 |
3 | const isShared = (state = false, action) => {
4 | switch (action.type) {
5 | case IS_SHARED:
6 | return true;
7 | default:
8 | return state
9 | }
10 | };
11 |
12 | export default isShared;
--------------------------------------------------------------------------------
/src/store/reducers/presence/shareAll.js:
--------------------------------------------------------------------------------
1 | import { SHARE_ALL_EXERCISES } from "../../actionTypes";
2 |
3 | const sharedAllExercises = (state = {}, action) => {
4 | switch (action.type) {
5 | case SHARE_ALL_EXERCISES:
6 | return { exercises: [...action.shared_exercises], allow_run_all: true };
7 | default:
8 | return state;
9 | }
10 | };
11 |
12 | export default sharedAllExercises;
13 |
--------------------------------------------------------------------------------
/src/store/reducers/presence/sharedExercises.js:
--------------------------------------------------------------------------------
1 | import {
2 | GET_SHARED_EXERCISES,
3 | ADD_SHARED_EXERCISE,
4 | REMOVE_SHARED_EXERCISE,
5 | ADD_SHARED_RESULT,
6 | } from "../../actionTypes";
7 |
8 | const sharedExercises = (state = [], action) => {
9 | switch (action.type) {
10 | case GET_SHARED_EXERCISES:
11 | return state;
12 | case ADD_SHARED_EXERCISE:
13 | return [...state, { ...action.exercise, shared_results: [] }];
14 | case REMOVE_SHARED_EXERCISE:
15 | return state.filter((exercise) => exercise.id !== action.id);
16 | case ADD_SHARED_RESULT:
17 | return state.map((exercise, i) => {
18 | if (exercise.id === action.result.id) {
19 | let temp = exercise;
20 | let score_added = false;
21 | temp.shared_results = temp.shared_results.map((result) => {
22 | if (result.user.name === action.result.user.name) {
23 | score_added = true;
24 | return action.result;
25 | }
26 | return result;
27 | });
28 | if (!score_added) temp.shared_results.push(action.result);
29 | return temp;
30 | }
31 | return exercise;
32 | });
33 | default:
34 | return state;
35 | }
36 | };
37 |
38 | export default sharedExercises;
39 |
--------------------------------------------------------------------------------
/src/store/reducers/presence/users.js:
--------------------------------------------------------------------------------
1 | import { ADD_USER, REMOVE_USER } from "../../actionTypes";
2 |
3 | const users = (state = [], action) => {
4 | switch (action.type) {
5 | case ADD_USER:
6 | return [...state, action.user];
7 | case REMOVE_USER:
8 | return state.filter((user) => user.networkId !== action.user.networkId);
9 | default:
10 | return state;
11 | }
12 | };
13 |
14 | export default users;
15 |
--------------------------------------------------------------------------------
/src/store/reducers/run_all.js:
--------------------------------------------------------------------------------
1 | import { SET_RUN_ALL_EXERCISE } from "../actionTypes";
2 |
3 | const run_all = (state = false, action) => {
4 | switch (action.type) {
5 | case SET_RUN_ALL_EXERCISE:
6 | return action.runAll;
7 | default:
8 | return state;
9 | }
10 | };
11 |
12 | export default run_all;
13 |
--------------------------------------------------------------------------------
/src/store/reducers/run_all_exercise_index.js:
--------------------------------------------------------------------------------
1 | import { SET_EXERCISE_INDEX } from "../actionTypes";
2 |
3 | const run_all_exercise_index = (state = -1, action) => {
4 | switch (action.type) {
5 | case SET_EXERCISE_INDEX:
6 | return action.index;
7 | default:
8 | return state;
9 | }
10 | };
11 |
12 | export default run_all_exercise_index;
13 |
--------------------------------------------------------------------------------
/src/translations/lang.js:
--------------------------------------------------------------------------------
1 | import en from "./en"
2 | import es from "./es"
3 | import fr from "./fr"
4 |
5 | let lang = {
6 | en: en,
7 | es: es,
8 | fr: fr
9 | };
10 |
11 | export default lang;
--------------------------------------------------------------------------------
/src/utils.js:
--------------------------------------------------------------------------------
1 | export const MULTIMEDIA = {
2 | text: 'text',
3 | image: 'image',
4 | audio: 'audio',
5 | textToSpeech: 'text-to-speech',
6 | video: 'video'
7 | };
8 |
9 | export function setDefaultMedia(li) {
10 | if (li.type === MULTIMEDIA.image && (!li.data.startsWith('data:image') && !li.data.includes('/static/'))) {
11 | return {
12 | type: li.type,
13 | data: require(`./media/defaultExerciseThumbnail/images/${li.data}`)
14 | }
15 | } else if (li.type === MULTIMEDIA.audio && (!li.data.startsWith('data:audio') && !li.data.includes('/static/'))) {
16 | return {
17 | type: li.type,
18 | data: require(`./media/defaultExerciseThumbnail/sounds/${li.data}`)
19 | }
20 | } else if (li.type === MULTIMEDIA.video && (!li.data.startsWith('data:video') && !li.data.includes('/static/'))) {
21 | return {
22 | type: li.type,
23 | data: require(`./media/defaultExerciseThumbnail/videos/${li.data}`)
24 | }
25 | } else {
26 | return li;
27 | }
28 | }
--------------------------------------------------------------------------------