maidr 2.17.3 → 2.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/maidr.js +536 -518
- package/dist/maidr.min.js +1 -1
- package/package.json +1 -1
package/dist/maidr.js
CHANGED
|
@@ -12,77 +12,77 @@ class Constants {
|
|
|
12
12
|
* @memberof HtmlIds
|
|
13
13
|
* @default 'chart-container'
|
|
14
14
|
*/
|
|
15
|
-
chart_container_id =
|
|
15
|
+
chart_container_id = "chart-container";
|
|
16
16
|
/**
|
|
17
17
|
* HTML id of the main container div.
|
|
18
18
|
* @type {string}
|
|
19
19
|
* @memberof HtmlIds
|
|
20
20
|
* @default 'maidr-container'
|
|
21
21
|
*/
|
|
22
|
-
main_container_id =
|
|
22
|
+
main_container_id = "maidr-container";
|
|
23
23
|
/**
|
|
24
24
|
* HTML id of the div containing the braille display input
|
|
25
25
|
* @type {string}
|
|
26
26
|
* @memberof HtmlIds
|
|
27
27
|
* @default 'braille-div'
|
|
28
28
|
*/
|
|
29
|
-
braille_container_id =
|
|
29
|
+
braille_container_id = "braille-div";
|
|
30
30
|
/**
|
|
31
31
|
* HTML id of the actual braille input element.
|
|
32
32
|
* @type {string}
|
|
33
33
|
* @memberof HtmlIds
|
|
34
34
|
* @default 'braille-input'
|
|
35
35
|
*/
|
|
36
|
-
braille_input_id =
|
|
36
|
+
braille_input_id = "braille-input";
|
|
37
37
|
/**
|
|
38
38
|
* HTML id of the div containing the info box.
|
|
39
39
|
* @type {string}
|
|
40
40
|
* @memberof HtmlIds
|
|
41
41
|
* @default 'info'
|
|
42
42
|
*/
|
|
43
|
-
info_id =
|
|
43
|
+
info_id = "info";
|
|
44
44
|
/**
|
|
45
45
|
* HTML id of the div containing announcements that hook directly into the screen reader via aria-live.
|
|
46
46
|
* @type {string}
|
|
47
47
|
* @memberof HtmlIds
|
|
48
48
|
* @default 'announcements'
|
|
49
49
|
*/
|
|
50
|
-
announcement_container_id =
|
|
50
|
+
announcement_container_id = "announcements";
|
|
51
51
|
/**
|
|
52
52
|
* HTML id of the div containing the end chime. To be implemented in the future.
|
|
53
53
|
* @type {string}
|
|
54
54
|
* @memberof HtmlIds
|
|
55
55
|
* @default 'end_chime'
|
|
56
56
|
*/
|
|
57
|
-
end_chime_id =
|
|
57
|
+
end_chime_id = "end_chime";
|
|
58
58
|
/**
|
|
59
59
|
* HTML id of the main container div.
|
|
60
60
|
* @type {string}
|
|
61
61
|
* @memberof HtmlIds
|
|
62
62
|
* @default 'container'
|
|
63
63
|
*/
|
|
64
|
-
container_id =
|
|
64
|
+
container_id = "container";
|
|
65
65
|
/**
|
|
66
66
|
* The main project id, used throughout the application.
|
|
67
67
|
* @type {string}
|
|
68
68
|
* @memberof HtmlIds
|
|
69
69
|
* @default 'maidr'
|
|
70
70
|
*/
|
|
71
|
-
project_id =
|
|
71
|
+
project_id = "maidr";
|
|
72
72
|
/**
|
|
73
73
|
* HTML id of the div containing the review text.
|
|
74
74
|
* @type {string}
|
|
75
75
|
* @memberof HtmlIds
|
|
76
76
|
* @default 'review_container'
|
|
77
77
|
*/
|
|
78
|
-
review_id_container =
|
|
78
|
+
review_id_container = "review_container";
|
|
79
79
|
/**
|
|
80
80
|
* HTML id of the review input element.
|
|
81
81
|
* @type {string}
|
|
82
82
|
* @memberof HtmlIds
|
|
83
83
|
* @default 'review'
|
|
84
84
|
*/
|
|
85
|
-
review_id =
|
|
85
|
+
review_id = "review";
|
|
86
86
|
/**
|
|
87
87
|
* Storage element, used to store the last focused element before moving to the review input so we can switch back to it easily.
|
|
88
88
|
* @type {HTMLElement}
|
|
@@ -99,7 +99,7 @@ class Constants {
|
|
|
99
99
|
* @type {string}
|
|
100
100
|
* @memberof HtmlIds
|
|
101
101
|
*/
|
|
102
|
-
chartId =
|
|
102
|
+
chartId = "";
|
|
103
103
|
/**
|
|
104
104
|
* @typedef {Object} EventListenerSetupObject
|
|
105
105
|
* @property {HTMLElement} element - The element to attach the event listener to.
|
|
@@ -128,14 +128,14 @@ class Constants {
|
|
|
128
128
|
* @memberof BTSModes
|
|
129
129
|
* @default 'verbose'
|
|
130
130
|
*/
|
|
131
|
-
textMode =
|
|
131
|
+
textMode = "verbose";
|
|
132
132
|
/**
|
|
133
133
|
* The current braille mode. Can be 'off' or 'on'.
|
|
134
134
|
* @type {("off"|"on")}
|
|
135
135
|
* @memberof BTSModes
|
|
136
136
|
* @default 'off'
|
|
137
137
|
*/
|
|
138
|
-
brailleMode =
|
|
138
|
+
brailleMode = "off";
|
|
139
139
|
|
|
140
140
|
/**
|
|
141
141
|
* We lock the selection so we don't pick up programatic selection changes
|
|
@@ -150,14 +150,14 @@ class Constants {
|
|
|
150
150
|
* @memberof BTSModes
|
|
151
151
|
* @default 'on'
|
|
152
152
|
*/
|
|
153
|
-
sonifMode =
|
|
153
|
+
sonifMode = "on";
|
|
154
154
|
/**
|
|
155
155
|
* The current review mode. Can be 'on' or 'off'.
|
|
156
156
|
* @type {("on"|"off")}
|
|
157
157
|
* @memberof BTSModes
|
|
158
158
|
* @default 'off'
|
|
159
159
|
*/
|
|
160
|
-
reviewMode =
|
|
160
|
+
reviewMode = "off";
|
|
161
161
|
|
|
162
162
|
// basic chart properties
|
|
163
163
|
/**
|
|
@@ -198,14 +198,14 @@ class Constants {
|
|
|
198
198
|
* @memberof HtmlIds
|
|
199
199
|
* @default ''
|
|
200
200
|
*/
|
|
201
|
-
plotId =
|
|
201
|
+
plotId = ""; // update with id in chart specific js
|
|
202
202
|
/**
|
|
203
203
|
* The chart type, sort of a short name of the chart such as 'box', 'bar', 'line', etc.
|
|
204
204
|
* @type {string}
|
|
205
205
|
* @default ''
|
|
206
206
|
* @memberof BasicChartProperties
|
|
207
207
|
*/
|
|
208
|
-
chartType =
|
|
208
|
+
chartType = "";
|
|
209
209
|
/**
|
|
210
210
|
* The navigation orientation of the chart. 0 = row navigation (up/down), 1 = col navigation (left/right).
|
|
211
211
|
* @type {number}
|
|
@@ -219,7 +219,7 @@ class Constants {
|
|
|
219
219
|
* @default 'horz'
|
|
220
220
|
* @memberof BasicChartProperties
|
|
221
221
|
*/
|
|
222
|
-
plotOrientation =
|
|
222
|
+
plotOrientation = "horz";
|
|
223
223
|
|
|
224
224
|
/**
|
|
225
225
|
* @namespace AudioProperties
|
|
@@ -329,7 +329,7 @@ class Constants {
|
|
|
329
329
|
* @default '#03C809' (green)
|
|
330
330
|
* @memberof UserSettings
|
|
331
331
|
*/
|
|
332
|
-
colorSelected =
|
|
332
|
+
colorSelected = "#03C809";
|
|
333
333
|
/**
|
|
334
334
|
* The length of the braille display in characters. Braille displays have a variety of sizes; 40 is pretty common, 32 is quite reliable. Set this to your actual display length so that the system can scale and display braille properly for you (where possible).
|
|
335
335
|
* @type {number}
|
|
@@ -397,7 +397,7 @@ class Constants {
|
|
|
397
397
|
* @default 50
|
|
398
398
|
* @memberof AdvancedUserSettings
|
|
399
399
|
*/
|
|
400
|
-
colorUnselected =
|
|
400
|
+
colorUnselected = "#595959"; // deprecated, todo: find all instances replace with storing old color method
|
|
401
401
|
/**
|
|
402
402
|
* Whether or not we're logging user data. This is off by default, but is used for research purposes.
|
|
403
403
|
* @type {boolean}
|
|
@@ -425,30 +425,30 @@ class Constants {
|
|
|
425
425
|
* @default 'assertive'
|
|
426
426
|
* @memberof AdvancedUserSettings
|
|
427
427
|
*/
|
|
428
|
-
ariaMode =
|
|
428
|
+
ariaMode = "assertive";
|
|
429
429
|
|
|
430
430
|
/**
|
|
431
431
|
* Full list of user settings, used internally to save and load settings.
|
|
432
432
|
* @type {string[]}
|
|
433
433
|
*/
|
|
434
434
|
userSettingsKeys = [
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
435
|
+
"vol",
|
|
436
|
+
"autoPlayRate",
|
|
437
|
+
"brailleDisplayLength",
|
|
438
|
+
"colorSelected",
|
|
439
|
+
"MIN_FREQUENCY",
|
|
440
|
+
"MAX_FREQUENCY",
|
|
441
|
+
"keypressInterval",
|
|
442
|
+
"ariaMode",
|
|
443
|
+
"openAIAuthKey",
|
|
444
|
+
"geminiAuthKey",
|
|
445
|
+
"skillLevel",
|
|
446
|
+
"skillLevelOther",
|
|
447
|
+
"LLMModel",
|
|
448
|
+
"LLMPreferences",
|
|
449
|
+
"LLMOpenAiMulti",
|
|
450
|
+
"LLMGeminiMulti",
|
|
451
|
+
"autoInitLLM",
|
|
452
452
|
];
|
|
453
453
|
|
|
454
454
|
// LLM settings
|
|
@@ -489,14 +489,14 @@ class Constants {
|
|
|
489
489
|
* @default 'high'
|
|
490
490
|
* @memberof LLMSettings
|
|
491
491
|
*/
|
|
492
|
-
LLMDetail =
|
|
492
|
+
LLMDetail = "high"; // low (default for testing, like 100 tokens) / high (default for real, like 1000 tokens)
|
|
493
493
|
/**
|
|
494
494
|
* Current LLM model in use. Can be 'openai' (default) or 'gemini' or 'multi'. More to be added.
|
|
495
495
|
* @type {("openai"|"gemini"|"multi")}
|
|
496
496
|
* @default 'openai'
|
|
497
497
|
* @memberof LLMSettings
|
|
498
498
|
*/
|
|
499
|
-
LLMModel =
|
|
499
|
+
LLMModel = "openai";
|
|
500
500
|
/**
|
|
501
501
|
* The default system message for the LLM. Helps the LLM understand the context of the chart and its role.
|
|
502
502
|
* @type {string}
|
|
@@ -504,21 +504,21 @@ class Constants {
|
|
|
504
504
|
* @memberof LLMSettings
|
|
505
505
|
*/
|
|
506
506
|
LLMSystemMessage =
|
|
507
|
-
|
|
507
|
+
"You are a helpful assistant describing the chart to a blind person. ";
|
|
508
508
|
/**
|
|
509
509
|
* The level of skill the user has with statistical charts. Can be 'basic', 'intermediate', 'expert', or 'other'. This is passed to the LLM on the initial message to help it speak correctly to the user. If 'other' is selected, the user can provide a custom skill level.
|
|
510
510
|
* @type {("basic"|"intermediate"|"expert"|"other")}
|
|
511
511
|
* @default 'basic'
|
|
512
512
|
* @memberof LLMSettings
|
|
513
513
|
*/
|
|
514
|
-
skillLevel =
|
|
514
|
+
skillLevel = "basic"; // basic / intermediate / expert
|
|
515
515
|
/**
|
|
516
516
|
* Custom skill level, used if the user selects 'other' as their skill level.
|
|
517
517
|
* @type {string}
|
|
518
518
|
* @default ''
|
|
519
519
|
* @memberof LLMSettings
|
|
520
520
|
*/
|
|
521
|
-
skillLevelOther =
|
|
521
|
+
skillLevelOther = ""; // custom skill level
|
|
522
522
|
/**
|
|
523
523
|
* The LLM can send the first default message containing the chart image on initialization, so when the user opens the chat window the LLM already has an initial response and is ready for a conversation.
|
|
524
524
|
* @type {boolean}
|
|
@@ -532,7 +532,7 @@ class Constants {
|
|
|
532
532
|
* @default ''
|
|
533
533
|
* @memberof LLMSettings
|
|
534
534
|
*/
|
|
535
|
-
verboseText =
|
|
535
|
+
verboseText = "";
|
|
536
536
|
/**
|
|
537
537
|
* An internal variable used to turn the waiting beep on and off.
|
|
538
538
|
* @type {number}
|
|
@@ -580,31 +580,31 @@ class Constants {
|
|
|
580
580
|
* @type {boolean}
|
|
581
581
|
* @memberof PlatformControls
|
|
582
582
|
*/
|
|
583
|
-
isMac = navigator.userAgent.toLowerCase().includes(
|
|
583
|
+
isMac = navigator.userAgent.toLowerCase().includes("mac"); // true if macOS
|
|
584
584
|
/**
|
|
585
585
|
* The control key for the user's platform. Can be 'Cmd' or 'Ctrl'. Used in keyboard shortcut display in help.
|
|
586
586
|
* @type {"Cmd"|"Ctrl"}
|
|
587
587
|
* @memberof PlatformControls
|
|
588
588
|
*/
|
|
589
|
-
control = this.isMac ?
|
|
589
|
+
control = this.isMac ? "Cmd" : "Ctrl";
|
|
590
590
|
/**
|
|
591
591
|
* The alt key for the user's platform. Can be 'option' or 'Alt'. Used in keyboard shortcut display in help.
|
|
592
592
|
* @type {"option"|"Alt"}
|
|
593
593
|
* @memberof PlatformControls
|
|
594
594
|
*/
|
|
595
|
-
alt = this.isMac ?
|
|
595
|
+
alt = this.isMac ? "option" : "Alt";
|
|
596
596
|
/**
|
|
597
597
|
* The home key for the user's platform. Can be 'fn + Left arrow' or 'Home'. Used in keyboard shortcut display in help.
|
|
598
598
|
* @type {"fn + Left arrow"|"Home"}
|
|
599
599
|
* @memberof PlatformControls
|
|
600
600
|
*/
|
|
601
|
-
home = this.isMac ?
|
|
601
|
+
home = this.isMac ? "fn + Left arrow" : "Home";
|
|
602
602
|
/**
|
|
603
603
|
* The end key for the user's platform. Can be 'fn + Right arrow' or 'End'. Used in keyboard shortcut display in help.
|
|
604
604
|
* @type {"fn + Right arrow"|"End"}
|
|
605
605
|
* @memberof PlatformControls
|
|
606
606
|
*/
|
|
607
|
-
end = this.isMac ?
|
|
607
|
+
end = this.isMac ? "fn + Right arrow" : "End";
|
|
608
608
|
|
|
609
609
|
// internal controls
|
|
610
610
|
// todo: are these even used? Sean doesn't think so (May 2024)
|
|
@@ -697,13 +697,13 @@ class Constants {
|
|
|
697
697
|
*/
|
|
698
698
|
ConvertHexToRGBString(hexColorString) {
|
|
699
699
|
return (
|
|
700
|
-
|
|
700
|
+
"rgb(" +
|
|
701
701
|
parseInt(hexColorString.slice(1, 3), 16) +
|
|
702
|
-
|
|
702
|
+
"," +
|
|
703
703
|
parseInt(hexColorString.slice(3, 5), 16) +
|
|
704
|
-
|
|
704
|
+
"," +
|
|
705
705
|
parseInt(hexColorString.slice(5, 7), 16) +
|
|
706
|
-
|
|
706
|
+
")"
|
|
707
707
|
);
|
|
708
708
|
}
|
|
709
709
|
|
|
@@ -713,12 +713,12 @@ class Constants {
|
|
|
713
713
|
* @returns {string} - hexadecimal color (e.g., "#595959").
|
|
714
714
|
*/
|
|
715
715
|
ConvertRGBStringToHex(rgbColorString) {
|
|
716
|
-
let rgb = rgbColorString.replace(/[^\d,]/g,
|
|
716
|
+
let rgb = rgbColorString.replace(/[^\d,]/g, "").split(",");
|
|
717
717
|
return (
|
|
718
|
-
|
|
719
|
-
rgb[0].toString(16).padStart(2,
|
|
720
|
-
rgb[1].toString(16).padStart(2,
|
|
721
|
-
rgb[2].toString(16).padStart(2,
|
|
718
|
+
"#" +
|
|
719
|
+
rgb[0].toString(16).padStart(2, "0") +
|
|
720
|
+
rgb[1].toString(16).padStart(2, "0") +
|
|
721
|
+
rgb[2].toString(16).padStart(2, "0")
|
|
722
722
|
);
|
|
723
723
|
}
|
|
724
724
|
|
|
@@ -730,11 +730,11 @@ class Constants {
|
|
|
730
730
|
*/
|
|
731
731
|
ColorInvert(color) {
|
|
732
732
|
// invert an rgb color
|
|
733
|
-
let rgb = color.replace(/[^\d,]/g,
|
|
733
|
+
let rgb = color.replace(/[^\d,]/g, "").split(",");
|
|
734
734
|
let r = 255 - rgb[0];
|
|
735
735
|
let g = 255 - rgb[1];
|
|
736
736
|
let b = 255 - rgb[2];
|
|
737
|
-
return
|
|
737
|
+
return "rgb(" + r + "," + g + "," + b + ")";
|
|
738
738
|
}
|
|
739
739
|
|
|
740
740
|
/**
|
|
@@ -743,11 +743,11 @@ class Constants {
|
|
|
743
743
|
* @returns {string} The better color
|
|
744
744
|
*/
|
|
745
745
|
GetBetterColor(oldColor) {
|
|
746
|
-
if (oldColor.indexOf(
|
|
746
|
+
if (oldColor.indexOf("#") !== -1) {
|
|
747
747
|
oldColor = this.ConvertHexToRGBString(oldColor);
|
|
748
748
|
}
|
|
749
749
|
let newColor = this.ColorInvert(oldColor);
|
|
750
|
-
let rgb = newColor.replace(/[^\d,]/g,
|
|
750
|
+
let rgb = newColor.replace(/[^\d,]/g, "").split(",");
|
|
751
751
|
if (
|
|
752
752
|
rgb[1] < rgb[0] + 10 &&
|
|
753
753
|
rgb[1] > rgb[0] - 10 &&
|
|
@@ -769,7 +769,7 @@ class Constants {
|
|
|
769
769
|
*/
|
|
770
770
|
GetStyleArrayFromString(styleString) {
|
|
771
771
|
// Get an array of CSS style attributes and values from a style string
|
|
772
|
-
return styleString.replaceAll(
|
|
772
|
+
return styleString.replaceAll(" ", "").split(/[:;]/);
|
|
773
773
|
}
|
|
774
774
|
|
|
775
775
|
/**
|
|
@@ -779,16 +779,16 @@ class Constants {
|
|
|
779
779
|
*/
|
|
780
780
|
GetStyleStringFromArray(styleArray) {
|
|
781
781
|
// Get CSS style string from an array of style attributes and values
|
|
782
|
-
let styleString =
|
|
782
|
+
let styleString = "";
|
|
783
783
|
for (let i = 0; i < styleArray.length; i++) {
|
|
784
784
|
if (i % 2 === 0) {
|
|
785
785
|
if (i !== styleArray.length - 1) {
|
|
786
|
-
styleString += styleArray[i] +
|
|
786
|
+
styleString += styleArray[i] + ": ";
|
|
787
787
|
} else {
|
|
788
788
|
styleString += styleArray[i];
|
|
789
789
|
}
|
|
790
790
|
} else {
|
|
791
|
-
styleString += styleArray[i] +
|
|
791
|
+
styleString += styleArray[i] + "; ";
|
|
792
792
|
}
|
|
793
793
|
}
|
|
794
794
|
return styleString;
|
|
@@ -801,35 +801,35 @@ class Constants {
|
|
|
801
801
|
class Resources {
|
|
802
802
|
constructor() {}
|
|
803
803
|
|
|
804
|
-
language =
|
|
805
|
-
knowledgeLevel =
|
|
804
|
+
language = "en"; // Current language, 2 char lang code
|
|
805
|
+
knowledgeLevel = "basic"; // basic, intermediate, expert
|
|
806
806
|
|
|
807
807
|
// language strings, per 2 char language code
|
|
808
808
|
strings = {
|
|
809
809
|
en: {
|
|
810
810
|
basic: {
|
|
811
|
-
upper_outlier:
|
|
812
|
-
lower_outlier:
|
|
813
|
-
min:
|
|
814
|
-
max:
|
|
815
|
-
25:
|
|
816
|
-
50:
|
|
817
|
-
75:
|
|
818
|
-
q1:
|
|
819
|
-
q2:
|
|
820
|
-
q3:
|
|
821
|
-
son_on:
|
|
822
|
-
son_off:
|
|
823
|
-
son_des:
|
|
824
|
-
son_comp:
|
|
825
|
-
son_ch:
|
|
826
|
-
son_sep:
|
|
827
|
-
son_same:
|
|
828
|
-
empty:
|
|
829
|
-
openai:
|
|
830
|
-
gemini:
|
|
831
|
-
multi:
|
|
832
|
-
processing:
|
|
811
|
+
upper_outlier: "Upper Outlier",
|
|
812
|
+
lower_outlier: "Lower Outlier",
|
|
813
|
+
min: "Minimum",
|
|
814
|
+
max: "Maximum",
|
|
815
|
+
25: "25%",
|
|
816
|
+
50: "50%",
|
|
817
|
+
75: "75%",
|
|
818
|
+
q1: "25%",
|
|
819
|
+
q2: "50%",
|
|
820
|
+
q3: "75%",
|
|
821
|
+
son_on: "Sonification on",
|
|
822
|
+
son_off: "Sonification off",
|
|
823
|
+
son_des: "Sonification descrete",
|
|
824
|
+
son_comp: "Sonification compare",
|
|
825
|
+
son_ch: "Sonification chord",
|
|
826
|
+
son_sep: "Sonification separate",
|
|
827
|
+
son_same: "Sonification combined",
|
|
828
|
+
empty: "Empty",
|
|
829
|
+
openai: "OpenAI Vision",
|
|
830
|
+
gemini: "Gemini Pro Vision",
|
|
831
|
+
multi: "Multiple AI",
|
|
832
|
+
processing: "Processing Chart...",
|
|
833
833
|
},
|
|
834
834
|
},
|
|
835
835
|
};
|
|
@@ -944,7 +944,11 @@ class Menu {
|
|
|
944
944
|
<td>Auto-play speed down</td>
|
|
945
945
|
<td>Comma (,)</td>
|
|
946
946
|
</tr>
|
|
947
|
-
|
|
947
|
+
<tr>
|
|
948
|
+
<td>Auto-play speed reset</td>
|
|
949
|
+
<td>Slash (/)</td>
|
|
950
|
+
</tr>
|
|
951
|
+
<tr>
|
|
948
952
|
<td>Check label for the title of current plot</td>
|
|
949
953
|
<td>l t</td>
|
|
950
954
|
</tr>
|
|
@@ -1000,12 +1004,12 @@ class Menu {
|
|
|
1000
1004
|
<div><fieldset>
|
|
1001
1005
|
<legend>Aria Mode</legend>
|
|
1002
1006
|
<p><input type="radio" id="aria_mode_assertive" name="aria_mode" value="assertive" ${
|
|
1003
|
-
constants.ariaMode ==
|
|
1004
|
-
?
|
|
1005
|
-
:
|
|
1007
|
+
constants.ariaMode == "assertive"
|
|
1008
|
+
? "checked"
|
|
1009
|
+
: ""
|
|
1006
1010
|
}><label for="aria_mode_assertive">Assertive</label></p>
|
|
1007
1011
|
<p><input type="radio" id="aria_mode_polite" name="aria_mode" value="polite" ${
|
|
1008
|
-
constants.ariaMode ==
|
|
1012
|
+
constants.ariaMode == "polite" ? "checked" : ""
|
|
1009
1013
|
}><label for="aria_mode_polite">Polite</label></p>
|
|
1010
1014
|
</fieldset></div>
|
|
1011
1015
|
<h5 class="modal-title">LLM Settings</h5>
|
|
@@ -1026,7 +1030,7 @@ class Menu {
|
|
|
1026
1030
|
<input type="password" size="50" id="gemini_auth_key"><button aria-label="Delete Gemini key" title="Delete Gemini key" id="delete_gemini_key" class="invis_button">×</button><label for="gemini_auth_key">Gemini Authentication Key</label>
|
|
1027
1031
|
</p>
|
|
1028
1032
|
<p><input type="checkbox" ${
|
|
1029
|
-
constants.autoInitLLM ?
|
|
1033
|
+
constants.autoInitLLM ? "checked" : ""
|
|
1030
1034
|
} id="init_llm_on_load" name="init_llm_on_load"><label for="init_llm_on_load">Start first LLM chat chart load</label></p>
|
|
1031
1035
|
<p>
|
|
1032
1036
|
<select id="skill_level">
|
|
@@ -1063,33 +1067,33 @@ class Menu {
|
|
|
1063
1067
|
CreateMenu() {
|
|
1064
1068
|
// menu element creation
|
|
1065
1069
|
document
|
|
1066
|
-
.querySelector(
|
|
1067
|
-
.insertAdjacentHTML(
|
|
1070
|
+
.querySelector("body")
|
|
1071
|
+
.insertAdjacentHTML("beforeend", this.menuHtml);
|
|
1068
1072
|
|
|
1069
1073
|
// menu close events
|
|
1070
|
-
let allClose = document.querySelectorAll(
|
|
1074
|
+
let allClose = document.querySelectorAll("#close_menu, #menu .close");
|
|
1071
1075
|
for (let i = 0; i < allClose.length; i++) {
|
|
1072
1076
|
constants.events.push([
|
|
1073
1077
|
allClose[i],
|
|
1074
|
-
|
|
1078
|
+
"click",
|
|
1075
1079
|
function (e) {
|
|
1076
1080
|
menu.Toggle(false);
|
|
1077
1081
|
},
|
|
1078
1082
|
]);
|
|
1079
1083
|
}
|
|
1080
1084
|
constants.events.push([
|
|
1081
|
-
document.getElementById(
|
|
1082
|
-
|
|
1085
|
+
document.getElementById("save_and_close_menu"),
|
|
1086
|
+
"click",
|
|
1083
1087
|
function (e) {
|
|
1084
1088
|
menu.SaveData();
|
|
1085
1089
|
menu.Toggle(false);
|
|
1086
1090
|
},
|
|
1087
1091
|
]);
|
|
1088
1092
|
constants.events.push([
|
|
1089
|
-
document.getElementById(
|
|
1090
|
-
|
|
1093
|
+
document.getElementById("menu"),
|
|
1094
|
+
"keyup",
|
|
1091
1095
|
function (e) {
|
|
1092
|
-
if (e.key ==
|
|
1096
|
+
if (e.key == "Esc") {
|
|
1093
1097
|
// esc
|
|
1094
1098
|
menu.Toggle(false);
|
|
1095
1099
|
}
|
|
@@ -1099,15 +1103,15 @@ class Menu {
|
|
|
1099
1103
|
// Menu open events
|
|
1100
1104
|
constants.events.push([
|
|
1101
1105
|
document,
|
|
1102
|
-
|
|
1106
|
+
"keyup",
|
|
1103
1107
|
function (e) {
|
|
1104
1108
|
// don't fire on input elements
|
|
1105
1109
|
if (
|
|
1106
|
-
e.target.tagName.toLowerCase() ==
|
|
1107
|
-
e.target.tagName.toLowerCase() ==
|
|
1110
|
+
e.target.tagName.toLowerCase() == "input" ||
|
|
1111
|
+
e.target.tagName.toLowerCase() == "textarea"
|
|
1108
1112
|
) {
|
|
1109
1113
|
return;
|
|
1110
|
-
} else if (e.key ==
|
|
1114
|
+
} else if (e.key == "h") {
|
|
1111
1115
|
menu.Toggle(true);
|
|
1112
1116
|
}
|
|
1113
1117
|
},
|
|
@@ -1115,71 +1119,71 @@ class Menu {
|
|
|
1115
1119
|
|
|
1116
1120
|
// toggle auth key fields
|
|
1117
1121
|
constants.events.push([
|
|
1118
|
-
document.getElementById(
|
|
1119
|
-
|
|
1122
|
+
document.getElementById("LLM_model"),
|
|
1123
|
+
"change",
|
|
1120
1124
|
function (e) {
|
|
1121
|
-
if (e.target.value ==
|
|
1125
|
+
if (e.target.value == "openai") {
|
|
1122
1126
|
document
|
|
1123
|
-
.getElementById(
|
|
1124
|
-
.classList.remove(
|
|
1127
|
+
.getElementById("openai_auth_key_container")
|
|
1128
|
+
.classList.remove("hidden");
|
|
1125
1129
|
document
|
|
1126
|
-
.getElementById(
|
|
1127
|
-
.classList.add(
|
|
1130
|
+
.getElementById("gemini_auth_key_container")
|
|
1131
|
+
.classList.add("hidden");
|
|
1128
1132
|
document
|
|
1129
|
-
.getElementById(
|
|
1130
|
-
.classList.add(
|
|
1133
|
+
.getElementById("openai_multi_container")
|
|
1134
|
+
.classList.add("hidden");
|
|
1131
1135
|
document
|
|
1132
|
-
.getElementById(
|
|
1133
|
-
.classList.add(
|
|
1134
|
-
document.getElementById(
|
|
1135
|
-
document.getElementById(
|
|
1136
|
-
} else if (e.target.value ==
|
|
1136
|
+
.getElementById("gemini_multi_container")
|
|
1137
|
+
.classList.add("hidden");
|
|
1138
|
+
document.getElementById("openai_multi").checked = true;
|
|
1139
|
+
document.getElementById("gemini_multi").checked = false;
|
|
1140
|
+
} else if (e.target.value == "gemini") {
|
|
1137
1141
|
document
|
|
1138
|
-
.getElementById(
|
|
1139
|
-
.classList.add(
|
|
1142
|
+
.getElementById("openai_auth_key_container")
|
|
1143
|
+
.classList.add("hidden");
|
|
1140
1144
|
document
|
|
1141
|
-
.getElementById(
|
|
1142
|
-
.classList.remove(
|
|
1145
|
+
.getElementById("gemini_auth_key_container")
|
|
1146
|
+
.classList.remove("hidden");
|
|
1143
1147
|
document
|
|
1144
|
-
.getElementById(
|
|
1145
|
-
.classList.add(
|
|
1148
|
+
.getElementById("openai_multi_container")
|
|
1149
|
+
.classList.add("hidden");
|
|
1146
1150
|
document
|
|
1147
|
-
.getElementById(
|
|
1148
|
-
.classList.add(
|
|
1149
|
-
document.getElementById(
|
|
1150
|
-
document.getElementById(
|
|
1151
|
-
} else if (e.target.value ==
|
|
1151
|
+
.getElementById("gemini_multi_container")
|
|
1152
|
+
.classList.add("hidden");
|
|
1153
|
+
document.getElementById("openai_multi").checked = false;
|
|
1154
|
+
document.getElementById("gemini_multi").checked = true;
|
|
1155
|
+
} else if (e.target.value == "multi") {
|
|
1152
1156
|
document
|
|
1153
|
-
.getElementById(
|
|
1154
|
-
.classList.remove(
|
|
1157
|
+
.getElementById("openai_auth_key_container")
|
|
1158
|
+
.classList.remove("hidden");
|
|
1155
1159
|
document
|
|
1156
|
-
.getElementById(
|
|
1157
|
-
.classList.remove(
|
|
1160
|
+
.getElementById("gemini_auth_key_container")
|
|
1161
|
+
.classList.remove("hidden");
|
|
1158
1162
|
document
|
|
1159
|
-
.getElementById(
|
|
1160
|
-
.classList.remove(
|
|
1163
|
+
.getElementById("openai_multi_container")
|
|
1164
|
+
.classList.remove("hidden");
|
|
1161
1165
|
document
|
|
1162
|
-
.getElementById(
|
|
1163
|
-
.classList.remove(
|
|
1164
|
-
document.getElementById(
|
|
1165
|
-
document.getElementById(
|
|
1166
|
+
.getElementById("gemini_multi_container")
|
|
1167
|
+
.classList.remove("hidden");
|
|
1168
|
+
document.getElementById("openai_multi").checked = true;
|
|
1169
|
+
document.getElementById("gemini_multi").checked = true;
|
|
1166
1170
|
}
|
|
1167
1171
|
},
|
|
1168
1172
|
]);
|
|
1169
1173
|
|
|
1170
1174
|
// Skill level other events
|
|
1171
1175
|
constants.events.push([
|
|
1172
|
-
document.getElementById(
|
|
1173
|
-
|
|
1176
|
+
document.getElementById("skill_level"),
|
|
1177
|
+
"change",
|
|
1174
1178
|
function (e) {
|
|
1175
|
-
if (e.target.value ==
|
|
1179
|
+
if (e.target.value == "other") {
|
|
1176
1180
|
document
|
|
1177
|
-
.getElementById(
|
|
1178
|
-
.classList.remove(
|
|
1181
|
+
.getElementById("skill_level_other_container")
|
|
1182
|
+
.classList.remove("hidden");
|
|
1179
1183
|
} else {
|
|
1180
1184
|
document
|
|
1181
|
-
.getElementById(
|
|
1182
|
-
.classList.add(
|
|
1185
|
+
.getElementById("skill_level_other_container")
|
|
1186
|
+
.classList.add("hidden");
|
|
1183
1187
|
}
|
|
1184
1188
|
},
|
|
1185
1189
|
]);
|
|
@@ -1187,16 +1191,16 @@ class Menu {
|
|
|
1187
1191
|
// trigger notification that LLM will be reset
|
|
1188
1192
|
// this is done on change of LLM model, multi settings, or skill level
|
|
1189
1193
|
let LLMResetIds = [
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1194
|
+
"LLM_model",
|
|
1195
|
+
"openai_multi",
|
|
1196
|
+
"gemini_multi",
|
|
1197
|
+
"skill_level",
|
|
1198
|
+
"LLM_preferences",
|
|
1195
1199
|
];
|
|
1196
1200
|
for (let i = 0; i < LLMResetIds.length; i++) {
|
|
1197
1201
|
constants.events.push([
|
|
1198
1202
|
document.getElementById(LLMResetIds[i]),
|
|
1199
|
-
|
|
1203
|
+
"change",
|
|
1200
1204
|
function (e) {
|
|
1201
1205
|
menu.NotifyOfLLMReset();
|
|
1202
1206
|
},
|
|
@@ -1210,11 +1214,11 @@ class Menu {
|
|
|
1210
1214
|
*/
|
|
1211
1215
|
Destroy() {
|
|
1212
1216
|
// menu element destruction
|
|
1213
|
-
let menu = document.getElementById(
|
|
1217
|
+
let menu = document.getElementById("menu");
|
|
1214
1218
|
if (menu) {
|
|
1215
1219
|
menu.remove();
|
|
1216
1220
|
}
|
|
1217
|
-
let backdrop = document.getElementById(
|
|
1221
|
+
let backdrop = document.getElementById("menu_modal_backdrop");
|
|
1218
1222
|
if (backdrop) {
|
|
1219
1223
|
backdrop.remove();
|
|
1220
1224
|
}
|
|
@@ -1226,16 +1230,16 @@ class Menu {
|
|
|
1226
1230
|
* @return {void}
|
|
1227
1231
|
*/
|
|
1228
1232
|
Toggle(onoff = false) {
|
|
1229
|
-
if (typeof onoff ==
|
|
1230
|
-
if (document.getElementById(
|
|
1233
|
+
if (typeof onoff == "undefined") {
|
|
1234
|
+
if (document.getElementById("menu").classList.contains("hidden")) {
|
|
1231
1235
|
onoff = true;
|
|
1232
1236
|
} else {
|
|
1233
1237
|
onoff = false;
|
|
1234
1238
|
}
|
|
1235
1239
|
}
|
|
1236
1240
|
// don't open if we have another modal open already
|
|
1237
|
-
if (onoff && document.getElementById(
|
|
1238
|
-
if (!document.getElementById(
|
|
1241
|
+
if (onoff && document.getElementById("chatLLM")) {
|
|
1242
|
+
if (!document.getElementById("chatLLM").classList.contains("hidden")) {
|
|
1239
1243
|
return;
|
|
1240
1244
|
}
|
|
1241
1245
|
}
|
|
@@ -1244,13 +1248,13 @@ class Menu {
|
|
|
1244
1248
|
this.whereWasMyFocus = document.activeElement;
|
|
1245
1249
|
this.PopulateData();
|
|
1246
1250
|
constants.tabMovement = 0;
|
|
1247
|
-
document.getElementById(
|
|
1248
|
-
document.getElementById(
|
|
1249
|
-
document.querySelector(
|
|
1251
|
+
document.getElementById("menu").classList.remove("hidden");
|
|
1252
|
+
document.getElementById("menu_modal_backdrop").classList.remove("hidden");
|
|
1253
|
+
document.querySelector("#menu .close").focus();
|
|
1250
1254
|
} else {
|
|
1251
1255
|
// close
|
|
1252
|
-
document.getElementById(
|
|
1253
|
-
document.getElementById(
|
|
1256
|
+
document.getElementById("menu").classList.add("hidden");
|
|
1257
|
+
document.getElementById("menu_modal_backdrop").classList.add("hidden");
|
|
1254
1258
|
this.whereWasMyFocus.focus();
|
|
1255
1259
|
this.whereWasMyFocus = null;
|
|
1256
1260
|
}
|
|
@@ -1261,89 +1265,89 @@ class Menu {
|
|
|
1261
1265
|
* @return {void}
|
|
1262
1266
|
*/
|
|
1263
1267
|
PopulateData() {
|
|
1264
|
-
document.getElementById(
|
|
1265
|
-
document.getElementById(
|
|
1266
|
-
document.getElementById(
|
|
1268
|
+
document.getElementById("vol").value = constants.vol;
|
|
1269
|
+
document.getElementById("autoplay_rate").value = constants.autoPlayRate;
|
|
1270
|
+
document.getElementById("braille_display_length").value =
|
|
1267
1271
|
constants.brailleDisplayLength;
|
|
1268
|
-
document.getElementById(
|
|
1269
|
-
document.getElementById(
|
|
1270
|
-
document.getElementById(
|
|
1271
|
-
document.getElementById(
|
|
1272
|
+
document.getElementById("color_selected").value = constants.colorSelected;
|
|
1273
|
+
document.getElementById("min_freq").value = constants.MIN_FREQUENCY;
|
|
1274
|
+
document.getElementById("max_freq").value = constants.MAX_FREQUENCY;
|
|
1275
|
+
document.getElementById("keypress_interval").value =
|
|
1272
1276
|
constants.keypressInterval;
|
|
1273
|
-
if (typeof constants.openAIAuthKey ==
|
|
1274
|
-
document.getElementById(
|
|
1277
|
+
if (typeof constants.openAIAuthKey == "string") {
|
|
1278
|
+
document.getElementById("openai_auth_key").value =
|
|
1275
1279
|
constants.openAIAuthKey;
|
|
1276
1280
|
}
|
|
1277
|
-
if (typeof constants.geminiAuthKey ==
|
|
1278
|
-
document.getElementById(
|
|
1281
|
+
if (typeof constants.geminiAuthKey == "string") {
|
|
1282
|
+
document.getElementById("gemini_auth_key").value =
|
|
1279
1283
|
constants.geminiAuthKey;
|
|
1280
1284
|
}
|
|
1281
|
-
document.getElementById(
|
|
1285
|
+
document.getElementById("skill_level").value = constants.skillLevel;
|
|
1282
1286
|
if (constants.skillLevelOther) {
|
|
1283
|
-
document.getElementById(
|
|
1287
|
+
document.getElementById("skill_level_other").value =
|
|
1284
1288
|
constants.skillLevelOther;
|
|
1285
1289
|
}
|
|
1286
|
-
document.getElementById(
|
|
1290
|
+
document.getElementById("LLM_model").value = constants.LLMModel;
|
|
1287
1291
|
|
|
1288
1292
|
// aria mode
|
|
1289
|
-
if (constants.ariaMode ==
|
|
1290
|
-
document.getElementById(
|
|
1291
|
-
document.getElementById(
|
|
1293
|
+
if (constants.ariaMode == "assertive") {
|
|
1294
|
+
document.getElementById("aria_mode_assertive").checked = true;
|
|
1295
|
+
document.getElementById("aria_mode_polite").checked = false;
|
|
1292
1296
|
} else {
|
|
1293
|
-
document.getElementById(
|
|
1294
|
-
document.getElementById(
|
|
1297
|
+
document.getElementById("aria_mode_polite").checked = true;
|
|
1298
|
+
document.getElementById("aria_mode_assertive").checked = false;
|
|
1295
1299
|
}
|
|
1296
1300
|
// hide either openai or gemini auth key field
|
|
1297
|
-
if (constants.LLMModel ==
|
|
1301
|
+
if (constants.LLMModel == "openai") {
|
|
1298
1302
|
document
|
|
1299
|
-
.getElementById(
|
|
1300
|
-
.classList.remove(
|
|
1303
|
+
.getElementById("openai_auth_key_container")
|
|
1304
|
+
.classList.remove("hidden");
|
|
1301
1305
|
document
|
|
1302
|
-
.getElementById(
|
|
1303
|
-
.classList.add(
|
|
1304
|
-
} else if (constants.LLMModel ==
|
|
1306
|
+
.getElementById("gemini_auth_key_container")
|
|
1307
|
+
.classList.add("hidden");
|
|
1308
|
+
} else if (constants.LLMModel == "gemini") {
|
|
1305
1309
|
document
|
|
1306
|
-
.getElementById(
|
|
1307
|
-
.classList.add(
|
|
1310
|
+
.getElementById("openai_auth_key_container")
|
|
1311
|
+
.classList.add("hidden");
|
|
1308
1312
|
document
|
|
1309
|
-
.getElementById(
|
|
1310
|
-
.classList.remove(
|
|
1311
|
-
} else if (constants.LLMModel ==
|
|
1313
|
+
.getElementById("gemini_auth_key_container")
|
|
1314
|
+
.classList.remove("hidden");
|
|
1315
|
+
} else if (constants.LLMModel == "multi") {
|
|
1312
1316
|
// multi LLM mode
|
|
1313
1317
|
document
|
|
1314
|
-
.getElementById(
|
|
1315
|
-
.classList.remove(
|
|
1318
|
+
.getElementById("openai_auth_key_container")
|
|
1319
|
+
.classList.remove("hidden");
|
|
1316
1320
|
document
|
|
1317
|
-
.getElementById(
|
|
1318
|
-
.classList.remove(
|
|
1321
|
+
.getElementById("gemini_auth_key_container")
|
|
1322
|
+
.classList.remove("hidden");
|
|
1319
1323
|
document
|
|
1320
|
-
.getElementById(
|
|
1321
|
-
.classList.remove(
|
|
1324
|
+
.getElementById("openai_multi_container")
|
|
1325
|
+
.classList.remove("hidden");
|
|
1322
1326
|
document
|
|
1323
|
-
.getElementById(
|
|
1324
|
-
.classList.remove(
|
|
1325
|
-
document.getElementById(
|
|
1327
|
+
.getElementById("gemini_multi_container")
|
|
1328
|
+
.classList.remove("hidden");
|
|
1329
|
+
document.getElementById("openai_multi").checked = false;
|
|
1326
1330
|
if (constants.LLMOpenAiMulti) {
|
|
1327
|
-
document.getElementById(
|
|
1331
|
+
document.getElementById("openai_multi").checked = true;
|
|
1328
1332
|
}
|
|
1329
|
-
document.getElementById(
|
|
1333
|
+
document.getElementById("gemini_multi").checked = false;
|
|
1330
1334
|
if (constants.LLMGeminiMulti) {
|
|
1331
|
-
document.getElementById(
|
|
1335
|
+
document.getElementById("gemini_multi").checked = true;
|
|
1332
1336
|
}
|
|
1333
1337
|
}
|
|
1334
1338
|
// skill level other
|
|
1335
|
-
if (constants.skillLevel ==
|
|
1339
|
+
if (constants.skillLevel == "other") {
|
|
1336
1340
|
document
|
|
1337
|
-
.getElementById(
|
|
1338
|
-
.classList.remove(
|
|
1341
|
+
.getElementById("skill_level_other_container")
|
|
1342
|
+
.classList.remove("hidden");
|
|
1339
1343
|
}
|
|
1340
1344
|
// LLM preferences
|
|
1341
1345
|
if (constants.LLMPreferences) {
|
|
1342
|
-
document.getElementById(
|
|
1346
|
+
document.getElementById("LLM_preferences").value =
|
|
1343
1347
|
constants.LLMPreferences;
|
|
1344
1348
|
}
|
|
1345
|
-
if (document.getElementById(
|
|
1346
|
-
document.getElementById(
|
|
1349
|
+
if (document.getElementById("LLM_reset_notification")) {
|
|
1350
|
+
document.getElementById("LLM_reset_notification").remove();
|
|
1347
1351
|
}
|
|
1348
1352
|
}
|
|
1349
1353
|
|
|
@@ -1354,33 +1358,33 @@ class Menu {
|
|
|
1354
1358
|
SaveData() {
|
|
1355
1359
|
let shouldReset = this.ShouldLLMReset();
|
|
1356
1360
|
|
|
1357
|
-
constants.vol = document.getElementById(
|
|
1358
|
-
constants.autoPlayRate = document.getElementById(
|
|
1361
|
+
constants.vol = document.getElementById("vol").value;
|
|
1362
|
+
constants.autoPlayRate = document.getElementById("autoplay_rate").value;
|
|
1359
1363
|
constants.brailleDisplayLength = document.getElementById(
|
|
1360
|
-
|
|
1364
|
+
"braille_display_length"
|
|
1361
1365
|
).value;
|
|
1362
|
-
constants.colorSelected = document.getElementById(
|
|
1363
|
-
constants.MIN_FREQUENCY = document.getElementById(
|
|
1364
|
-
constants.MAX_FREQUENCY = document.getElementById(
|
|
1366
|
+
constants.colorSelected = document.getElementById("color_selected").value;
|
|
1367
|
+
constants.MIN_FREQUENCY = document.getElementById("min_freq").value;
|
|
1368
|
+
constants.MAX_FREQUENCY = document.getElementById("max_freq").value;
|
|
1365
1369
|
constants.keypressInterval =
|
|
1366
|
-
document.getElementById(
|
|
1370
|
+
document.getElementById("keypress_interval").value;
|
|
1367
1371
|
|
|
1368
|
-
constants.openAIAuthKey = document.getElementById(
|
|
1369
|
-
constants.geminiAuthKey = document.getElementById(
|
|
1370
|
-
constants.skillLevel = document.getElementById(
|
|
1372
|
+
constants.openAIAuthKey = document.getElementById("openai_auth_key").value;
|
|
1373
|
+
constants.geminiAuthKey = document.getElementById("gemini_auth_key").value;
|
|
1374
|
+
constants.skillLevel = document.getElementById("skill_level").value;
|
|
1371
1375
|
constants.skillLevelOther =
|
|
1372
|
-
document.getElementById(
|
|
1373
|
-
constants.LLMModel = document.getElementById(
|
|
1374
|
-
constants.LLMPreferences = document.getElementById(
|
|
1375
|
-
constants.LLMOpenAiMulti = document.getElementById(
|
|
1376
|
-
constants.LLMGeminiMulti = document.getElementById(
|
|
1377
|
-
constants.autoInitLLM = document.getElementById(
|
|
1376
|
+
document.getElementById("skill_level_other").value;
|
|
1377
|
+
constants.LLMModel = document.getElementById("LLM_model").value;
|
|
1378
|
+
constants.LLMPreferences = document.getElementById("LLM_preferences").value;
|
|
1379
|
+
constants.LLMOpenAiMulti = document.getElementById("openai_multi").checked;
|
|
1380
|
+
constants.LLMGeminiMulti = document.getElementById("gemini_multi").checked;
|
|
1381
|
+
constants.autoInitLLM = document.getElementById("init_llm_on_load").checked;
|
|
1378
1382
|
|
|
1379
1383
|
// aria
|
|
1380
|
-
if (document.getElementById(
|
|
1381
|
-
constants.ariaMode =
|
|
1382
|
-
} else if (document.getElementById(
|
|
1383
|
-
constants.ariaMode =
|
|
1384
|
+
if (document.getElementById("aria_mode_assertive").checked) {
|
|
1385
|
+
constants.ariaMode = "assertive";
|
|
1386
|
+
} else if (document.getElementById("aria_mode_polite").checked) {
|
|
1387
|
+
constants.ariaMode = "polite";
|
|
1384
1388
|
}
|
|
1385
1389
|
|
|
1386
1390
|
this.SaveDataToLocalStorage();
|
|
@@ -1399,29 +1403,29 @@ class Menu {
|
|
|
1399
1403
|
*/
|
|
1400
1404
|
UpdateHtml() {
|
|
1401
1405
|
// set aria attributes
|
|
1402
|
-
constants.infoDiv.setAttribute(
|
|
1406
|
+
constants.infoDiv.setAttribute("aria-live", constants.ariaMode);
|
|
1403
1407
|
document
|
|
1404
1408
|
.getElementById(constants.announcement_container_id)
|
|
1405
|
-
.setAttribute(
|
|
1409
|
+
.setAttribute("aria-live", constants.ariaMode);
|
|
1406
1410
|
|
|
1407
|
-
document.getElementById(
|
|
1408
|
-
const scatter = document.getElementsByClassName(
|
|
1409
|
-
const heatmap = document.getElementById(
|
|
1410
|
-
const line = document.getElementById(
|
|
1411
|
+
document.getElementById("init_llm_on_load").checked = constants.autoInitLLM;
|
|
1412
|
+
const scatter = document.getElementsByClassName("highlight_point");
|
|
1413
|
+
const heatmap = document.getElementById("highlight_rect");
|
|
1414
|
+
const line = document.getElementById("highlight_point");
|
|
1411
1415
|
|
|
1412
1416
|
if (scatter !== null && scatter.length > 0) {
|
|
1413
1417
|
for (let i = 0; i < scatter.length; i++) {
|
|
1414
|
-
scatter[i].setAttribute(
|
|
1415
|
-
scatter[i].setAttribute(
|
|
1418
|
+
scatter[i].setAttribute("stroke", constants.colorSelected);
|
|
1419
|
+
scatter[i].setAttribute("fill", constants.colorSelected);
|
|
1416
1420
|
}
|
|
1417
1421
|
}
|
|
1418
1422
|
|
|
1419
1423
|
if (heatmap !== null) {
|
|
1420
|
-
heatmap.setAttribute(
|
|
1424
|
+
heatmap.setAttribute("stroke", constants.colorSelected);
|
|
1421
1425
|
}
|
|
1422
1426
|
|
|
1423
1427
|
if (line !== null) {
|
|
1424
|
-
line.setAttribute(
|
|
1428
|
+
line.setAttribute("stroke", constants.colorSelected);
|
|
1425
1429
|
}
|
|
1426
1430
|
}
|
|
1427
1431
|
|
|
@@ -1433,19 +1437,19 @@ class Menu {
|
|
|
1433
1437
|
let html =
|
|
1434
1438
|
'<p id="LLM_reset_notification">Note: Changes in LLM settings will reset any existing conversation.</p>';
|
|
1435
1439
|
|
|
1436
|
-
if (document.getElementById(
|
|
1437
|
-
document.getElementById(
|
|
1440
|
+
if (document.getElementById("LLM_reset_notification")) {
|
|
1441
|
+
document.getElementById("LLM_reset_notification").remove();
|
|
1438
1442
|
}
|
|
1439
1443
|
document
|
|
1440
|
-
.getElementById(
|
|
1441
|
-
.parentElement.insertAdjacentHTML(
|
|
1444
|
+
.getElementById("save_and_close_menu")
|
|
1445
|
+
.parentElement.insertAdjacentHTML("afterend", html);
|
|
1442
1446
|
|
|
1443
1447
|
// add to aria button text
|
|
1444
1448
|
document
|
|
1445
|
-
.getElementById(
|
|
1449
|
+
.getElementById("save_and_close_menu")
|
|
1446
1450
|
.setAttribute(
|
|
1447
|
-
|
|
1448
|
-
|
|
1451
|
+
"aria-labelledby",
|
|
1452
|
+
"save_and_close_text LLM_reset_notification"
|
|
1449
1453
|
);
|
|
1450
1454
|
}
|
|
1451
1455
|
/**
|
|
@@ -1457,29 +1461,29 @@ class Menu {
|
|
|
1457
1461
|
let shouldReset = false;
|
|
1458
1462
|
if (
|
|
1459
1463
|
!shouldReset &&
|
|
1460
|
-
constants.skillLevel != document.getElementById(
|
|
1464
|
+
constants.skillLevel != document.getElementById("skill_level").value
|
|
1461
1465
|
) {
|
|
1462
1466
|
shouldReset = true;
|
|
1463
1467
|
}
|
|
1464
1468
|
if (
|
|
1465
1469
|
!shouldReset &&
|
|
1466
1470
|
constants.LLMPreferences !=
|
|
1467
|
-
document.getElementById(
|
|
1471
|
+
document.getElementById("LLM_preferences").value
|
|
1468
1472
|
) {
|
|
1469
1473
|
shouldReset = true;
|
|
1470
1474
|
}
|
|
1471
1475
|
if (
|
|
1472
1476
|
!shouldReset &&
|
|
1473
|
-
constants.LLMModel != document.getElementById(
|
|
1477
|
+
constants.LLMModel != document.getElementById("LLM_model").value
|
|
1474
1478
|
) {
|
|
1475
1479
|
shouldReset = true;
|
|
1476
1480
|
}
|
|
1477
1481
|
if (
|
|
1478
1482
|
!shouldReset &&
|
|
1479
1483
|
(constants.LLMOpenAiMulti !=
|
|
1480
|
-
document.getElementById(
|
|
1484
|
+
document.getElementById("openai_multi").checked ||
|
|
1481
1485
|
constants.LLMGeminiMulti !=
|
|
1482
|
-
document.getElementById(
|
|
1486
|
+
document.getElementById("gemini_multi").checked)
|
|
1483
1487
|
) {
|
|
1484
1488
|
shouldReset = true;
|
|
1485
1489
|
}
|
|
@@ -1497,23 +1501,23 @@ class Menu {
|
|
|
1497
1501
|
data[constants.userSettingsKeys[i]] =
|
|
1498
1502
|
constants[constants.userSettingsKeys[i]];
|
|
1499
1503
|
}
|
|
1500
|
-
localStorage.setItem(
|
|
1504
|
+
localStorage.setItem("settings_data", JSON.stringify(data));
|
|
1501
1505
|
|
|
1502
1506
|
// also save to tracking if we're doing that
|
|
1503
1507
|
if (constants.isTracking) {
|
|
1504
1508
|
// but not auth keys
|
|
1505
|
-
data.openAIAuthKey =
|
|
1506
|
-
data.geminiAuthKey =
|
|
1509
|
+
data.openAIAuthKey = "hidden";
|
|
1510
|
+
data.geminiAuthKey = "hidden";
|
|
1507
1511
|
// and need a timestamp
|
|
1508
1512
|
data.timestamp = new Date().toISOString();
|
|
1509
|
-
tracker.SetData(
|
|
1513
|
+
tracker.SetData("settings", data);
|
|
1510
1514
|
}
|
|
1511
1515
|
}
|
|
1512
1516
|
/**
|
|
1513
1517
|
* Loads data from 'settings_data' localStorage, and updates contants variables
|
|
1514
1518
|
*/
|
|
1515
1519
|
LoadDataFromLocalStorage() {
|
|
1516
|
-
let data = JSON.parse(localStorage.getItem(
|
|
1520
|
+
let data = JSON.parse(localStorage.getItem("settings_data"));
|
|
1517
1521
|
if (data) {
|
|
1518
1522
|
for (let i = 0; i < constants.userSettingsKeys.length; i++) {
|
|
1519
1523
|
constants[constants.userSettingsKeys[i]] =
|
|
@@ -1539,9 +1543,9 @@ class ChatLLM {
|
|
|
1539
1543
|
if (constants.autoInitLLM) {
|
|
1540
1544
|
// only run if we have API keys set
|
|
1541
1545
|
if (
|
|
1542
|
-
(constants.LLMModel ==
|
|
1543
|
-
(constants.LLMModel ==
|
|
1544
|
-
(constants.LLMModel ==
|
|
1546
|
+
(constants.LLMModel == "openai" && constants.openAIAuthKey) ||
|
|
1547
|
+
(constants.LLMModel == "gemini" && constants.geminiAuthKey) ||
|
|
1548
|
+
(constants.LLMModel == "multi" &&
|
|
1545
1549
|
constants.openAIAuthKey &&
|
|
1546
1550
|
constants.geminiAuthKey)
|
|
1547
1551
|
) {
|
|
@@ -1596,7 +1600,7 @@ class ChatLLM {
|
|
|
1596
1600
|
</div>
|
|
1597
1601
|
<div id="chatLLM_modal_backdrop" class="modal-backdrop hidden"></div>
|
|
1598
1602
|
`;
|
|
1599
|
-
document.querySelector(
|
|
1603
|
+
document.querySelector("body").insertAdjacentHTML("beforeend", html);
|
|
1600
1604
|
}
|
|
1601
1605
|
|
|
1602
1606
|
/**
|
|
@@ -1605,21 +1609,21 @@ class ChatLLM {
|
|
|
1605
1609
|
*/
|
|
1606
1610
|
SetEvents() {
|
|
1607
1611
|
// chatLLM close events
|
|
1608
|
-
let allClose = document.querySelectorAll(
|
|
1612
|
+
let allClose = document.querySelectorAll("#close_chatLLM, #chatLLM .close");
|
|
1609
1613
|
for (let i = 0; i < allClose.length; i++) {
|
|
1610
1614
|
constants.events.push([
|
|
1611
1615
|
allClose[i],
|
|
1612
|
-
|
|
1616
|
+
"click",
|
|
1613
1617
|
function (e) {
|
|
1614
1618
|
chatLLM.Toggle(false);
|
|
1615
1619
|
},
|
|
1616
1620
|
]);
|
|
1617
1621
|
}
|
|
1618
1622
|
constants.events.push([
|
|
1619
|
-
document.getElementById(
|
|
1620
|
-
|
|
1623
|
+
document.getElementById("chatLLM"),
|
|
1624
|
+
"keyup",
|
|
1621
1625
|
function (e) {
|
|
1622
|
-
if (e.key ==
|
|
1626
|
+
if (e.key == "Esc") {
|
|
1623
1627
|
// esc
|
|
1624
1628
|
chatLLM.Toggle(false);
|
|
1625
1629
|
}
|
|
@@ -1629,9 +1633,9 @@ class ChatLLM {
|
|
|
1629
1633
|
// ChatLLM open/close toggle
|
|
1630
1634
|
constants.events.push([
|
|
1631
1635
|
document,
|
|
1632
|
-
|
|
1636
|
+
"keyup",
|
|
1633
1637
|
function (e) {
|
|
1634
|
-
if ((e.key ==
|
|
1638
|
+
if ((e.key == "?" && (e.ctrlKey || e.metaKey)) || e.key == "¿") {
|
|
1635
1639
|
chatLLM.Toggle();
|
|
1636
1640
|
}
|
|
1637
1641
|
},
|
|
@@ -1639,21 +1643,21 @@ class ChatLLM {
|
|
|
1639
1643
|
|
|
1640
1644
|
// ChatLLM request events
|
|
1641
1645
|
constants.events.push([
|
|
1642
|
-
document.getElementById(
|
|
1643
|
-
|
|
1646
|
+
document.getElementById("chatLLM_submit"),
|
|
1647
|
+
"click",
|
|
1644
1648
|
function (e) {
|
|
1645
|
-
let text = document.getElementById(
|
|
1646
|
-
chatLLM.DisplayChatMessage(
|
|
1649
|
+
let text = document.getElementById("chatLLM_input").value;
|
|
1650
|
+
chatLLM.DisplayChatMessage("User", text);
|
|
1647
1651
|
chatLLM.Submit(text);
|
|
1648
1652
|
},
|
|
1649
1653
|
]);
|
|
1650
1654
|
constants.events.push([
|
|
1651
|
-
document.getElementById(
|
|
1652
|
-
|
|
1655
|
+
document.getElementById("chatLLM_input"),
|
|
1656
|
+
"keyup",
|
|
1653
1657
|
function (e) {
|
|
1654
|
-
if (e.key ==
|
|
1655
|
-
let text = document.getElementById(
|
|
1656
|
-
chatLLM.DisplayChatMessage(
|
|
1658
|
+
if (e.key == "Enter" && !e.shiftKey) {
|
|
1659
|
+
let text = document.getElementById("chatLLM_input").value;
|
|
1660
|
+
chatLLM.DisplayChatMessage("User", text);
|
|
1657
1661
|
chatLLM.Submit(text);
|
|
1658
1662
|
}
|
|
1659
1663
|
},
|
|
@@ -1662,15 +1666,15 @@ class ChatLLM {
|
|
|
1662
1666
|
// ChatLLM suggestion events
|
|
1663
1667
|
// actual suggestions:
|
|
1664
1668
|
let suggestions = document.querySelectorAll(
|
|
1665
|
-
|
|
1669
|
+
"#chatLLM .LLM_suggestions button:not(#more_suggestions)"
|
|
1666
1670
|
);
|
|
1667
1671
|
for (let i = 0; i < suggestions.length; i++) {
|
|
1668
1672
|
constants.events.push([
|
|
1669
1673
|
suggestions[i],
|
|
1670
|
-
|
|
1674
|
+
"click",
|
|
1671
1675
|
function (e) {
|
|
1672
1676
|
let text = e.target.innerHTML;
|
|
1673
|
-
chatLLM.DisplayChatMessage(
|
|
1677
|
+
chatLLM.DisplayChatMessage("User", text);
|
|
1674
1678
|
chatLLM.Submit(text);
|
|
1675
1679
|
},
|
|
1676
1680
|
]);
|
|
@@ -1678,24 +1682,24 @@ class ChatLLM {
|
|
|
1678
1682
|
|
|
1679
1683
|
// Delete OpenAI and Gemini keys
|
|
1680
1684
|
constants.events.push([
|
|
1681
|
-
document.getElementById(
|
|
1682
|
-
|
|
1685
|
+
document.getElementById("delete_openai_key"),
|
|
1686
|
+
"click",
|
|
1683
1687
|
function (e) {
|
|
1684
|
-
document.getElementById(
|
|
1688
|
+
document.getElementById("openai_auth_key").value = "";
|
|
1685
1689
|
},
|
|
1686
1690
|
]);
|
|
1687
1691
|
constants.events.push([
|
|
1688
|
-
document.getElementById(
|
|
1689
|
-
|
|
1692
|
+
document.getElementById("delete_gemini_key"),
|
|
1693
|
+
"click",
|
|
1690
1694
|
function (e) {
|
|
1691
|
-
document.getElementById(
|
|
1695
|
+
document.getElementById("gemini_auth_key").value = "";
|
|
1692
1696
|
},
|
|
1693
1697
|
]);
|
|
1694
1698
|
|
|
1695
1699
|
// Reset chatLLM
|
|
1696
1700
|
constants.events.push([
|
|
1697
|
-
document.getElementById(
|
|
1698
|
-
|
|
1701
|
+
document.getElementById("reset_chatLLM"),
|
|
1702
|
+
"click",
|
|
1699
1703
|
function (e) {
|
|
1700
1704
|
chatLLM.ResetLLM();
|
|
1701
1705
|
},
|
|
@@ -1703,15 +1707,15 @@ class ChatLLM {
|
|
|
1703
1707
|
|
|
1704
1708
|
// copy to clipboard
|
|
1705
1709
|
constants.events.push([
|
|
1706
|
-
document.getElementById(
|
|
1707
|
-
|
|
1710
|
+
document.getElementById("chatLLM"),
|
|
1711
|
+
"click",
|
|
1708
1712
|
function (e) {
|
|
1709
1713
|
chatLLM.CopyChatHistory(e);
|
|
1710
1714
|
},
|
|
1711
1715
|
]);
|
|
1712
1716
|
constants.events.push([
|
|
1713
|
-
document.getElementById(
|
|
1714
|
-
|
|
1717
|
+
document.getElementById("chatLLM"),
|
|
1718
|
+
"keyup",
|
|
1715
1719
|
function (e) {
|
|
1716
1720
|
chatLLM.CopyChatHistory(e);
|
|
1717
1721
|
},
|
|
@@ -1729,96 +1733,96 @@ class ChatLLM {
|
|
|
1729
1733
|
* @param {Event|undefined} e - The event that triggered the copy action. If undefined, the entire chat history is copied.
|
|
1730
1734
|
*/
|
|
1731
1735
|
CopyChatHistory(e) {
|
|
1732
|
-
let text =
|
|
1733
|
-
if (typeof e ==
|
|
1736
|
+
let text = "";
|
|
1737
|
+
if (typeof e == "undefined") {
|
|
1734
1738
|
// check for passthrough
|
|
1735
1739
|
// get html of the full chat history
|
|
1736
|
-
text = document.getElementById(
|
|
1737
|
-
} else if (e.type ==
|
|
1740
|
+
text = document.getElementById("chatLLM_chat_history").innerHTML;
|
|
1741
|
+
} else if (e.type == "click") {
|
|
1738
1742
|
// check for buttons
|
|
1739
|
-
if (e.target.id ==
|
|
1743
|
+
if (e.target.id == "chatLLM_copy_all") {
|
|
1740
1744
|
// get html of the full chat history
|
|
1741
|
-
text = document.getElementById(
|
|
1742
|
-
} else if (e.target.classList.contains(
|
|
1745
|
+
text = document.getElementById("chatLLM_chat_history").innerHTML;
|
|
1746
|
+
} else if (e.target.classList.contains("chatLLM_message_copy_button")) {
|
|
1743
1747
|
// get the text of the element before the button
|
|
1744
|
-
text = e.target.closest(
|
|
1748
|
+
text = e.target.closest("p").previousElementSibling.innerHTML;
|
|
1745
1749
|
}
|
|
1746
|
-
} else if (e.type ==
|
|
1750
|
+
} else if (e.type == "keyup") {
|
|
1747
1751
|
// check for alt shift c or ctrl shift c
|
|
1748
|
-
if (e.key ==
|
|
1752
|
+
if (e.key == "C" && (e.ctrlKey || e.metaKey || e.altKey) && e.shiftKey) {
|
|
1749
1753
|
e.preventDefault();
|
|
1750
1754
|
// get the last message
|
|
1751
1755
|
let elem = document.querySelector(
|
|
1752
|
-
|
|
1756
|
+
"#chatLLM_chat_history > .chatLLM_message_other:last-of-type"
|
|
1753
1757
|
);
|
|
1754
1758
|
if (elem) {
|
|
1755
1759
|
text = elem.innerHTML;
|
|
1756
1760
|
}
|
|
1757
1761
|
} else if (
|
|
1758
|
-
e.key ==
|
|
1762
|
+
e.key == "A" &&
|
|
1759
1763
|
(e.ctrlKey || e.metaKey || e.altKey) &&
|
|
1760
1764
|
e.shiftKey
|
|
1761
1765
|
) {
|
|
1762
1766
|
e.preventDefault();
|
|
1763
1767
|
// get html of the full chat history
|
|
1764
|
-
text = document.getElementById(
|
|
1768
|
+
text = document.getElementById("chatLLM_chat_history").innerHTML;
|
|
1765
1769
|
}
|
|
1766
1770
|
}
|
|
1767
1771
|
|
|
1768
|
-
if (text ==
|
|
1772
|
+
if (text == "") {
|
|
1769
1773
|
return;
|
|
1770
1774
|
} else {
|
|
1771
1775
|
// clear the html, removing buttons etc
|
|
1772
|
-
let cleanElems = document.createElement(
|
|
1776
|
+
let cleanElems = document.createElement("div");
|
|
1773
1777
|
cleanElems.innerHTML = text;
|
|
1774
|
-
let removeThese = cleanElems.querySelectorAll(
|
|
1778
|
+
let removeThese = cleanElems.querySelectorAll(".chatLLM_message_copy");
|
|
1775
1779
|
removeThese.forEach((elem) => elem.remove());
|
|
1776
1780
|
|
|
1777
1781
|
// convert from html to markdown
|
|
1778
1782
|
let markdown = this.htmlToMarkdown(cleanElems);
|
|
1779
1783
|
// this messes up a bit with spacing, so kill more than 2 newlines in a row
|
|
1780
|
-
markdown = markdown.replace(/\n{3,}/g,
|
|
1784
|
+
markdown = markdown.replace(/\n{3,}/g, "\n\n");
|
|
1781
1785
|
|
|
1782
1786
|
try {
|
|
1783
1787
|
navigator.clipboard.writeText(markdown); // note: this fails if you're on the inspector. That's fine as it'll never happen to real users
|
|
1784
1788
|
} catch (err) {
|
|
1785
|
-
console.error(
|
|
1789
|
+
console.error("Failed to copy: ", err);
|
|
1786
1790
|
}
|
|
1787
1791
|
return markdown;
|
|
1788
1792
|
}
|
|
1789
1793
|
}
|
|
1790
1794
|
|
|
1791
1795
|
htmlToMarkdown(element) {
|
|
1792
|
-
let markdown =
|
|
1796
|
+
let markdown = "";
|
|
1793
1797
|
|
|
1794
1798
|
const convertElementToMarkdown = (element) => {
|
|
1795
1799
|
switch (element.tagName) {
|
|
1796
|
-
case
|
|
1800
|
+
case "H1":
|
|
1797
1801
|
return `# ${element.textContent}`;
|
|
1798
|
-
case
|
|
1802
|
+
case "H2":
|
|
1799
1803
|
return `## ${element.textContent}`;
|
|
1800
|
-
case
|
|
1804
|
+
case "H3":
|
|
1801
1805
|
return `### ${element.textContent}`;
|
|
1802
|
-
case
|
|
1806
|
+
case "H4":
|
|
1803
1807
|
return `#### ${element.textContent}`;
|
|
1804
|
-
case
|
|
1808
|
+
case "H5":
|
|
1805
1809
|
return `##### ${element.textContent}`;
|
|
1806
|
-
case
|
|
1810
|
+
case "H6":
|
|
1807
1811
|
return `###### ${element.textContent}`;
|
|
1808
|
-
case
|
|
1812
|
+
case "P":
|
|
1809
1813
|
return element.textContent;
|
|
1810
|
-
case
|
|
1814
|
+
case "DIV":
|
|
1811
1815
|
// For divs, process each child and add newlines as needed
|
|
1812
1816
|
return (
|
|
1813
1817
|
Array.from(element.childNodes)
|
|
1814
1818
|
.map((child) => convertElementToMarkdown(child))
|
|
1815
|
-
.join(
|
|
1819
|
+
.join("\n") + "\n\n"
|
|
1816
1820
|
);
|
|
1817
1821
|
default:
|
|
1818
1822
|
// For any other element, process its children recursively
|
|
1819
1823
|
return Array.from(element.childNodes)
|
|
1820
1824
|
.map((child) => convertElementToMarkdown(child))
|
|
1821
|
-
.join(
|
|
1825
|
+
.join("");
|
|
1822
1826
|
}
|
|
1823
1827
|
};
|
|
1824
1828
|
|
|
@@ -1826,7 +1830,7 @@ class ChatLLM {
|
|
|
1826
1830
|
markdown += convertElementToMarkdown(element);
|
|
1827
1831
|
} else if (
|
|
1828
1832
|
element.nodeType === Node.TEXT_NODE &&
|
|
1829
|
-
element.textContent.trim() !==
|
|
1833
|
+
element.textContent.trim() !== ""
|
|
1830
1834
|
) {
|
|
1831
1835
|
markdown += element.textContent.trim();
|
|
1832
1836
|
}
|
|
@@ -1851,14 +1855,14 @@ class ChatLLM {
|
|
|
1851
1855
|
|
|
1852
1856
|
// if this is the user's first message (or we're gemini, in which case we need to send every time), prepend prompt with user position
|
|
1853
1857
|
if (
|
|
1854
|
-
(this.firstOpen || constants.LLMModel ==
|
|
1858
|
+
(this.firstOpen || constants.LLMModel == "gemini") &&
|
|
1855
1859
|
!firsttime &&
|
|
1856
1860
|
constants.verboseText.length > 0
|
|
1857
1861
|
) {
|
|
1858
1862
|
text =
|
|
1859
1863
|
"Here is the current position in the chart; no response necessarily needed, use this info only if it's relevant to future questions: " +
|
|
1860
1864
|
constants.verboseText +
|
|
1861
|
-
|
|
1865
|
+
". My question is: " +
|
|
1862
1866
|
text;
|
|
1863
1867
|
|
|
1864
1868
|
this.firstOpen = false;
|
|
@@ -1869,15 +1873,15 @@ class ChatLLM {
|
|
|
1869
1873
|
this.WaitingSound(true);
|
|
1870
1874
|
}
|
|
1871
1875
|
|
|
1872
|
-
if (constants.LLMOpenAiMulti || constants.LLMModel ==
|
|
1876
|
+
if (constants.LLMOpenAiMulti || constants.LLMModel == "openai") {
|
|
1873
1877
|
if (firsttime) {
|
|
1874
|
-
img = await this.ConvertSVGtoJPG(singleMaidr.id,
|
|
1878
|
+
img = await this.ConvertSVGtoJPG(singleMaidr.id, "openai");
|
|
1875
1879
|
}
|
|
1876
1880
|
chatLLM.OpenAIPrompt(text, img);
|
|
1877
1881
|
}
|
|
1878
|
-
if (constants.LLMGeminiMulti || constants.LLMModel ==
|
|
1882
|
+
if (constants.LLMGeminiMulti || constants.LLMModel == "gemini") {
|
|
1879
1883
|
if (firsttime) {
|
|
1880
|
-
img = await this.ConvertSVGtoJPG(singleMaidr.id,
|
|
1884
|
+
img = await this.ConvertSVGtoJPG(singleMaidr.id, "gemini");
|
|
1881
1885
|
}
|
|
1882
1886
|
chatLLM.GeminiPrompt(text, img);
|
|
1883
1887
|
}
|
|
@@ -1938,7 +1942,7 @@ class ChatLLM {
|
|
|
1938
1942
|
}, 30000);
|
|
1939
1943
|
|
|
1940
1944
|
// set queue for multi
|
|
1941
|
-
if (constants.LLMModel !=
|
|
1945
|
+
if (constants.LLMModel != "multi") {
|
|
1942
1946
|
constants.waitingQueue = 1;
|
|
1943
1947
|
} else {
|
|
1944
1948
|
constants.waitingQueue = 0;
|
|
@@ -1970,7 +1974,7 @@ class ChatLLM {
|
|
|
1970
1974
|
// get name from resource
|
|
1971
1975
|
let LLMName = resources.GetString(constants.LLMModel);
|
|
1972
1976
|
this.firstTime = false;
|
|
1973
|
-
this.DisplayChatMessage(LLMName, resources.GetString(
|
|
1977
|
+
this.DisplayChatMessage(LLMName, resources.GetString("processing"), true);
|
|
1974
1978
|
let defaultPrompt = this.GetDefaultPrompt();
|
|
1975
1979
|
this.Submit(defaultPrompt, true);
|
|
1976
1980
|
}
|
|
@@ -1982,35 +1986,35 @@ class ChatLLM {
|
|
|
1982
1986
|
*/
|
|
1983
1987
|
ProcessLLMResponse(data, model) {
|
|
1984
1988
|
chatLLM.WaitingSound(false);
|
|
1985
|
-
console.log(
|
|
1986
|
-
let text =
|
|
1989
|
+
console.log("LLM response: ", data);
|
|
1990
|
+
let text = "";
|
|
1987
1991
|
let LLMName = resources.GetString(model);
|
|
1988
1992
|
|
|
1989
|
-
if (model ==
|
|
1993
|
+
if (model == "openai") {
|
|
1990
1994
|
text = data.choices[0].message.content;
|
|
1991
1995
|
let i = this.requestJson.messages.length;
|
|
1992
1996
|
this.requestJson.messages[i] = {};
|
|
1993
|
-
this.requestJson.messages[i].role =
|
|
1997
|
+
this.requestJson.messages[i].role = "assistant";
|
|
1994
1998
|
this.requestJson.messages[i].content = text;
|
|
1995
1999
|
|
|
1996
2000
|
if (data.error) {
|
|
1997
|
-
chatLLM.DisplayChatMessage(LLMName,
|
|
2001
|
+
chatLLM.DisplayChatMessage(LLMName, "Error processing request.", true);
|
|
1998
2002
|
chatLLM.WaitingSound(false);
|
|
1999
2003
|
} else {
|
|
2000
2004
|
chatLLM.DisplayChatMessage(LLMName, text);
|
|
2001
2005
|
}
|
|
2002
|
-
} else if (model ==
|
|
2006
|
+
} else if (model == "gemini") {
|
|
2003
2007
|
if (data.text()) {
|
|
2004
2008
|
text = data.text();
|
|
2005
2009
|
chatLLM.DisplayChatMessage(LLMName, text);
|
|
2006
2010
|
} else {
|
|
2007
2011
|
if (!data.error) {
|
|
2008
|
-
data.error =
|
|
2012
|
+
data.error = "Error processing request.";
|
|
2009
2013
|
chatLLM.WaitingSound(false);
|
|
2010
2014
|
}
|
|
2011
2015
|
}
|
|
2012
2016
|
if (data.error) {
|
|
2013
|
-
chatLLM.DisplayChatMessage(LLMName,
|
|
2017
|
+
chatLLM.DisplayChatMessage(LLMName, "Error processing request.", true);
|
|
2014
2018
|
chatLLM.WaitingSound(false);
|
|
2015
2019
|
} else {
|
|
2016
2020
|
// todo: display actual response
|
|
@@ -2020,7 +2024,7 @@ class ChatLLM {
|
|
|
2020
2024
|
// if we're tracking, log the data
|
|
2021
2025
|
if (constants.isTracking) {
|
|
2022
2026
|
let chatHist = chatLLM.CopyChatHistory();
|
|
2023
|
-
tracker.SetData(
|
|
2027
|
+
tracker.SetData("ChatHistory", chatHist);
|
|
2024
2028
|
}
|
|
2025
2029
|
}
|
|
2026
2030
|
|
|
@@ -2034,11 +2038,11 @@ class ChatLLM {
|
|
|
2034
2038
|
if (this.requestJson.messages.length > 2) {
|
|
2035
2039
|
// subsequent responses
|
|
2036
2040
|
responseText = {
|
|
2037
|
-
id:
|
|
2038
|
-
object:
|
|
2041
|
+
id: "chatcmpl-8Y44iRCRrohYbAqm8rfBbJqTUADC7",
|
|
2042
|
+
object: "chat.completion",
|
|
2039
2043
|
created: 1703129508,
|
|
2040
2044
|
//model: 'gpt-4-1106-vision-preview',
|
|
2041
|
-
model:
|
|
2045
|
+
model: "gpt4-o",
|
|
2042
2046
|
usage: {
|
|
2043
2047
|
prompt_tokens: 451,
|
|
2044
2048
|
completion_tokens: 16,
|
|
@@ -2047,10 +2051,10 @@ class ChatLLM {
|
|
|
2047
2051
|
choices: [
|
|
2048
2052
|
{
|
|
2049
2053
|
message: {
|
|
2050
|
-
role:
|
|
2051
|
-
content:
|
|
2054
|
+
role: "assistant",
|
|
2055
|
+
content: "A fake response from the LLM. Nice.",
|
|
2052
2056
|
},
|
|
2053
|
-
finish_reason:
|
|
2057
|
+
finish_reason: "length",
|
|
2054
2058
|
index: 0,
|
|
2055
2059
|
},
|
|
2056
2060
|
],
|
|
@@ -2058,10 +2062,10 @@ class ChatLLM {
|
|
|
2058
2062
|
} else {
|
|
2059
2063
|
// first response
|
|
2060
2064
|
responseText = {
|
|
2061
|
-
id:
|
|
2062
|
-
object:
|
|
2065
|
+
id: "chatcmpl-8Y44iRCRrohYbAqm8rfBbJqTUADC7",
|
|
2066
|
+
object: "chat.completion",
|
|
2063
2067
|
created: 1703129508,
|
|
2064
|
-
model:
|
|
2068
|
+
model: "gpt-4-1106-vision-preview",
|
|
2065
2069
|
usage: {
|
|
2066
2070
|
prompt_tokens: 451,
|
|
2067
2071
|
completion_tokens: 16,
|
|
@@ -2070,11 +2074,11 @@ class ChatLLM {
|
|
|
2070
2074
|
choices: [
|
|
2071
2075
|
{
|
|
2072
2076
|
message: {
|
|
2073
|
-
role:
|
|
2077
|
+
role: "assistant",
|
|
2074
2078
|
content:
|
|
2075
|
-
|
|
2079
|
+
"The chart you're referring to is a bar graph titled \"The Number of Diamonds",
|
|
2076
2080
|
},
|
|
2077
|
-
finish_reason:
|
|
2081
|
+
finish_reason: "length",
|
|
2078
2082
|
index: 0,
|
|
2079
2083
|
},
|
|
2080
2084
|
],
|
|
@@ -2093,49 +2097,49 @@ class ChatLLM {
|
|
|
2093
2097
|
*/
|
|
2094
2098
|
OpenAIPrompt(text, img = null) {
|
|
2095
2099
|
// request init
|
|
2096
|
-
let url =
|
|
2100
|
+
let url = "https://api.openai.com/v1/chat/completions";
|
|
2097
2101
|
let auth = constants.openAIAuthKey;
|
|
2098
2102
|
let requestJson = chatLLM.OpenAIJson(text, img);
|
|
2099
|
-
console.log(
|
|
2103
|
+
console.log("LLM request: ", requestJson);
|
|
2100
2104
|
|
|
2101
2105
|
fetch(url, {
|
|
2102
|
-
method:
|
|
2106
|
+
method: "POST",
|
|
2103
2107
|
headers: {
|
|
2104
|
-
|
|
2105
|
-
Authorization:
|
|
2108
|
+
"Content-Type": "application/json",
|
|
2109
|
+
Authorization: "Bearer " + auth,
|
|
2106
2110
|
},
|
|
2107
2111
|
body: JSON.stringify(requestJson),
|
|
2108
2112
|
})
|
|
2109
2113
|
.then((response) => response.json())
|
|
2110
2114
|
.then((data) => {
|
|
2111
|
-
chatLLM.ProcessLLMResponse(data,
|
|
2115
|
+
chatLLM.ProcessLLMResponse(data, "openai");
|
|
2112
2116
|
})
|
|
2113
2117
|
.catch((error) => {
|
|
2114
2118
|
chatLLM.WaitingSound(false);
|
|
2115
|
-
console.error(
|
|
2116
|
-
chatLLM.DisplayChatMessage(
|
|
2119
|
+
console.error("Error:", error);
|
|
2120
|
+
chatLLM.DisplayChatMessage("OpenAI", "Error processing request.", true);
|
|
2117
2121
|
// also todo: handle errors somehow
|
|
2118
2122
|
});
|
|
2119
2123
|
}
|
|
2120
2124
|
OpenAIJson(text, img = null) {
|
|
2121
2125
|
let sysMessage = constants.LLMSystemMessage;
|
|
2122
2126
|
let backupMessage =
|
|
2123
|
-
|
|
2127
|
+
"Describe " + singleMaidr.type + " charts to a blind person";
|
|
2124
2128
|
// headers and sys message
|
|
2125
2129
|
if (!this.requestJson) {
|
|
2126
2130
|
this.requestJson = {};
|
|
2127
2131
|
//this.requestJson.model = 'gpt-4-vision-preview';
|
|
2128
|
-
this.requestJson.model =
|
|
2132
|
+
this.requestJson.model = "gpt-4o-2024-08-06";
|
|
2129
2133
|
this.requestJson.max_tokens = constants.LLMmaxResponseTokens; // note: if this is too short (tested with less than 200), the response gets cut off
|
|
2130
2134
|
|
|
2131
2135
|
// sys message
|
|
2132
2136
|
this.requestJson.messages = [];
|
|
2133
2137
|
this.requestJson.messages[0] = {};
|
|
2134
|
-
this.requestJson.messages[0].role =
|
|
2138
|
+
this.requestJson.messages[0].role = "system";
|
|
2135
2139
|
this.requestJson.messages[0].content = sysMessage;
|
|
2136
2140
|
if (constants.LLMPreferences) {
|
|
2137
2141
|
this.requestJson.messages[1] = {};
|
|
2138
|
-
this.requestJson.messages[1].role =
|
|
2142
|
+
this.requestJson.messages[1].role = "system";
|
|
2139
2143
|
this.requestJson.messages[1].content = constants.LLMPreferences;
|
|
2140
2144
|
}
|
|
2141
2145
|
}
|
|
@@ -2144,16 +2148,16 @@ class ChatLLM {
|
|
|
2144
2148
|
// if we have an image (first time only), send the image and the text, otherwise just the text
|
|
2145
2149
|
let i = this.requestJson.messages.length;
|
|
2146
2150
|
this.requestJson.messages[i] = {};
|
|
2147
|
-
this.requestJson.messages[i].role =
|
|
2151
|
+
this.requestJson.messages[i].role = "user";
|
|
2148
2152
|
if (img) {
|
|
2149
2153
|
// first message, include the img
|
|
2150
2154
|
this.requestJson.messages[i].content = [
|
|
2151
2155
|
{
|
|
2152
|
-
type:
|
|
2156
|
+
type: "text",
|
|
2153
2157
|
text: text,
|
|
2154
2158
|
},
|
|
2155
2159
|
{
|
|
2156
|
-
type:
|
|
2160
|
+
type: "image_url",
|
|
2157
2161
|
image_url: { url: img },
|
|
2158
2162
|
},
|
|
2159
2163
|
];
|
|
@@ -2178,12 +2182,12 @@ class ChatLLM {
|
|
|
2178
2182
|
|
|
2179
2183
|
// Import the module
|
|
2180
2184
|
const { GoogleGenerativeAI } = await import(
|
|
2181
|
-
|
|
2185
|
+
"https://esm.run/@google/generative-ai"
|
|
2182
2186
|
);
|
|
2183
2187
|
const API_KEY = constants.geminiAuthKey;
|
|
2184
2188
|
const genAI = new GoogleGenerativeAI(API_KEY);
|
|
2185
2189
|
const model = genAI.getGenerativeModel({
|
|
2186
|
-
model:
|
|
2190
|
+
model: "gemini-1.5-pro-latest",
|
|
2187
2191
|
}); // old model was 'gemini-pro-vision'
|
|
2188
2192
|
|
|
2189
2193
|
// Create the prompt
|
|
@@ -2191,25 +2195,25 @@ class ChatLLM {
|
|
|
2191
2195
|
if (constants.LLMPreferences) {
|
|
2192
2196
|
prompt += constants.LLMPreferences;
|
|
2193
2197
|
}
|
|
2194
|
-
prompt +=
|
|
2198
|
+
prompt += "\n\n" + text; // Use the text parameter as the prompt
|
|
2195
2199
|
const image = {
|
|
2196
2200
|
inlineData: {
|
|
2197
2201
|
data: imgBase64, // Use the base64 image string
|
|
2198
|
-
mimeType:
|
|
2202
|
+
mimeType: "image/png", // Or the appropriate mime type of your image
|
|
2199
2203
|
},
|
|
2200
2204
|
};
|
|
2201
2205
|
|
|
2202
2206
|
// Generate the content
|
|
2203
|
-
console.log(
|
|
2207
|
+
console.log("LLM request: ", prompt, image);
|
|
2204
2208
|
const result = await model.generateContent([prompt, image]);
|
|
2205
2209
|
console.log(result.response.text());
|
|
2206
2210
|
|
|
2207
2211
|
// Process the response
|
|
2208
|
-
chatLLM.ProcessLLMResponse(result.response,
|
|
2212
|
+
chatLLM.ProcessLLMResponse(result.response, "gemini");
|
|
2209
2213
|
} catch (error) {
|
|
2210
2214
|
chatLLM.WaitingSound(false);
|
|
2211
|
-
chatLLM.DisplayChatMessage(
|
|
2212
|
-
console.error(
|
|
2215
|
+
chatLLM.DisplayChatMessage("Gemini", "Error processing request.", true);
|
|
2216
|
+
console.error("Error in GeminiPrompt:", error);
|
|
2213
2217
|
throw error; // Rethrow the error for further handling if necessary
|
|
2214
2218
|
}
|
|
2215
2219
|
}
|
|
@@ -2221,11 +2225,11 @@ class ChatLLM {
|
|
|
2221
2225
|
* @memberof module:constants
|
|
2222
2226
|
* @returns {void}
|
|
2223
2227
|
*/
|
|
2224
|
-
DisplayChatMessage(user =
|
|
2225
|
-
let hLevel =
|
|
2226
|
-
if (!isSystem && constants.LLMModel ==
|
|
2228
|
+
DisplayChatMessage(user = "User", text = "", isSystem = false) {
|
|
2229
|
+
let hLevel = "h3";
|
|
2230
|
+
if (!isSystem && constants.LLMModel == "multi" && user != "User") {
|
|
2227
2231
|
if (this.firstMulti) {
|
|
2228
|
-
let multiAIName = resources.GetString(
|
|
2232
|
+
let multiAIName = resources.GetString("multi");
|
|
2229
2233
|
let titleHtml = `
|
|
2230
2234
|
<div class="chatLLM_message chatLLM_message_other">
|
|
2231
2235
|
<h3 class="chatLLM_message_user">${multiAIName} Responses</h3>
|
|
@@ -2234,20 +2238,20 @@ class ChatLLM {
|
|
|
2234
2238
|
this.RenderChatMessage(titleHtml);
|
|
2235
2239
|
this.firstMulti = false;
|
|
2236
2240
|
}
|
|
2237
|
-
hLevel =
|
|
2241
|
+
hLevel = "h4";
|
|
2238
2242
|
}
|
|
2239
2243
|
let html = `
|
|
2240
2244
|
<div class="chatLLM_message ${
|
|
2241
|
-
user ==
|
|
2245
|
+
user == "User" ? "chatLLM_message_self" : "chatLLM_message_other"
|
|
2242
2246
|
}">`;
|
|
2243
|
-
if (text != resources.GetString(
|
|
2247
|
+
if (text != resources.GetString("processing")) {
|
|
2244
2248
|
html += `<${hLevel} class="chatLLM_message_user">${user}</${hLevel}>`;
|
|
2245
2249
|
}
|
|
2246
2250
|
html += `<p class="chatLLM_message_text">${text}</p>
|
|
2247
2251
|
</div>
|
|
2248
2252
|
`;
|
|
2249
2253
|
// add a copy button to actual messages
|
|
2250
|
-
if (user !=
|
|
2254
|
+
if (user != "User" && text != resources.GetString("processing")) {
|
|
2251
2255
|
html += `
|
|
2252
2256
|
<p class="chatLLM_message_copy"><button class="chatLLM_message_copy_button">Copy</button></p>
|
|
2253
2257
|
`;
|
|
@@ -2257,13 +2261,13 @@ class ChatLLM {
|
|
|
2257
2261
|
}
|
|
2258
2262
|
RenderChatMessage(html) {
|
|
2259
2263
|
document
|
|
2260
|
-
.getElementById(
|
|
2261
|
-
.insertAdjacentHTML(
|
|
2262
|
-
document.getElementById(
|
|
2264
|
+
.getElementById("chatLLM_chat_history")
|
|
2265
|
+
.insertAdjacentHTML("beforeend", html);
|
|
2266
|
+
document.getElementById("chatLLM_input").value = "";
|
|
2263
2267
|
|
|
2264
2268
|
// scroll to bottom
|
|
2265
|
-
document.getElementById(
|
|
2266
|
-
document.getElementById(
|
|
2269
|
+
document.getElementById("chatLLM_chat_history").scrollTop =
|
|
2270
|
+
document.getElementById("chatLLM_chat_history").scrollHeight;
|
|
2267
2271
|
}
|
|
2268
2272
|
|
|
2269
2273
|
/**
|
|
@@ -2271,7 +2275,7 @@ class ChatLLM {
|
|
|
2271
2275
|
*/
|
|
2272
2276
|
ResetLLM() {
|
|
2273
2277
|
// clear the main chat history
|
|
2274
|
-
document.getElementById(
|
|
2278
|
+
document.getElementById("chatLLM_chat_history").innerHTML = "";
|
|
2275
2279
|
|
|
2276
2280
|
// reset the data
|
|
2277
2281
|
this.requestJson = null;
|
|
@@ -2292,11 +2296,11 @@ class ChatLLM {
|
|
|
2292
2296
|
*/
|
|
2293
2297
|
Destroy() {
|
|
2294
2298
|
// chatLLM element destruction
|
|
2295
|
-
let chatLLM = document.getElementById(
|
|
2299
|
+
let chatLLM = document.getElementById("chatLLM");
|
|
2296
2300
|
if (chatLLM) {
|
|
2297
2301
|
chatLLM.remove();
|
|
2298
2302
|
}
|
|
2299
|
-
let backdrop = document.getElementById(
|
|
2303
|
+
let backdrop = document.getElementById("chatLLM_modal_backdrop");
|
|
2300
2304
|
if (backdrop) {
|
|
2301
2305
|
backdrop.remove();
|
|
2302
2306
|
}
|
|
@@ -2307,8 +2311,8 @@ class ChatLLM {
|
|
|
2307
2311
|
* @param {boolean} [onoff=false] - Whether to turn the chatLLM on or off. Defaults to false (close).
|
|
2308
2312
|
*/
|
|
2309
2313
|
Toggle(onoff) {
|
|
2310
|
-
if (typeof onoff ==
|
|
2311
|
-
if (document.getElementById(
|
|
2314
|
+
if (typeof onoff == "undefined") {
|
|
2315
|
+
if (document.getElementById("chatLLM").classList.contains("hidden")) {
|
|
2312
2316
|
onoff = true;
|
|
2313
2317
|
} else {
|
|
2314
2318
|
onoff = false;
|
|
@@ -2319,19 +2323,19 @@ class ChatLLM {
|
|
|
2319
2323
|
// open
|
|
2320
2324
|
this.whereWasMyFocus = document.activeElement;
|
|
2321
2325
|
constants.tabMovement = 0;
|
|
2322
|
-
document.getElementById(
|
|
2326
|
+
document.getElementById("chatLLM").classList.remove("hidden");
|
|
2323
2327
|
document
|
|
2324
|
-
.getElementById(
|
|
2325
|
-
.classList.remove(
|
|
2326
|
-
document.querySelector(
|
|
2328
|
+
.getElementById("chatLLM_modal_backdrop")
|
|
2329
|
+
.classList.remove("hidden");
|
|
2330
|
+
document.querySelector("#chatLLM .close").focus();
|
|
2327
2331
|
|
|
2328
2332
|
if (this.firstTime) {
|
|
2329
2333
|
this.InitChatMessage();
|
|
2330
2334
|
}
|
|
2331
2335
|
} else {
|
|
2332
2336
|
// close
|
|
2333
|
-
document.getElementById(
|
|
2334
|
-
document.getElementById(
|
|
2337
|
+
document.getElementById("chatLLM").classList.add("hidden");
|
|
2338
|
+
document.getElementById("chatLLM_modal_backdrop").classList.add("hidden");
|
|
2335
2339
|
this.whereWasMyFocus.focus();
|
|
2336
2340
|
this.whereWasMyFocus = null;
|
|
2337
2341
|
this.firstOpen = true;
|
|
@@ -2345,11 +2349,11 @@ class ChatLLM {
|
|
|
2345
2349
|
async ConvertSVGtoJPG(id, model) {
|
|
2346
2350
|
let svgElement = document.getElementById(id);
|
|
2347
2351
|
return new Promise((resolve, reject) => {
|
|
2348
|
-
var canvas = document.createElement(
|
|
2349
|
-
var ctx = canvas.getContext(
|
|
2352
|
+
var canvas = document.createElement("canvas");
|
|
2353
|
+
var ctx = canvas.getContext("2d");
|
|
2350
2354
|
|
|
2351
2355
|
var svgData = new XMLSerializer().serializeToString(svgElement);
|
|
2352
|
-
if (!svgData.startsWith(
|
|
2356
|
+
if (!svgData.startsWith("<svg xmlns")) {
|
|
2353
2357
|
svgData = `<svg xmlns="http://www.w3.org/2000/svg" ${svgData.slice(4)}`;
|
|
2354
2358
|
}
|
|
2355
2359
|
|
|
@@ -2361,11 +2365,11 @@ class ChatLLM {
|
|
|
2361
2365
|
var img = new Image();
|
|
2362
2366
|
img.onload = function () {
|
|
2363
2367
|
ctx.drawImage(img, 0, 0, svgSize.width, svgSize.height);
|
|
2364
|
-
var jpegData = canvas.toDataURL(
|
|
2365
|
-
if (model ==
|
|
2368
|
+
var jpegData = canvas.toDataURL("image/jpeg", 0.9); // 0.9 is the quality parameter
|
|
2369
|
+
if (model == "openai") {
|
|
2366
2370
|
resolve(jpegData);
|
|
2367
|
-
} else if (model ==
|
|
2368
|
-
let base64Data = jpegData.split(
|
|
2371
|
+
} else if (model == "gemini") {
|
|
2372
|
+
let base64Data = jpegData.split(",")[1];
|
|
2369
2373
|
resolve(base64Data);
|
|
2370
2374
|
//resolve(jpegData);
|
|
2371
2375
|
}
|
|
@@ -2373,11 +2377,11 @@ class ChatLLM {
|
|
|
2373
2377
|
};
|
|
2374
2378
|
|
|
2375
2379
|
img.onerror = function () {
|
|
2376
|
-
reject(new Error(
|
|
2380
|
+
reject(new Error("Error loading SVG"));
|
|
2377
2381
|
};
|
|
2378
2382
|
|
|
2379
2383
|
var svgBlob = new Blob([svgData], {
|
|
2380
|
-
type:
|
|
2384
|
+
type: "image/svg+xml;charset=utf-8",
|
|
2381
2385
|
});
|
|
2382
2386
|
var url = URL.createObjectURL(svgBlob);
|
|
2383
2387
|
img.src = url;
|
|
@@ -2390,25 +2394,25 @@ class ChatLLM {
|
|
|
2390
2394
|
* The prompt includes information about the blind person's skill level and the chart's image and raw data, if available.
|
|
2391
2395
|
*/
|
|
2392
2396
|
GetDefaultPrompt() {
|
|
2393
|
-
let text =
|
|
2397
|
+
let text = "Describe this chart to a blind person";
|
|
2394
2398
|
if (constants.skillLevel) {
|
|
2395
|
-
if (constants.skillLevel ==
|
|
2399
|
+
if (constants.skillLevel == "other" && constants.skillLevelOther) {
|
|
2396
2400
|
text +=
|
|
2397
|
-
|
|
2401
|
+
" who has a " +
|
|
2398
2402
|
constants.skillLevelOther +
|
|
2399
|
-
|
|
2403
|
+
" understanding of statistical charts. ";
|
|
2400
2404
|
} else {
|
|
2401
2405
|
text +=
|
|
2402
|
-
|
|
2406
|
+
" who has a " +
|
|
2403
2407
|
constants.skillLevel +
|
|
2404
|
-
|
|
2408
|
+
" understanding of statistical charts. ";
|
|
2405
2409
|
}
|
|
2406
2410
|
} else {
|
|
2407
|
-
text +=
|
|
2411
|
+
text += " who has a basic understanding of statistical charts. ";
|
|
2408
2412
|
}
|
|
2409
|
-
text +=
|
|
2413
|
+
text += "Here is a chart in image format";
|
|
2410
2414
|
if (singleMaidr) {
|
|
2411
|
-
text +=
|
|
2415
|
+
text += " and raw data in json format: \n";
|
|
2412
2416
|
text += JSON.stringify(singleMaidr);
|
|
2413
2417
|
}
|
|
2414
2418
|
|
|
@@ -2463,26 +2467,26 @@ class Description {
|
|
|
2463
2467
|
|
|
2464
2468
|
`;
|
|
2465
2469
|
|
|
2466
|
-
document.querySelector(
|
|
2470
|
+
document.querySelector("body").insertAdjacentHTML("beforeend", html);
|
|
2467
2471
|
|
|
2468
2472
|
// close events
|
|
2469
2473
|
let allClose = document.querySelectorAll(
|
|
2470
|
-
|
|
2474
|
+
"#close_desc, #description .close"
|
|
2471
2475
|
);
|
|
2472
2476
|
for (let i = 0; i < allClose.length; i++) {
|
|
2473
2477
|
constants.events.push([
|
|
2474
2478
|
allClose[i],
|
|
2475
|
-
|
|
2479
|
+
"click",
|
|
2476
2480
|
function (e) {
|
|
2477
2481
|
description.Toggle(false);
|
|
2478
2482
|
},
|
|
2479
2483
|
]);
|
|
2480
2484
|
}
|
|
2481
2485
|
constants.events.push([
|
|
2482
|
-
document.getElementById(
|
|
2483
|
-
|
|
2486
|
+
document.getElementById("description"),
|
|
2487
|
+
"keyup",
|
|
2484
2488
|
function (e) {
|
|
2485
|
-
if (e.key ==
|
|
2489
|
+
if (e.key == "Esc") {
|
|
2486
2490
|
// esc
|
|
2487
2491
|
description.Toggle(false);
|
|
2488
2492
|
}
|
|
@@ -2492,9 +2496,9 @@ class Description {
|
|
|
2492
2496
|
// open events
|
|
2493
2497
|
constants.events.push([
|
|
2494
2498
|
document,
|
|
2495
|
-
|
|
2499
|
+
"keyup",
|
|
2496
2500
|
function (e) {
|
|
2497
|
-
if (e.key ==
|
|
2501
|
+
if (e.key == "d") {
|
|
2498
2502
|
description.Toggle(true);
|
|
2499
2503
|
}
|
|
2500
2504
|
},
|
|
@@ -2506,11 +2510,11 @@ class Description {
|
|
|
2506
2510
|
*/
|
|
2507
2511
|
Destroy() {
|
|
2508
2512
|
// description element destruction
|
|
2509
|
-
let description = document.getElementById(
|
|
2513
|
+
let description = document.getElementById("menu");
|
|
2510
2514
|
if (description) {
|
|
2511
2515
|
description.remove();
|
|
2512
2516
|
}
|
|
2513
|
-
let backdrop = document.getElementById(
|
|
2517
|
+
let backdrop = document.getElementById("desc_modal_backdrop");
|
|
2514
2518
|
if (backdrop) {
|
|
2515
2519
|
backdrop.remove();
|
|
2516
2520
|
}
|
|
@@ -2521,8 +2525,8 @@ class Description {
|
|
|
2521
2525
|
* @param {boolean} [onoff=false] - Whether to turn the description element on or off.
|
|
2522
2526
|
*/
|
|
2523
2527
|
Toggle(onoff = false) {
|
|
2524
|
-
if (typeof onoff ==
|
|
2525
|
-
if (document.getElementById(
|
|
2528
|
+
if (typeof onoff == "undefined") {
|
|
2529
|
+
if (document.getElementById("description").classList.contains("hidden")) {
|
|
2526
2530
|
onoff = true;
|
|
2527
2531
|
} else {
|
|
2528
2532
|
onoff = false;
|
|
@@ -2533,13 +2537,13 @@ class Description {
|
|
|
2533
2537
|
this.whereWasMyFocus = document.activeElement;
|
|
2534
2538
|
constants.tabMovement = 0;
|
|
2535
2539
|
this.PopulateData();
|
|
2536
|
-
document.getElementById(
|
|
2537
|
-
document.getElementById(
|
|
2538
|
-
document.querySelector(
|
|
2540
|
+
document.getElementById("description").classList.remove("hidden");
|
|
2541
|
+
document.getElementById("desc_modal_backdrop").classList.remove("hidden");
|
|
2542
|
+
document.querySelector("#description .close").focus();
|
|
2539
2543
|
} else {
|
|
2540
2544
|
// close
|
|
2541
|
-
document.getElementById(
|
|
2542
|
-
document.getElementById(
|
|
2545
|
+
document.getElementById("description").classList.add("hidden");
|
|
2546
|
+
document.getElementById("desc_modal_backdrop").classList.add("hidden");
|
|
2543
2547
|
this.whereWasMyFocus.focus();
|
|
2544
2548
|
this.whereWasMyFocus = null;
|
|
2545
2549
|
}
|
|
@@ -2549,22 +2553,22 @@ class Description {
|
|
|
2549
2553
|
* Populates the data for the chart and table based on the chart type and plot data.
|
|
2550
2554
|
*/
|
|
2551
2555
|
PopulateData() {
|
|
2552
|
-
let descHtml =
|
|
2556
|
+
let descHtml = "";
|
|
2553
2557
|
|
|
2554
2558
|
// chart labels and descriptions
|
|
2555
|
-
let descType =
|
|
2556
|
-
if (constants.chartType ==
|
|
2557
|
-
descType =
|
|
2558
|
-
} else if (constants.chartType ==
|
|
2559
|
-
descType =
|
|
2560
|
-
} else if (constants.chartType ==
|
|
2561
|
-
descType =
|
|
2562
|
-
} else if (constants.chartType ==
|
|
2563
|
-
descType =
|
|
2564
|
-
} else if (constants.chartType ==
|
|
2565
|
-
descType =
|
|
2566
|
-
} else if (constants.chartType ==
|
|
2567
|
-
descType =
|
|
2559
|
+
let descType = "";
|
|
2560
|
+
if (constants.chartType == "bar") {
|
|
2561
|
+
descType = "Bar chart";
|
|
2562
|
+
} else if (constants.chartType == "heat") {
|
|
2563
|
+
descType = "Heatmap";
|
|
2564
|
+
} else if (constants.chartType == "box") {
|
|
2565
|
+
descType = "Box plot";
|
|
2566
|
+
} else if (constants.chartType == "scatter") {
|
|
2567
|
+
descType = "Scatter plot";
|
|
2568
|
+
} else if (constants.chartType == "line") {
|
|
2569
|
+
descType = "Line chart";
|
|
2570
|
+
} else if (constants.chartType == "hist") {
|
|
2571
|
+
descType = "Histogram";
|
|
2568
2572
|
}
|
|
2569
2573
|
|
|
2570
2574
|
if (descType) {
|
|
@@ -2581,7 +2585,7 @@ class Description {
|
|
|
2581
2585
|
}
|
|
2582
2586
|
|
|
2583
2587
|
// table of data, prep
|
|
2584
|
-
let descTableHtml =
|
|
2588
|
+
let descTableHtml = "";
|
|
2585
2589
|
let descLabelX = null;
|
|
2586
2590
|
let descLabelY = null;
|
|
2587
2591
|
let descTickX = null;
|
|
@@ -2591,7 +2595,7 @@ class Description {
|
|
|
2591
2595
|
let descNumColsWithLabels = 0;
|
|
2592
2596
|
let descNumRows = 0;
|
|
2593
2597
|
let descNumRowsWithLabels = 0;
|
|
2594
|
-
if (constants.chartType ==
|
|
2598
|
+
if (constants.chartType == "bar") {
|
|
2595
2599
|
if (plot.plotLegend.x != null) {
|
|
2596
2600
|
descLabelX = plot.plotLegend.x;
|
|
2597
2601
|
descNumColsWithLabels += 1;
|
|
@@ -2616,43 +2620,43 @@ class Description {
|
|
|
2616
2620
|
|
|
2617
2621
|
// table of data, create
|
|
2618
2622
|
if (descData != null) {
|
|
2619
|
-
descTableHtml +=
|
|
2623
|
+
descTableHtml += "<table>";
|
|
2620
2624
|
|
|
2621
2625
|
// header rows
|
|
2622
2626
|
if (descLabelX != null || descTickX != null) {
|
|
2623
|
-
descTableHtml +=
|
|
2627
|
+
descTableHtml += "<thead>";
|
|
2624
2628
|
if (descLabelX != null) {
|
|
2625
|
-
descTableHtml +=
|
|
2629
|
+
descTableHtml += "<tr>";
|
|
2626
2630
|
if (descLabelY != null) {
|
|
2627
|
-
descTableHtml +=
|
|
2631
|
+
descTableHtml += "<td></td>";
|
|
2628
2632
|
}
|
|
2629
2633
|
if (descTickY != null) {
|
|
2630
|
-
descTableHtml +=
|
|
2634
|
+
descTableHtml += "<td></td>";
|
|
2631
2635
|
}
|
|
2632
2636
|
descTableHtml += `<th scope="col" colspan="${descNumCols}">${descLabelX}</th>`;
|
|
2633
|
-
descTableHtml +=
|
|
2637
|
+
descTableHtml += "</tr>";
|
|
2634
2638
|
}
|
|
2635
2639
|
if (descTickX != null) {
|
|
2636
|
-
descTableHtml +=
|
|
2640
|
+
descTableHtml += "<tr>";
|
|
2637
2641
|
if (descLabelY != null) {
|
|
2638
|
-
descTableHtml +=
|
|
2642
|
+
descTableHtml += "<td></td>";
|
|
2639
2643
|
}
|
|
2640
2644
|
if (descTickY != null) {
|
|
2641
|
-
descTableHtml +=
|
|
2645
|
+
descTableHtml += "<td></td>";
|
|
2642
2646
|
}
|
|
2643
2647
|
for (let i = 0; i < descNumCols; i++) {
|
|
2644
2648
|
descTableHtml += `<th scope="col">${descTickX[i]}</th>`;
|
|
2645
2649
|
}
|
|
2646
|
-
descTableHtml +=
|
|
2650
|
+
descTableHtml += "</tr>";
|
|
2647
2651
|
}
|
|
2648
|
-
descTableHtml +=
|
|
2652
|
+
descTableHtml += "</thead>";
|
|
2649
2653
|
}
|
|
2650
2654
|
|
|
2651
2655
|
// body rows
|
|
2652
2656
|
if (descNumRows > 0) {
|
|
2653
|
-
descTableHtml +=
|
|
2657
|
+
descTableHtml += "<tbody>";
|
|
2654
2658
|
for (let i = 0; i < descNumRows; i++) {
|
|
2655
|
-
descTableHtml +=
|
|
2659
|
+
descTableHtml += "<tr>";
|
|
2656
2660
|
if (descLabelY != null && i == 0) {
|
|
2657
2661
|
descTableHtml += `<th scope="row" rowspan="${descNumRows}">${descLabelY}</th>`;
|
|
2658
2662
|
}
|
|
@@ -2662,19 +2666,19 @@ class Description {
|
|
|
2662
2666
|
for (let j = 0; j < descNumCols; j++) {
|
|
2663
2667
|
descTableHtml += `<td>${descData[i][j]}</td>`;
|
|
2664
2668
|
}
|
|
2665
|
-
descTableHtml +=
|
|
2669
|
+
descTableHtml += "</tr>";
|
|
2666
2670
|
}
|
|
2667
|
-
descTableHtml +=
|
|
2671
|
+
descTableHtml += "</tbody>";
|
|
2668
2672
|
}
|
|
2669
2673
|
|
|
2670
|
-
descTableHtml +=
|
|
2674
|
+
descTableHtml += "</table>";
|
|
2671
2675
|
}
|
|
2672
2676
|
|
|
2673
2677
|
// bar: don't need colspan or rowspan stuff, put legendX and Y as headers
|
|
2674
2678
|
|
|
2675
|
-
document.getElementById(
|
|
2676
|
-
document.getElementById(
|
|
2677
|
-
document.getElementById(
|
|
2679
|
+
document.getElementById("desc_title").innerHTML = descType + " description";
|
|
2680
|
+
document.getElementById("desc_content").innerHTML = descHtml;
|
|
2681
|
+
document.getElementById("desc_table").innerHTML = descTableHtml;
|
|
2678
2682
|
}
|
|
2679
2683
|
}
|
|
2680
2684
|
|
|
@@ -2744,11 +2748,11 @@ class Tracker {
|
|
|
2744
2748
|
* Downloads the tracker data as a JSON file.
|
|
2745
2749
|
*/
|
|
2746
2750
|
DownloadTrackerData() {
|
|
2747
|
-
let link = document.createElement(
|
|
2751
|
+
let link = document.createElement("a");
|
|
2748
2752
|
let data = this.GetTrackerData();
|
|
2749
|
-
let fileStr = new Blob([JSON.stringify(data)], { type:
|
|
2753
|
+
let fileStr = new Blob([JSON.stringify(data)], { type: "text/plain" });
|
|
2750
2754
|
link.href = URL.createObjectURL(fileStr);
|
|
2751
|
-
link.download =
|
|
2755
|
+
link.download = "tracking.json";
|
|
2752
2756
|
link.click();
|
|
2753
2757
|
}
|
|
2754
2758
|
|
|
@@ -2777,7 +2781,7 @@ class Tracker {
|
|
|
2777
2781
|
this.data = null;
|
|
2778
2782
|
|
|
2779
2783
|
if (constants.debugLevel > 0) {
|
|
2780
|
-
console.log(
|
|
2784
|
+
console.log("tracking data cleared");
|
|
2781
2785
|
}
|
|
2782
2786
|
|
|
2783
2787
|
this.DataSetup();
|
|
@@ -2785,12 +2789,12 @@ class Tracker {
|
|
|
2785
2789
|
|
|
2786
2790
|
SaveSettings() {
|
|
2787
2791
|
// fetch all settings, push to data.settings
|
|
2788
|
-
let settings = JSON.parse(localStorage.getItem(
|
|
2792
|
+
let settings = JSON.parse(localStorage.getItem("settings_data"));
|
|
2789
2793
|
if (settings) {
|
|
2790
2794
|
// don't store their auth keys
|
|
2791
|
-
settings.openAIAuthKey =
|
|
2792
|
-
settings.geminiAuthKey =
|
|
2793
|
-
this.SetData(
|
|
2795
|
+
settings.openAIAuthKey = "hidden";
|
|
2796
|
+
settings.geminiAuthKey = "hidden";
|
|
2797
|
+
this.SetData("settings", settings);
|
|
2794
2798
|
}
|
|
2795
2799
|
}
|
|
2796
2800
|
|
|
@@ -2884,7 +2888,7 @@ class Tracker {
|
|
|
2884
2888
|
}
|
|
2885
2889
|
if (!this.isUndefinedOrNull(constants.infoDiv.innerHTML)) {
|
|
2886
2890
|
let textDisplay = Object.assign(constants.infoDiv.innerHTML);
|
|
2887
|
-
textDisplay = textDisplay.replaceAll(/<[^>]*>?/gm,
|
|
2891
|
+
textDisplay = textDisplay.replaceAll(/<[^>]*>?/gm, "");
|
|
2888
2892
|
eventToLog.text_display = textDisplay;
|
|
2889
2893
|
}
|
|
2890
2894
|
if (!this.isUndefinedOrNull(location.href)) {
|
|
@@ -2892,13 +2896,13 @@ class Tracker {
|
|
|
2892
2896
|
}
|
|
2893
2897
|
|
|
2894
2898
|
// chart specific values
|
|
2895
|
-
let x_tickmark =
|
|
2896
|
-
let y_tickmark =
|
|
2897
|
-
let x_label =
|
|
2898
|
-
let y_label =
|
|
2899
|
-
let value =
|
|
2900
|
-
let fill_value =
|
|
2901
|
-
if (constants.chartType ==
|
|
2899
|
+
let x_tickmark = "";
|
|
2900
|
+
let y_tickmark = "";
|
|
2901
|
+
let x_label = "";
|
|
2902
|
+
let y_label = "";
|
|
2903
|
+
let value = "";
|
|
2904
|
+
let fill_value = "";
|
|
2905
|
+
if (constants.chartType == "bar") {
|
|
2902
2906
|
if (!this.isUndefinedOrNull(plot.columnLabels[position.x])) {
|
|
2903
2907
|
x_tickmark = plot.columnLabels[position.x];
|
|
2904
2908
|
}
|
|
@@ -2911,7 +2915,7 @@ class Tracker {
|
|
|
2911
2915
|
if (!this.isUndefinedOrNull(plot.plotData[position.x])) {
|
|
2912
2916
|
value = plot.plotData[position.x];
|
|
2913
2917
|
}
|
|
2914
|
-
} else if (constants.chartType ==
|
|
2918
|
+
} else if (constants.chartType == "heat") {
|
|
2915
2919
|
if (!this.isUndefinedOrNull(plot.x_labels[position.x])) {
|
|
2916
2920
|
x_tickmark = plot.x_labels[position.x].trim();
|
|
2917
2921
|
}
|
|
@@ -2932,11 +2936,11 @@ class Tracker {
|
|
|
2932
2936
|
if (!this.isUndefinedOrNull(plot.group_labels[2])) {
|
|
2933
2937
|
fill_value = plot.group_labels[2];
|
|
2934
2938
|
}
|
|
2935
|
-
} else if (constants.chartType ==
|
|
2939
|
+
} else if (constants.chartType == "box") {
|
|
2936
2940
|
let plotPos =
|
|
2937
|
-
constants.plotOrientation ==
|
|
2941
|
+
constants.plotOrientation == "vert" ? position.x : position.y;
|
|
2938
2942
|
let sectionPos =
|
|
2939
|
-
constants.plotOrientation ==
|
|
2943
|
+
constants.plotOrientation == "vert" ? position.y : position.x;
|
|
2940
2944
|
let sectionLabel = plot.sections[sectionPos];
|
|
2941
2945
|
|
|
2942
2946
|
if (!this.isUndefinedOrNull(plot.x_group_label)) {
|
|
@@ -2945,7 +2949,7 @@ class Tracker {
|
|
|
2945
2949
|
if (!this.isUndefinedOrNull(plot.y_group_label)) {
|
|
2946
2950
|
y_label = plot.y_group_label;
|
|
2947
2951
|
}
|
|
2948
|
-
if (constants.plotOrientation ==
|
|
2952
|
+
if (constants.plotOrientation == "vert") {
|
|
2949
2953
|
if (plotPos > -1 && sectionPos > -1) {
|
|
2950
2954
|
if (!this.isUndefinedOrNull(sectionLabel)) {
|
|
2951
2955
|
y_tickmark = sectionLabel;
|
|
@@ -2970,7 +2974,7 @@ class Tracker {
|
|
|
2970
2974
|
}
|
|
2971
2975
|
}
|
|
2972
2976
|
}
|
|
2973
|
-
} else if (constants.chartType ==
|
|
2977
|
+
} else if (constants.chartType == "point") {
|
|
2974
2978
|
if (!this.isUndefinedOrNull(plot.x_group_label)) {
|
|
2975
2979
|
x_label = plot.x_group_label;
|
|
2976
2980
|
}
|
|
@@ -2997,13 +3001,13 @@ class Tracker {
|
|
|
2997
3001
|
|
|
2998
3002
|
//console.log("x_tickmark: '", x_tickmark, "', y_tickmark: '", y_tickmark, "', x_label: '", x_label, "', y_label: '", y_label, "', value: '", value, "', fill_value: '", fill_value);
|
|
2999
3003
|
|
|
3000
|
-
this.SetData(
|
|
3004
|
+
this.SetData("events", eventToLog);
|
|
3001
3005
|
//console.log('logged an event');
|
|
3002
3006
|
}
|
|
3003
3007
|
|
|
3004
3008
|
SetData(key, value) {
|
|
3005
3009
|
let data = this.GetTrackerData();
|
|
3006
|
-
let arrayKeys = [
|
|
3010
|
+
let arrayKeys = ["events", "ChatHistory", "settings"];
|
|
3007
3011
|
if (!arrayKeys.includes(key)) {
|
|
3008
3012
|
data[key] = value;
|
|
3009
3013
|
} else {
|
|
@@ -3044,20 +3048,20 @@ class Review {
|
|
|
3044
3048
|
// true means on or show
|
|
3045
3049
|
if (onoff) {
|
|
3046
3050
|
constants.reviewSaveSpot = document.activeElement;
|
|
3047
|
-
constants.review_container.classList.remove(
|
|
3051
|
+
constants.review_container.classList.remove("hidden");
|
|
3048
3052
|
constants.reviewSaveBrailleMode = constants.brailleMode;
|
|
3049
3053
|
constants.review.focus();
|
|
3050
3054
|
|
|
3051
|
-
display.announceText(
|
|
3055
|
+
display.announceText("Review on");
|
|
3052
3056
|
} else {
|
|
3053
|
-
constants.review_container.classList.add(
|
|
3054
|
-
if (constants.reviewSaveBrailleMode ==
|
|
3057
|
+
constants.review_container.classList.add("hidden");
|
|
3058
|
+
if (constants.reviewSaveBrailleMode == "on") {
|
|
3055
3059
|
// we have to turn braille mode back on
|
|
3056
|
-
display.toggleBrailleMode(
|
|
3060
|
+
display.toggleBrailleMode("on");
|
|
3057
3061
|
} else {
|
|
3058
3062
|
constants.reviewSaveSpot.focus();
|
|
3059
3063
|
}
|
|
3060
|
-
display.announceText(
|
|
3064
|
+
display.announceText("Review off");
|
|
3061
3065
|
}
|
|
3062
3066
|
}
|
|
3063
3067
|
}
|
|
@@ -3074,7 +3078,7 @@ class LogError {
|
|
|
3074
3078
|
* @param {string} a - The absent element to log.
|
|
3075
3079
|
*/
|
|
3076
3080
|
LogAbsentElement(a) {
|
|
3077
|
-
console.log(a,
|
|
3081
|
+
console.log(a, "not found. Visual highlighting is turned off.");
|
|
3078
3082
|
}
|
|
3079
3083
|
|
|
3080
3084
|
/**
|
|
@@ -3082,7 +3086,7 @@ class LogError {
|
|
|
3082
3086
|
* @param {string} a - The critical element to log.
|
|
3083
3087
|
*/
|
|
3084
3088
|
LogCriticalElement(a) {
|
|
3085
|
-
consolelog(a,
|
|
3089
|
+
consolelog(a, "is critical. MAIDR unable to run");
|
|
3086
3090
|
}
|
|
3087
3091
|
|
|
3088
3092
|
/**
|
|
@@ -3093,9 +3097,9 @@ class LogError {
|
|
|
3093
3097
|
LogDifferentLengths(a, b) {
|
|
3094
3098
|
console.log(
|
|
3095
3099
|
a,
|
|
3096
|
-
|
|
3100
|
+
"and",
|
|
3097
3101
|
b,
|
|
3098
|
-
|
|
3102
|
+
"do not have the same length. Visual highlighting is turned off."
|
|
3099
3103
|
);
|
|
3100
3104
|
}
|
|
3101
3105
|
|
|
@@ -3106,11 +3110,11 @@ class LogError {
|
|
|
3106
3110
|
*/
|
|
3107
3111
|
LogTooManyElements(a, b) {
|
|
3108
3112
|
console.log(
|
|
3109
|
-
|
|
3113
|
+
"Too many",
|
|
3110
3114
|
a,
|
|
3111
|
-
|
|
3115
|
+
"elements. Only the first",
|
|
3112
3116
|
b,
|
|
3113
|
-
|
|
3117
|
+
"will be highlighted."
|
|
3114
3118
|
);
|
|
3115
3119
|
}
|
|
3116
3120
|
|
|
@@ -3119,7 +3123,7 @@ class LogError {
|
|
|
3119
3123
|
* @param {*} a - The parameter that is not an array.
|
|
3120
3124
|
*/
|
|
3121
3125
|
LogNotArray(a) {
|
|
3122
|
-
console.log(a,
|
|
3126
|
+
console.log(a, "is not an array. Visual highlighting is turned off.");
|
|
3123
3127
|
}
|
|
3124
3128
|
}
|
|
3125
3129
|
|
|
@@ -11201,10 +11205,18 @@ function InitMaidr(thisMaidr) {
|
|
|
11201
11205
|
// actually do eventlisteners for all events
|
|
11202
11206
|
this.SetEvents();
|
|
11203
11207
|
|
|
11208
|
+
// Set img role for chart
|
|
11209
|
+
constants.chart.setAttribute('role', 'img');
|
|
11210
|
+
|
|
11204
11211
|
// once everything is set up, announce the chart name (or title as a backup) to the user
|
|
11205
|
-
setTimeout(function () {
|
|
11206
|
-
|
|
11207
|
-
|
|
11212
|
+
// setTimeout(function () {
|
|
11213
|
+
if ('name' in singleMaidr) {
|
|
11214
|
+
|
|
11215
|
+
// Add the aria-label and title attributes to the chart
|
|
11216
|
+
constants.chart.setAttribute('aria-label', announceText);
|
|
11217
|
+
constants.chart.setAttribute('title', announceText);
|
|
11218
|
+
|
|
11219
|
+
// display.announceText(singleMaidr.name);
|
|
11208
11220
|
} else if (
|
|
11209
11221
|
'title' in singleMaidr ||
|
|
11210
11222
|
('labels' in singleMaidr && 'title' in singleMaidr.labels)
|
|
@@ -11232,10 +11244,16 @@ function InitMaidr(thisMaidr) {
|
|
|
11232
11244
|
isMultiLayered ? multiLayerInstruction : ' '
|
|
11233
11245
|
}Toggle B for Braille, T for Text, S for Sonification, and R for Review mode. Use H for Help.`;
|
|
11234
11246
|
|
|
11247
|
+
// Add the aria-label and title attributes to the chart
|
|
11248
|
+
constants.chart.setAttribute('aria-label', announceText);
|
|
11249
|
+
constants.chart.setAttribute('title', announceText);
|
|
11250
|
+
|
|
11251
|
+
|
|
11252
|
+
|
|
11235
11253
|
// Display the announcement text
|
|
11236
|
-
display.announceText(announceText);
|
|
11254
|
+
// display.announceText(announceText);
|
|
11237
11255
|
}
|
|
11238
|
-
}, 100);
|
|
11256
|
+
// }, 100);
|
|
11239
11257
|
}
|
|
11240
11258
|
}
|
|
11241
11259
|
|