Skip to main content

script/dom/filesystem/
filesystementry.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::cell::Cell;
6use std::rc::Rc;
7
8use dom_struct::dom_struct;
9use script_bindings::cell::DomRefCell;
10use script_bindings::reflector::Reflector;
11
12use crate::dom::bindings::callback::ExceptionHandling;
13use crate::dom::bindings::codegen::Bindings::FileSystemBinding::FileSystemMethods;
14use crate::dom::bindings::codegen::Bindings::FileSystemEntryBinding::{
15    ErrorCallback, FileSystemEntryCallback, FileSystemEntryMethods,
16};
17use crate::dom::bindings::refcounted::Trusted;
18use crate::dom::bindings::reflector::DomGlobal;
19use crate::dom::bindings::root::{DomRoot, MutNullableDom};
20use crate::dom::bindings::str::USVString;
21use crate::dom::filesystem::FileSystem;
22
23#[dom_struct]
24pub(crate) struct FileSystemEntry {
25    reflector_: Reflector,
26    name: USVString,
27    full_path: USVString,
28    is_file: bool,
29    filesystem: MutNullableDom<FileSystem>,
30    pending_callbacks: DomRefCell<Vec<PendingEntryCallback>>,
31    next_callback: Cell<usize>,
32}
33
34#[derive(JSTraceable, MallocSizeOf)]
35struct PendingEntryCallback {
36    id: usize,
37    #[conditional_malloc_size_of]
38    callback: Rc<FileSystemEntryCallback>,
39}
40
41impl FileSystemEntry {
42    pub(crate) fn new_inherited(
43        name: USVString,
44        full_path: USVString,
45        is_file: bool,
46    ) -> FileSystemEntry {
47        FileSystemEntry {
48            reflector_: Reflector::new(),
49            name,
50            full_path,
51            is_file,
52            filesystem: MutNullableDom::new(None),
53            pending_callbacks: Default::default(),
54            next_callback: Cell::new(0),
55        }
56    }
57
58    pub(crate) fn set_filesystem(&self, fs: &FileSystem) {
59        self.filesystem.set(Some(fs));
60    }
61}
62
63impl FileSystemEntryMethods<crate::DomTypeHolder> for FileSystemEntry {
64    /// <https://wicg.github.io/entries-api/#dom-filesystementry-isfile>
65    fn IsFile(&self) -> bool {
66        self.is_file
67    }
68
69    /// <https://wicg.github.io/entries-api/#dom-filesystementry-isdirectory>
70    fn IsDirectory(&self) -> bool {
71        !self.is_file
72    }
73
74    /// <https://wicg.github.io/entries-api/#dom-filesystementry-name>
75    fn Name(&self) -> USVString {
76        self.name.clone()
77    }
78
79    /// <https://wicg.github.io/entries-api/#dom-filesystementry-fullpath>
80    fn FullPath(&self) -> USVString {
81        self.full_path.clone()
82    }
83
84    /// <https://wicg.github.io/entries-api/#dom-filesystementry-filesystem>
85    fn Filesystem(&self) -> DomRoot<FileSystem> {
86        self.filesystem
87            .get()
88            .expect("FileSystemEntry must be associated with a FileSystem")
89    }
90
91    /// <https://wicg.github.io/entries-api/#dom-filesystementry-getparent>
92    fn GetParent(
93        &self,
94        success_callback: Option<Rc<FileSystemEntryCallback>>,
95        _error_callback: Option<Rc<ErrorCallback>>,
96    ) {
97        let Some(callback) = success_callback else {
98            return;
99        };
100        // Per spec 7.1: in parallel,
101        // 1. (TODO) Let `path` be the result of resolve ".." relative to this's full path.
102        // 2. (TODO) Let `item` be the result of evaluating a path with this’s root and path.
103        // 3. (TODO) Queue errorCallback if `item` is failure.
104        // 4 - 5.  Queue a task to invoke
105        // successCallback with the parent directory entry.
106        //
107        // NOTE: For now, the parent is always the root directory, which is correct
108        // as the `FileSystemEntry` can only be created by webkitGetAsEntry(), which is
109        // single level DnD.
110
111        let id = self.next_callback.get();
112        let pending_callback = PendingEntryCallback { id, callback };
113        self.pending_callbacks.borrow_mut().push(pending_callback);
114        self.next_callback.set(id + 1);
115
116        let this = Trusted::new(self);
117        self.global()
118            .task_manager()
119            .dom_manipulation_task_source()
120            .queue(task!(invoke_get_parent: move |cx| {
121                let this = this.root();
122                let maybe_index = this
123                    .pending_callbacks
124                    .borrow()
125                    .iter()
126                    .position(|val| val.id == id);
127                if let Some(index) = maybe_index {
128                    let callback = this
129                        .pending_callbacks
130                        .safe_borrow_mut(cx.no_gc())
131                        .swap_remove(index)
132                        .callback;
133                    let entry = DomRoot::upcast::<FileSystemEntry>(this.Filesystem().Root());
134                    let _ = callback.Call__(cx, &entry, ExceptionHandling::Report);
135                }
136            }));
137    }
138}