Fossil SCM
Moved chat audio notification files to src/alerts, per chatroom discussion. Chat audio is now configurable using a selection of builtin WAV files and audio files stored in /uv/alert-sounds/*.XYZ (==ogg, wav, mp3). The addition of a selection list means that closing the chat settings popup now requires tapping either a popup entry or the settings button - tapping in the page body won't do it because that handling collides with the selection list event handling.
Commit
4c34053c587cb375c0c74c8f34225b7fa64014b0fa67d72c8f3b2165e3ed3631
Parent
be93625468b03cd…
16 files changed
+31
+56
-17
+12
+3
-1
+1
-66
+3
-1
+6
-2
+24
~
src/alerts/b-flat.wav
~
src/alerts/g-minor-triad.wav
~
src/alerts/mkwav.c
~
src/alerts/plunk.wav
~
src/chat.c
~
src/chat.js
~
src/default.css
~
src/main.mk
~
src/makemake.tcl
-
src/sounds/b-flat.wav
-
src/sounds/g-minor-triad.wav
-
src/sounds/mkwav.c
-
src/sounds/plunk.wav
~
win/Makefile.mingw
~
win/Makefile.msc
~
www/chat.md
Binary file
Binary file
No diff available
Binary file
+31
| --- src/chat.c | ||
| +++ src/chat.c | ||
| @@ -39,10 +39,40 @@ | ||
| 39 | 39 | ** configuration. |
| 40 | 40 | */ |
| 41 | 41 | #include "config.h" |
| 42 | 42 | #include <assert.h> |
| 43 | 43 | #include "chat.h" |
| 44 | + | |
| 45 | +/* | |
| 46 | +** Outputs JS code to initialize a list of chat alert audio files for | |
| 47 | +** use by the chat front-end client. A handful of builtin files | |
| 48 | +** (from alerts/\*.wav) and all unversioned files matching | |
| 49 | +** alert-sounds/\*.{mp3,ogg,wav} are included. | |
| 50 | +*/ | |
| 51 | +static void chat_emit_alert_list(void){ | |
| 52 | + Stmt q = empty_Stmt; | |
| 53 | + unsigned int i; | |
| 54 | + const char * azBuiltins[] = { | |
| 55 | + "builtin/alerts/plunk.wav", | |
| 56 | + "builtin/alerts/b-flat.wav", | |
| 57 | + "builtin/alerts/g-minor-triad.wav" | |
| 58 | + }; | |
| 59 | + CX("window.fossil.config.chat.alerts = [\n"); | |
| 60 | + for(i=0; i < sizeof(azBuiltins)/sizeof(azBuiltins[0]); ++i){ | |
| 61 | + CX("%s%!j", i ? ", " : "", azBuiltins[i]); | |
| 62 | + } | |
| 63 | + db_prepare(&q, "SELECT 'uv/'||name FROM unversioned " | |
| 64 | + "WHERE content IS NOT NULL " | |
| 65 | + "AND (name LIKE 'alert-sounds/%%.wav' " | |
| 66 | + "OR name LIKE 'alert-sounds/%%.mp3' " | |
| 67 | + "OR name LIKE 'alert-sounds/%%.ogg')"); | |
| 68 | + while(SQLITE_ROW==db_step(&q)){ | |
| 69 | + CX(", %!j", db_column_text(&q, 0)); | |
| 70 | + } | |
| 71 | + db_finalize(&q); | |
| 72 | + CX("\n].sort();\n"); | |
| 73 | +} | |
| 44 | 74 | |
| 45 | 75 | /* Settings that can be used to control chat */ |
| 46 | 76 | /* |
| 47 | 77 | ** SETTING: chat-initial-history width=10 default=50 |
| 48 | 78 | ** |
| @@ -153,10 +183,11 @@ | ||
| 153 | 183 | @ window.fossil.config.chat = { |
| 154 | 184 | @ fromcli: %h(PB("cli")?"true":"false"), |
| 155 | 185 | @ initSize: %d(db_get_int("chat-initial-history",50)), |
| 156 | 186 | @ imagesInline: !!%d(db_get_boolean("chat-inline-images",1)) |
| 157 | 187 | @ }; |
| 188 | + chat_emit_alert_list(); | |
| 158 | 189 | cgi_append_content(builtin_text("chat.js"),-1); |
| 159 | 190 | @ }, false); |
| 160 | 191 | @ </script> |
| 161 | 192 | |
| 162 | 193 | style_finish_page(); |
| 163 | 194 |
| --- src/chat.c | |
| +++ src/chat.c | |
| @@ -39,10 +39,40 @@ | |
| 39 | ** configuration. |
| 40 | */ |
| 41 | #include "config.h" |
| 42 | #include <assert.h> |
| 43 | #include "chat.h" |
| 44 | |
| 45 | /* Settings that can be used to control chat */ |
| 46 | /* |
| 47 | ** SETTING: chat-initial-history width=10 default=50 |
| 48 | ** |
| @@ -153,10 +183,11 @@ | |
| 153 | @ window.fossil.config.chat = { |
| 154 | @ fromcli: %h(PB("cli")?"true":"false"), |
| 155 | @ initSize: %d(db_get_int("chat-initial-history",50)), |
| 156 | @ imagesInline: !!%d(db_get_boolean("chat-inline-images",1)) |
| 157 | @ }; |
| 158 | cgi_append_content(builtin_text("chat.js"),-1); |
| 159 | @ }, false); |
| 160 | @ </script> |
| 161 | |
| 162 | style_finish_page(); |
| 163 |
| --- src/chat.c | |
| +++ src/chat.c | |
| @@ -39,10 +39,40 @@ | |
| 39 | ** configuration. |
| 40 | */ |
| 41 | #include "config.h" |
| 42 | #include <assert.h> |
| 43 | #include "chat.h" |
| 44 | |
| 45 | /* |
| 46 | ** Outputs JS code to initialize a list of chat alert audio files for |
| 47 | ** use by the chat front-end client. A handful of builtin files |
| 48 | ** (from alerts/\*.wav) and all unversioned files matching |
| 49 | ** alert-sounds/\*.{mp3,ogg,wav} are included. |
| 50 | */ |
| 51 | static void chat_emit_alert_list(void){ |
| 52 | Stmt q = empty_Stmt; |
| 53 | unsigned int i; |
| 54 | const char * azBuiltins[] = { |
| 55 | "builtin/alerts/plunk.wav", |
| 56 | "builtin/alerts/b-flat.wav", |
| 57 | "builtin/alerts/g-minor-triad.wav" |
| 58 | }; |
| 59 | CX("window.fossil.config.chat.alerts = [\n"); |
| 60 | for(i=0; i < sizeof(azBuiltins)/sizeof(azBuiltins[0]); ++i){ |
| 61 | CX("%s%!j", i ? ", " : "", azBuiltins[i]); |
| 62 | } |
| 63 | db_prepare(&q, "SELECT 'uv/'||name FROM unversioned " |
| 64 | "WHERE content IS NOT NULL " |
| 65 | "AND (name LIKE 'alert-sounds/%%.wav' " |
| 66 | "OR name LIKE 'alert-sounds/%%.mp3' " |
| 67 | "OR name LIKE 'alert-sounds/%%.ogg')"); |
| 68 | while(SQLITE_ROW==db_step(&q)){ |
| 69 | CX(", %!j", db_column_text(&q, 0)); |
| 70 | } |
| 71 | db_finalize(&q); |
| 72 | CX("\n].sort();\n"); |
| 73 | } |
| 74 | |
| 75 | /* Settings that can be used to control chat */ |
| 76 | /* |
| 77 | ** SETTING: chat-initial-history width=10 default=50 |
| 78 | ** |
| @@ -153,10 +183,11 @@ | |
| 183 | @ window.fossil.config.chat = { |
| 184 | @ fromcli: %h(PB("cli")?"true":"false"), |
| 185 | @ initSize: %d(db_get_int("chat-initial-history",50)), |
| 186 | @ imagesInline: !!%d(db_get_boolean("chat-inline-images",1)) |
| 187 | @ }; |
| 188 | chat_emit_alert_list(); |
| 189 | cgi_append_content(builtin_text("chat.js"),-1); |
| 190 | @ }, false); |
| 191 | @ </script> |
| 192 | |
| 193 | style_finish_page(); |
| 194 |
+56
-17
| --- src/chat.js | ||
| +++ src/chat.js | ||
| @@ -373,20 +373,34 @@ | ||
| 373 | 373 | }, |
| 374 | 374 | /** Plays a new-message notification sound IF the audible-alert |
| 375 | 375 | setting is true, else this is a no-op. Returns this. |
| 376 | 376 | */ |
| 377 | 377 | playNewMessageSound: function f(){ |
| 378 | - if(this.settings.getBool('audible-alert',false)){ | |
| 378 | + if(f.uri){ | |
| 379 | 379 | try{ |
| 380 | - if(!f.audio) f.audio = new Audio(F.rootPath+"chat-alert"); | |
| 381 | - f.audio.currentTime = 0; | |
| 382 | - f.audio.play(); | |
| 380 | + if(!f.audio) f.audio = new Audio(F.rootPath+f.uri); | |
| 381 | + if(f.audio){ | |
| 382 | + f.audio.currentTime = 0; | |
| 383 | + f.audio.play(); | |
| 384 | + } | |
| 383 | 385 | }catch(e){ |
| 384 | 386 | console.error("Audio playblack failed.",e); |
| 385 | 387 | } |
| 386 | 388 | } |
| 387 | 389 | return this; |
| 390 | + }, | |
| 391 | + /** | |
| 392 | + Sets the current new-message audio alert URI (must be a | |
| 393 | + repository-relative path which responds with an audio | |
| 394 | + file). Pass a falsy value to disable audio alerts. Returns | |
| 395 | + this. This setting is persistent. | |
| 396 | + */ | |
| 397 | + setNewMessageSound: function f(uri){ | |
| 398 | + delete this.playNewMessageSound.audio; | |
| 399 | + this.playNewMessageSound.uri = uri; | |
| 400 | + this.settings.set('audible-alert', uri || ''); | |
| 401 | + return this; | |
| 388 | 402 | } |
| 389 | 403 | }; |
| 390 | 404 | cs.e.inputCurrent = cs.e.inputSingle; |
| 391 | 405 | /* Install default settings... */ |
| 392 | 406 | Object.keys(cs.settings.defaults).forEach(function(k){ |
| @@ -933,30 +947,47 @@ | ||
| 933 | 947 | boolValue: ()=>!document.body.classList.contains('my-messages-right'), |
| 934 | 948 | callback: function f(){ |
| 935 | 949 | document.body.classList.toggle('my-messages-right'); |
| 936 | 950 | } |
| 937 | 951 | },{ |
| 938 | - label: "Message home/end buttons", | |
| 939 | - boolValue: ()=>!Chat.e.btnMsgHome.classList.contains('hidden'), | |
| 940 | - callback: ()=>Chat.toggleNavButtons() | |
| 941 | - },{ | |
| 942 | 952 | label: "Images inline", |
| 943 | 953 | boolValue: ()=>Chat.settings.getBool('images-inline'), |
| 944 | 954 | callback: function(){ |
| 945 | 955 | const v = Chat.settings.toggle('images-inline'); |
| 946 | 956 | F.toast.message("Image mode set to "+(v ? "inline" : "hyperlink")+"."); |
| 947 | 957 | } |
| 948 | 958 | },{ |
| 949 | - label: "Audible alerts", | |
| 950 | - boolValue: ()=>Chat.settings.getBool('audible-alert'), | |
| 951 | - callback: function(){ | |
| 952 | - const v = Chat.settings.toggle('audible-alert'); | |
| 953 | - if(v) setTimeout(()=>Chat.playNewMessageSound(), 50); | |
| 954 | - F.toast.message("Audio notifications "+(v ? "enabled" : "disabled")+"."); | |
| 955 | - } | |
| 959 | + label: "Message home/end buttons", | |
| 960 | + boolValue: ()=>!Chat.e.btnMsgHome.classList.contains('hidden'), | |
| 961 | + callback: ()=>Chat.toggleNavButtons() | |
| 956 | 962 | }]; |
| 957 | 963 | |
| 964 | + /** Set up selection list of notification sounds. */ | |
| 965 | + const selectSound = D.addClass(D.select(), 'menu-entry'); | |
| 966 | + D.disable(D.option(selectSound, "0", "Audible alert...")); | |
| 967 | + D.option(selectSound, "", "(no audio)"); | |
| 968 | + F.config.chat.alerts.forEach(function(a){ | |
| 969 | + D.option(selectSound, a); | |
| 970 | + }); | |
| 971 | + if(true===Chat.settings.getBool('audible-alert')){ | |
| 972 | + selectSound.selectedIndex = 2/*first audio file in the list*/; | |
| 973 | + }else{ | |
| 974 | + selectSound.value = Chat.settings.get('audible-alert',''); | |
| 975 | + if(selectSound.selectedIndex<0){ | |
| 976 | + /*Missing file - removed after this setting was applied. Fall back | |
| 977 | + to the first sound in the list. */ | |
| 978 | + selectSound.selectedIndex = 2; | |
| 979 | + } | |
| 980 | + } | |
| 981 | + selectSound.addEventListener('change',function(){ | |
| 982 | + const v = this.selectedIndex>1 ? this.value : ''; | |
| 983 | + Chat.setNewMessageSound(v); | |
| 984 | + F.toast.message("Audio notifications "+(v ? "enabled" : "disabled")+"."); | |
| 985 | + if(v) setTimeout(()=>Chat.playNewMessageSound(), 50); | |
| 986 | + settingsPopup.hide(); | |
| 987 | + }, false); | |
| 988 | + Chat.setNewMessageSound(selectSound.value); | |
| 958 | 989 | /** |
| 959 | 990 | Rebuild the menu each time it's shown so that the toggles can |
| 960 | 991 | show their current values. |
| 961 | 992 | */ |
| 962 | 993 | settingsPopup.options.refresh = function(){ |
| @@ -978,19 +1009,27 @@ | ||
| 978 | 1009 | D.append(line, check); |
| 979 | 1010 | } |
| 980 | 1011 | D.append(settingsPopup.e, line); |
| 981 | 1012 | line.addEventListener('click', callback); |
| 982 | 1013 | }); |
| 1014 | + D.append(settingsPopup.e, selectSound); | |
| 983 | 1015 | }; |
| 984 | - settingsPopup.installHideHandlers(false, true, true) | |
| 1016 | + settingsPopup.installHideHandlers(false, false, true) | |
| 985 | 1017 | /** Reminder: click-to-hide interferes with "?" embedded within |
| 986 | 1018 | the popup, so cannot be used together with those. Enabling |
| 987 | 1019 | this means, however, that tapping the menu button to toggle |
| 988 | 1020 | the menu cannot work because tapping the menu button while the |
| 989 | 1021 | menu is opened will, because of the click-to-hide handler, |
| 990 | 1022 | hide the menu before the button gets an event saying to toggle |
| 991 | - it.*/; | |
| 1023 | + it. | |
| 1024 | + | |
| 1025 | + Reminder: because we need a SELECT element for the audio file | |
| 1026 | + selection (since that list can be arbitrarily long), we have | |
| 1027 | + to disable tap-outside-the-popup-to-close-it via passing false | |
| 1028 | + as the 2nd argument to installHideHandlers(). If we don't, | |
| 1029 | + tapping on the select element is unreliable on desktop | |
| 1030 | + browsers and doesn't seem to work at all on mobile. */; | |
| 992 | 1031 | D.attr(settingsButton, 'role', 'button'); |
| 993 | 1032 | settingsButton.addEventListener('click',function(ev){ |
| 994 | 1033 | //ev.preventDefault(); |
| 995 | 1034 | if(settingsPopup.isShown()) settingsPopup.hide(); |
| 996 | 1035 | else settingsPopup.show(settingsButton); |
| 997 | 1036 |
| --- src/chat.js | |
| +++ src/chat.js | |
| @@ -373,20 +373,34 @@ | |
| 373 | }, |
| 374 | /** Plays a new-message notification sound IF the audible-alert |
| 375 | setting is true, else this is a no-op. Returns this. |
| 376 | */ |
| 377 | playNewMessageSound: function f(){ |
| 378 | if(this.settings.getBool('audible-alert',false)){ |
| 379 | try{ |
| 380 | if(!f.audio) f.audio = new Audio(F.rootPath+"chat-alert"); |
| 381 | f.audio.currentTime = 0; |
| 382 | f.audio.play(); |
| 383 | }catch(e){ |
| 384 | console.error("Audio playblack failed.",e); |
| 385 | } |
| 386 | } |
| 387 | return this; |
| 388 | } |
| 389 | }; |
| 390 | cs.e.inputCurrent = cs.e.inputSingle; |
| 391 | /* Install default settings... */ |
| 392 | Object.keys(cs.settings.defaults).forEach(function(k){ |
| @@ -933,30 +947,47 @@ | |
| 933 | boolValue: ()=>!document.body.classList.contains('my-messages-right'), |
| 934 | callback: function f(){ |
| 935 | document.body.classList.toggle('my-messages-right'); |
| 936 | } |
| 937 | },{ |
| 938 | label: "Message home/end buttons", |
| 939 | boolValue: ()=>!Chat.e.btnMsgHome.classList.contains('hidden'), |
| 940 | callback: ()=>Chat.toggleNavButtons() |
| 941 | },{ |
| 942 | label: "Images inline", |
| 943 | boolValue: ()=>Chat.settings.getBool('images-inline'), |
| 944 | callback: function(){ |
| 945 | const v = Chat.settings.toggle('images-inline'); |
| 946 | F.toast.message("Image mode set to "+(v ? "inline" : "hyperlink")+"."); |
| 947 | } |
| 948 | },{ |
| 949 | label: "Audible alerts", |
| 950 | boolValue: ()=>Chat.settings.getBool('audible-alert'), |
| 951 | callback: function(){ |
| 952 | const v = Chat.settings.toggle('audible-alert'); |
| 953 | if(v) setTimeout(()=>Chat.playNewMessageSound(), 50); |
| 954 | F.toast.message("Audio notifications "+(v ? "enabled" : "disabled")+"."); |
| 955 | } |
| 956 | }]; |
| 957 | |
| 958 | /** |
| 959 | Rebuild the menu each time it's shown so that the toggles can |
| 960 | show their current values. |
| 961 | */ |
| 962 | settingsPopup.options.refresh = function(){ |
| @@ -978,19 +1009,27 @@ | |
| 978 | D.append(line, check); |
| 979 | } |
| 980 | D.append(settingsPopup.e, line); |
| 981 | line.addEventListener('click', callback); |
| 982 | }); |
| 983 | }; |
| 984 | settingsPopup.installHideHandlers(false, true, true) |
| 985 | /** Reminder: click-to-hide interferes with "?" embedded within |
| 986 | the popup, so cannot be used together with those. Enabling |
| 987 | this means, however, that tapping the menu button to toggle |
| 988 | the menu cannot work because tapping the menu button while the |
| 989 | menu is opened will, because of the click-to-hide handler, |
| 990 | hide the menu before the button gets an event saying to toggle |
| 991 | it.*/; |
| 992 | D.attr(settingsButton, 'role', 'button'); |
| 993 | settingsButton.addEventListener('click',function(ev){ |
| 994 | //ev.preventDefault(); |
| 995 | if(settingsPopup.isShown()) settingsPopup.hide(); |
| 996 | else settingsPopup.show(settingsButton); |
| 997 |
| --- src/chat.js | |
| +++ src/chat.js | |
| @@ -373,20 +373,34 @@ | |
| 373 | }, |
| 374 | /** Plays a new-message notification sound IF the audible-alert |
| 375 | setting is true, else this is a no-op. Returns this. |
| 376 | */ |
| 377 | playNewMessageSound: function f(){ |
| 378 | if(f.uri){ |
| 379 | try{ |
| 380 | if(!f.audio) f.audio = new Audio(F.rootPath+f.uri); |
| 381 | if(f.audio){ |
| 382 | f.audio.currentTime = 0; |
| 383 | f.audio.play(); |
| 384 | } |
| 385 | }catch(e){ |
| 386 | console.error("Audio playblack failed.",e); |
| 387 | } |
| 388 | } |
| 389 | return this; |
| 390 | }, |
| 391 | /** |
| 392 | Sets the current new-message audio alert URI (must be a |
| 393 | repository-relative path which responds with an audio |
| 394 | file). Pass a falsy value to disable audio alerts. Returns |
| 395 | this. This setting is persistent. |
| 396 | */ |
| 397 | setNewMessageSound: function f(uri){ |
| 398 | delete this.playNewMessageSound.audio; |
| 399 | this.playNewMessageSound.uri = uri; |
| 400 | this.settings.set('audible-alert', uri || ''); |
| 401 | return this; |
| 402 | } |
| 403 | }; |
| 404 | cs.e.inputCurrent = cs.e.inputSingle; |
| 405 | /* Install default settings... */ |
| 406 | Object.keys(cs.settings.defaults).forEach(function(k){ |
| @@ -933,30 +947,47 @@ | |
| 947 | boolValue: ()=>!document.body.classList.contains('my-messages-right'), |
| 948 | callback: function f(){ |
| 949 | document.body.classList.toggle('my-messages-right'); |
| 950 | } |
| 951 | },{ |
| 952 | label: "Images inline", |
| 953 | boolValue: ()=>Chat.settings.getBool('images-inline'), |
| 954 | callback: function(){ |
| 955 | const v = Chat.settings.toggle('images-inline'); |
| 956 | F.toast.message("Image mode set to "+(v ? "inline" : "hyperlink")+"."); |
| 957 | } |
| 958 | },{ |
| 959 | label: "Message home/end buttons", |
| 960 | boolValue: ()=>!Chat.e.btnMsgHome.classList.contains('hidden'), |
| 961 | callback: ()=>Chat.toggleNavButtons() |
| 962 | }]; |
| 963 | |
| 964 | /** Set up selection list of notification sounds. */ |
| 965 | const selectSound = D.addClass(D.select(), 'menu-entry'); |
| 966 | D.disable(D.option(selectSound, "0", "Audible alert...")); |
| 967 | D.option(selectSound, "", "(no audio)"); |
| 968 | F.config.chat.alerts.forEach(function(a){ |
| 969 | D.option(selectSound, a); |
| 970 | }); |
| 971 | if(true===Chat.settings.getBool('audible-alert')){ |
| 972 | selectSound.selectedIndex = 2/*first audio file in the list*/; |
| 973 | }else{ |
| 974 | selectSound.value = Chat.settings.get('audible-alert',''); |
| 975 | if(selectSound.selectedIndex<0){ |
| 976 | /*Missing file - removed after this setting was applied. Fall back |
| 977 | to the first sound in the list. */ |
| 978 | selectSound.selectedIndex = 2; |
| 979 | } |
| 980 | } |
| 981 | selectSound.addEventListener('change',function(){ |
| 982 | const v = this.selectedIndex>1 ? this.value : ''; |
| 983 | Chat.setNewMessageSound(v); |
| 984 | F.toast.message("Audio notifications "+(v ? "enabled" : "disabled")+"."); |
| 985 | if(v) setTimeout(()=>Chat.playNewMessageSound(), 50); |
| 986 | settingsPopup.hide(); |
| 987 | }, false); |
| 988 | Chat.setNewMessageSound(selectSound.value); |
| 989 | /** |
| 990 | Rebuild the menu each time it's shown so that the toggles can |
| 991 | show their current values. |
| 992 | */ |
| 993 | settingsPopup.options.refresh = function(){ |
| @@ -978,19 +1009,27 @@ | |
| 1009 | D.append(line, check); |
| 1010 | } |
| 1011 | D.append(settingsPopup.e, line); |
| 1012 | line.addEventListener('click', callback); |
| 1013 | }); |
| 1014 | D.append(settingsPopup.e, selectSound); |
| 1015 | }; |
| 1016 | settingsPopup.installHideHandlers(false, false, true) |
| 1017 | /** Reminder: click-to-hide interferes with "?" embedded within |
| 1018 | the popup, so cannot be used together with those. Enabling |
| 1019 | this means, however, that tapping the menu button to toggle |
| 1020 | the menu cannot work because tapping the menu button while the |
| 1021 | menu is opened will, because of the click-to-hide handler, |
| 1022 | hide the menu before the button gets an event saying to toggle |
| 1023 | it. |
| 1024 | |
| 1025 | Reminder: because we need a SELECT element for the audio file |
| 1026 | selection (since that list can be arbitrarily long), we have |
| 1027 | to disable tap-outside-the-popup-to-close-it via passing false |
| 1028 | as the 2nd argument to installHideHandlers(). If we don't, |
| 1029 | tapping on the select element is unreliable on desktop |
| 1030 | browsers and doesn't seem to work at all on mobile. */; |
| 1031 | D.attr(settingsButton, 'role', 'button'); |
| 1032 | settingsButton.addEventListener('click',function(ev){ |
| 1033 | //ev.preventDefault(); |
| 1034 | if(settingsPopup.isShown()) settingsPopup.hide(); |
| 1035 | else settingsPopup.show(settingsButton); |
| 1036 |
+12
| --- src/default.css | ||
| +++ src/default.css | ||
| @@ -1640,10 +1640,22 @@ | ||
| 1640 | 1640 | flex: 1 1 auto/*eliminates dead no-click zones on the right*/; |
| 1641 | 1641 | } |
| 1642 | 1642 | body.chat .chat-settings-popup > span.menu-entry > input[type=checkbox] { |
| 1643 | 1643 | cursor: inherit; |
| 1644 | 1644 | } |
| 1645 | +body.chat .chat-settings-popup > select.menu-entry { | |
| 1646 | + flex: 1 1 auto; | |
| 1647 | + padding: 0; | |
| 1648 | + cursor: pointer; | |
| 1649 | + min-height: 2.5em; | |
| 1650 | + border-radius: 0.25em; | |
| 1651 | +} | |
| 1652 | +body.chat .chat-settings-popup > select.menu-entry > option { | |
| 1653 | + /*Recall that many browsers don't allow styling of OPTION | |
| 1654 | + elements, or allow only very limited styling.*/ | |
| 1655 | +} | |
| 1656 | + | |
| 1645 | 1657 | /** Container for the list of /chat messages. */ |
| 1646 | 1658 | body.chat #chat-messages-wrapper { |
| 1647 | 1659 | overflow: auto; |
| 1648 | 1660 | /*max-height: 800em*//*will be re-calc'd in JS*/; |
| 1649 | 1661 | flex: 2 1 auto; |
| 1650 | 1662 |
| --- src/default.css | |
| +++ src/default.css | |
| @@ -1640,10 +1640,22 @@ | |
| 1640 | flex: 1 1 auto/*eliminates dead no-click zones on the right*/; |
| 1641 | } |
| 1642 | body.chat .chat-settings-popup > span.menu-entry > input[type=checkbox] { |
| 1643 | cursor: inherit; |
| 1644 | } |
| 1645 | /** Container for the list of /chat messages. */ |
| 1646 | body.chat #chat-messages-wrapper { |
| 1647 | overflow: auto; |
| 1648 | /*max-height: 800em*//*will be re-calc'd in JS*/; |
| 1649 | flex: 2 1 auto; |
| 1650 |
| --- src/default.css | |
| +++ src/default.css | |
| @@ -1640,10 +1640,22 @@ | |
| 1640 | flex: 1 1 auto/*eliminates dead no-click zones on the right*/; |
| 1641 | } |
| 1642 | body.chat .chat-settings-popup > span.menu-entry > input[type=checkbox] { |
| 1643 | cursor: inherit; |
| 1644 | } |
| 1645 | body.chat .chat-settings-popup > select.menu-entry { |
| 1646 | flex: 1 1 auto; |
| 1647 | padding: 0; |
| 1648 | cursor: pointer; |
| 1649 | min-height: 2.5em; |
| 1650 | border-radius: 0.25em; |
| 1651 | } |
| 1652 | body.chat .chat-settings-popup > select.menu-entry > option { |
| 1653 | /*Recall that many browsers don't allow styling of OPTION |
| 1654 | elements, or allow only very limited styling.*/ |
| 1655 | } |
| 1656 | |
| 1657 | /** Container for the list of /chat messages. */ |
| 1658 | body.chat #chat-messages-wrapper { |
| 1659 | overflow: auto; |
| 1660 | /*max-height: 800em*//*will be re-calc'd in JS*/; |
| 1661 | flex: 2 1 auto; |
| 1662 |
+3
-1
| --- src/main.mk | ||
| +++ src/main.mk | ||
| @@ -220,10 +220,13 @@ | ||
| 220 | 220 | $(SRCDIR)/../skins/xekri/css.txt \ |
| 221 | 221 | $(SRCDIR)/../skins/xekri/details.txt \ |
| 222 | 222 | $(SRCDIR)/../skins/xekri/footer.txt \ |
| 223 | 223 | $(SRCDIR)/../skins/xekri/header.txt \ |
| 224 | 224 | $(SRCDIR)/accordion.js \ |
| 225 | + $(SRCDIR)/alerts/b-flat.wav \ | |
| 226 | + $(SRCDIR)/alerts/g-minor-triad.wav \ | |
| 227 | + $(SRCDIR)/alerts/plunk.wav \ | |
| 225 | 228 | $(SRCDIR)/chat.js \ |
| 226 | 229 | $(SRCDIR)/ci_edit.js \ |
| 227 | 230 | $(SRCDIR)/copybtn.js \ |
| 228 | 231 | $(SRCDIR)/default.css \ |
| 229 | 232 | $(SRCDIR)/diff.tcl \ |
| @@ -266,11 +269,10 @@ | ||
| 266 | 269 | $(SRCDIR)/sounds/b.wav \ |
| 267 | 270 | $(SRCDIR)/sounds/c.wav \ |
| 268 | 271 | $(SRCDIR)/sounds/d.wav \ |
| 269 | 272 | $(SRCDIR)/sounds/e.wav \ |
| 270 | 273 | $(SRCDIR)/sounds/f.wav \ |
| 271 | - $(SRCDIR)/sounds/plunk.wav \ | |
| 272 | 274 | $(SRCDIR)/style.admin_log.css \ |
| 273 | 275 | $(SRCDIR)/style.fileedit.css \ |
| 274 | 276 | $(SRCDIR)/style.wikiedit.css \ |
| 275 | 277 | $(SRCDIR)/tree.js \ |
| 276 | 278 | $(SRCDIR)/useredit.js \ |
| 277 | 279 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -220,10 +220,13 @@ | |
| 220 | $(SRCDIR)/../skins/xekri/css.txt \ |
| 221 | $(SRCDIR)/../skins/xekri/details.txt \ |
| 222 | $(SRCDIR)/../skins/xekri/footer.txt \ |
| 223 | $(SRCDIR)/../skins/xekri/header.txt \ |
| 224 | $(SRCDIR)/accordion.js \ |
| 225 | $(SRCDIR)/chat.js \ |
| 226 | $(SRCDIR)/ci_edit.js \ |
| 227 | $(SRCDIR)/copybtn.js \ |
| 228 | $(SRCDIR)/default.css \ |
| 229 | $(SRCDIR)/diff.tcl \ |
| @@ -266,11 +269,10 @@ | |
| 266 | $(SRCDIR)/sounds/b.wav \ |
| 267 | $(SRCDIR)/sounds/c.wav \ |
| 268 | $(SRCDIR)/sounds/d.wav \ |
| 269 | $(SRCDIR)/sounds/e.wav \ |
| 270 | $(SRCDIR)/sounds/f.wav \ |
| 271 | $(SRCDIR)/sounds/plunk.wav \ |
| 272 | $(SRCDIR)/style.admin_log.css \ |
| 273 | $(SRCDIR)/style.fileedit.css \ |
| 274 | $(SRCDIR)/style.wikiedit.css \ |
| 275 | $(SRCDIR)/tree.js \ |
| 276 | $(SRCDIR)/useredit.js \ |
| 277 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -220,10 +220,13 @@ | |
| 220 | $(SRCDIR)/../skins/xekri/css.txt \ |
| 221 | $(SRCDIR)/../skins/xekri/details.txt \ |
| 222 | $(SRCDIR)/../skins/xekri/footer.txt \ |
| 223 | $(SRCDIR)/../skins/xekri/header.txt \ |
| 224 | $(SRCDIR)/accordion.js \ |
| 225 | $(SRCDIR)/alerts/b-flat.wav \ |
| 226 | $(SRCDIR)/alerts/g-minor-triad.wav \ |
| 227 | $(SRCDIR)/alerts/plunk.wav \ |
| 228 | $(SRCDIR)/chat.js \ |
| 229 | $(SRCDIR)/ci_edit.js \ |
| 230 | $(SRCDIR)/copybtn.js \ |
| 231 | $(SRCDIR)/default.css \ |
| 232 | $(SRCDIR)/diff.tcl \ |
| @@ -266,11 +269,10 @@ | |
| 269 | $(SRCDIR)/sounds/b.wav \ |
| 270 | $(SRCDIR)/sounds/c.wav \ |
| 271 | $(SRCDIR)/sounds/d.wav \ |
| 272 | $(SRCDIR)/sounds/e.wav \ |
| 273 | $(SRCDIR)/sounds/f.wav \ |
| 274 | $(SRCDIR)/style.admin_log.css \ |
| 275 | $(SRCDIR)/style.fileedit.css \ |
| 276 | $(SRCDIR)/style.wikiedit.css \ |
| 277 | $(SRCDIR)/tree.js \ |
| 278 | $(SRCDIR)/useredit.js \ |
| 279 |
+1
| --- src/makemake.tcl | ||
| +++ src/makemake.tcl | ||
| @@ -185,10 +185,11 @@ | ||
| 185 | 185 | *.js |
| 186 | 186 | default.css |
| 187 | 187 | style.*.css |
| 188 | 188 | ../skins/*/*.txt |
| 189 | 189 | sounds/*.wav |
| 190 | + alerts/*.wav | |
| 190 | 191 | } |
| 191 | 192 | |
| 192 | 193 | # Options used to compile the included SQLite library. |
| 193 | 194 | # |
| 194 | 195 | set SQLITE_OPTIONS { |
| 195 | 196 | |
| 196 | 197 | DELETED src/sounds/b-flat.wav |
| 197 | 198 | DELETED src/sounds/g-minor-triad.wav |
| 198 | 199 | DELETED src/sounds/mkwav.c |
| 199 | 200 | DELETED src/sounds/plunk.wav |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -185,10 +185,11 @@ | |
| 185 | *.js |
| 186 | default.css |
| 187 | style.*.css |
| 188 | ../skins/*/*.txt |
| 189 | sounds/*.wav |
| 190 | } |
| 191 | |
| 192 | # Options used to compile the included SQLite library. |
| 193 | # |
| 194 | set SQLITE_OPTIONS { |
| 195 | |
| 196 | ELETED src/sounds/b-flat.wav |
| 197 | ELETED src/sounds/g-minor-triad.wav |
| 198 | ELETED src/sounds/mkwav.c |
| 199 | ELETED src/sounds/plunk.wav |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -185,10 +185,11 @@ | |
| 185 | *.js |
| 186 | default.css |
| 187 | style.*.css |
| 188 | ../skins/*/*.txt |
| 189 | sounds/*.wav |
| 190 | alerts/*.wav |
| 191 | } |
| 192 | |
| 193 | # Options used to compile the included SQLite library. |
| 194 | # |
| 195 | set SQLITE_OPTIONS { |
| 196 | |
| 197 | ELETED src/sounds/b-flat.wav |
| 198 | ELETED src/sounds/g-minor-triad.wav |
| 199 | ELETED src/sounds/mkwav.c |
| 200 | ELETED src/sounds/plunk.wav |
D
src/sounds/b-flat.wav
Binary file
D
src/sounds/g-minor-triad.wav
Binary file
D
src/sounds/mkwav.c
-66
| --- a/src/sounds/mkwav.c | ||
| +++ b/src/sounds/mkwav.c | ||
| @@ -1,66 +0,0 @@ | ||
| 1 | -/* | |
| 2 | -** This C program was used to generate the "g-minor-triad.wav" file. | |
| 3 | -** A small modification generated the "b-flat.wav" file. | |
| 4 | -** | |
| 5 | -** This code is saved as an historical reference. It is not part | |
| 6 | -** of Fossil. | |
| 7 | -*/ | |
| 8 | -#include <stdio.h> | |
| 9 | -#include <math.h> | |
| 10 | -#include <stdlib.h> | |
| 11 | - | |
| 12 | -/* | |
| 13 | -** Write a four-byte little-endian integer value to out. | |
| 14 | -*/ | |
| 15 | -void write_int4(FILE *out, unsigned int i){ | |
| 16 | - unsigned char z[4]; | |
| 17 | - z[0] = i&0xff; | |
| 18 | - z[1] = (i>>8)&0xff; | |
| 19 | - z[2] = (i>>16)&0xff; | |
| 20 | - z[3] = (i>>24)&0xff; | |
| 21 | - fwrite(z, 4, 1, out); | |
| 22 | -} | |
| 23 | - | |
| 24 | -/* | |
| 25 | -** Write out the WAV file | |
| 26 | -*/ | |
| 27 | -void write_wave( | |
| 28 | - const char *zFilename, /* The file to write */ | |
| 29 | - unsigned int nData, /* Bytes of data */ | |
| 30 | - unsigned char *aData /* 8000 samples/sec, 8 bit samples */ | |
| 31 | -){ | |
| 32 | - const unsigned char aWavFmt[] = { | |
| 33 | - 0x57, 0x41, 0x56, 0x45, /* "WAVE" */ | |
| 34 | - 0x66, 0x6d, 0x74, 0x20, /* "fmt " */ | |
| 35 | - 0x10, 0x00, 0x00, 0x00, /* 16 bytes in the "fmt " section */ | |
| 36 | - 0x01, 0x00, /* FormatTag: WAVE_FORMAT_PCM */ | |
| 37 | - 0x01, 0x00, /* 1 channel */ | |
| 38 | - 0x40, 0x1f, 0x00, 0x00, /* 8000 samples/second */ | |
| 39 | - 0x40, 0x1f, 0x00, 0x00, /* 8000 bytes/second */ | |
| 40 | - 0x01, 0x00, /* Block alignment */ | |
| 41 | - 0x08, 0x00, /* bits/sample */ | |
| 42 | - 0x64, 0x61, 0x74, 0x61, /* "data" */ | |
| 43 | - }; | |
| 44 | - FILE *out = fopen(zFilename,"wb"); | |
| 45 | - if( out==0 ){ | |
| 46 | - fprintf(stderr, "cannot open \"%s\" for writing\n", zFilename); | |
| 47 | - exit(1); | |
| 48 | - } | |
| 49 | - fwrite("RIFF", 4, 1, out); | |
| 50 | - write_int4(out, nData+4+20+8); | |
| 51 | - fwrite(aWavFmt, sizeof(aWavFmt), 1, out); | |
| 52 | - write_int4(out, nData); | |
| 53 | - fwrite(aData, nData, 1, out); | |
| 54 | - fclose(out); | |
| 55 | -} | |
| 56 | - | |
| 57 | -int main(int argc, char **argv){ | |
| 58 | - int i = 0; | |
| 59 | - unsigned char aBuf[800]; | |
| 60 | -# define N sizeof(aBuf) | |
| 61 | -# define pitch1 195.9977*2 /* G */ | |
| 62 | -# define pitch2 233.0819*2 /* B-flat */ | |
| 63 | -# define pitch3 293.6648*2 /* D */ | |
| 64 | - while( i<N ){ | |
| 65 | - double v; | |
| 66 | - v = 33v += 33.0*sin((2*M_PI*p |
| --- a/src/sounds/mkwav.c | |
| +++ b/src/sounds/mkwav.c | |
| @@ -1,66 +0,0 @@ | |
| 1 | /* |
| 2 | ** This C program was used to generate the "g-minor-triad.wav" file. |
| 3 | ** A small modification generated the "b-flat.wav" file. |
| 4 | ** |
| 5 | ** This code is saved as an historical reference. It is not part |
| 6 | ** of Fossil. |
| 7 | */ |
| 8 | #include <stdio.h> |
| 9 | #include <math.h> |
| 10 | #include <stdlib.h> |
| 11 | |
| 12 | /* |
| 13 | ** Write a four-byte little-endian integer value to out. |
| 14 | */ |
| 15 | void write_int4(FILE *out, unsigned int i){ |
| 16 | unsigned char z[4]; |
| 17 | z[0] = i&0xff; |
| 18 | z[1] = (i>>8)&0xff; |
| 19 | z[2] = (i>>16)&0xff; |
| 20 | z[3] = (i>>24)&0xff; |
| 21 | fwrite(z, 4, 1, out); |
| 22 | } |
| 23 | |
| 24 | /* |
| 25 | ** Write out the WAV file |
| 26 | */ |
| 27 | void write_wave( |
| 28 | const char *zFilename, /* The file to write */ |
| 29 | unsigned int nData, /* Bytes of data */ |
| 30 | unsigned char *aData /* 8000 samples/sec, 8 bit samples */ |
| 31 | ){ |
| 32 | const unsigned char aWavFmt[] = { |
| 33 | 0x57, 0x41, 0x56, 0x45, /* "WAVE" */ |
| 34 | 0x66, 0x6d, 0x74, 0x20, /* "fmt " */ |
| 35 | 0x10, 0x00, 0x00, 0x00, /* 16 bytes in the "fmt " section */ |
| 36 | 0x01, 0x00, /* FormatTag: WAVE_FORMAT_PCM */ |
| 37 | 0x01, 0x00, /* 1 channel */ |
| 38 | 0x40, 0x1f, 0x00, 0x00, /* 8000 samples/second */ |
| 39 | 0x40, 0x1f, 0x00, 0x00, /* 8000 bytes/second */ |
| 40 | 0x01, 0x00, /* Block alignment */ |
| 41 | 0x08, 0x00, /* bits/sample */ |
| 42 | 0x64, 0x61, 0x74, 0x61, /* "data" */ |
| 43 | }; |
| 44 | FILE *out = fopen(zFilename,"wb"); |
| 45 | if( out==0 ){ |
| 46 | fprintf(stderr, "cannot open \"%s\" for writing\n", zFilename); |
| 47 | exit(1); |
| 48 | } |
| 49 | fwrite("RIFF", 4, 1, out); |
| 50 | write_int4(out, nData+4+20+8); |
| 51 | fwrite(aWavFmt, sizeof(aWavFmt), 1, out); |
| 52 | write_int4(out, nData); |
| 53 | fwrite(aData, nData, 1, out); |
| 54 | fclose(out); |
| 55 | } |
| 56 | |
| 57 | int main(int argc, char **argv){ |
| 58 | int i = 0; |
| 59 | unsigned char aBuf[800]; |
| 60 | # define N sizeof(aBuf) |
| 61 | # define pitch1 195.9977*2 /* G */ |
| 62 | # define pitch2 233.0819*2 /* B-flat */ |
| 63 | # define pitch3 293.6648*2 /* D */ |
| 64 | while( i<N ){ |
| 65 | double v; |
| 66 | v = 33v += 33.0*sin((2*M_PI*p |
| --- a/src/sounds/mkwav.c | |
| +++ b/src/sounds/mkwav.c | |
| @@ -1,66 +0,0 @@ | |
D
src/sounds/plunk.wav
Binary file
+3
-1
| --- win/Makefile.mingw | ||
| +++ win/Makefile.mingw | ||
| @@ -632,10 +632,13 @@ | ||
| 632 | 632 | $(SRCDIR)/../skins/xekri/css.txt \ |
| 633 | 633 | $(SRCDIR)/../skins/xekri/details.txt \ |
| 634 | 634 | $(SRCDIR)/../skins/xekri/footer.txt \ |
| 635 | 635 | $(SRCDIR)/../skins/xekri/header.txt \ |
| 636 | 636 | $(SRCDIR)/accordion.js \ |
| 637 | + $(SRCDIR)/alerts/b-flat.wav \ | |
| 638 | + $(SRCDIR)/alerts/g-minor-triad.wav \ | |
| 639 | + $(SRCDIR)/alerts/plunk.wav \ | |
| 637 | 640 | $(SRCDIR)/chat.js \ |
| 638 | 641 | $(SRCDIR)/ci_edit.js \ |
| 639 | 642 | $(SRCDIR)/copybtn.js \ |
| 640 | 643 | $(SRCDIR)/default.css \ |
| 641 | 644 | $(SRCDIR)/diff.tcl \ |
| @@ -678,11 +681,10 @@ | ||
| 678 | 681 | $(SRCDIR)/sounds/b.wav \ |
| 679 | 682 | $(SRCDIR)/sounds/c.wav \ |
| 680 | 683 | $(SRCDIR)/sounds/d.wav \ |
| 681 | 684 | $(SRCDIR)/sounds/e.wav \ |
| 682 | 685 | $(SRCDIR)/sounds/f.wav \ |
| 683 | - $(SRCDIR)/sounds/plunk.wav \ | |
| 684 | 686 | $(SRCDIR)/style.admin_log.css \ |
| 685 | 687 | $(SRCDIR)/style.fileedit.css \ |
| 686 | 688 | $(SRCDIR)/style.wikiedit.css \ |
| 687 | 689 | $(SRCDIR)/tree.js \ |
| 688 | 690 | $(SRCDIR)/useredit.js \ |
| 689 | 691 |
| --- win/Makefile.mingw | |
| +++ win/Makefile.mingw | |
| @@ -632,10 +632,13 @@ | |
| 632 | $(SRCDIR)/../skins/xekri/css.txt \ |
| 633 | $(SRCDIR)/../skins/xekri/details.txt \ |
| 634 | $(SRCDIR)/../skins/xekri/footer.txt \ |
| 635 | $(SRCDIR)/../skins/xekri/header.txt \ |
| 636 | $(SRCDIR)/accordion.js \ |
| 637 | $(SRCDIR)/chat.js \ |
| 638 | $(SRCDIR)/ci_edit.js \ |
| 639 | $(SRCDIR)/copybtn.js \ |
| 640 | $(SRCDIR)/default.css \ |
| 641 | $(SRCDIR)/diff.tcl \ |
| @@ -678,11 +681,10 @@ | |
| 678 | $(SRCDIR)/sounds/b.wav \ |
| 679 | $(SRCDIR)/sounds/c.wav \ |
| 680 | $(SRCDIR)/sounds/d.wav \ |
| 681 | $(SRCDIR)/sounds/e.wav \ |
| 682 | $(SRCDIR)/sounds/f.wav \ |
| 683 | $(SRCDIR)/sounds/plunk.wav \ |
| 684 | $(SRCDIR)/style.admin_log.css \ |
| 685 | $(SRCDIR)/style.fileedit.css \ |
| 686 | $(SRCDIR)/style.wikiedit.css \ |
| 687 | $(SRCDIR)/tree.js \ |
| 688 | $(SRCDIR)/useredit.js \ |
| 689 |
| --- win/Makefile.mingw | |
| +++ win/Makefile.mingw | |
| @@ -632,10 +632,13 @@ | |
| 632 | $(SRCDIR)/../skins/xekri/css.txt \ |
| 633 | $(SRCDIR)/../skins/xekri/details.txt \ |
| 634 | $(SRCDIR)/../skins/xekri/footer.txt \ |
| 635 | $(SRCDIR)/../skins/xekri/header.txt \ |
| 636 | $(SRCDIR)/accordion.js \ |
| 637 | $(SRCDIR)/alerts/b-flat.wav \ |
| 638 | $(SRCDIR)/alerts/g-minor-triad.wav \ |
| 639 | $(SRCDIR)/alerts/plunk.wav \ |
| 640 | $(SRCDIR)/chat.js \ |
| 641 | $(SRCDIR)/ci_edit.js \ |
| 642 | $(SRCDIR)/copybtn.js \ |
| 643 | $(SRCDIR)/default.css \ |
| 644 | $(SRCDIR)/diff.tcl \ |
| @@ -678,11 +681,10 @@ | |
| 681 | $(SRCDIR)/sounds/b.wav \ |
| 682 | $(SRCDIR)/sounds/c.wav \ |
| 683 | $(SRCDIR)/sounds/d.wav \ |
| 684 | $(SRCDIR)/sounds/e.wav \ |
| 685 | $(SRCDIR)/sounds/f.wav \ |
| 686 | $(SRCDIR)/style.admin_log.css \ |
| 687 | $(SRCDIR)/style.fileedit.css \ |
| 688 | $(SRCDIR)/style.wikiedit.css \ |
| 689 | $(SRCDIR)/tree.js \ |
| 690 | $(SRCDIR)/useredit.js \ |
| 691 |
+6
-2
| --- win/Makefile.msc | ||
| +++ win/Makefile.msc | ||
| @@ -553,10 +553,13 @@ | ||
| 553 | 553 | "$(SRCDIR)\..\skins\xekri\css.txt" \ |
| 554 | 554 | "$(SRCDIR)\..\skins\xekri\details.txt" \ |
| 555 | 555 | "$(SRCDIR)\..\skins\xekri\footer.txt" \ |
| 556 | 556 | "$(SRCDIR)\..\skins\xekri\header.txt" \ |
| 557 | 557 | "$(SRCDIR)\accordion.js" \ |
| 558 | + "$(SRCDIR)\alerts\b-flat.wav" \ | |
| 559 | + "$(SRCDIR)\alerts\g-minor-triad.wav" \ | |
| 560 | + "$(SRCDIR)\alerts\plunk.wav" \ | |
| 558 | 561 | "$(SRCDIR)\chat.js" \ |
| 559 | 562 | "$(SRCDIR)\ci_edit.js" \ |
| 560 | 563 | "$(SRCDIR)\copybtn.js" \ |
| 561 | 564 | "$(SRCDIR)\default.css" \ |
| 562 | 565 | "$(SRCDIR)\diff.tcl" \ |
| @@ -599,11 +602,10 @@ | ||
| 599 | 602 | "$(SRCDIR)\sounds\b.wav" \ |
| 600 | 603 | "$(SRCDIR)\sounds\c.wav" \ |
| 601 | 604 | "$(SRCDIR)\sounds\d.wav" \ |
| 602 | 605 | "$(SRCDIR)\sounds\e.wav" \ |
| 603 | 606 | "$(SRCDIR)\sounds\f.wav" \ |
| 604 | - "$(SRCDIR)\sounds\plunk.wav" \ | |
| 605 | 607 | "$(SRCDIR)\style.admin_log.css" \ |
| 606 | 608 | "$(SRCDIR)\style.fileedit.css" \ |
| 607 | 609 | "$(SRCDIR)\style.wikiedit.css" \ |
| 608 | 610 | "$(SRCDIR)\tree.js" \ |
| 609 | 611 | "$(SRCDIR)\useredit.js" \ |
| @@ -1163,10 +1165,13 @@ | ||
| 1163 | 1165 | echo "$(SRCDIR)\../skins/xekri/css.txt" >> $@ |
| 1164 | 1166 | echo "$(SRCDIR)\../skins/xekri/details.txt" >> $@ |
| 1165 | 1167 | echo "$(SRCDIR)\../skins/xekri/footer.txt" >> $@ |
| 1166 | 1168 | echo "$(SRCDIR)\../skins/xekri/header.txt" >> $@ |
| 1167 | 1169 | echo "$(SRCDIR)\accordion.js" >> $@ |
| 1170 | + echo "$(SRCDIR)\alerts/b-flat.wav" >> $@ | |
| 1171 | + echo "$(SRCDIR)\alerts/g-minor-triad.wav" >> $@ | |
| 1172 | + echo "$(SRCDIR)\alerts/plunk.wav" >> $@ | |
| 1168 | 1173 | echo "$(SRCDIR)\chat.js" >> $@ |
| 1169 | 1174 | echo "$(SRCDIR)\ci_edit.js" >> $@ |
| 1170 | 1175 | echo "$(SRCDIR)\copybtn.js" >> $@ |
| 1171 | 1176 | echo "$(SRCDIR)\default.css" >> $@ |
| 1172 | 1177 | echo "$(SRCDIR)\diff.tcl" >> $@ |
| @@ -1209,11 +1214,10 @@ | ||
| 1209 | 1214 | echo "$(SRCDIR)\sounds/b.wav" >> $@ |
| 1210 | 1215 | echo "$(SRCDIR)\sounds/c.wav" >> $@ |
| 1211 | 1216 | echo "$(SRCDIR)\sounds/d.wav" >> $@ |
| 1212 | 1217 | echo "$(SRCDIR)\sounds/e.wav" >> $@ |
| 1213 | 1218 | echo "$(SRCDIR)\sounds/f.wav" >> $@ |
| 1214 | - echo "$(SRCDIR)\sounds/plunk.wav" >> $@ | |
| 1215 | 1219 | echo "$(SRCDIR)\style.admin_log.css" >> $@ |
| 1216 | 1220 | echo "$(SRCDIR)\style.fileedit.css" >> $@ |
| 1217 | 1221 | echo "$(SRCDIR)\style.wikiedit.css" >> $@ |
| 1218 | 1222 | echo "$(SRCDIR)\tree.js" >> $@ |
| 1219 | 1223 | echo "$(SRCDIR)\useredit.js" >> $@ |
| 1220 | 1224 |
| --- win/Makefile.msc | |
| +++ win/Makefile.msc | |
| @@ -553,10 +553,13 @@ | |
| 553 | "$(SRCDIR)\..\skins\xekri\css.txt" \ |
| 554 | "$(SRCDIR)\..\skins\xekri\details.txt" \ |
| 555 | "$(SRCDIR)\..\skins\xekri\footer.txt" \ |
| 556 | "$(SRCDIR)\..\skins\xekri\header.txt" \ |
| 557 | "$(SRCDIR)\accordion.js" \ |
| 558 | "$(SRCDIR)\chat.js" \ |
| 559 | "$(SRCDIR)\ci_edit.js" \ |
| 560 | "$(SRCDIR)\copybtn.js" \ |
| 561 | "$(SRCDIR)\default.css" \ |
| 562 | "$(SRCDIR)\diff.tcl" \ |
| @@ -599,11 +602,10 @@ | |
| 599 | "$(SRCDIR)\sounds\b.wav" \ |
| 600 | "$(SRCDIR)\sounds\c.wav" \ |
| 601 | "$(SRCDIR)\sounds\d.wav" \ |
| 602 | "$(SRCDIR)\sounds\e.wav" \ |
| 603 | "$(SRCDIR)\sounds\f.wav" \ |
| 604 | "$(SRCDIR)\sounds\plunk.wav" \ |
| 605 | "$(SRCDIR)\style.admin_log.css" \ |
| 606 | "$(SRCDIR)\style.fileedit.css" \ |
| 607 | "$(SRCDIR)\style.wikiedit.css" \ |
| 608 | "$(SRCDIR)\tree.js" \ |
| 609 | "$(SRCDIR)\useredit.js" \ |
| @@ -1163,10 +1165,13 @@ | |
| 1163 | echo "$(SRCDIR)\../skins/xekri/css.txt" >> $@ |
| 1164 | echo "$(SRCDIR)\../skins/xekri/details.txt" >> $@ |
| 1165 | echo "$(SRCDIR)\../skins/xekri/footer.txt" >> $@ |
| 1166 | echo "$(SRCDIR)\../skins/xekri/header.txt" >> $@ |
| 1167 | echo "$(SRCDIR)\accordion.js" >> $@ |
| 1168 | echo "$(SRCDIR)\chat.js" >> $@ |
| 1169 | echo "$(SRCDIR)\ci_edit.js" >> $@ |
| 1170 | echo "$(SRCDIR)\copybtn.js" >> $@ |
| 1171 | echo "$(SRCDIR)\default.css" >> $@ |
| 1172 | echo "$(SRCDIR)\diff.tcl" >> $@ |
| @@ -1209,11 +1214,10 @@ | |
| 1209 | echo "$(SRCDIR)\sounds/b.wav" >> $@ |
| 1210 | echo "$(SRCDIR)\sounds/c.wav" >> $@ |
| 1211 | echo "$(SRCDIR)\sounds/d.wav" >> $@ |
| 1212 | echo "$(SRCDIR)\sounds/e.wav" >> $@ |
| 1213 | echo "$(SRCDIR)\sounds/f.wav" >> $@ |
| 1214 | echo "$(SRCDIR)\sounds/plunk.wav" >> $@ |
| 1215 | echo "$(SRCDIR)\style.admin_log.css" >> $@ |
| 1216 | echo "$(SRCDIR)\style.fileedit.css" >> $@ |
| 1217 | echo "$(SRCDIR)\style.wikiedit.css" >> $@ |
| 1218 | echo "$(SRCDIR)\tree.js" >> $@ |
| 1219 | echo "$(SRCDIR)\useredit.js" >> $@ |
| 1220 |
| --- win/Makefile.msc | |
| +++ win/Makefile.msc | |
| @@ -553,10 +553,13 @@ | |
| 553 | "$(SRCDIR)\..\skins\xekri\css.txt" \ |
| 554 | "$(SRCDIR)\..\skins\xekri\details.txt" \ |
| 555 | "$(SRCDIR)\..\skins\xekri\footer.txt" \ |
| 556 | "$(SRCDIR)\..\skins\xekri\header.txt" \ |
| 557 | "$(SRCDIR)\accordion.js" \ |
| 558 | "$(SRCDIR)\alerts\b-flat.wav" \ |
| 559 | "$(SRCDIR)\alerts\g-minor-triad.wav" \ |
| 560 | "$(SRCDIR)\alerts\plunk.wav" \ |
| 561 | "$(SRCDIR)\chat.js" \ |
| 562 | "$(SRCDIR)\ci_edit.js" \ |
| 563 | "$(SRCDIR)\copybtn.js" \ |
| 564 | "$(SRCDIR)\default.css" \ |
| 565 | "$(SRCDIR)\diff.tcl" \ |
| @@ -599,11 +602,10 @@ | |
| 602 | "$(SRCDIR)\sounds\b.wav" \ |
| 603 | "$(SRCDIR)\sounds\c.wav" \ |
| 604 | "$(SRCDIR)\sounds\d.wav" \ |
| 605 | "$(SRCDIR)\sounds\e.wav" \ |
| 606 | "$(SRCDIR)\sounds\f.wav" \ |
| 607 | "$(SRCDIR)\style.admin_log.css" \ |
| 608 | "$(SRCDIR)\style.fileedit.css" \ |
| 609 | "$(SRCDIR)\style.wikiedit.css" \ |
| 610 | "$(SRCDIR)\tree.js" \ |
| 611 | "$(SRCDIR)\useredit.js" \ |
| @@ -1163,10 +1165,13 @@ | |
| 1165 | echo "$(SRCDIR)\../skins/xekri/css.txt" >> $@ |
| 1166 | echo "$(SRCDIR)\../skins/xekri/details.txt" >> $@ |
| 1167 | echo "$(SRCDIR)\../skins/xekri/footer.txt" >> $@ |
| 1168 | echo "$(SRCDIR)\../skins/xekri/header.txt" >> $@ |
| 1169 | echo "$(SRCDIR)\accordion.js" >> $@ |
| 1170 | echo "$(SRCDIR)\alerts/b-flat.wav" >> $@ |
| 1171 | echo "$(SRCDIR)\alerts/g-minor-triad.wav" >> $@ |
| 1172 | echo "$(SRCDIR)\alerts/plunk.wav" >> $@ |
| 1173 | echo "$(SRCDIR)\chat.js" >> $@ |
| 1174 | echo "$(SRCDIR)\ci_edit.js" >> $@ |
| 1175 | echo "$(SRCDIR)\copybtn.js" >> $@ |
| 1176 | echo "$(SRCDIR)\default.css" >> $@ |
| 1177 | echo "$(SRCDIR)\diff.tcl" >> $@ |
| @@ -1209,11 +1214,10 @@ | |
| 1214 | echo "$(SRCDIR)\sounds/b.wav" >> $@ |
| 1215 | echo "$(SRCDIR)\sounds/c.wav" >> $@ |
| 1216 | echo "$(SRCDIR)\sounds/d.wav" >> $@ |
| 1217 | echo "$(SRCDIR)\sounds/e.wav" >> $@ |
| 1218 | echo "$(SRCDIR)\sounds/f.wav" >> $@ |
| 1219 | echo "$(SRCDIR)\style.admin_log.css" >> $@ |
| 1220 | echo "$(SRCDIR)\style.fileedit.css" >> $@ |
| 1221 | echo "$(SRCDIR)\style.wikiedit.css" >> $@ |
| 1222 | echo "$(SRCDIR)\tree.js" >> $@ |
| 1223 | echo "$(SRCDIR)\useredit.js" >> $@ |
| 1224 |
+24
| --- www/chat.md | ||
| +++ www/chat.md | ||
| @@ -99,10 +99,34 @@ | ||
| 99 | 99 | page is reloaded. Admin users may additionally choose to globally |
| 100 | 100 | delete a message from the chat record, which deletes it not only from |
| 101 | 101 | their own browser but also propagates the removal to all connected |
| 102 | 102 | clients the next time they poll for new messages. |
| 103 | 103 | |
| 104 | +### Audible Notifications | |
| 105 | + | |
| 106 | +On platforms which support it, chat can optionally play an audio file | |
| 107 | +when a new message arrives from any user other than oneself. The sound | |
| 108 | +can be selected or disabled via the settings menu. The list of sounds | |
| 109 | +includes a small selection of sounds built in to the fossil binary and | |
| 110 | +new sound files may be added to a repository as unversioned content: | |
| 111 | +when the chat page is loaded, it includes a list of all unversioned | |
| 112 | +files named `alert-sounds/*.XYZ`, where `XYZ` is one of (`wav`, `mp3`, | |
| 113 | +`ogg`) case-insensitive. | |
| 114 | + | |
| 115 | +For example, a Unix-style shell command like the following would | |
| 116 | +install all WAV files in a local directory to the list: | |
| 117 | + | |
| 118 | +``` | |
| 119 | +for i in *.wav; do fossil uv add "$i" --as "alert-sounds/$i"; done | |
| 120 | +``` | |
| 121 | + | |
| 122 | +The list of sound files is sorted client-side for display in the | |
| 123 | +selection list. The user's selection of audio file is persistent in | |
| 124 | +a given browser, but if the file is subsequently removed from the | |
| 125 | +server then the next time the chat page is reloaded the sound will | |
| 126 | +fall back to the first one in the selection list. | |
| 127 | + | |
| 104 | 128 | ## Implementation Details |
| 105 | 129 | |
| 106 | 130 | *You do not need to understand how Fossil chat works in order to use it. |
| 107 | 131 | But many developers prefer to know how their tools work. |
| 108 | 132 | This section is provided for the benefit of those curious developers.* |
| 109 | 133 |
| --- www/chat.md | |
| +++ www/chat.md | |
| @@ -99,10 +99,34 @@ | |
| 99 | page is reloaded. Admin users may additionally choose to globally |
| 100 | delete a message from the chat record, which deletes it not only from |
| 101 | their own browser but also propagates the removal to all connected |
| 102 | clients the next time they poll for new messages. |
| 103 | |
| 104 | ## Implementation Details |
| 105 | |
| 106 | *You do not need to understand how Fossil chat works in order to use it. |
| 107 | But many developers prefer to know how their tools work. |
| 108 | This section is provided for the benefit of those curious developers.* |
| 109 |
| --- www/chat.md | |
| +++ www/chat.md | |
| @@ -99,10 +99,34 @@ | |
| 99 | page is reloaded. Admin users may additionally choose to globally |
| 100 | delete a message from the chat record, which deletes it not only from |
| 101 | their own browser but also propagates the removal to all connected |
| 102 | clients the next time they poll for new messages. |
| 103 | |
| 104 | ### Audible Notifications |
| 105 | |
| 106 | On platforms which support it, chat can optionally play an audio file |
| 107 | when a new message arrives from any user other than oneself. The sound |
| 108 | can be selected or disabled via the settings menu. The list of sounds |
| 109 | includes a small selection of sounds built in to the fossil binary and |
| 110 | new sound files may be added to a repository as unversioned content: |
| 111 | when the chat page is loaded, it includes a list of all unversioned |
| 112 | files named `alert-sounds/*.XYZ`, where `XYZ` is one of (`wav`, `mp3`, |
| 113 | `ogg`) case-insensitive. |
| 114 | |
| 115 | For example, a Unix-style shell command like the following would |
| 116 | install all WAV files in a local directory to the list: |
| 117 | |
| 118 | ``` |
| 119 | for i in *.wav; do fossil uv add "$i" --as "alert-sounds/$i"; done |
| 120 | ``` |
| 121 | |
| 122 | The list of sound files is sorted client-side for display in the |
| 123 | selection list. The user's selection of audio file is persistent in |
| 124 | a given browser, but if the file is subsequently removed from the |
| 125 | server then the next time the chat page is reloaded the sound will |
| 126 | fall back to the first one in the selection list. |
| 127 | |
| 128 | ## Implementation Details |
| 129 | |
| 130 | *You do not need to understand how Fossil chat works in order to use it. |
| 131 | But many developers prefer to know how their tools work. |
| 132 | This section is provided for the benefit of those curious developers.* |
| 133 |