Skip to content

Commit de2f7e0

Browse files
Fix question list layout change
1 parent 2805567 commit de2f7e0

File tree

4 files changed

+67
-63
lines changed

4 files changed

+67
-63
lines changed

Speak-New-Questions/dist/StackSpeakNewQuestions.user.js

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// @description Speaks new question titles aloud as they come in
44
// @author CertainPerformance
55
// @namespace https://github.com/CertainPerformance/Stack-Exchange-Userscripts
6-
// @version 1.0.3
6+
// @version 1.0.4
77
// @include /^https://(?:[^/]+\.)?(?:(?:stackoverflow|serverfault|superuser|stackexchange|askubuntu|stackapps)\.com|mathoverflow\.net)/questions(?:/\d+|$|\?tab=Newest$|/tagged/.*sort=newest)/
88
// @include /^https://example\.com/fakepage$/
99
// @grant none
@@ -239,16 +239,20 @@ const targetBlankAllAnchors_1 = __webpack_require__(/*! ./targetBlankAllAnchors
239239
const addBorderWhenClicked_1 = __webpack_require__(/*! ./addBorderWhenClicked */ "./src/questionListPage/addBorderWhenClicked.ts");
240240
const temporarilyPreventClicks_1 = __webpack_require__(/*! ./temporarilyPreventClicks */ "./src/questionListPage/temporarilyPreventClicks.ts");
241241
const pendingQuestionColor_1 = __webpack_require__(/*! ../pendingQuestionColor */ "./src/pendingQuestionColor.ts");
242-
const seenQuestionsIds = new Set([...document.querySelectorAll('#questions > div.question-summary')].map(({ id }) => id));
242+
const getQuestionDivs = () => [...document.querySelectorAll('#questions div.question-summary')];
243+
const getQuestionId = (questionDiv) => Number(questionDiv.id.match(/\d+$/)[0]);
244+
const seenQuestionsIds = new Set(getQuestionDivs().map(getQuestionId));
243245
const watchedTags = ((_a = document.querySelector('#search input')) === null || _a === void 0 ? void 0 : _a.value.match(/[^\[\]]+(?=\])/g)) || [];
244246
const questionTagCountsLeftById = {};
245247
const siteName = window.location.href === 'https://example.com/fakepage' ? '' : window.StackExchange.options.site.name;
246248
const siteNameSpokenText = siteName === 'Stack Overflow' ? '' : `${siteName}, `;
247249
exports.checkNewQuestions = () => {
248250
temporarilyPreventClicks_1.temporarilyPreventClicks();
249-
[...document.querySelectorAll('#questions > div.question-summary')]
250-
.filter(questionDiv => !seenQuestionsIds.has(questionDiv.id))
251-
.forEach((questionDiv) => {
251+
for (const questionDiv of getQuestionDivs()) {
252+
const questionId = getQuestionId(questionDiv);
253+
if (!questionId || seenQuestionsIds.has(questionId)) {
254+
continue;
255+
}
252256
targetBlankAllAnchors_1.targetBlankAllAnchors(questionDiv);
253257
const { focusing } = state_1.getState();
254258
// New question divs that have not been spoken yet will be highlighted yellow
@@ -267,7 +271,6 @@ exports.checkNewQuestions = () => {
267271
* just wait for the question to appear in the questions list for the nth time, where n is the number of watched tags that question has
268272
* Only on that nth time does the code below result in the questionDiv actually getting changed, watched, and linked to the utterance that gets queued
269273
*/
270-
const questionId = questionDiv.id;
271274
if (!questionTagCountsLeftById.hasOwnProperty(questionId)) {
272275
const watchedTagCountForThisQuestion = Array.from(questionDiv.querySelectorAll('.tags > a'), a => a.textContent)
273276
.reduce((a, tag) => a + Number(watchedTags.includes(tag)), 0);
@@ -277,19 +280,19 @@ exports.checkNewQuestions = () => {
277280
// User may not be watching any tags - may be just on /questions?tab=Newest page
278281
// in which case there's nothing to count, and only one socket message per question, so queue the question immediately
279282
if (watchedTags.length && questionTagCountsLeftById[questionId] !== 0) {
280-
return;
283+
continue;
281284
}
282285
seenQuestionsIds.add(questionId);
283286
addBorderWhenClicked_1.addBorderWhenClicked(questionDiv);
284287
if (focusing) {
285-
return;
288+
continue;
286289
}
287290
const questionText = questionDiv.querySelector('.question-hyperlink').textContent;
288291
const questionTags = [...questionDiv.querySelectorAll('.tags > a')]
289292
.map(tagA => tagA.textContent.replace(/\./g, ' dot '));
290293
const textToSpeak = `Question, ${siteNameSpokenText} ${questionText} ---- ${questionTags.join(', ')}`;
291294
queueUtterance_1.queueUtterance(textToSpeak, questionId);
292-
});
295+
}
293296
};
294297

295298

@@ -552,7 +555,7 @@ exports.queueUtterance = (textToSpeak, questionId) => {
552555
}
553556
return;
554557
}
555-
const questionElement = document.getElementById(questionId);
558+
const questionElement = document.getElementById(`question-summary-${questionId}`);
556559
const channel = state_1.getState().channel;
557560
if (questionElement && questionId) {
558561
// This will pretty much always already be highlighted, but just in case

Speak-New-Questions/src/questionListPage/checkNewQuestions.ts

Lines changed: 51 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -5,62 +5,63 @@ import { addBorderWhenClicked } from './addBorderWhenClicked';
55
import { temporarilyPreventClicks } from './temporarilyPreventClicks';
66
import { pendingQuestionColor } from '../pendingQuestionColor';
77

8-
const seenQuestionsIds = new Set(
9-
[...document.querySelectorAll('#questions > div.question-summary')].map(({ id }) => id),
10-
);
8+
const getQuestionDivs = () => [...document.querySelectorAll<HTMLInputElement>('#questions div.question-summary')];
9+
const getQuestionId = (questionDiv: HTMLElement) => Number(questionDiv.id.match(/\d+$/)![0]);
10+
const seenQuestionsIds = new Set(getQuestionDivs().map(getQuestionId));
1111
const watchedTags = document.querySelector<HTMLInputElement>('#search input')?.value.match(/[^\[\]]+(?=\])/g) || [];
1212
const questionTagCountsLeftById: { [questionId: string]: number } = {};
1313
const siteName = window.location.href === 'https://example.com/fakepage' ? '' : window.StackExchange.options.site.name;
1414
const siteNameSpokenText = siteName === 'Stack Overflow' ? '' : `${siteName}, `;
1515

1616
export const checkNewQuestions = () => {
1717
temporarilyPreventClicks();
18-
[...document.querySelectorAll<HTMLElement>('#questions > div.question-summary')]
19-
.filter(questionDiv => !seenQuestionsIds.has(questionDiv.id))
20-
.forEach((questionDiv) => {
21-
targetBlankAllAnchors(questionDiv);
22-
const { focusing } = getState();
23-
// New question divs that have not been spoken yet will be highlighted yellow
24-
// But these divs may get removed and replaced with copies before being passed to queueUtterance (see below)
25-
// For style consistency while the divs are appearing, highlight them immediately
26-
if (!focusing) {
27-
questionDiv.style.backgroundColor = pendingQuestionColor;
28-
}
18+
for (const questionDiv of getQuestionDivs()) {
19+
const questionId = getQuestionId(questionDiv);
20+
if (!questionId || seenQuestionsIds.has(questionId)) {
21+
continue;
22+
}
23+
targetBlankAllAnchors(questionDiv);
24+
const { focusing } = getState();
25+
// New question divs that have not been spoken yet will be highlighted yellow
26+
// But these divs may get removed and replaced with copies before being passed to queueUtterance (see below)
27+
// For style consistency while the divs are appearing, highlight them immediately
28+
if (!focusing) {
29+
questionDiv.style.backgroundColor = pendingQuestionColor;
30+
}
2931

30-
/* StackExchange will send the client new info about an active question *for every question, and for every tag in that question* that you're watching
31-
* Eg if you're watching 5 tags, and a question is posted with 3 of them, the websocket will send you info 3 times
32-
* (there may be a moderate fraction of a second delay between each)
33-
* and each time, if the existing question div is already in the document, it will be completely removed and replaced
34-
* See: https://dev.stackoverflow.com/content//Js/full.en.js
35-
* search for: $('#question-summary-' + activeq.id).remove();
36-
* Rather than fiddling with the element (and with the styles added by the userscript, and with the linked audio) every time it gets replaced
37-
* just wait for the question to appear in the questions list for the nth time, where n is the number of watched tags that question has
38-
* Only on that nth time does the code below result in the questionDiv actually getting changed, watched, and linked to the utterance that gets queued
39-
*/
40-
const questionId = questionDiv.id;
41-
if (!questionTagCountsLeftById.hasOwnProperty(questionId)) {
42-
const watchedTagCountForThisQuestion = Array.from(
43-
questionDiv.querySelectorAll('.tags > a'),
44-
a => a.textContent!,
45-
)
46-
.reduce((a, tag) => a + Number(watchedTags.includes(tag)), 0);
47-
questionTagCountsLeftById[questionId] = watchedTagCountForThisQuestion;
48-
}
49-
questionTagCountsLeftById[questionId] -= 1;
50-
// User may not be watching any tags - may be just on /questions?tab=Newest page
51-
// in which case there's nothing to count, and only one socket message per question, so queue the question immediately
52-
if (watchedTags.length && questionTagCountsLeftById[questionId] !== 0) {
53-
return;
54-
}
55-
seenQuestionsIds.add(questionId);
56-
addBorderWhenClicked(questionDiv);
57-
if (focusing) {
58-
return;
59-
}
60-
const questionText = questionDiv.querySelector('.question-hyperlink')!.textContent;
61-
const questionTags = [...questionDiv.querySelectorAll('.tags > a')]
62-
.map(tagA => tagA.textContent!.replace(/\./g, ' dot '));
63-
const textToSpeak = `Question, ${siteNameSpokenText} ${questionText} ---- ${questionTags.join(', ')}`;
64-
queueUtterance(textToSpeak, questionId);
65-
});
32+
/* StackExchange will send the client new info about an active question *for every question, and for every tag in that question* that you're watching
33+
* Eg if you're watching 5 tags, and a question is posted with 3 of them, the websocket will send you info 3 times
34+
* (there may be a moderate fraction of a second delay between each)
35+
* and each time, if the existing question div is already in the document, it will be completely removed and replaced
36+
* See: https://dev.stackoverflow.com/content//Js/full.en.js
37+
* search for: $('#question-summary-' + activeq.id).remove();
38+
* Rather than fiddling with the element (and with the styles added by the userscript, and with the linked audio) every time it gets replaced
39+
* just wait for the question to appear in the questions list for the nth time, where n is the number of watched tags that question has
40+
* Only on that nth time does the code below result in the questionDiv actually getting changed, watched, and linked to the utterance that gets queued
41+
*/
42+
if (!questionTagCountsLeftById.hasOwnProperty(questionId)) {
43+
const watchedTagCountForThisQuestion = Array.from(
44+
questionDiv.querySelectorAll('.tags > a'),
45+
a => a.textContent!,
46+
)
47+
.reduce((a, tag) => a + Number(watchedTags.includes(tag)), 0);
48+
questionTagCountsLeftById[questionId] = watchedTagCountForThisQuestion;
49+
}
50+
questionTagCountsLeftById[questionId] -= 1;
51+
// User may not be watching any tags - may be just on /questions?tab=Newest page
52+
// in which case there's nothing to count, and only one socket message per question, so queue the question immediately
53+
if (watchedTags.length && questionTagCountsLeftById[questionId] !== 0) {
54+
continue;
55+
}
56+
seenQuestionsIds.add(questionId);
57+
addBorderWhenClicked(questionDiv);
58+
if (focusing) {
59+
continue;
60+
}
61+
const questionText = questionDiv.querySelector('.question-hyperlink')!.textContent;
62+
const questionTags = [...questionDiv.querySelectorAll('.tags > a')]
63+
.map(tagA => tagA.textContent!.replace(/\./g, ' dot '));
64+
const textToSpeak = `Question, ${siteNameSpokenText} ${questionText} ---- ${questionTags.join(', ')}`;
65+
queueUtterance(textToSpeak, questionId);
66+
}
6667
};

Speak-New-Questions/src/questionListPage/queueUtterance.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { speakNext } from './speakNext';
22
import { getState } from './state';
33
import { pendingQuestionColor } from '../pendingQuestionColor';
44

5-
export const queueUtterance = (textToSpeak: string, questionId?: string) => {
5+
export const queueUtterance = (textToSpeak: string, questionId?: number) => {
66
const { textToSpeakQueue } = getState();
77
if (!questionId) {
88
textToSpeakQueue.push({ textToSpeak });
@@ -11,7 +11,7 @@ export const queueUtterance = (textToSpeak: string, questionId?: string) => {
1111
}
1212
return;
1313
}
14-
const questionElement = document.getElementById(questionId)!;
14+
const questionElement = document.getElementById(`question-summary-${questionId}`)!;
1515
const channel = getState().channel!;
1616
if (questionElement && questionId) {
1717
// This will pretty much always already be highlighted, but just in case

Speak-New-Questions/src/userscript-metadata-block.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// @description Speaks new question titles aloud as they come in
44
// @author CertainPerformance
55
// @namespace https://github.com/CertainPerformance/Stack-Exchange-Userscripts
6-
// @version 1.0.3
6+
// @version 1.0.4
77
// @include /^https://(?:[^/]+\.)?(?:(?:stackoverflow|serverfault|superuser|stackexchange|askubuntu|stackapps)\.com|mathoverflow\.net)/questions(?:/\d+|$|\?tab=Newest$|/tagged/.*sort=newest)/
88
// @include /^https://example\.com/fakepage$/
99
// @grant none

0 commit comments

Comments
 (0)