View Javadoc
1   /*
2    * Copyright (c) 2002-2026 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript.host;
16  
17  import java.io.IOException;
18  import java.net.MalformedURLException;
19  import java.net.URL;
20  
21  import org.htmlunit.WebWindow;
22  import org.htmlunit.html.HtmlPage;
23  import org.htmlunit.javascript.HtmlUnitScriptable;
24  import org.htmlunit.javascript.JavaScriptEngine;
25  import org.htmlunit.javascript.configuration.JsxClass;
26  import org.htmlunit.javascript.configuration.JsxConstructor;
27  import org.htmlunit.javascript.configuration.JsxFunction;
28  import org.htmlunit.javascript.configuration.JsxGetter;
29  import org.htmlunit.javascript.configuration.JsxSetter;
30  import org.htmlunit.util.StringUtils;
31  
32  /**
33   * JavaScript host object for the client's browsing history.
34   *
35   * @author Mike Bowler
36   * @author Chris Erskine
37   * @author Daniel Gredler
38   * @author Ahmed Ashour
39   * @author Ronald Brill
40   * @author Adam Afeltowicz
41   * @author Lai Quang Duong
42   *
43   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/History">MDN Documentation</a>
44   */
45  @JsxClass
46  public class History extends HtmlUnitScriptable {
47      private static final String SCROLL_RESTAURATION_AUTO = "auto";
48      private static final String SCROLL_RESTAURATION_MANUAL = "manual";
49  
50      private String scrollRestoration_ = SCROLL_RESTAURATION_AUTO;
51  
52      /**
53       * Creates an instance of this object.
54       */
55      @JsxConstructor
56      public void jsConstructor() {
57          // nothing to do
58      }
59  
60      /**
61       * Returns the {@code length} property.
62       *
63       * @return the number of entries in the session history
64       */
65      @JsxGetter
66      public int getLength() {
67          final WebWindow w = getWindow().getWebWindow();
68          return w.getHistory().getLength();
69      }
70  
71      /**
72       * Returns the {@code state} property.
73       *
74       * @return the current history state object
75       */
76      @JsxGetter
77      public Object getState() {
78          final WebWindow w = getWindow().getWebWindow();
79          return w.getHistory().getCurrentState();
80      }
81  
82      /**
83       * Navigates one step back in the session history.
84       */
85      @JsxFunction
86      public void back() {
87          try {
88              getWindow().getWebWindow().getHistory().back();
89          }
90          catch (final IOException e) {
91              throw JavaScriptEngine.throwAsScriptRuntimeEx(e);
92          }
93      }
94  
95      /**
96       * Navigates one step forward in the session history.
97       */
98      @JsxFunction
99      public void forward() {
100         try {
101             getWindow().getWebWindow().getHistory().forward();
102         }
103         catch (final IOException e) {
104             throw JavaScriptEngine.throwAsScriptRuntimeEx(e);
105         }
106     }
107 
108     /**
109      * Navigates by the given number of steps relative to the current position in the session history.
110      *
111      * @param relativeIndex the relative number of steps to navigate (positive or negative)
112      */
113     @JsxFunction
114     public void go(final int relativeIndex) {
115         try {
116             getWindow().getWebWindow().getHistory().go(relativeIndex);
117         }
118         catch (final IOException e) {
119             throw JavaScriptEngine.throwAsScriptRuntimeEx(e);
120         }
121     }
122 
123     /**
124      * Replaces the current history entry with the given state.
125      *
126      * @param object the new state object
127      * @param title the title (currently ignored by most browsers)
128      * @param url an optional new URL for the history entry
129      */
130     @JsxFunction
131     public void replaceState(final Object object, final String title, final Object url) {
132         final WebWindow w = getWindow().getWebWindow();
133         try {
134             w.getHistory().replaceState(object, buildNewStateUrl(w, url));
135         }
136         catch (final MalformedURLException e) {
137             throw JavaScriptEngine.throwAsScriptRuntimeEx(e);
138         }
139     }
140 
141     /**
142      * Pushes a new state onto the session history stack.
143      *
144      * @param object the new state object
145      * @param title the title (currently ignored by most browsers)
146      * @param url an optional new URL for the new history entry
147      */
148     @JsxFunction
149     public void pushState(final Object object, final String title, final Object url) {
150         final WebWindow w = getWindow().getWebWindow();
151         try {
152             w.getHistory().pushState(object, buildNewStateUrl(w, url));
153         }
154         catch (final IOException e) {
155             throw JavaScriptEngine.throwAsScriptRuntimeEx(e);
156         }
157     }
158 
159     private static URL buildNewStateUrl(final WebWindow webWindow, final Object url) throws MalformedURLException {
160         URL newStateUrl = null;
161         if (url != null && !JavaScriptEngine.isUndefined(url)) {
162             final String urlString = JavaScriptEngine.toString(url);
163             if (StringUtils.isNotBlank(urlString)) {
164                 final HtmlPage page = (HtmlPage) webWindow.getEnclosedPage();
165                 newStateUrl = page.getFullyQualifiedUrl(urlString);
166             }
167         }
168         return newStateUrl;
169     }
170 
171     /**
172      * Returns the {@code scrollRestoration} property.
173      *
174      * @return the {@code scrollRestoration} property
175      */
176     @JsxGetter
177     public String getScrollRestoration() {
178         return scrollRestoration_;
179     }
180 
181     /**
182      * Sets the {@code scrollRestoration} property.
183      *
184      * @param scrollRestoration the new value; either {@code "auto"} or {@code "manual"}
185      */
186     @JsxSetter
187     public void setScrollRestoration(final String scrollRestoration) {
188         if (SCROLL_RESTAURATION_AUTO.equals(scrollRestoration)) {
189             scrollRestoration_ = SCROLL_RESTAURATION_AUTO;
190             return;
191         }
192         if (SCROLL_RESTAURATION_MANUAL.equals(scrollRestoration)) {
193             scrollRestoration_ = SCROLL_RESTAURATION_MANUAL;
194         }
195     }
196 }