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