maidr 2.24.0 → 2.25.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/dist/maidr.js CHANGED
@@ -810,6 +810,51 @@ class Constants {
810
810
  }
811
811
  return styleString;
812
812
  }
813
+ /**
814
+ * Converts the active chart to a jpg image.
815
+ * @id {string} - The html ID of the chart to convert.
816
+ */
817
+ async ConvertSVGtoJPG(id, model) {
818
+ let svgElement = document.getElementById(id);
819
+ return new Promise((resolve, reject) => {
820
+ var canvas = document.createElement('canvas');
821
+ var ctx = canvas.getContext('2d');
822
+
823
+ var svgData = new XMLSerializer().serializeToString(svgElement);
824
+ if (!svgData.startsWith('<svg xmlns')) {
825
+ svgData = `<svg xmlns="http://www.w3.org/2000/svg" ${svgData.slice(4)}`;
826
+ }
827
+
828
+ var svgSize =
829
+ svgElement.viewBox.baseVal || svgElement.getBoundingClientRect();
830
+ canvas.width = svgSize.width;
831
+ canvas.height = svgSize.height;
832
+
833
+ var img = new Image();
834
+ img.onload = function () {
835
+ ctx.drawImage(img, 0, 0, svgSize.width, svgSize.height);
836
+ var jpegData = canvas.toDataURL('image/jpeg', 0.9); // 0.9 is the quality parameter
837
+ if (model == 'openai') {
838
+ resolve(jpegData);
839
+ } else if (model == 'gemini' || model == 'claude') {
840
+ let base64Data = jpegData.split(',')[1];
841
+ resolve(base64Data);
842
+ //resolve(jpegData);
843
+ }
844
+ URL.revokeObjectURL(url);
845
+ };
846
+
847
+ img.onerror = function () {
848
+ reject(new Error('Error loading SVG'));
849
+ };
850
+
851
+ var svgBlob = new Blob([svgData], {
852
+ type: 'image/svg+xml;charset=utf-8',
853
+ });
854
+ var url = URL.createObjectURL(svgBlob);
855
+ img.src = url;
856
+ });
857
+ }
813
858
  }
814
859
 
815
860
  /**
@@ -1962,6 +2007,7 @@ class ChatLLM {
1962
2007
  */
1963
2008
  CopyChatHistory(e) {
1964
2009
  let text = '';
2010
+ let notificationText = '';
1965
2011
  if (typeof e == 'undefined') {
1966
2012
  // check for passthrough
1967
2013
  // get html of the full chat history
@@ -1971,9 +2017,11 @@ class ChatLLM {
1971
2017
  if (e.target.id == 'chatLLM_copy_all') {
1972
2018
  // get html of the full chat history
1973
2019
  text = document.getElementById('chatLLM_chat_history').innerHTML;
2020
+ notificationText = 'Copied All.';
1974
2021
  } else if (e.target.classList.contains('chatLLM_message_copy_button')) {
1975
2022
  // get the text of the element before the button
1976
2023
  text = e.target.closest('p').previousElementSibling.innerHTML;
2024
+ notificationText = 'Copied.';
1977
2025
  }
1978
2026
  } else if (e.type == 'keyup') {
1979
2027
  // check for alt shift c or ctrl shift c
@@ -1985,6 +2033,7 @@ class ChatLLM {
1985
2033
  );
1986
2034
  if (elem) {
1987
2035
  text = elem.innerHTML;
2036
+ notificationText = 'Copied.';
1988
2037
  }
1989
2038
  } else if (
1990
2039
  e.key == 'A' &&
@@ -1994,6 +2043,7 @@ class ChatLLM {
1994
2043
  e.preventDefault();
1995
2044
  // get html of the full chat history
1996
2045
  text = document.getElementById('chatLLM_chat_history').innerHTML;
2046
+ notificationText = 'Copied All.';
1997
2047
  }
1998
2048
  }
1999
2049
 
@@ -2011,6 +2061,12 @@ class ChatLLM {
2011
2061
  // this messes up a bit with spacing, so kill more than 2 newlines in a row
2012
2062
  markdown = markdown.replace(/\n{3,}/g, '\n\n');
2013
2063
 
2064
+ if (notificationText != '') {
2065
+ if (display) {
2066
+ display.announceText(notificationText);
2067
+ }
2068
+ }
2069
+
2014
2070
  try {
2015
2071
  navigator.clipboard.writeText(markdown); // note: this fails if you're on the inspector. That's fine as it'll never happen to real users
2016
2072
  } catch (err) {
@@ -2103,7 +2159,7 @@ class ChatLLM {
2103
2159
 
2104
2160
  if ('openai' in constants.LLMModels) {
2105
2161
  if (firsttime) {
2106
- img = await this.ConvertSVGtoJPG(singleMaidr.id, 'openai');
2162
+ img = await constants.ConvertSVGtoJPG(singleMaidr.id, 'openai');
2107
2163
  }
2108
2164
  if (constants.emailAuthKey) {
2109
2165
  chatLLM.OpenAIPromptAPI(text, img);
@@ -2113,7 +2169,7 @@ class ChatLLM {
2113
2169
  }
2114
2170
  if ('gemini' in constants.LLMModels) {
2115
2171
  if (firsttime) {
2116
- img = await this.ConvertSVGtoJPG(singleMaidr.id, 'gemini');
2172
+ img = await constants.ConvertSVGtoJPG(singleMaidr.id, 'gemini');
2117
2173
  }
2118
2174
  if (constants.emailAuthKey) {
2119
2175
  chatLLM.GeminiPromptAPI(text, img);
@@ -2124,7 +2180,7 @@ class ChatLLM {
2124
2180
 
2125
2181
  if ('claude' in constants.LLMModels) {
2126
2182
  if (firsttime) {
2127
- img = await this.ConvertSVGtoJPG(singleMaidr.id, 'claude');
2183
+ img = await constants.ConvertSVGtoJPG(singleMaidr.id, 'claude');
2128
2184
  }
2129
2185
  if (constants.emailAuthKey) {
2130
2186
  chatLLM.ClaudePromptAPI(text, img);
@@ -2271,8 +2327,7 @@ class ChatLLM {
2271
2327
  if (data.text()) {
2272
2328
  text = data.text();
2273
2329
  chatLLM.DisplayChatMessage(LLMName, text);
2274
- }
2275
- if (data.error) {
2330
+ } else if (data.error) {
2276
2331
  chatLLM.DisplayChatMessage(LLMName, 'Error processing request.', true);
2277
2332
  chatLLM.WaitingSound(false);
2278
2333
  }
@@ -2281,7 +2336,10 @@ class ChatLLM {
2281
2336
  // if we're tracking, log the data
2282
2337
  if (constants.canTrack) {
2283
2338
  let chatHist = chatLLM.CopyChatHistory();
2284
- tracker.SetData('ChatHistory', chatHist);
2339
+ let data = {};
2340
+ data.chatHistory = chatHist;
2341
+ if (constants.emailAuthKey) data.username = constants.emailAuthKey;
2342
+ tracker.SetData('ChatHistory', data);
2285
2343
  }
2286
2344
  }
2287
2345
 
@@ -2818,52 +2876,6 @@ class ChatLLM {
2818
2876
  }
2819
2877
  }
2820
2878
 
2821
- /**
2822
- * Converts the active chart to a jpg image.
2823
- * @id {string} - The html ID of the chart to convert.
2824
- */
2825
- async ConvertSVGtoJPG(id, model) {
2826
- let svgElement = document.getElementById(id);
2827
- return new Promise((resolve, reject) => {
2828
- var canvas = document.createElement('canvas');
2829
- var ctx = canvas.getContext('2d');
2830
-
2831
- var svgData = new XMLSerializer().serializeToString(svgElement);
2832
- if (!svgData.startsWith('<svg xmlns')) {
2833
- svgData = `<svg xmlns="http://www.w3.org/2000/svg" ${svgData.slice(4)}`;
2834
- }
2835
-
2836
- var svgSize =
2837
- svgElement.viewBox.baseVal || svgElement.getBoundingClientRect();
2838
- canvas.width = svgSize.width;
2839
- canvas.height = svgSize.height;
2840
-
2841
- var img = new Image();
2842
- img.onload = function () {
2843
- ctx.drawImage(img, 0, 0, svgSize.width, svgSize.height);
2844
- var jpegData = canvas.toDataURL('image/jpeg', 0.9); // 0.9 is the quality parameter
2845
- if (model == 'openai') {
2846
- resolve(jpegData);
2847
- } else if (model == 'gemini' || model == 'claude') {
2848
- let base64Data = jpegData.split(',')[1];
2849
- resolve(base64Data);
2850
- //resolve(jpegData);
2851
- }
2852
- URL.revokeObjectURL(url);
2853
- };
2854
-
2855
- img.onerror = function () {
2856
- reject(new Error('Error loading SVG'));
2857
- };
2858
-
2859
- var svgBlob = new Blob([svgData], {
2860
- type: 'image/svg+xml;charset=utf-8',
2861
- });
2862
- var url = URL.createObjectURL(svgBlob);
2863
- img.src = url;
2864
- });
2865
- }
2866
-
2867
2879
  /**
2868
2880
  * GetDefaultPrompt is an asynchronous function that generates a prompt for describing a chart to a blind person.
2869
2881
  * It converts the chart to a JPG image using the ConvertSVGtoJPG method and then submits the prompt to the chatLLM function.
@@ -3205,7 +3217,7 @@ class Tracker {
3205
3217
  /**
3206
3218
  * Sets up the tracker data by checking if previous data exists and creating new data if it doesn't.
3207
3219
  */
3208
- DataSetup() {
3220
+ async DataSetup() {
3209
3221
  let prevData = this.GetTrackerData();
3210
3222
  if (!this.isLocal || !prevData) {
3211
3223
  let data = {};
@@ -3214,6 +3226,10 @@ class Tracker {
3214
3226
  data.language = Object.assign(navigator.language);
3215
3227
  data.platform = Object.assign(navigator.platform);
3216
3228
  data.geolocation = Object.assign(navigator.geolocation);
3229
+ data.imageBase64 = await constants.ConvertSVGtoJPG(
3230
+ singleMaidr.id,
3231
+ 'gemini'
3232
+ );
3217
3233
  data.log_type = 'system_data';
3218
3234
  data.events = [];
3219
3235
  data.settings = [];
@@ -3659,9 +3675,20 @@ class LogError {
3659
3675
  */
3660
3676
  class Audio {
3661
3677
  constructor() {
3662
- this.AudioContext = window['AudioContext'] || window['webkitAudioContext'];
3663
- this.audioContext = new AudioContext();
3664
- this.compressor = this.compressorSetup(this.audioContext);
3678
+ this.fixAudioContext();
3679
+ }
3680
+
3681
+ fixAudioContext() {
3682
+ if (!this.audioContext) {
3683
+ this.AudioContext =
3684
+ window['AudioContext'] || window['webkitAudioContext'];
3685
+ this.audioContext = new AudioContext();
3686
+ this.compressor = this.compressorSetup(this.audioContext);
3687
+ } else if (this.audioContext.state === 'suspended') {
3688
+ this.audioContext.resume().then(() => {
3689
+ console.log('AudioContext resumed');
3690
+ });
3691
+ }
3665
3692
  }
3666
3693
 
3667
3694
  /**
@@ -4408,6 +4435,10 @@ class Display {
4408
4435
  this.announceText(resources.GetString('son_off'));
4409
4436
  }
4410
4437
  }
4438
+
4439
+ if (constants.sonifMode != 'off') {
4440
+ audio.fixAudioContext();
4441
+ }
4411
4442
  }
4412
4443
 
4413
4444
  /**
@@ -9019,15 +9050,19 @@ class Control {
9019
9050
  // we lock the selection while we're changing stuff so it doesn't loop
9020
9051
  constants.lockSelection = true;
9021
9052
 
9022
- // exception: don't let users click the seperator char
9053
+ // exception: don't let users click the seperator char, so make them click just before
9023
9054
  let seperatorPositions = constants.brailleInput.value
9024
9055
  .split('')
9025
9056
  .reduce((positions, char, index) => {
9026
9057
  if (char === '⠳') positions.push(index);
9027
9058
  return positions;
9028
9059
  }, []);
9060
+ console.log('seperatorPositions', seperatorPositions);
9061
+ console.log('pos', pos);
9029
9062
  if (seperatorPositions.includes(pos)) {
9030
- return;
9063
+ if (pos > 0) {
9064
+ pos += -1;
9065
+ }
9031
9066
  }
9032
9067
 
9033
9068
  // we're using braille cursor, update the selection from what was clicked