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.dom;
16
17 import org.htmlunit.html.impl.SimpleRange;
18 import org.htmlunit.javascript.HtmlUnitScriptable;
19 import org.htmlunit.javascript.JavaScriptEngine;
20 import org.htmlunit.javascript.configuration.JsxClass;
21 import org.htmlunit.javascript.configuration.JsxConstructor;
22 import org.htmlunit.javascript.configuration.JsxGetter;
23
24 /**
25 * The JavaScript object that represents an AbstractRange.
26 *
27 * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/AbstractRange">MDN Documentation</a>
28 * @author Ronald Brill
29 */
30 @JsxClass
31 public class AbstractRange extends HtmlUnitScriptable {
32
33 private Node startContainer_;
34 private Node endContainer_;
35 private int startOffset_;
36 private int endOffset_;
37
38 /**
39 * Creates an instance.
40 */
41 public AbstractRange() {
42 super();
43 }
44
45 /**
46 * Creates an instance.
47 */
48 @JsxConstructor
49 public void jsConstructor() {
50 throw JavaScriptEngine.typeErrorIllegalConstructor();
51 }
52
53 /**
54 * Creates a new instance.
55 *
56 * @param startContainer the start node
57 * @param endContainer the end node
58 * @param startOffset the start offset
59 * @param endOffset the end offset
60 */
61 protected AbstractRange(final Node startContainer, final Node endContainer,
62 final int startOffset, final int endOffset) {
63 super();
64 startContainer_ = startContainer;
65 endContainer_ = endContainer;
66
67 startOffset_ = startOffset;
68 endOffset_ = endOffset;
69 }
70
71 /**
72 * Returns the start container.
73 * @return the start container
74 */
75 protected Node internGetStartContainer() {
76 return startContainer_;
77 }
78
79 /**
80 * Sets the start container.
81 *
82 * @param startContainer the new start container
83 */
84 protected void internSetStartContainer(final Node startContainer) {
85 startContainer_ = startContainer;
86 }
87
88 /**
89 * Returns the end container.
90 * @return the end container
91 */
92 protected Node internGetEndContainer() {
93 return endContainer_;
94 }
95
96 /**
97 * Sets the end container.
98 *
99 * @param endContainer the new end container
100 */
101 protected void internSetEndContainer(final Node endContainer) {
102 endContainer_ = endContainer;
103 }
104
105 /**
106 * Returns the start offset.
107 * @return the start offset
108 */
109 protected int internGetStartOffset() {
110 return startOffset_;
111 }
112
113 /**
114 * Sets the start offset.
115 *
116 * @param startOffset the new start offset
117 */
118 protected void internSetStartOffset(final int startOffset) {
119 startOffset_ = startOffset;
120 }
121
122 /**
123 * Returns the end offset.
124 * @return the end offset
125 */
126 protected int internGetEndOffset() {
127 return endOffset_;
128 }
129
130 /**
131 * Sets the end offset.
132 *
133 * @param endOffset the new end offset
134 */
135 protected void internSetEndOffset(final int endOffset) {
136 endOffset_ = endOffset;
137 }
138
139 /**
140 * {@inheritDoc}
141 */
142 @Override
143 public Object getDefaultValue(final Class<?> hint) {
144 if (getPrototype() == null
145 || startContainer_ == null
146 || endContainer_ == null) {
147 return super.getDefaultValue(hint);
148 }
149 return getSimpleRange().toString();
150 }
151
152 /**
153 * Gets the node within which the Range begins.
154 * @return <code>undefined</code> if not initialized
155 */
156 @JsxGetter
157 public Object getStartContainer() {
158 if (startContainer_ == null) {
159 return JavaScriptEngine.UNDEFINED;
160 }
161 return startContainer_;
162 }
163
164 /**
165 * Gets the node within which the Range ends.
166 * @return <code>undefined</code> if not initialized
167 */
168 @JsxGetter
169 public Object getEndContainer() {
170 if (endContainer_ == null) {
171 return JavaScriptEngine.UNDEFINED;
172 }
173 return endContainer_;
174 }
175
176 /**
177 * Gets the offset within the starting node of the Range.
178 * @return <code>0</code> if not initialized
179 */
180 @JsxGetter
181 public int getStartOffset() {
182 return startOffset_;
183 }
184
185 /**
186 * Gets the offset within the end node of the Range.
187 * @return <code>0</code> if not initialized
188 */
189 @JsxGetter
190 public int getEndOffset() {
191 return endOffset_;
192 }
193
194 /**
195 * Indicates if the range is collapsed.
196 * @return {@code true} if the range is collapsed
197 */
198 @JsxGetter
199 public boolean isCollapsed() {
200 return startContainer_ == endContainer_ && startOffset_ == endOffset_;
201 }
202
203 /**
204 * Returns a {@link SimpleRange} version of this object.
205 * @return a {@link SimpleRange} version of this object
206 */
207 public SimpleRange getSimpleRange() {
208 return new SimpleRange(startContainer_.getDomNodeOrNull(), startOffset_,
209 endContainer_.getDomNodeOrDie(), endOffset_);
210 }
211
212 @Override
213 protected Object equivalentValues(final Object value) {
214 if (!(value instanceof AbstractRange other)) {
215 return false;
216 }
217 return startContainer_ == other.startContainer_
218 && endContainer_ == other.endContainer_
219 && startOffset_ == other.startOffset_
220 && endOffset_ == other.endOffset_;
221 }
222 }