/* * Copyright (c) 2020-2022, the SerenityOS developers. * Copyright (c) 2022, MacDue * Copyright (c) 2023, Bastiaan van der Plaat * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include namespace Web::HTML { JS_DEFINE_ALLOCATOR(HTMLProgressElement); HTMLProgressElement::HTMLProgressElement(DOM::Document& document, DOM::QualifiedName qualified_name) : HTMLElement(document, move(qualified_name)) { } HTMLProgressElement::~HTMLProgressElement() = default; void HTMLProgressElement::initialize(JS::Realm& realm) { Base::initialize(realm); set_prototype(&Bindings::ensure_web_prototype(realm, "HTMLProgressElement"_fly_string)); } void HTMLProgressElement::visit_edges(Cell::Visitor& visitor) { Base::visit_edges(visitor); visitor.visit(m_progress_value_element); } // https://html.spec.whatwg.org/multipage/form-elements.html#dom-progress-value double HTMLProgressElement::value() const { auto maybe_value_string = get_attribute(HTML::AttributeNames::value); if (!maybe_value_string.has_value()) return 0; auto maybe_value = parse_floating_point_number(maybe_value_string.value()); if (!maybe_value.has_value()) return 0; return clamp(maybe_value.value(), 0, max()); } WebIDL::ExceptionOr HTMLProgressElement::set_value(double value) { if (value < 0 || value > max()) return {}; TRY(set_attribute(HTML::AttributeNames::value, MUST(String::number(value)))); update_progress_value_element(); document().invalidate_layout(); return {}; } // https://html.spec.whatwg.org/multipage/form-elements.html#dom-progress-max double HTMLProgressElement::max() const { auto maybe_max_string = get_attribute(HTML::AttributeNames::max); if (!maybe_max_string.has_value()) return 1; auto maybe_max = parse_floating_point_number(maybe_max_string.value()); if (!maybe_max.has_value()) return 1; return AK::max(maybe_max.value(), 0); } WebIDL::ExceptionOr HTMLProgressElement::set_max(double value) { if (value <= 0) return {}; TRY(set_attribute(HTML::AttributeNames::max, MUST(String::number(value)))); update_progress_value_element(); document().invalidate_layout(); return {}; } double HTMLProgressElement::position() const { if (!is_determinate()) return -1; return value() / max(); } void HTMLProgressElement::inserted() { create_shadow_tree_if_needed(); } void HTMLProgressElement::removed_from(DOM::Node*) { set_shadow_root(nullptr); } void HTMLProgressElement::create_shadow_tree_if_needed() { if (shadow_root_internal()) return; auto shadow_root = heap().allocate(realm(), document(), *this, Bindings::ShadowRootMode::Closed); set_shadow_root(shadow_root); auto progress_bar_element = heap().allocate(realm(), document()); MUST(shadow_root->append_child(*progress_bar_element)); m_progress_value_element = heap().allocate(realm(), document()); MUST(progress_bar_element->append_child(*m_progress_value_element)); update_progress_value_element(); } void HTMLProgressElement::update_progress_value_element() { MUST(m_progress_value_element->set_attribute(HTML::AttributeNames::style, MUST(String::formatted("width: {}%;", position() * 100)))); } }