View Javadoc
1   /*
2    * Copyright (c) 2002-2025 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.apache.commons.lang3.StringUtils;
22  import org.htmlunit.WebWindow;
23  import org.htmlunit.html.HtmlPage;
24  import org.htmlunit.javascript.HtmlUnitScriptable;
25  import org.htmlunit.javascript.JavaScriptEngine;
26  import org.htmlunit.javascript.configuration.JsxClass;
27  import org.htmlunit.javascript.configuration.JsxConstructor;
28  import org.htmlunit.javascript.configuration.JsxFunction;
29  import org.htmlunit.javascript.configuration.JsxGetter;
30  import org.htmlunit.javascript.configuration.JsxSetter;
31  
32  /**
33   * A JavaScript object for the client's browsing history.
34   *
35   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
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  @JsxClass
44  public class History extends HtmlUnitScriptable {
45      private static final String SCROLL_RESTAURATION_AUTO = "auto";
46      private static final String SCROLL_RESTAURATION_MANUAL = "manual";
47  
48      private String scrollRestoration_ = SCROLL_RESTAURATION_AUTO;
49  
50      /**
51       * JavaScript constructor.
52       */
53      @JsxConstructor
54      public void jsConstructor() {
55          // nothing to do
56      }
57  
58      /**
59       * Returns the {@code length} property.
60       * @return the {@code length} property
61       */
62      @JsxGetter
63      public int getLength() {
64          final WebWindow w = getWindow().getWebWindow();
65          return w.getHistory().getLength();
66      }
67  
68      /**
69       * Returns the {@code state} property.
70       * @return the {@code state} property
71       */
72      @JsxGetter
73      public Object getState() {
74          final WebWindow w = getWindow().getWebWindow();
75          return w.getHistory().getCurrentState();
76      }
77  
78      /**
79       * JavaScript function "back".
80       */
81      @JsxFunction
82      public void back() {
83          try {
84              getWindow().getWebWindow().getHistory().back();
85          }
86          catch (final IOException e) {
87              throw JavaScriptEngine.throwAsScriptRuntimeEx(e);
88          }
89      }
90  
91      /**
92       * JavaScript function "forward".
93       */
94      @JsxFunction
95      public void forward() {
96          try {
97              getWindow().getWebWindow().getHistory().forward();
98          }
99          catch (final IOException e) {
100             throw JavaScriptEngine.throwAsScriptRuntimeEx(e);
101         }
102     }
103 
104     /**
105      * JavaScript function "go".
106      * @param relativeIndex the relative index
107      */
108     @JsxFunction
109     public void go(final int relativeIndex) {
110         try {
111             getWindow().getWebWindow().getHistory().go(relativeIndex);
112         }
113         catch (final IOException e) {
114             throw JavaScriptEngine.throwAsScriptRuntimeEx(e);
115         }
116     }
117 
118     /**
119      * Replaces a state.
120      * @param object the state object
121      * @param title the title
122      * @param url an optional URL
123      */
124     @JsxFunction
125     public void replaceState(final Object object, final String title, final Object url) {
126         final WebWindow w = getWindow().getWebWindow();
127         try {
128             w.getHistory().replaceState(object, buildNewStateUrl(w, url));
129         }
130         catch (final MalformedURLException e) {
131             throw JavaScriptEngine.throwAsScriptRuntimeEx(e);
132         }
133     }
134 
135     /**
136      * Pushes a state.
137      * @param object the state object
138      * @param title the title
139      * @param url an optional URL
140      */
141     @JsxFunction
142     public void pushState(final Object object, final String title, final Object url) {
143         final WebWindow w = getWindow().getWebWindow();
144         try {
145             w.getHistory().pushState(object, buildNewStateUrl(w, url));
146         }
147         catch (final IOException e) {
148             throw JavaScriptEngine.throwAsScriptRuntimeEx(e);
149         }
150     }
151 
152     private static URL buildNewStateUrl(final WebWindow webWindow, final Object url) throws MalformedURLException {
153         URL newStateUrl = null;
154         if (url != null && !JavaScriptEngine.isUndefined(url)) {
155             final String urlString = JavaScriptEngine.toString(url);
156             if (StringUtils.isNotBlank(urlString)) {
157                 final HtmlPage page = (HtmlPage) webWindow.getEnclosedPage();
158                 newStateUrl = page.getFullyQualifiedUrl(urlString);
159             }
160         }
161         return newStateUrl;
162     }
163 
164     /**
165      * Returns the {@code scrollRestoration} property.
166      * @return the {@code scrollRestoration} property
167      */
168     @JsxGetter
169     public String getScrollRestoration() {
170         return scrollRestoration_;
171     }
172 
173     /**
174      * @param scrollRestoration the new value
175      */
176     @JsxSetter
177     public void setScrollRestoration(final String scrollRestoration) {
178         if (SCROLL_RESTAURATION_AUTO.equals(scrollRestoration)) {
179             scrollRestoration_ = SCROLL_RESTAURATION_AUTO;
180             return;
181         }
182         if (SCROLL_RESTAURATION_MANUAL.equals(scrollRestoration)) {
183             scrollRestoration_ = SCROLL_RESTAURATION_MANUAL;
184         }
185     }
186 }