Skip to main content

script/dom/execcommand/commands/
createlink.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 html5ever::local_name;
6use js::context::JSContext;
7use script_bindings::inheritance::Castable;
8
9use crate::dom::ShadowIncluding;
10use crate::dom::bindings::codegen::Bindings::HTMLAnchorElementBinding::HTMLAnchorElementMethods;
11use crate::dom::bindings::str::DOMString;
12use crate::dom::document::Document;
13use crate::dom::element::Element;
14use crate::dom::execcommand::basecommand::CommandName;
15use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
16use crate::dom::selection::Selection;
17
18/// <https://w3c.github.io/editing/docs/execCommand/#the-createlink-command>
19pub(crate) fn execute_createlink_command(
20    cx: &mut JSContext,
21    document: &Document,
22    selection: &Selection,
23    value: DOMString,
24) -> bool {
25    // Step 1. If value is the empty string, return false.
26    if value.is_empty() {
27        return false;
28    }
29    // Step 2. For each editable a element that has an href attribute and
30    // is an ancestor of some node effectively contained in the active range,
31    // set that a element's href attribute to value.
32    let active_range = selection
33        .active_range()
34        .expect("Must always have an active range");
35    active_range.for_each_effectively_contained_child(|node| {
36        for ancestor in node.inclusive_ancestors(ShadowIncluding::No) {
37            if !ancestor.is_editable() {
38                return;
39            }
40            let Some(anchor) = ancestor.downcast::<HTMLAnchorElement>() else {
41                return;
42            };
43            if anchor
44                .upcast::<Element>()
45                .has_attribute(&local_name!("href"))
46            {
47                anchor.SetHref(cx, value.to_string().into());
48            }
49        }
50    });
51    // Step 3. Set the selection's value to value.
52    selection.set_the_selection_value(cx, Some(value), CommandName::CreateLink, document);
53    // Step 4. Return true.
54    true
55}