DataTransfer.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*
  2. * Copyright (c) 2024, Tim Flynn <trflynn89@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibJS/Runtime/Realm.h>
  7. #include <LibWeb/Bindings/DataTransferPrototype.h>
  8. #include <LibWeb/Bindings/Intrinsics.h>
  9. #include <LibWeb/FileAPI/Blob.h>
  10. #include <LibWeb/FileAPI/File.h>
  11. #include <LibWeb/FileAPI/FileList.h>
  12. #include <LibWeb/HTML/DataTransfer.h>
  13. namespace Web::HTML {
  14. JS_DEFINE_ALLOCATOR(DataTransfer);
  15. namespace DataTransferEffect {
  16. #define __ENUMERATE_DATA_TRANSFER_EFFECT(name) FlyString name = #name##_fly_string;
  17. ENUMERATE_DATA_TRANSFER_EFFECTS
  18. #undef __ENUMERATE_DATA_TRANSFER_EFFECT
  19. }
  20. JS::NonnullGCPtr<DataTransfer> DataTransfer::construct_impl(JS::Realm& realm)
  21. {
  22. return realm.heap().allocate<DataTransfer>(realm, realm);
  23. }
  24. DataTransfer::DataTransfer(JS::Realm& realm)
  25. : PlatformObject(realm)
  26. {
  27. }
  28. DataTransfer::~DataTransfer() = default;
  29. void DataTransfer::initialize(JS::Realm& realm)
  30. {
  31. Base::initialize(realm);
  32. WEB_SET_PROTOTYPE_FOR_INTERFACE(DataTransfer);
  33. }
  34. void DataTransfer::set_drop_effect(String const& drop_effect)
  35. {
  36. set_drop_effect(FlyString { drop_effect });
  37. }
  38. void DataTransfer::set_drop_effect(FlyString drop_effect)
  39. {
  40. using namespace DataTransferEffect;
  41. // On setting, if the new value is one of "none", "copy", "link", or "move", then the attribute's current value must
  42. // be set to the new value. Other values must be ignored.
  43. if (drop_effect.is_one_of(none, copy, link, move))
  44. m_drop_effect = AK::move(drop_effect);
  45. }
  46. void DataTransfer::set_effect_allowed(String const& effect_allowed)
  47. {
  48. set_effect_allowed(FlyString { effect_allowed });
  49. }
  50. void DataTransfer::set_effect_allowed(FlyString effect_allowed)
  51. {
  52. // On setting, if drag data store's mode is the read/write mode and the new value is one of "none", "copy", "copyLink",
  53. // "copyMove", "link", "linkMove", "move", "all", or "uninitialized", then the attribute's current value must be set
  54. // to the new value. Otherwise, it must be left unchanged.
  55. if (m_associated_drag_data_store.has_value() && m_associated_drag_data_store->mode() == DragDataStore::Mode::ReadWrite)
  56. set_effect_allowed_internal(move(effect_allowed));
  57. }
  58. void DataTransfer::set_effect_allowed_internal(FlyString effect_allowed)
  59. {
  60. // AD-HOC: We need to be able to set the effectAllowed attribute internally regardless of the state of the drag data store.
  61. using namespace DataTransferEffect;
  62. if (effect_allowed.is_one_of(none, copy, copyLink, copyMove, link, linkMove, move, all, uninitialized))
  63. m_effect_allowed = AK::move(effect_allowed);
  64. }
  65. // https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-types
  66. ReadonlySpan<String> DataTransfer::types() const
  67. {
  68. // The types attribute must return this DataTransfer object's types array.
  69. return m_types;
  70. }
  71. // https://html.spec.whatwg.org/multipage/dnd.html#dom-datatransfer-files
  72. JS::NonnullGCPtr<FileAPI::FileList> DataTransfer::files() const
  73. {
  74. auto& realm = this->realm();
  75. // 1. Start with an empty list L.
  76. auto files = FileAPI::FileList::create(realm);
  77. // 2. If the DataTransfer object is no longer associated with a drag data store, the FileList is empty. Return
  78. // the empty list L.
  79. if (!m_associated_drag_data_store.has_value())
  80. return files;
  81. // 3. If the drag data store's mode is the protected mode, return the empty list L.
  82. if (m_associated_drag_data_store->mode() == DragDataStore::Mode::Protected)
  83. return files;
  84. // 4. For each item in the drag data store item list whose kind is File, add the item's data (the file, in
  85. // particular its name and contents, as well as its type) to the list L.
  86. for (auto const& item : m_associated_drag_data_store->item_list()) {
  87. if (item.kind != DragDataStoreItem::Kind::File)
  88. continue;
  89. auto blob = FileAPI::Blob::create(realm, item.data, item.type_string);
  90. // FIXME: The FileAPI should use ByteString for file names.
  91. auto file_name = MUST(String::from_byte_string(item.file_name));
  92. // FIXME: Fill in other fields (e.g. last_modified).
  93. FileAPI::FilePropertyBag options {};
  94. options.type = item.type_string;
  95. auto file = MUST(FileAPI::File::create(realm, { JS::make_handle(blob) }, file_name, move(options)));
  96. files->add_file(file);
  97. }
  98. // 5. The files found by these steps are those in the list L.
  99. return files;
  100. }
  101. void DataTransfer::associate_with_drag_data_store(DragDataStore& drag_data_store)
  102. {
  103. m_associated_drag_data_store = drag_data_store;
  104. update_data_transfer_types_list();
  105. }
  106. void DataTransfer::disassociate_with_drag_data_store()
  107. {
  108. m_associated_drag_data_store.clear();
  109. update_data_transfer_types_list();
  110. }
  111. // https://html.spec.whatwg.org/multipage/dnd.html#concept-datatransfer-types
  112. void DataTransfer::update_data_transfer_types_list()
  113. {
  114. // 1. Let L be an empty sequence.
  115. Vector<String> types;
  116. // 2. If the DataTransfer object is still associated with a drag data store, then:
  117. if (m_associated_drag_data_store.has_value()) {
  118. bool contains_file = false;
  119. // 1. For each item in the DataTransfer object's drag data store item list whose kind is text, add an entry to L
  120. // consisting of the item's type string.
  121. for (auto const& item : m_associated_drag_data_store->item_list()) {
  122. switch (item.kind) {
  123. case DragDataStoreItem::Kind::Text:
  124. types.append(item.type_string);
  125. break;
  126. case DragDataStoreItem::Kind::File:
  127. contains_file = true;
  128. break;
  129. }
  130. }
  131. // 2. If there are any items in the DataTransfer object's drag data store item list whose kind is File, then add
  132. // an entry to L consisting of the string "Files". (This value can be distinguished from the other values
  133. // because it is not lowercase.)
  134. if (contains_file)
  135. types.append("Files"_string);
  136. }
  137. // 3. Set the DataTransfer object's types array to the result of creating a frozen array from L.
  138. m_types = move(types);
  139. }
  140. }