11document . addEventListener ( "DOMContentLoaded" , ( ) => {
22 browser . tabs . query ( { active : true , currentWindow : true } ) . then ( ( tabs ) => {
33 const tab = tabs [ 0 ] ;
4- // Get the problem slug from the URL
4+
55 const url = new URL ( tab . url ) ;
66 const pathParts = url . pathname . split ( "/" ) . filter ( Boolean ) ;
77 const slug = pathParts [ 1 ] || null ;
88 if ( ! slug ) {
9- document . body . innerHTML = "<p>Not a leetcode problem page</p>" ;
9+ document . getElementById ( "popupContent" ) . innerHTML = "<p>To track a problem, please visit a leetcode problem page</p>" ;
1010 return ;
1111 }
12- // Ask background for the latest problem data
13- browser . runtime . sendMessage ( { type : "GET_PROBLEM_DATA" , slug } )
12+
13+ browser . runtime
14+ . sendMessage ( { type : "GET_PROBLEM_DATA" , slug } )
1415 . then ( ( data ) => {
16+ const container = document . getElementById ( "popupContent" ) ;
1517 if ( ! data ) {
16- document . body . innerHTML = "<p>Not a leetcode problem page</p>" ;
18+ container . innerHTML = "<p>To track a problem please visit a leetcode problem page</p>" ;
1719 return ;
1820 }
19- const container = document . getElementById ( "popupContent" ) ;
2021
2122 container . innerHTML = "" ;
2223 const titleEl = document . createElement ( "h3" ) ;
@@ -34,133 +35,143 @@ document.addEventListener("DOMContentLoaded", () => {
3435
3536 // Listen for problem solved message
3637 browser . runtime . onMessage . addListener ( ( msg ) => {
37- if ( msg . type === "PROBLEM_SOLVED" && msg . slug === data . slug ) {
38- const statusEl = document . getElementById ( "status" ) ;
39- if ( statusEl ) statusEl . textContent = "Solved ✅" ;
40- }
38+ if ( msg . type === "PROBLEM_SOLVED" && msg . slug === data . slug ) {
39+ const statusEl = document . getElementById ( "status" ) ;
40+ if ( statusEl ) statusEl . textContent = "Solved ✅" ;
41+ }
4142 } ) ;
4243 } )
4344 . catch ( ( err ) => {
44- document . body . innerHTML = "<p>Unable to read this page</p>" ;
45+ document . getElementById ( "popupContent" ) . innerHTML = "<p>Unable to read this page</p>" ;
4546 console . error ( err ) ;
4647 } ) ;
4748 } ) ;
4849} ) ;
4950
5051document . addEventListener ( "DOMContentLoaded" , ( ) => {
51- browser . storage . local . get ( null ) . then ( ( allData ) => {
52- // Filter out invalid/undefined problems before displaying
53- const problems = Object . values ( allData ) . filter ( p =>
54- p &&
55- typeof p . title === 'string' && p . title !== 'Unknown Title' &&
56- typeof p . slug === 'string' && p . slug !== 'unknown-problem' &&
57- typeof p . difficulty === 'string' && p . difficulty !== 'Unknown Difficulty' &&
58- p . status === "Solved"
59- ) ;
60- // Sort by solvedAt descending (most recent first)
61- problems . sort ( ( a , b ) => ( b . solvedAt || 0 ) - ( a . solvedAt || 0 ) ) ;
52+ browser . storage . local . get ( null ) . then ( ( allData ) => {
53+ // Filter out invalid/undefined problems before displaying
54+ const problems = Object . values ( allData ) . filter (
55+ ( p ) =>
56+ p &&
57+ typeof p . title === "string" &&
58+ p . title !== "Unknown Title" &&
59+ typeof p . slug === "string" &&
60+ p . slug !== "unknown-problem" &&
61+ typeof p . difficulty === "string" &&
62+ p . difficulty !== "Unknown Difficulty" &&
63+ p . status === "Solved"
64+ ) ;
65+ // Sort by solvedAt descending (most recent first)
66+ problems . sort ( ( a , b ) => ( b . solvedAt || 0 ) - ( a . solvedAt || 0 ) ) ;
6267
63- // Collect all unique tags (flattened)
64- const tagSet = new Set ( ) ;
65- problems . forEach ( p => {
66- if ( Array . isArray ( p . tags ) ) {
67- p . tags . forEach ( tag => tagSet . add ( tag ) ) ;
68- }
68+ // Collect all unique tags (flattened)
69+ const tagSet = new Set ( ) ;
70+ problems . forEach ( ( p ) => {
71+ if ( Array . isArray ( p . tags ) ) {
72+ p . tags . forEach ( ( tag ) => tagSet . add ( tag ) ) ;
73+ }
74+ } ) ;
75+ const tags = Array . from ( tagSet ) ;
76+
77+ // Populate tag filter dropdown
78+ const tagFilter = document . getElementById ( "tagFilter" ) ;
79+ if ( tagFilter ) {
80+ // Remove old options except 'All'
81+ tagFilter . innerHTML = '<option value="all">All</option>' ;
82+ if ( tags . length > 0 ) {
83+ tags . forEach ( ( tag ) => {
84+ const opt = document . createElement ( "option" ) ;
85+ opt . value = tag ;
86+ opt . textContent = tag ;
87+ tagFilter . appendChild ( opt ) ;
6988 } ) ;
70- const tags = Array . from ( tagSet ) ;
89+ } else {
90+ const opt = document . createElement ( "option" ) ;
91+ opt . value = "none" ;
92+ opt . textContent = "No tags" ;
93+ tagFilter . appendChild ( opt ) ;
94+ }
95+ }
7196
72- // Populate tag filter dropdown
73- const tagFilter = document . getElementById ( "tagFilter" ) ;
74- if ( tagFilter ) {
75- // Remove old options except 'All'
76- tagFilter . innerHTML = '<option value="all">All</option>' ;
77- if ( tags . length > 0 ) {
78- tags . forEach ( tag => {
79- const opt = document . createElement ( "option" ) ;
80- opt . value = tag ;
81- opt . textContent = tag ;
82- tagFilter . appendChild ( opt ) ;
83- } ) ;
84- } else {
85- const opt = document . createElement ( "option" ) ;
86- opt . value = "none" ;
87- opt . textContent = "No tags" ;
88- tagFilter . appendChild ( opt ) ;
89- }
90- }
97+ // Render problems (filtered and limited)
98+ function renderProblems ( ) {
99+ const list = document . getElementById ( "solvedList" ) ;
100+ list . innerHTML = "" ;
101+ let filtered = problems ;
102+ const selectedTag = tagFilter ? tagFilter . value : "all" ;
103+ if ( selectedTag && selectedTag !== "all" && selectedTag !== "none" ) {
104+ filtered = problems . filter (
105+ ( p ) => Array . isArray ( p . tags ) && p . tags . includes ( selectedTag )
106+ ) ;
107+ }
108+ const toShow = filtered . slice ( 0 , 5 ) ;
109+ if ( toShow . length === 0 ) {
110+ list . innerHTML = "<p>No solved problems yet</p>" ;
111+ }
112+ toShow . forEach ( ( problem ) => {
113+ const item = document . createElement ( "div" ) ;
114+ item . className = "problem-item" ;
115+ const difficultyClass = problem . difficulty
116+ ? problem . difficulty . toLowerCase ( )
117+ : "" ;
118+ // Use DOM methods instead of innerHTML for safety
119+ const link = document . createElement ( "a" ) ;
120+ link . href = problem . url ;
121+ link . target = "_blank" ;
122+ link . textContent = problem . title ;
91123
92- // Render problems (filtered and limited)
93- function renderProblems ( ) {
94- const list = document . getElementById ( "solvedList" ) ;
95- list . innerHTML = "" ;
96- let filtered = problems ;
97- const selectedTag = tagFilter ? tagFilter . value : "all" ;
98- if ( selectedTag && selectedTag !== "all" && selectedTag !== "none" ) {
99- filtered = problems . filter ( p => Array . isArray ( p . tags ) && p . tags . includes ( selectedTag ) ) ;
100- }
101- const toShow = filtered . slice ( 0 , 5 ) ;
102- if ( toShow . length === 0 ) {
103- list . innerHTML = "<p>No solved problems yet</p>" ;
104- }
105- toShow . forEach ( problem => {
106- const item = document . createElement ( "div" ) ;
107- item . className = "problem-item" ;
108- const difficultyClass = problem . difficulty ? problem . difficulty . toLowerCase ( ) : "" ;
109- // Use DOM methods instead of innerHTML for safety
110- const link = document . createElement ( 'a' ) ;
111- link . href = problem . url ;
112- link . target = '_blank' ;
113- link . textContent = problem . title ;
124+ const diffSpan = document . createElement ( "span" ) ;
125+ diffSpan . className = `difficulty ${ difficultyClass } ` ;
126+ diffSpan . textContent = problem . difficulty ;
114127
115- const diffSpan = document . createElement ( 'span' ) ;
116- diffSpan . className = `difficulty ${ difficultyClass } ` ;
117- diffSpan . textContent = problem . difficulty ;
128+ const tagsSpan = document . createElement ( "span" ) ;
129+ tagsSpan . style . fontSize = "0.85em" ;
130+ tagsSpan . style . color =
131+ problem . tags && problem . tags . length > 0 ? "#666" : "#bbb" ;
132+ tagsSpan . style . marginLeft = "8px" ;
133+ tagsSpan . textContent =
134+ problem . tags && problem . tags . length > 0
135+ ? `[${ problem . tags . join ( ", " ) } ]`
136+ : "[No tags]" ;
118137
119- const tagsSpan = document . createElement ( 'span' ) ;
120- tagsSpan . style . fontSize = '0.85em' ;
121- tagsSpan . style . color = problem . tags && problem . tags . length > 0 ? '#666' : '#bbb' ;
122- tagsSpan . style . marginLeft = '8px' ;
123- tagsSpan . textContent = problem . tags && problem . tags . length > 0
124- ? `[${ problem . tags . join ( ', ' ) } ]`
125- : '[No tags]' ;
138+ item . appendChild ( link ) ;
139+ item . appendChild ( diffSpan ) ;
140+ item . appendChild ( tagsSpan ) ;
141+ list . appendChild ( item ) ;
142+ } ) ;
143+ }
126144
127- item . appendChild ( link ) ;
128- item . appendChild ( diffSpan ) ;
129- item . appendChild ( tagsSpan ) ;
130- list . appendChild ( item ) ;
131- } ) ;
132- }
145+ if ( tagFilter ) {
146+ tagFilter . addEventListener ( "change" , renderProblems ) ;
147+ }
148+ renderProblems ( ) ;
149+ } ) ;
133150
134- if ( tagFilter ) {
135- tagFilter . addEventListener ( "change" , renderProblems ) ;
136- }
137- renderProblems ( ) ;
151+ // View All link opens options page
152+ const viewAllLink = document . getElementById ( "viewAllLink" ) ;
153+ if ( viewAllLink ) {
154+ viewAllLink . addEventListener ( "click" , ( e ) => {
155+ e . preventDefault ( ) ;
156+ if ( browser . runtime && browser . runtime . openOptionsPage ) {
157+ browser . runtime . openOptionsPage ( ) ;
158+ } else {
159+ window . open ( "../options/options.html" , "_blank" ) ;
160+ }
138161 } ) ;
139-
140- // View All link opens options page
141- const viewAllLink = document . getElementById ( "viewAllLink" ) ;
142- if ( viewAllLink ) {
143- viewAllLink . addEventListener ( "click" , ( e ) => {
144- e . preventDefault ( ) ;
145- if ( browser . runtime && browser . runtime . openOptionsPage ) {
146- browser . runtime . openOptionsPage ( ) ;
147- } else {
148- window . open ( "../options/options.html" , "_blank" ) ;
149- }
150- } ) ;
151- }
162+ }
152163} ) ;
153164
154165document . addEventListener ( "DOMContentLoaded" , ( ) => {
155- const optionsBtn = document . getElementById ( "optionsBtn" ) ;
156- if ( optionsBtn ) {
157- optionsBtn . addEventListener ( "click" , ( ) => {
158- if ( browser . runtime && browser . runtime . openOptionsPage ) {
159- browser . runtime . openOptionsPage ( ) ;
160- } else {
161- // fallback for browsers that don't support openOptionsPage
162- window . open ( "../options/options.html" , "_blank" ) ;
163- }
164- } ) ;
165- }
166+ const optionsBtn = document . getElementById ( "optionsBtn" ) ;
167+ if ( optionsBtn ) {
168+ optionsBtn . addEventListener ( "click" , ( ) => {
169+ if ( browser . runtime && browser . runtime . openOptionsPage ) {
170+ browser . runtime . openOptionsPage ( ) ;
171+ } else {
172+ // fallback for browsers that don't support openOptionsPage
173+ window . open ( "../options/options.html" , "_blank" ) ;
174+ }
175+ } ) ;
176+ }
166177} ) ;
0 commit comments