Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | chat: added preliminary audio notification support (may require toggling that capability on for a given server in the browser). Center-aligned chat error messages and removed the 'fossil' user name from them, for compatibility with upcoming timeline-style notifications. Added wav files to the binary-glob versioned setting. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
99caeec643bd1fc87da245180b1bb9b8 |
| User & Date: | stephan 2021-01-03 11:08:54.644 |
Context
|
2021-01-03
| ||
| 12:41 | chat: when enabling audio notification, play the notification sound after a half-second delay. Slimmed down the option menu buttons a bit. ... (check-in: 729e1fc56d user: stephan tags: trunk) | |
| 11:08 | chat: added preliminary audio notification support (may require toggling that capability on for a given server in the browser). Center-aligned chat error messages and removed the 'fossil' user name from them, for compatibility with upcoming timeline-style notifications. Added wav files to the binary-glob versioned setting. ... (check-in: 99caeec643 user: stephan tags: trunk) | |
|
2021-01-02
| ||
| 19:06 | Improved chat.js error reporting a bit. Connection errors for send and history-fetch ops are now reported as error-style messags in the chat feed. ... (check-in: a08dfbabbd user: stephan tags: trunk) | |
Changes
Changes to .fossil-settings/binary-glob.
1 2 3 4 5 6 7 8 9 10 11 | *.gif *.ico *.jpg *.odp *.dia *.pdf *.png compat/zlib/contrib/blast/test.pk compat/zlib/contrib/dotzlib/DotZLib.chm compat/zlib/contrib/puff/zeros.raw compat/zlib/zlib.3.pdf | > | 1 2 3 4 5 6 7 8 9 10 11 12 | *.gif *.ico *.jpg *.odp *.dia *.pdf *.png *.wav compat/zlib/contrib/blast/test.pk compat/zlib/contrib/dotzlib/DotZLib.chm compat/zlib/contrib/puff/zeros.raw compat/zlib/zlib.3.pdf |
Changes to src/chat.c.
| ︙ | ︙ | |||
233 234 235 236 237 238 239 |
char * zTime = cgi_iso8601_datestamp();
cgi_set_content_type("application/json");
if(fAsMessageList){
CX("{\"msgs\":[{");
}else{
CX("{");
}
| | | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
char * zTime = cgi_iso8601_datestamp();
cgi_set_content_type("application/json");
if(fAsMessageList){
CX("{\"msgs\":[{");
}else{
CX("{");
}
CX("\"isError\": true, \"xfrom\": null,");
CX("\"mtime\": %!j, \"lmtime\": %!j,", zTime, zTime);
CX("\"xmsg\": \"Missing permissions or not logged in. "
"Try <a href='%R/login?g=%R/chat'>logging in</a>.\"");
if(fAsMessageList){
CX("}]}");
}else{
CX("}");
|
| ︙ | ︙ | |||
464 465 466 467 468 469 470 |
** permissions cannot be verified because their login cookie expired, the
** request returns a slightly modified structure:
**
** | {
** | "msgs":[
** | {
** | "isError": true,
| | | 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 |
** permissions cannot be verified because their login cookie expired, the
** request returns a slightly modified structure:
**
** | {
** | "msgs":[
** | {
** | "isError": true,
** | "xfrom": null,
** | "xmsg": "error details"
** | "mtime": as above,
** | "ltime": same as mtime
** | }
** | ]
** | }
**
|
| ︙ | ︙ | |||
674 675 676 677 678 679 680 681 682 683 684 685 686 687 |
void chat_ping_webpage(void){
const char *zIpAddr = PD("REMOTE_ADDR","nil");
if( cgi_is_loopback(zIpAddr) ){
cgi_append_header("Access-Control-Allow-Origin: *\r\n");
fputc(7, stderr);
}
}
/*
** COMMAND: chat
**
** Usage: %fossil chat ?URL?
**
** Bring up a window to the chatroom feature of the Fossil repository
| > > > > > > > > > > > > > > > > | 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 |
void chat_ping_webpage(void){
const char *zIpAddr = PD("REMOTE_ADDR","nil");
if( cgi_is_loopback(zIpAddr) ){
cgi_append_header("Access-Control-Allow-Origin: *\r\n");
fputc(7, stderr);
}
}
/*
** WEBPAGE: chat-audio-received
**
** Responds with an audio stream suitable for use as a /chat
** new-message-arrived notification.
*/
void chat_audio_alert(void){
Blob audio = empty_blob;
int n = 0;
const char * zAudio =
(const char *)builtin_file("sounds/chat-received.wav", &n);
blob_init(&audio, zAudio, n);
cgi_set_content_type("audio/wav");
cgi_set_content(&audio);
}
/*
** COMMAND: chat
**
** Usage: %fossil chat ?URL?
**
** Bring up a window to the chatroom feature of the Fossil repository
|
| ︙ | ︙ |
Changes to src/chat.js.
| ︙ | ︙ | |||
352 353 354 355 356 357 358 |
get: (k,dflt)=>F.storage.get(k,dflt),
getBool: (k,dflt)=>F.storage.getBool(k,dflt),
set: (k,v)=>F.storage.set(k,v),
defaults:{
"images-inline": !!F.config.chat.imagesInline,
"edit-multiline": false,
"monospace-messages": false,
| | > > > > > > > > > > > > > > > > | 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 |
get: (k,dflt)=>F.storage.get(k,dflt),
getBool: (k,dflt)=>F.storage.getBool(k,dflt),
set: (k,v)=>F.storage.set(k,v),
defaults:{
"images-inline": !!F.config.chat.imagesInline,
"edit-multiline": false,
"monospace-messages": false,
"chat-only-mode": false,
"audio-notification": true,
}
},
/** Plays a new-message notification sound IF the audio-notification
setting is true, else this is a no-op. Returns this.
*/
playNewMessageSound: function f(){
if(this.settings.getBool('audio-notification',false)){
try{
if(!f.audio) f.audio = new Audio(F.rootPath+"chat-audio-received");
f.audio.currentTime = 0;
f.audio.play();
}catch(e){
console.error("Audio playblack failed.",e);
}
}
return this;
}
};
cs.e.inputCurrent = cs.e.inputSingle;
/* Install default settings... */
Object.keys(cs.settings.defaults).forEach(function(k){
const v = cs.settings.get(k,cs);
if(cs===v) cs.settings.set(k,cs.settings.defaults[k]);
|
| ︙ | ︙ | |||
403 404 405 406 407 408 409 |
*/
cs.reportErrorAsMessage = function(/*msg args*/){
const args = argsToArray(arguments);
console.error("chat error:",args);
const d = new Date().toISOString(),
msg = {
isError: true,
| | | < | 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 |
*/
cs.reportErrorAsMessage = function(/*msg args*/){
const args = argsToArray(arguments);
console.error("chat error:",args);
const d = new Date().toISOString(),
msg = {
isError: true,
xfrom: null,
msgid: -1,
mtime: d,
lmtime: d,
xmsg: args
}, mw = new this.MessageWidget(msg);
this.injectMessageElem(mw.e.body);
mw.scrollIntoView();
};
cs.getMessageElemById = function(id){
return qs('[data-msgid="'+id+'"]');
};
|
| ︙ | ︙ | |||
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 |
instance). These are modelled after FIELDSET elements but we
don't use FIELDSET because of cross-browser inconsistencies in
features of the FIELDSET/LEGEND combination, e.g. inability to
align legends via CSS in Firefox and clicking-related
deficiencies in Safari.
*/
Chat.MessageWidget = (function(){
const cf = function(){
this.e = {
body: D.addClass(D.div(), 'message-widget'),
tab: D.addClass(D.span(), 'message-widget-tab'),
content: D.addClass(D.div(), 'message-widget-content')
};
D.append(this.e.body, this.e.tab, this.e.content);
this.e.tab.setAttribute('role', 'button');
};
cf.prototype = {
setLabel: function(label){
return this;
},
scrollIntoView: function(){
this.e.content.scrollIntoView();
},
setMessage: function(m){
const ds = this.e.body.dataset;
ds.timestamp = m.mtime;
ds.lmtime = m.lmtime;
ds.msgid = m.msgid;
| > > > > > > > > > > > > | > | | > > > > | | < | < < | > | | | > > > > > > | | 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 |
instance). These are modelled after FIELDSET elements but we
don't use FIELDSET because of cross-browser inconsistencies in
features of the FIELDSET/LEGEND combination, e.g. inability to
align legends via CSS in Firefox and clicking-related
deficiencies in Safari.
*/
Chat.MessageWidget = (function(){
/**
Constructor. If passed an argument, it is passed to
this.setMessage() after initialization.
*/
const cf = function(){
this.e = {
body: D.addClass(D.div(), 'message-widget'),
tab: D.addClass(D.span(), 'message-widget-tab'),
content: D.addClass(D.div(), 'message-widget-content')
};
D.append(this.e.body, this.e.tab, this.e.content);
this.e.tab.setAttribute('role', 'button');
if(arguments.length){
this.setMessage(arguments[0]);
}
};
const theTime = function(d){
return [d.getHours(),":",
(d.getMinutes()+100).toString().slice(1,3)
].join('');
};
cf.prototype = {
setLabel: function(label){
return this;
},
scrollIntoView: function(){
this.e.content.scrollIntoView();
},
setMessage: function(m){
const ds = this.e.body.dataset;
ds.timestamp = m.mtime;
ds.lmtime = m.lmtime;
ds.msgid = m.msgid;
ds.xfrom = m.xfrom || '';
if(m.xfrom === Chat.me){
D.addClass(this.e.body, 'mine');
}
if(m.uclr){
this.e.content.style.backgroundColor = m.uclr;
this.e.tab.style.backgroundColor = m.uclr;
}
const d = new Date(m.mtime);
D.clearElement(this.e.tab);
var contentTarget = this.e.content;
if(m.xfrom){
D.append(
this.e.tab,
D.text(m.xfrom," #",(m.msgid||'???'),' @ ',theTime(d))
);
}else{/*notification*/
D.addClass(this.e.body, 'notification');
if(m.isError){
D.addClass([contentTarget, this.e.tab], 'error');
}
D.append(
this.e.tab,
D.text('notification @ ',theTime(d))
);
}
if( m.xfrom && m.fsize>0 ){
if( m.fmime
&& m.fmime.startsWith("image/")
&& Chat.settings.getBool('images-inline',true)
){
contentTarget.appendChild(D.img("chat-download/" + m.msgid));
ds.hasImage = 1;
}else{
|
| ︙ | ︙ | |||
622 623 624 625 626 627 628 |
refresh:function(){
const eMsg = this._eMsg;
if(!eMsg) return;
D.clearElement(this.e);
const d = new Date(eMsg.dataset.timestamp);
if(d.getMinutes().toString()!=="NaN"){
// Date works, render informative timestamps
| | | 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 |
refresh:function(){
const eMsg = this._eMsg;
if(!eMsg) return;
D.clearElement(this.e);
const d = new Date(eMsg.dataset.timestamp);
if(d.getMinutes().toString()!=="NaN"){
// Date works, render informative timestamps
const xfrom = eMsg.dataset.xfrom || 'server';
D.append(this.e,
D.append(D.span(), localTimeString(d)," ",Chat.me," time"),
D.append(D.span(), iso8601ish(d)));
if(eMsg.dataset.lmtime && xfrom!==Chat.me){
D.append(this.e,
D.append(D.span(), localTime8601(
new Date(eMsg.dataset.lmtime)
|
| ︙ | ︙ | |||
890 891 892 893 894 895 896 |
},{
label: "Message home/end buttons",
boolValue: ()=>!Chat.e.btnMsgHome.classList.contains('hidden'),
callback: ()=>Chat.toggleNavButtons()
},{
label: "Images inline",
boolValue: ()=>Chat.settings.getBool('images-inline'),
| < > > > > > > > > | 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 |
},{
label: "Message home/end buttons",
boolValue: ()=>!Chat.e.btnMsgHome.classList.contains('hidden'),
callback: ()=>Chat.toggleNavButtons()
},{
label: "Images inline",
boolValue: ()=>Chat.settings.getBool('images-inline'),
callback: function(){
const v = Chat.settings.getBool('images-inline',true);
Chat.settings.set('images-inline', !v);
F.toast.message("Image mode set to "+(v ? "hyperlink" : "inline")+".");
}
},{
label: "Audio notifications",
boolValue: ()=>Chat.settings.getBool('audio-notification'),
callback: function(){
const v = Chat.settings.getBool('audio-notification');
Chat.settings.set('audio-notification', !v);
F.toast.message("Audio notifications "+(v ? "disabled" : "enabled")+".");
}
}];
/**
Rebuild the menu each time it's shown so that the toggles can
show their current values.
*/
settingsPopup.options.refresh = function(){
|
| ︙ | ︙ | |||
987 988 989 990 991 992 993 |
if( m.msgid>Chat.mxMsg ) Chat.mxMsg = m.msgid;
if( !Chat.mnMsg || m.msgid<Chat.mnMsg) Chat.mnMsg = m.msgid;
if( m.mdel ){
/* A record deletion notice. */
Chat.deleteMessageElem(m.mdel);
return;
}
| > > > | < | 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 |
if( m.msgid>Chat.mxMsg ) Chat.mxMsg = m.msgid;
if( !Chat.mnMsg || m.msgid<Chat.mnMsg) Chat.mnMsg = m.msgid;
if( m.mdel ){
/* A record deletion notice. */
Chat.deleteMessageElem(m.mdel);
return;
}
if(!Chat._isBatchLoading && Chat.me!==m.xfrom && Chat.playNewMessageSound){
Chat.playNewMessageSound();
}
const row = new Chat.MessageWidget(m);
Chat.injectMessageElem(row.e.body,atEnd);
if(m.isError){
Chat._gotServerError = m;
}
}/*processPost()*/;
}/*end static init*/
jx.msgs.forEach((m)=>f.processPost(m,atEnd));
|
| ︙ | ︙ |
Changes to src/default.css.
| ︙ | ︙ | |||
1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 |
border: none;
align-items: flex-start;
}
body.chat.my-messages-right .message-widget.mine {
/* Right-aligns a user's own chat messages, similar to how
most mobile messaging apps do it. */
align-items: flex-end;
}
/* The content area of a message. */
body.chat .message-widget-content {
display: inline-block;
border-radius: 0.25em;
border: 1px solid rgba(0,0,0,0.2);
box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29);
| > > > > | 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 |
border: none;
align-items: flex-start;
}
body.chat.my-messages-right .message-widget.mine {
/* Right-aligns a user's own chat messages, similar to how
most mobile messaging apps do it. */
align-items: flex-end;
}
body.chat.my-messages-right .message-widget.notification {
/* Center-aligns a system-level notification message. */
align-items: center;
}
/* The content area of a message. */
body.chat .message-widget-content {
display: inline-block;
border-radius: 0.25em;
border: 1px solid rgba(0,0,0,0.2);
box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29);
|
| ︙ | ︙ |
Changes to src/main.mk.
| ︙ | ︙ | |||
261 262 263 264 265 266 267 268 269 270 271 272 273 274 | $(SRCDIR)/sounds/6.wav \ $(SRCDIR)/sounds/7.wav \ $(SRCDIR)/sounds/8.wav \ $(SRCDIR)/sounds/9.wav \ $(SRCDIR)/sounds/a.wav \ $(SRCDIR)/sounds/b.wav \ $(SRCDIR)/sounds/c.wav \ $(SRCDIR)/sounds/d.wav \ $(SRCDIR)/sounds/e.wav \ $(SRCDIR)/sounds/f.wav \ $(SRCDIR)/style.admin_log.css \ $(SRCDIR)/style.fileedit.css \ $(SRCDIR)/style.wikiedit.css \ $(SRCDIR)/tree.js \ | > | 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 | $(SRCDIR)/sounds/6.wav \ $(SRCDIR)/sounds/7.wav \ $(SRCDIR)/sounds/8.wav \ $(SRCDIR)/sounds/9.wav \ $(SRCDIR)/sounds/a.wav \ $(SRCDIR)/sounds/b.wav \ $(SRCDIR)/sounds/c.wav \ $(SRCDIR)/sounds/chat-received.wav \ $(SRCDIR)/sounds/d.wav \ $(SRCDIR)/sounds/e.wav \ $(SRCDIR)/sounds/f.wav \ $(SRCDIR)/style.admin_log.css \ $(SRCDIR)/style.fileedit.css \ $(SRCDIR)/style.wikiedit.css \ $(SRCDIR)/tree.js \ |
| ︙ | ︙ |
Changes to src/sounds/README.md.
|
| | | | | | | > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | The `[0-9a-f].wav` files in this directory contain a human voice speaking each of the 16 hexadecimal digits. If a captcha string consists of just hexadecimal digits (as is the case for captchas generated by the [../captcha.c module](../captcha.c)) then these WAV files can be concatenated together to generate an audio reading of the captcha, which enables visually impaired users to complete the captcha. Each of the WAV files uses 8000 samples per second, 8 bits per sample and are 6000 samples in length. The recordings are made by Philip Bennefall and are of his own voice. Mr. Bennefall is himself blind and uses this system implemented with these recordings to complete captchas for Fossil. ======================================================================== `chat-received.wav` is a Creative Commons Attribution-licensed audio file obtained from: https://notificationsounds.com/notification-sounds/time-is-now-585 License: https://creativecommons.org/licenses/by/4.0/legalcode This copy has been truncated, down-sampled, and converted to a different format than the original. |
Added src/sounds/chat-received.wav.
cannot compute difference between binary files
Changes to win/Makefile.mingw.
| ︙ | ︙ | |||
673 674 675 676 677 678 679 680 681 682 683 684 685 686 | $(SRCDIR)/sounds/6.wav \ $(SRCDIR)/sounds/7.wav \ $(SRCDIR)/sounds/8.wav \ $(SRCDIR)/sounds/9.wav \ $(SRCDIR)/sounds/a.wav \ $(SRCDIR)/sounds/b.wav \ $(SRCDIR)/sounds/c.wav \ $(SRCDIR)/sounds/d.wav \ $(SRCDIR)/sounds/e.wav \ $(SRCDIR)/sounds/f.wav \ $(SRCDIR)/style.admin_log.css \ $(SRCDIR)/style.fileedit.css \ $(SRCDIR)/style.wikiedit.css \ $(SRCDIR)/tree.js \ | > | 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 | $(SRCDIR)/sounds/6.wav \ $(SRCDIR)/sounds/7.wav \ $(SRCDIR)/sounds/8.wav \ $(SRCDIR)/sounds/9.wav \ $(SRCDIR)/sounds/a.wav \ $(SRCDIR)/sounds/b.wav \ $(SRCDIR)/sounds/c.wav \ $(SRCDIR)/sounds/chat-received.wav \ $(SRCDIR)/sounds/d.wav \ $(SRCDIR)/sounds/e.wav \ $(SRCDIR)/sounds/f.wav \ $(SRCDIR)/style.admin_log.css \ $(SRCDIR)/style.fileedit.css \ $(SRCDIR)/style.wikiedit.css \ $(SRCDIR)/tree.js \ |
| ︙ | ︙ |
Changes to win/Makefile.msc.
| ︙ | ︙ | |||
594 595 596 597 598 599 600 601 602 603 604 605 606 607 |
"$(SRCDIR)\sounds\6.wav" \
"$(SRCDIR)\sounds\7.wav" \
"$(SRCDIR)\sounds\8.wav" \
"$(SRCDIR)\sounds\9.wav" \
"$(SRCDIR)\sounds\a.wav" \
"$(SRCDIR)\sounds\b.wav" \
"$(SRCDIR)\sounds\c.wav" \
"$(SRCDIR)\sounds\d.wav" \
"$(SRCDIR)\sounds\e.wav" \
"$(SRCDIR)\sounds\f.wav" \
"$(SRCDIR)\style.admin_log.css" \
"$(SRCDIR)\style.fileedit.css" \
"$(SRCDIR)\style.wikiedit.css" \
"$(SRCDIR)\tree.js" \
| > | 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 |
"$(SRCDIR)\sounds\6.wav" \
"$(SRCDIR)\sounds\7.wav" \
"$(SRCDIR)\sounds\8.wav" \
"$(SRCDIR)\sounds\9.wav" \
"$(SRCDIR)\sounds\a.wav" \
"$(SRCDIR)\sounds\b.wav" \
"$(SRCDIR)\sounds\c.wav" \
"$(SRCDIR)\sounds\chat-received.wav" \
"$(SRCDIR)\sounds\d.wav" \
"$(SRCDIR)\sounds\e.wav" \
"$(SRCDIR)\sounds\f.wav" \
"$(SRCDIR)\style.admin_log.css" \
"$(SRCDIR)\style.fileedit.css" \
"$(SRCDIR)\style.wikiedit.css" \
"$(SRCDIR)\tree.js" \
|
| ︙ | ︙ | |||
1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 | echo "$(SRCDIR)\sounds/6.wav" >> $@ echo "$(SRCDIR)\sounds/7.wav" >> $@ echo "$(SRCDIR)\sounds/8.wav" >> $@ echo "$(SRCDIR)\sounds/9.wav" >> $@ echo "$(SRCDIR)\sounds/a.wav" >> $@ echo "$(SRCDIR)\sounds/b.wav" >> $@ echo "$(SRCDIR)\sounds/c.wav" >> $@ echo "$(SRCDIR)\sounds/d.wav" >> $@ echo "$(SRCDIR)\sounds/e.wav" >> $@ echo "$(SRCDIR)\sounds/f.wav" >> $@ echo "$(SRCDIR)\style.admin_log.css" >> $@ echo "$(SRCDIR)\style.fileedit.css" >> $@ echo "$(SRCDIR)\style.wikiedit.css" >> $@ echo "$(SRCDIR)\tree.js" >> $@ | > | 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 | echo "$(SRCDIR)\sounds/6.wav" >> $@ echo "$(SRCDIR)\sounds/7.wav" >> $@ echo "$(SRCDIR)\sounds/8.wav" >> $@ echo "$(SRCDIR)\sounds/9.wav" >> $@ echo "$(SRCDIR)\sounds/a.wav" >> $@ echo "$(SRCDIR)\sounds/b.wav" >> $@ echo "$(SRCDIR)\sounds/c.wav" >> $@ echo "$(SRCDIR)\sounds/chat-received.wav" >> $@ echo "$(SRCDIR)\sounds/d.wav" >> $@ echo "$(SRCDIR)\sounds/e.wav" >> $@ echo "$(SRCDIR)\sounds/f.wav" >> $@ echo "$(SRCDIR)\style.admin_log.css" >> $@ echo "$(SRCDIR)\style.fileedit.css" >> $@ echo "$(SRCDIR)\style.wikiedit.css" >> $@ echo "$(SRCDIR)\tree.js" >> $@ |
| ︙ | ︙ |