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.draganddrop;
16  
17  import java.util.ArrayList;
18  
19  import org.htmlunit.corejs.javascript.Context;
20  import org.htmlunit.corejs.javascript.Function;
21  import org.htmlunit.corejs.javascript.Scriptable;
22  import org.htmlunit.corejs.javascript.VarScope;
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.JsxSymbol;
30  import org.htmlunit.javascript.host.file.File;
31  import org.htmlunit.javascript.host.file.FileList;
32  
33  /**
34   * A JavaScript object for {@code DataTransferItemList}.
35   *
36   * @author Ahmed Ashour
37   * @author Ronald Brill
38   */
39  @JsxClass
40  public class DataTransferItemList extends HtmlUnitScriptable {
41  
42      private ArrayList<DataTransferItem> items_;
43      private FileList fileList_;
44  
45      /**
46       * JavaScript constructor.
47       */
48      @JsxConstructor
49      public void jsConstructor() {
50          // nothing to do
51      }
52  
53      /**
54       * @return the {@code length} property
55       */
56      @JsxGetter
57      public int getLength() {
58          if (items_ == null) {
59              return 0;
60          }
61          return items_.size();
62      }
63  
64      /**
65       * Creates a new {@link DataTransferItem} using the specified data and adds it to the drag data list.
66       * The item may be a {@link File} or a string of a given type. If the item is successfully added to the list,
67       * the newly-created {@link DataTransferItem} object is returned.
68       *
69       * @param context the JavaScript context
70       * @param scope the scope
71       * @param thisObj the scriptable
72       * @param args the arguments passed into the method
73       * @param function the function
74       * @return the newly-created {@link DataTransferItem} object
75       * @see <a href="http://msdn.microsoft.com/en-us/library/ms536782.aspx">MSDN documentation</a>
76       */
77      @JsxFunction
78      public static DataTransferItem add(final Context context, final VarScope scope,
79              final Scriptable thisObj, final Object[] args, final Function function) {
80          final DataTransferItemList itemList = (DataTransferItemList) thisObj;
81          if (args.length == 1) {
82              if (args[0] instanceof File file) {
83                  final DataTransferItem item = DataTransferItem.buildFileItem(file);
84                  item.setParentScope(scope);
85                  item.setPrototype(itemList.getPrototype(item.getClass()));
86  
87                  if (itemList.items_ == null) {
88                      itemList.items_ = new ArrayList<>();
89                  }
90                  itemList.items_.add(item);
91                  itemList.updateFileList();
92  
93                  return item;
94              }
95              throw JavaScriptEngine.typeError(
96                      "Failed to execute 'add' on 'DataTransferItemList': parameter 1 is not of type 'File'.");
97          }
98  
99          if (args.length > 1) {
100             final String data = JavaScriptEngine.toString(args[0]);
101             final String type = JavaScriptEngine.toString(args[1]);
102             final DataTransferItem item = DataTransferItem.buildStringItem(data, type);
103             item.setParentScope(scope);
104             item.setPrototype(itemList.getPrototype(item.getClass()));
105 
106             if (itemList.items_ == null) {
107                 itemList.items_ = new ArrayList<>();
108             }
109             itemList.items_.add(item);
110 
111             return item;
112         }
113 
114         throw JavaScriptEngine.typeError(
115                 "Failed to execute 'add' on 'DataTransferItemList' - no args provided.");
116     }
117 
118     /**
119      * Removes all DataTransferItem objects from the drag data items list, leaving the list empty.
120      */
121     @JsxFunction
122     public void clear() {
123         if (items_ != null) {
124             items_.clear();
125             if (fileList_ != null) {
126                 fileList_.updateFiles(new ArrayList<>());
127             }
128         }
129     }
130 
131     /**
132      * Removes the DataTransferItem at the specified index from the list. If the index is less
133      * than zero or greater than one less than the length of the list, the list will not be changed.
134      * @param index the zero-based index number of the item in the drag data list to remove.
135      *        If the index doesn't correspond to an existing item in the list, the list is left unchanged.
136      */
137     @JsxFunction
138     public void remove(final int index) {
139         if (items_ != null) {
140             if (index >= 0 && index < items_.size()) {
141                 items_.remove(index);
142                 updateFileList();
143             }
144         }
145     }
146 
147     /**
148      * {@inheritDoc}
149      */
150     @Override
151     public Object get(final int index, final Scriptable start) {
152         if (this == start) {
153             if (index >= 0 && index < items_.size()) {
154                 return items_.get(index);
155             }
156         }
157         return super.get(index, start);
158     }
159 
160     /**
161      * Returns an Iterator allowing to go through all keys contained in this object.
162      * @return a NativeArrayIterator
163      */
164     @JsxSymbol(symbolName = "iterator")
165     public Scriptable values() {
166         return JavaScriptEngine.newArrayIteratorTypeValues(getParentScope(), this);
167     }
168 
169     /**
170      * <span style="color:red">INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.</span>
171      * Maintains the file list for the parent DataTrasnfer object.
172      * @return the {@code files} property
173      */
174     public FileList getFiles() {
175         if (fileList_ == null) {
176             final FileList list = new FileList(new java.io.File[0]);
177             list.setParentScope(getParentScope());
178             list.setPrototype(getPrototype(list.getClass()));
179             fileList_ = list;
180 
181             if (items_ != null) {
182                 updateFileList();
183             }
184         }
185         return fileList_;
186     }
187 
188     private void updateFileList() {
189         if (fileList_ != null) {
190             final ArrayList<File> files = new ArrayList<>();
191             for (final DataTransferItem item : items_) {
192                 if (item.isFile()) {
193                     files.add(item.getAsFile());
194                 }
195             }
196             fileList_.updateFiles(files);
197         }
198     }
199 }