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