@@ -221,9 +221,29 @@ pub const HTMLAnchorElement = struct {
221221 return parser .anchorGetHref (self );
222222 }
223223
224- pub fn set_href (self : * parser.Anchor , href : []const u8 , page : * const Page ) ! void {
224+ pub fn set_href (self : * parser.Anchor , href : []const u8 , page : * Page ) ! void {
225225 const full = try urlStitch (page .call_arena , href , page .url .getHref (), .{});
226- return parser .anchorSetHref (self , full );
226+
227+ // Get the stored internal URL if we had one.
228+ if (page .getObjectData (self )) | internal_url | {
229+ const u = NativeURL .fromInternal (internal_url );
230+ // Reparse with the new href.
231+ _ = try u .reparse (full );
232+ errdefer u .deinit ();
233+
234+ // TODO: Remove the entry from the map on an error situation.
235+
236+ return parser .anchorSetHref (self , u .getHref ());
237+ }
238+
239+ // We don't have internal URL stored in object_data yet.
240+ // Create one for this anchor element.
241+ const u = try NativeURL .parse (full , null );
242+ errdefer u .deinit ();
243+ // Save to map.
244+ try page .putObjectData (self , u .internal .? );
245+
246+ return parser .anchorSetHref (self , u .getHref ());
227247 }
228248
229249 pub fn get_hreflang (self : * parser.Anchor ) ! []const u8 {
@@ -258,170 +278,188 @@ pub const HTMLAnchorElement = struct {
258278 return try parser .nodeSetTextContent (parser .anchorToNode (self ), v );
259279 }
260280
261- fn url (self : * parser.Anchor , page : * Page ) ! URL {
262- // Although the URL.constructor union accepts an .{.element = X}, we
263- // can't use this here because the behavior is different.
264- // URL.constructor(document.createElement('a')
265- // should fail (a.href isn't a valid URL)
266- // But
267- // document.createElement('a').host
268- // should not fail, it should return an empty string
269- if (try parser .elementGetAttribute (@ptrCast (@alignCast (self )), "href" )) | href | {
270- return URL .constructor (.{ .string = href }, null , page ); // TODO inject base url
281+ fn getHref (self : * parser.Anchor ) ! ? []const u8 {
282+ return parser .elementGetAttribute (@ptrCast (@alignCast (self )), "href" );
283+ }
284+
285+ /// Returns the URL associated with given anchor element.
286+ /// Creates a new URL object if not created before.
287+ fn getURL (self : * parser.Anchor , page : * Page ) ! NativeURL {
288+ if (page .getObjectData (self )) | internal_url | {
289+ return NativeURL .fromInternal (internal_url );
271290 }
272- return .empty ;
291+
292+ // Try to get href string.
293+ const maybe_anchor_href = try getHref (self );
294+ if (maybe_anchor_href ) | anchor_href | {
295+ // Allocate a URL for this anchor element.
296+ const u = try NativeURL .parse (anchor_href , null );
297+ // Save in map.
298+ try page .putObjectData (self , u .internal .? );
299+
300+ return u ;
301+ }
302+
303+ // No anchor href string found; let's just return an error.
304+ return error .HrefAttributeNotGiven ;
273305 }
274306
275307 // TODO return a disposable string
276308 pub fn get_origin (self : * parser.Anchor , page : * Page ) ! []const u8 {
277- var u = try url (self , page );
278- return u .get_origin (page );
309+ const u = getURL (self , page ) catch return "" ;
310+ // Though we store the URL in object data map, we still have to allocate
311+ // for origin string sadly.
312+ return u .getOrigin (page .arena );
279313 }
280314
281315 // TODO return a disposable string
282316 pub fn get_protocol (self : * parser.Anchor , page : * Page ) ! []const u8 {
283- var u = try url (self , page );
284- return u .get_protocol ();
317+ const u = getURL (self , page ) catch return "" ;
318+ return u .getProtocol ();
285319 }
286320
287321 pub fn set_protocol (self : * parser.Anchor , v : []const u8 , page : * Page ) ! void {
288- const arena = page .arena ;
289- _ = arena ;
290- var u = try url (self , page );
291-
292- u .set_protocol (v );
293- const href = try u .get_href (page );
294- try parser .anchorSetHref (self , href );
322+ const u = try getURL (self , page );
323+ try u .setProtocol (v );
324+ return parser .anchorSetHref (self , u .getHref ());
295325 }
296326
297- pub fn get_host (self : * parser.Anchor , page : * Page ) ! []const u8 {
298- var u = try url (self , page );
299- return u .get_host ();
300- }
301-
302- pub fn set_host (self : * parser.Anchor , v : []const u8 , page : * Page ) ! void {
303- // search : separator
304- var p : ? []const u8 = null ;
305- var h : []const u8 = undefined ;
306- for (v , 0.. ) | c , i | {
307- if (c == ':' ) {
308- h = v [0.. i ];
309- //p = try std.fmt.parseInt(u16, v[i + 1 ..], 10);
310- p = v [i + 1 .. ];
311- break ;
312- }
313- }
314-
315- var u = try url (self , page );
316-
317- if (p ) | port | {
318- u .set_host (h );
319- u .set_port (port );
320- } else {
321- u .set_host (v );
322- }
327+ const NativeURL = @import ("../../url.zig" ).URL ;
323328
324- const href = try u .get_href (page );
325- try parser .anchorSetHref (self , href );
329+ // TODO: Return a disposable string.
330+ pub fn get_host (self : * parser.Anchor , page : * Page ) ! []const u8 {
331+ const u = getURL (self , page ) catch return "" ;
332+ return u .host ();
326333 }
327334
328- pub fn get_hostname (self : * parser.Anchor , page : * Page ) ! []const u8 {
329- var u = try url (self , page );
330- return u .get_hostname ();
331- }
335+ pub fn set_host (self : * parser.Anchor , host_str : []const u8 , page : * Page ) ! void {
336+ const u = blk : {
337+ if (page .getObjectData (self )) | internal_url | {
338+ break :blk NativeURL .fromInternal (internal_url );
339+ }
332340
333- pub fn set_hostname (self : * parser.Anchor , v : []const u8 , page : * Page ) ! void {
334- var u = try url (self , page );
335- u .set_host (v );
336- const href = try u .get_href (page );
337- try parser .anchorSetHref (self , href );
338- }
341+ const maybe_anchor_href = try getHref (self );
342+ if (maybe_anchor_href ) | anchor_href | {
343+ const new_u = try NativeURL .parse (anchor_href , null );
344+ try page .putObjectData (self , new_u .internal .? );
345+ break :blk new_u ;
346+ }
347+
348+ // Last resort; try to create URL object out of host_str.
349+ const new_u = try NativeURL .parse (host_str , null );
350+ // We can just return here since host is updated.
351+ return page .putObjectData (self , new_u .internal .? );
352+ };
353+
354+ try u .setHost (host_str );
355+ return parser .anchorSetHref (self , u .getHref ());
356+ }
357+
358+ //pub fn get_hostname(self: *parser.Anchor, page: *Page) ![]const u8 {
359+ // const maybe_href_str = try getAnchorHref(self);
360+ // const href_str = maybe_href_str orelse return "";
361+ //
362+ // const u = try NativeURL.parse(href_str, null);
363+ // defer u.deinit();
364+ //
365+ // return page.arena.dupe(u8, u.getHostname());
366+ //}
367+
368+ //pub fn set_hostname(self: *parser.Anchor, v: []const u8) !void {
369+ // const maybe_href_str = try getAnchorHref(self);
370+ //
371+ // if (maybe_href_str) |href_str| {
372+ // const u = try NativeURL.parse(href_str, null);
373+ // defer u.deinit();
374+ //
375+ // try u.setHostname(v);
376+ //
377+ // return parser.anchorSetHref(self, u.getHref());
378+ // }
379+ //
380+ // // No href string there; use the given value as href.
381+ // const u = try NativeURL.parse(v, null);
382+ // defer u.deinit();
383+ //
384+ // return parser.anchorSetHref(self, u.getHref());
385+ //}
339386
340387 // TODO return a disposable string
341388 pub fn get_port (self : * parser.Anchor , page : * Page ) ! []const u8 {
342- var u = try url (self , page );
343- return u .get_port ();
389+ const u = getURL (self , page ) catch return "" ;
390+ return u .getPort ();
344391 }
345392
346- pub fn set_port (self : * parser.Anchor , v : ? []const u8 , page : * Page ) ! void {
347- var u = try url (self , page );
393+ pub fn set_port (self : * parser.Anchor , maybe_port : ? []const u8 , page : * Page ) ! void {
394+ // TODO: Check for valid port (u16 integer).
395+ if (maybe_port ) | port | {
396+ const u = try getURL (self , page );
397+ try u .setPort (port );
348398
349- if (v != null and v .? .len > 0 ) {
350- u .set_host (v .? );
399+ return parser .anchorSetHref (self , u .getHref ());
351400 }
352-
353- const href = try u .get_href (page );
354- try parser .anchorSetHref (self , href );
355401 }
356402
357403 // TODO return a disposable string
358404 pub fn get_username (self : * parser.Anchor , page : * Page ) ! []const u8 {
359- var u = try url (self , page );
360- return u .get_username () ;
405+ const u = try getURL (self , page );
406+ return u .getUsername () orelse "" ;
361407 }
362408
363- pub fn set_username (self : * parser.Anchor , v : ? []const u8 , page : * Page ) ! void {
364- if (v ) | username | {
365- var u = try url (self , page );
366- u .set_username (username );
367-
368- const href = try u .get_href (page );
369- try parser .anchorSetHref (self , href );
409+ pub fn set_username (self : * parser.Anchor , maybe_username : ? []const u8 , page : * Page ) ! void {
410+ if (maybe_username ) | username | {
411+ const u = try getURL (self , page );
412+ try u .setUsername (username );
413+ try parser .anchorSetHref (self , u .getHref ());
370414 }
371415 }
372416
373417 pub fn get_password (self : * parser.Anchor , page : * Page ) ! []const u8 {
374- var u = try url (self , page );
375- return u .get_password () ;
418+ const u = try getURL (self , page );
419+ return u .getPassword () orelse "" ;
376420 }
377421
378- pub fn set_password (self : * parser.Anchor , v : ? []const u8 , page : * Page ) ! void {
379- if (v ) | password | {
380- var u = try url (self , page );
381- u .set_password (password );
382-
383- const href = try u .get_href (page );
384- try parser .anchorSetHref (self , href );
422+ pub fn set_password (self : * parser.Anchor , maybe_password : ? []const u8 , page : * Page ) ! void {
423+ if (maybe_password ) | password | {
424+ const u = try getURL (self , page );
425+ try u .setPassword (password );
426+ try parser .anchorSetHref (self , u .getHref ());
385427 }
386428 }
387429
388430 // TODO return a disposable string
389431 pub fn get_pathname (self : * parser.Anchor , page : * Page ) ! []const u8 {
390- var u = try url (self , page );
391- return u .get_pathname ();
432+ const u = try getURL (self , page );
433+ return u .getPath ();
392434 }
393435
394- pub fn set_pathname (self : * parser.Anchor , v : []const u8 , page : * Page ) ! void {
395- var u = try url (self , page );
396- u .set_pathname (v );
397- const href = try u .get_href (page );
398- try parser .anchorSetHref (self , href );
436+ pub fn set_pathname (self : * parser.Anchor , pathname : []const u8 , page : * Page ) ! void {
437+ const u = try getURL (self , page );
438+ try u .setPath (pathname );
439+ return parser .anchorSetHref (self , u .getHref ());
399440 }
400441
401442 pub fn get_search (self : * parser.Anchor , page : * Page ) ! []const u8 {
402- var u = try url (self , page );
403- return u .get_search ( page ) ;
443+ const u = try getURL (self , page );
444+ return u .getSearch () orelse "" ;
404445 }
405446
406- pub fn set_search (self : * parser.Anchor , v : []const u8 , page : * Page ) ! void {
407- var u = try url (self , page );
408- try u .set_search (v , page );
409-
410- const href = try u .get_href (page );
411- try parser .anchorSetHref (self , href );
447+ pub fn set_search (self : * parser.Anchor , search : []const u8 , page : * Page ) ! void {
448+ const u = try getURL (self , page );
449+ u .setSearch (search );
450+ return parser .anchorSetHref (self , u .getHref ());
412451 }
413452
414453 // TODO return a disposable string
415454 pub fn get_hash (self : * parser.Anchor , page : * Page ) ! []const u8 {
416- var u = try url (self , page );
417- return u .get_hash () ;
455+ const u = try getURL (self , page );
456+ return u .getHash () orelse "" ;
418457 }
419458
420- pub fn set_hash (self : * parser.Anchor , v : []const u8 , page : * Page ) ! void {
421- var u = try url (self , page );
422- u .set_hash (v );
423- const href = try u .get_href (page );
424- try parser .anchorSetHref (self , href );
459+ pub fn set_hash (self : * parser.Anchor , hash : []const u8 , page : * Page ) ! void {
460+ const u = try getURL (self , page );
461+ u .setHash (hash );
462+ return parser .anchorSetHref (self , u .getHref ());
425463 }
426464};
427465
0 commit comments