From dbb20b3708532aa38d2ab308e63413a270a12f92 Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Thu, 4 Jun 2020 12:34:46 -0500 Subject: [PATCH 001/122] re-organized config to prefab dir --- source/prefab/ConfigPanel.h | 146 ++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 source/prefab/ConfigPanel.h diff --git a/source/prefab/ConfigPanel.h b/source/prefab/ConfigPanel.h new file mode 100644 index 0000000000..b1212646c3 --- /dev/null +++ b/source/prefab/ConfigPanel.h @@ -0,0 +1,146 @@ +#ifndef EMP_CONFIG_WEB_INTERFACE_H +#define EMP_CONFIG_WEB_INTERFACE_H + +#include "config.h" +#include "../web/Div.h" +#include "../web/Element.h" +#include "../web/Input.h" + +#include +#include +#include "../tools/set_utils.h" +#include "../tools/string_utils.h" + +namespace emp { + + class ConfigPanel { + private: + inline static std::set numeric_types = {"int", "double", "float", "uint32_t", "uint64_t", "size_t"}; + Config & config; + web::Div settings_div; + std::set exclude; + std::map group_divs; + std::map input_map; + std::function on_change_fun = [](const std::string & val){;}; + std::function format_label_fun = [](std::string name){ + emp::vector sliced = slice(name, '_'); + return to_titlecase(join(sliced, " ")); + }; + public: + ConfigPanel(Config & c, const std::string & div_name = "settings_div") + : config(c), settings_div(div_name) {;} + + void SetOnChangeFun(std::function fun) {on_change_fun = fun;} + + template + void SetDefaultRangeFloatingPoint(web::Input & input, T val) { + if (val > 0 && val < 1) { + // This is a common range for numbers to be in + input.Min(0); + if (val > .1) { + input.Max(1); + } else { + input.Max(val * 100); + } + input.Step(val/10.0); + } else if (val > 0) { + // Assume this is a positive number + input.Min(0); + input.Max(val * 10); + input.Step(val/10.0); + } else if (val < 0) { + input.Min(val * 10); // since val is negative + input.Max(val * -10); + input.Step(val/-10.0); // A negative step would be confusing + } + + // Otherwise val is 0 and we have nothing to go on + } + + void SetDefaultRangeFixedPoint(web::Input & input, int val) { + // Default step is 1, which should be fine for fixed point + + if (val > 0) { + // Assume this is a positive number + input.Min(0); + input.Max(val * 10); + } else if (val < 0) { + input.Min(val * 10); // since val is negative + input.Max(val * -10); + } + + // Otherwise val is 0 and we have nothing to go on + } + + void ExcludeConfig(std::string setting) { + exclude.insert(setting); + } + + void Setup(const std::string & id_prefix = "settings_") { + + for (auto group : config.group_set) { + // std::cout << "GROUP: " << group->GetName() << std::endl; + std::string group_name = group->GetName(); + group_divs[group_name] = web::Div(id_prefix + group_name); + group_divs[group_name] << "

" << group->GetDesc() << "

"; + for (size_t i = 0; i < group->GetSize(); i++) { + // std::cout << group->GetEntry(i)->GetType() << std::endl; + std::string name = group->GetEntry(i)->GetName(); + if (Has(exclude, name)) { + continue; + } + std::string type = group->GetEntry(i)->GetType(); + std::string value = group->GetEntry(i)->GetValue(); + + if (Has(numeric_types, type)) { + input_map[name] = emp::web::Input( + [this, name](std::string val){ + std::cout << name << " " << val << " " <(value)); + } else if (type == "float") { + SetDefaultRangeFloatingPoint(input_map[name], emp::from_string(value)); + } else { + // TODO: Correctly handle all types (although I'm not sure it actually matters?) + SetDefaultRangeFixedPoint(input_map[name], emp::from_string(value)); + } + + } else if (type == "bool") { + input_map[name] = emp::web::Input( + [this, name](std::string val){config.Set(name, val); + on_change_fun(val);}, + "checkbox", format_label_fun(name), name + "_input_checkbox" + ); + } else { + input_map[name] = emp::web::Input( + [this, name](std::string val){config.Set(name, val); + on_change_fun(val);}, + "text", format_label_fun(name), name + "_input_textbox" + ); + + } + + input_map[name].Value(value); + + group_divs[group_name] << web::Element("form") << input_map[name]; + + } + settings_div << group_divs[group_name]; + } + + } + + web::Div & GetDiv() {return settings_div;} + + }; + +} + +#endif From abf66c93095cfb681cec5c91bb09c755c072bc4a Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 4 Jun 2020 14:00:04 -0400 Subject: [PATCH 002/122] Fix config include path --- source/prefab/ConfigPanel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/prefab/ConfigPanel.h b/source/prefab/ConfigPanel.h index b1212646c3..42817d6407 100644 --- a/source/prefab/ConfigPanel.h +++ b/source/prefab/ConfigPanel.h @@ -1,7 +1,7 @@ #ifndef EMP_CONFIG_WEB_INTERFACE_H #define EMP_CONFIG_WEB_INTERFACE_H -#include "config.h" +#include "../config/config.h" #include "../web/Div.h" #include "../web/Element.h" #include "../web/Input.h" From 284b94af2a0fdbd386ee3fd50b905aff4b3bed88 Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Thu, 4 Jun 2020 16:14:29 -0500 Subject: [PATCH 003/122] added getter method for group_set vector --- source/config/config.h | 5 +++++ source/prefab/ConfigPanel.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/source/config/config.h b/source/config/config.h index 99c83903ec..02de15b81a 100644 --- a/source/config/config.h +++ b/source/config/config.h @@ -670,6 +670,11 @@ namespace emp { std::bind(&ConfigManager::UseObject, new_manager, _1) ); } + // Access group_set using this method since it is protected + emp::vector GetGroupSet(){ + return group_set; + } + }; } diff --git a/source/prefab/ConfigPanel.h b/source/prefab/ConfigPanel.h index 42817d6407..c0385b94f1 100644 --- a/source/prefab/ConfigPanel.h +++ b/source/prefab/ConfigPanel.h @@ -78,7 +78,7 @@ namespace emp { void Setup(const std::string & id_prefix = "settings_") { - for (auto group : config.group_set) { + for (auto group : config.GetGroupSet()) { // std::cout << "GROUP: " << group->GetName() << std::endl; std::string group_name = group->GetName(); group_divs[group_name] = web::Div(id_prefix + group_name); From 3659db67918d08076107777af3c2c488fb1c3134 Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Fri, 5 Jun 2020 12:58:23 -0500 Subject: [PATCH 004/122] added collapsible settings cards --- source/prefab/ConfigPanel.h | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/source/prefab/ConfigPanel.h b/source/prefab/ConfigPanel.h index c0385b94f1..53a36e33c1 100644 --- a/source/prefab/ConfigPanel.h +++ b/source/prefab/ConfigPanel.h @@ -82,7 +82,24 @@ namespace emp { // std::cout << "GROUP: " << group->GetName() << std::endl; std::string group_name = group->GetName(); group_divs[group_name] = web::Div(id_prefix + group_name); - group_divs[group_name] << "

" << group->GetDesc() << "

"; + // group_divs[group_name] << "

" << group->GetDesc() << "

"; + + web::Div card("card_" + group_name); + web::Div card_header("card_header_" + group_name); + web::Element collapse_link("a"); + collapse_link.SetAttr("data-toggle", "collapse").SetAttr("href", "#card_body_" + group_name); + collapse_link << "

" << group->GetDesc() << "

"; + card_header << collapse_link; + card << card_header; + + + web::Div card_body("card_body_" + group_name); + card_body.SetAttr("class", "collapse").SetAttr("class", "show"); + // make card true bootstrap cards + card.SetAttr("class", "card"); + card_header.SetAttr("class", "card-header"); + card_body.SetAttr("class", "card-body"); + for (size_t i = 0; i < group->GetSize(); i++) { // std::cout << group->GetEntry(i)->GetType() << std::endl; std::string name = group->GetEntry(i)->GetName(); @@ -129,9 +146,12 @@ namespace emp { input_map[name].Value(value); - group_divs[group_name] << web::Element("form") << input_map[name]; + // group_divs[group_name] << web::Element("form") << input_map[name]; + card_body << web::Element("form") << input_map[name]; + group_divs[group_name] << card << card_body; } + // settings_div.SetAttr("class", "col-lg-6 col-md-12"); makes all CSS go away!!!! settings_div << group_divs[group_name]; } From 29eef50d3116df2fcd49da1962b140909f6e03e5 Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Fri, 5 Jun 2020 17:56:22 -0500 Subject: [PATCH 005/122] added css styling to form and dropdown box --- source/prefab/ConfigPanel.h | 80 +++++++++++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 8 deletions(-) diff --git a/source/prefab/ConfigPanel.h b/source/prefab/ConfigPanel.h index 53a36e33c1..bea29b1146 100644 --- a/source/prefab/ConfigPanel.h +++ b/source/prefab/ConfigPanel.h @@ -109,6 +109,7 @@ namespace emp { std::string type = group->GetEntry(i)->GetType(); std::string value = group->GetEntry(i)->GetValue(); +<<<<<<< HEAD if (Has(numeric_types, type)) { input_map[name] = emp::web::Input( [this, name](std::string val){ @@ -118,6 +119,48 @@ namespace emp { on_change_fun(val);}, "range", format_label_fun(name), name + "_input_slider", true ); +======= + web::Div mobile_dropdown("mobile_dropdown_" + name); + mobile_dropdown.SetAttr("class", "d-md-none"); + + web::Div setting_element(name + "_row"); + setting_element.SetCSS("width", "100%"); + web::Element title_span("span"); + web::Element title("a"); + title.SetAttr("data-toggle", "collapse").SetAttr("href", "#" + name + "_dropdown"); + title << format_label_fun(name); + title_span.SetCSS("width", "38%").SetCSS("display", "inline-block"); + setting_element << title_span << title; + + if (Has(numeric_types, type)) { + // Seems more efficient to use web::Input, but it's not working + // TODO: need to define on change function to use built in Input + // emp::web::Input slider([this, name](std::string val){ + // std::cout << name << " " << val << " " <" << mobile_slider; + + // NOTE: adding an id to slider or number breaks it! // Attempt to have intelligent defaults if (type == "double") { @@ -136,18 +179,39 @@ namespace emp { "checkbox", format_label_fun(name), name + "_input_checkbox" ); } else { - input_map[name] = emp::web::Input( - [this, name](std::string val){config.Set(name, val); - on_change_fun(val);}, - "text", format_label_fun(name), name + "_input_textbox" - ); - + // input_map[name] = emp::web::Input( + // [this, name](std::string val){config.Set(name, val); + // on_change_fun(val);}, + // "text", format_label_fun(name), name + "_input_textbox" + // ); + web::Element text_input("input"); + text_input.SetAttr("type", "text"); + text_input.SetCSS("width", "39%"); + setting_element << text_input; } - input_map[name].Value(value); + // Dropdown bubble + // Should probably be modularlized in the future + web::Div drop_down(name + "_dropdown"); + web::Div triangle(name + "_triangle_up"); + web::Div content(name + "_content"); + triangle.SetCSS("width", "0").SetCSS("height", "0").SetCSS("border-left", "12px solid transparent").SetCSS("border-right", "12px solid transparent").SetCSS("border-bottom", "12px solid #ede9e8").SetCSS("margin-left", "15px"); + drop_down << triangle; + content.SetAttr("class", "p-3").SetCSS("font-style", "italic"); + content << "hello world!"; + content << mobile_dropdown; + drop_down << triangle; + drop_down << content; + content.SetBackground("#ede9e8"); + drop_down.SetAttr("class", "collapse"); + + // input_map[name].Value(value); + input_divs[name] << setting_element; + input_divs[name] << drop_down; // group_divs[group_name] << web::Element("form") << input_map[name]; - card_body << web::Element("form") << input_map[name]; + card_body << web::Element("form").SetCSS("width", "100%") << input_divs[name]; +>>>>>>> c0edc65... added css styling to form and dropdown box group_divs[group_name] << card << card_body; } From 876b8ab782dd1610feed0f85b2bee985fca9f7fd Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Tue, 9 Jun 2020 14:14:30 -0500 Subject: [PATCH 006/122] display appropriate setting descriptions and synchronize form when one input is changed --- source/prefab/ConfigPanel.h | 157 +++++++++++++++++++++++++++++++----- 1 file changed, 138 insertions(+), 19 deletions(-) diff --git a/source/prefab/ConfigPanel.h b/source/prefab/ConfigPanel.h index bea29b1146..41fcf91de0 100644 --- a/source/prefab/ConfigPanel.h +++ b/source/prefab/ConfigPanel.h @@ -5,6 +5,8 @@ #include "../web/Div.h" #include "../web/Element.h" #include "../web/Input.h" +#include // to use EM_JS +#include "../web/JSWrap.h" // to use EM_ASM #include #include @@ -26,6 +28,18 @@ namespace emp { emp::vector sliced = slice(name, '_'); return to_titlecase(join(sliced, " ")); }; + void SyncForm(std::string val, std::string input1, std::string input2){ + std::cout << "Begin SyncForm" << std::endl; + emp::web::Input div1(settings_div.Find(input1)); + div1.Value(val); + emp::web::Input div2(settings_div.Find(input2)); + div2.Value(val); + std::cout << "SyncForm: after updating other two divs" << std::endl; + + div1.Redraw(); + div2.Redraw(); + std::cout << "SyncForm: after redraw" << std::endl; + } public: ConfigPanel(Config & c, const std::string & div_name = "settings_div") : config(c), settings_div(div_name) {;} @@ -82,24 +96,29 @@ namespace emp { // std::cout << "GROUP: " << group->GetName() << std::endl; std::string group_name = group->GetName(); group_divs[group_name] = web::Div(id_prefix + group_name); - // group_divs[group_name] << "

" << group->GetDesc() << "

"; + settings_div << group_divs[group_name]; + // Setting card setup web::Div card("card_" + group_name); + group_divs[group_name] << card; web::Div card_header("card_header_" + group_name); + card << card_header; web::Element collapse_link("a"); + card_header << collapse_link; collapse_link.SetAttr("data-toggle", "collapse").SetAttr("href", "#card_body_" + group_name); collapse_link << "

" << group->GetDesc() << "

"; - card_header << collapse_link; - card << card_header; web::Div card_body("card_body_" + group_name); + card << card_body; card_body.SetAttr("class", "collapse").SetAttr("class", "show"); // make card true bootstrap cards card.SetAttr("class", "card"); card_header.SetAttr("class", "card-header"); card_body.SetAttr("class", "card-body"); + + for (size_t i = 0; i < group->GetSize(); i++) { // std::cout << group->GetEntry(i)->GetType() << std::endl; std::string name = group->GetEntry(i)->GetName(); @@ -109,6 +128,9 @@ namespace emp { std::string type = group->GetEntry(i)->GetType(); std::string value = group->GetEntry(i)->GetValue(); + card_body << web::Element("form").SetCSS("width", "100%") << input_divs[name]; + +<<<<<<< HEAD <<<<<<< HEAD if (Has(numeric_types, type)) { input_map[name] = emp::web::Input( @@ -123,16 +145,40 @@ namespace emp { web::Div mobile_dropdown("mobile_dropdown_" + name); mobile_dropdown.SetAttr("class", "d-md-none"); +======= + // Setting element label +>>>>>>> 9738447... display appropriate setting descriptions and synchronize form when one input is changed web::Div setting_element(name + "_row"); + input_divs[name] << setting_element; setting_element.SetCSS("width", "100%"); web::Element title_span("span"); web::Element title("a"); + setting_element << title_span << title; title.SetAttr("data-toggle", "collapse").SetAttr("href", "#" + name + "_dropdown"); title << format_label_fun(name); title_span.SetCSS("width", "38%").SetCSS("display", "inline-block"); - setting_element << title_span << title; + + // Dropdown bubble + // Should probably be modularlized in the future + web::Div drop_down(name + "_dropdown"); + input_divs[name] << drop_down; + web::Div triangle(name + "_triangle_up"); + drop_down << triangle; + web::Div content(name + "_content"); + drop_down << content; + triangle.SetCSS("width", "0").SetCSS("height", "0").SetCSS("border-left", "12px solid transparent").SetCSS("border-right", "12px solid transparent").SetCSS("border-bottom", "12px solid #ede9e8").SetCSS("margin-left", "15px"); + content.SetAttr("class", "p-3").SetCSS("font-style", "italic"); + content << group->GetEntry(i)->GetDescription(); + content.SetBackground("#ede9e8"); + drop_down.SetAttr("class", "collapse"); + drop_down.SetCSS("width", "auto").SetCSS("margin-bottom", "10px"); + // Portion of dropdown only visible on small screens + web::Div mobile_dropdown("mobile_dropdown_" + name); + content << mobile_dropdown; + mobile_dropdown.SetAttr("class", "d-md-none"); if (Has(numeric_types, type)) { +<<<<<<< HEAD // Seems more efficient to use web::Input, but it's not working // TODO: need to define on change function to use built in Input // emp::web::Input slider([this, name](std::string val){ @@ -147,23 +193,67 @@ namespace emp { web::Element number("input"); +======= + // Empty div to keep elements aligned in mobile view +>>>>>>> 9738447... display appropriate setting descriptions and synchronize form when one input is changed web::Element spacer("span"); - spacer.SetCSS("width", "38%").SetAttr("class", "d-inline-block d-md-none"); - number.SetAttr("type", "number"); - slider.SetCSS("width", "38%").SetAttr("class", "d-none d-md-inline-block"); - number.SetCSS("width", "18%").SetCSS("right", "10px"); setting_element << spacer; + spacer.SetCSS("width", "38%").SetAttr("class", "d-inline-block d-md-none"); + + const std::string name_input_slider = name + "_input_slider"; + const std::string name_input_number = name + "_input_number"; + const std::string name_input_mobile_slider = name + "_input_mobile_slider"; + emp::web::Input slider( [](std::string x){ + std::cout << "empty slider function" << std::endl;}, + "range", NULL, name_input_slider + ); setting_element << slider; - setting_element << number; - web::Element mobile_slider("input"); - mobile_slider.SetAttr("type", "range"); + emp::web::Input number([](std::string val){ + std::cout << "empty number function" << std::endl; + }, + "number", NULL, name_input_number + ); + setting_element << number; + emp::web::Input mobile_slider([](std::string val){ + std::cout << "empty mobile slider function" << std::endl; + }, + "range", NULL, name_input_mobile_slider + ); mobile_dropdown << "
" << mobile_slider; - // NOTE: adding an id to slider or number breaks it! + // Set onchange behavior for inputs + slider.Callback( + [this,name, name_input_number, name_input_mobile_slider](std::string val){ + config.Set(name, val); + std::cout << "slider callback: after setting new value" << std::endl; + + SyncForm(val, name_input_number, name_input_mobile_slider); + }); + number.Callback( + [this,name, name_input_slider, name_input_mobile_slider](std::string val){ + config.Set(name, val); + std::cout << "slider callback: after setting new value" << std::endl; + + SyncForm(val, name_input_slider, name_input_mobile_slider); + }); + mobile_slider.Callback( + [this,name, name_input_number, name_input_slider](std::string val){ + config.Set(name, val); + std::cout << "slider callback: after setting new value" << std::endl; + + SyncForm(val, name_input_number, name_input_slider); + }); + // Set initial values + slider.Value(config.Get(name)); + number.Value(config.Get(name)); + mobile_slider.Value(config.Get(name)); + slider.SetCSS("width", "38%").SetCSS("margin-right", "10px").SetAttr("class", "d-none d-md-inline-block"); + number.SetCSS("width", "18%").SetCSS("right", "10px"); // Attempt to have intelligent defaults if (type == "double") { +<<<<<<< HEAD SetDefaultRangeFloatingPoint(input_map[name], emp::from_string(value)); } else if (type == "float") { SetDefaultRangeFloatingPoint(input_map[name], emp::from_string(value)); @@ -178,17 +268,43 @@ namespace emp { on_change_fun(val);}, "checkbox", format_label_fun(name), name + "_input_checkbox" ); +======= + SetDefaultRangeFloatingPoint(slider, emp::from_string(value)); + SetDefaultRangeFloatingPoint(number, emp::from_string(value)); + SetDefaultRangeFloatingPoint(mobile_slider, emp::from_string(value)); + } else if (type == "float") { + SetDefaultRangeFloatingPoint(slider, emp::from_string(value)); + SetDefaultRangeFloatingPoint(number, emp::from_string(value)); + SetDefaultRangeFloatingPoint(mobile_slider, emp::from_string(value)); + } else { + // TODO: Correctly handle all types (although I'm not sure it actually matters?) + SetDefaultRangeFixedPoint(slider, emp::from_string(value)); + SetDefaultRangeFixedPoint(number, emp::from_string(value)); + SetDefaultRangeFixedPoint(mobile_slider, emp::from_string(value)); + } + + } + else if (type == "bool") { + emp::web::Input bool_input( + [this, name](std::string val){config.Set(name, val); + on_change_fun(val);}, + "checkbox", NULL, name + "_input_checkbox" + ); + setting_element << bool_input; + +>>>>>>> 9738447... display appropriate setting descriptions and synchronize form when one input is changed } else { - // input_map[name] = emp::web::Input( - // [this, name](std::string val){config.Set(name, val); - // on_change_fun(val);}, - // "text", format_label_fun(name), name + "_input_textbox" - // ); - web::Element text_input("input"); + emp::web::Input text_input( + [this, name](std::string val){config.Set(name, val); + on_change_fun(val);}, + "text", NULL, name + "_input_textbox" + ); + setting_element << text_input; + text_input.Value("none"); text_input.SetAttr("type", "text"); text_input.SetCSS("width", "39%"); - setting_element << text_input; } +<<<<<<< HEAD // Dropdown bubble // Should probably be modularlized in the future @@ -217,6 +333,9 @@ namespace emp { } // settings_div.SetAttr("class", "col-lg-6 col-md-12"); makes all CSS go away!!!! settings_div << group_divs[group_name]; +======= + } +>>>>>>> 9738447... display appropriate setting descriptions and synchronize form when one input is changed } } From 6cd8f950f0ff4880a9991f398a670bd94fc4eae6 Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Fri, 12 Jun 2020 11:42:04 -0500 Subject: [PATCH 007/122] added glyphs for dropdown bubble and card toggle --- source/prefab/ConfigPanel.h | 53 ++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/source/prefab/ConfigPanel.h b/source/prefab/ConfigPanel.h index 41fcf91de0..63dfd80abf 100644 --- a/source/prefab/ConfigPanel.h +++ b/source/prefab/ConfigPanel.h @@ -103,15 +103,40 @@ namespace emp { group_divs[group_name] << card; web::Div card_header("card_header_" + group_name); card << card_header; +<<<<<<< HEAD web::Element collapse_link("a"); card_header << collapse_link; collapse_link.SetAttr("data-toggle", "collapse").SetAttr("href", "#card_body_" + group_name); collapse_link << "

" << group->GetDesc() << "

"; +======= + web::Div inline_elements(group_name + "_inline"); + inline_elements.SetAttr("class", "clearfix"); + card_header << inline_elements; + web::Element collapse_name_link("button"); + inline_elements << collapse_name_link; + collapse_name_link.SetAttr("data-toggle", "collapse").SetAttr("data-target", "#card_collapse_" + group_name); + collapse_name_link.SetAttr("class", "btn btn-link float-left collapse_toggle setting_heading").SetAttr("type", "button").SetAttr("aria-expanded", "true").SetAttr("aria-controls", "#card_body_" + group_name); + collapse_name_link << "

" << group->GetDesc() << "

"; + web::Element collapse_icon_link("button"); + inline_elements << collapse_icon_link; + collapse_icon_link.SetAttr("data-toggle", "collapse").SetAttr("data-target", "#card_collapse_" + group_name); + collapse_icon_link.SetAttr("class", "btn btn-link float-right collapse_toggle").SetAttr("type", "button").SetAttr("aria-expanded", "true").SetAttr("aria-controls", "#card_body_" + group_name); + + // Toggle Icons + web::Element arrow_down("span"); + collapse_icon_link << arrow_down; + arrow_down.SetAttr("class", "fa fa-angle-double-down"); + web::Element arrow_up("span"); + collapse_icon_link << arrow_up; + arrow_up.SetAttr("class", "fa fa-angle-double-up"); + + web::Div card_collapse("card_collapse_" + group_name); + card << card_collapse; + card_collapse.SetAttr("class", "collapse show").SetAttr("data-parent", "card_" + group_name).SetAttr("aria-labelledby", "card_header_" + group_name); web::Div card_body("card_body_" + group_name); - card << card_body; - card_body.SetAttr("class", "collapse").SetAttr("class", "show"); + card_collapse << card_body; // make card true bootstrap cards card.SetAttr("class", "card"); card_header.SetAttr("class", "card-header"); @@ -130,24 +155,10 @@ namespace emp { card_body << web::Element("form").SetCSS("width", "100%") << input_divs[name]; -<<<<<<< HEAD -<<<<<<< HEAD - if (Has(numeric_types, type)) { - input_map[name] = emp::web::Input( - [this, name](std::string val){ - std::cout << name << " " << val << " " <>>>>>> 9738447... display appropriate setting descriptions and synchronize form when one input is changed web::Div setting_element(name + "_row"); input_divs[name] << setting_element; setting_element.SetCSS("width", "100%"); @@ -155,6 +166,13 @@ namespace emp { web::Element title("a"); setting_element << title_span << title; title.SetAttr("data-toggle", "collapse").SetAttr("href", "#" + name + "_dropdown"); + title.SetAttr("class", "collapse_toggle").SetAttr("role", "button").SetAttr("aria-expanded", "false").SetAttr("aria-controls", "#" + name + "_dropdown"); + web::Element arrow_down_for_dropdown("span"); + title << arrow_down_for_dropdown; + arrow_down_for_dropdown.SetAttr("class", "fa fa-angle-double-right toggle_icon_left_margin"); + web::Element arrow_up_for_dropdown("span"); + title << arrow_up_for_dropdown; + arrow_up_for_dropdown.SetAttr("class", "fa fa-angle-double-up toggle_icon_left_margin"); title << format_label_fun(name); title_span.SetCSS("width", "38%").SetCSS("display", "inline-block"); @@ -178,7 +196,6 @@ namespace emp { mobile_dropdown.SetAttr("class", "d-md-none"); if (Has(numeric_types, type)) { -<<<<<<< HEAD // Seems more efficient to use web::Input, but it's not working // TODO: need to define on change function to use built in Input // emp::web::Input slider([this, name](std::string val){ @@ -302,7 +319,7 @@ namespace emp { setting_element << text_input; text_input.Value("none"); text_input.SetAttr("type", "text"); - text_input.SetCSS("width", "39%"); + text_input.SetCSS("width", "57%"); } <<<<<<< HEAD From 6f3e0b8d71aa3524a9316184da5227f97b08e765 Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Fri, 12 Jun 2020 12:27:53 -0500 Subject: [PATCH 008/122] moved styling for config panel to a separate file --- source/prefab/ConfigPanel.h | 26 +++---- source/prefab/DefaultConfigPanelStyle.css | 83 +++++++++++++++++++++++ 2 files changed, 94 insertions(+), 15 deletions(-) create mode 100644 source/prefab/DefaultConfigPanelStyle.css diff --git a/source/prefab/ConfigPanel.h b/source/prefab/ConfigPanel.h index 63dfd80abf..813445f4bd 100644 --- a/source/prefab/ConfigPanel.h +++ b/source/prefab/ConfigPanel.h @@ -5,8 +5,6 @@ #include "../web/Div.h" #include "../web/Element.h" #include "../web/Input.h" -#include // to use EM_JS -#include "../web/JSWrap.h" // to use EM_ASM #include #include @@ -161,7 +159,7 @@ namespace emp { // Setting element label web::Div setting_element(name + "_row"); input_divs[name] << setting_element; - setting_element.SetCSS("width", "100%"); + setting_element.SetAttr("class", "setting_element"); web::Element title_span("span"); web::Element title("a"); setting_element << title_span << title; @@ -174,7 +172,7 @@ namespace emp { title << arrow_up_for_dropdown; arrow_up_for_dropdown.SetAttr("class", "fa fa-angle-double-up toggle_icon_left_margin"); title << format_label_fun(name); - title_span.SetCSS("width", "38%").SetCSS("display", "inline-block"); + title_span.SetAttr("class", "title_area"); // Dropdown bubble // Should probably be modularlized in the future @@ -182,18 +180,17 @@ namespace emp { input_divs[name] << drop_down; web::Div triangle(name + "_triangle_up"); drop_down << triangle; + triangle.SetAttr("class", "dropdown_triangle"); web::Div content(name + "_content"); drop_down << content; - triangle.SetCSS("width", "0").SetCSS("height", "0").SetCSS("border-left", "12px solid transparent").SetCSS("border-right", "12px solid transparent").SetCSS("border-bottom", "12px solid #ede9e8").SetCSS("margin-left", "15px"); - content.SetAttr("class", "p-3").SetCSS("font-style", "italic"); + content.SetAttr("class", "dropdown_content"); content << group->GetEntry(i)->GetDescription(); - content.SetBackground("#ede9e8"); drop_down.SetAttr("class", "collapse"); - drop_down.SetCSS("width", "auto").SetCSS("margin-bottom", "10px"); + // Portion of dropdown only visible on small screens web::Div mobile_dropdown("mobile_dropdown_" + name); content << mobile_dropdown; - mobile_dropdown.SetAttr("class", "d-md-none"); + mobile_dropdown.SetAttr("class", "mobile_dropdown"); if (Has(numeric_types, type)) { // Seems more efficient to use web::Input, but it's not working @@ -215,7 +212,7 @@ namespace emp { >>>>>>> 9738447... display appropriate setting descriptions and synchronize form when one input is changed web::Element spacer("span"); setting_element << spacer; - spacer.SetCSS("width", "38%").SetAttr("class", "d-inline-block d-md-none"); + spacer.SetAttr("class", "blank_div"); const std::string name_input_slider = name + "_input_slider"; const std::string name_input_number = name + "_input_number"; @@ -265,8 +262,8 @@ namespace emp { slider.Value(config.Get(name)); number.Value(config.Get(name)); mobile_slider.Value(config.Get(name)); - slider.SetCSS("width", "38%").SetCSS("margin-right", "10px").SetAttr("class", "d-none d-md-inline-block"); - number.SetCSS("width", "18%").SetCSS("right", "10px"); + slider.SetAttr("class", "input_slider"); + number.SetAttr("class", "input_number"); // Attempt to have intelligent defaults if (type == "double") { @@ -317,9 +314,8 @@ namespace emp { "text", NULL, name + "_input_textbox" ); setting_element << text_input; - text_input.Value("none"); - text_input.SetAttr("type", "text"); - text_input.SetCSS("width", "57%"); + text_input.SetAttr("class", "input_text").SetAttr("type", "text"); + text_input.Value(config.Get(name)); } <<<<<<< HEAD diff --git a/source/prefab/DefaultConfigPanelStyle.css b/source/prefab/DefaultConfigPanelStyle.css new file mode 100644 index 0000000000..f9fa1a73d2 --- /dev/null +++ b/source/prefab/DefaultConfigPanelStyle.css @@ -0,0 +1,83 @@ +/* Glyphicon Toggle */ +.collapse_toggle[aria-expanded=true] .fa-angle-double-down{ + display: none; +} +.collapse_toggle[aria-expanded=true] .fa-angle-double-right{ + display: none; +} +.collapse_toggle[aria-expanded=false] .fa-angle-double-up{ + display: none; +} +.toggle_icon_left_margin{ + margin-right: 10px; +} + +/* Card Header */ +.setting_heading{ + color: black; + text-decoration: underline; +} +.setting_heading:hover{ + color: #0275d8 /* Bootstrap default pirmary color */ +} + +/* Card Body */ +.setting_element { + width: 100%; +} +.title_area{ + width: 38%; + display: inline-block; +} +.blank_div{ + width: 38%; + display: none; +} +/* Form Inputs */ +.input_slider{ + width: 38%; + margin-right: 10px; +} +.input_number{ + width: 18%; + right: 10px; +} +.input_text{ + width: 57%; +} + +/* Dropdown Bubble */ +.dropdown_triangle{ + width: 0; + height: 0; + border-left: 12px solid transparent; + border-right: 12px solid transparent; + + border-bottom: 12px solid #ede9e8; + margin-left: 15px; +} +.dropdown_content{ + font-style: italic; + padding: 10px; + background-color: #ede9e8; + border-radius: 5px; + margin-bottom: 10px; + width: 95%; +} +.mobile_dropdown{ + display: none; +} + +/* Mobile Version */ +@media screen and (max-width: 992px) { + .blank_div{ + display: inline-block; + } + .input_slider{ + display: none; + } + /* Dropdown Bubble */ + .mobile_dropdown{ + display: inline; + } +} \ No newline at end of file From 892a0f9451866815562e4f14d305ae43289abe2c Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Mon, 15 Jun 2020 17:44:26 -0500 Subject: [PATCH 009/122] added prefab module for comment box --- source/prefab/CommentBox.h | 42 ++++++++++++++ source/prefab/ConfigPanel.h | 108 ++++++++++++++++++++++-------------- 2 files changed, 109 insertions(+), 41 deletions(-) create mode 100644 source/prefab/CommentBox.h diff --git a/source/prefab/CommentBox.h b/source/prefab/CommentBox.h new file mode 100644 index 0000000000..7631616498 --- /dev/null +++ b/source/prefab/CommentBox.h @@ -0,0 +1,42 @@ +#ifndef EMP_COMMENT_BOX_H +#define EMP_COMMENT_BOX_H + +#include "../config/config.h" +#include "../web/Div.h" +#include "../web/Element.h" +#include "../web/Input.h" +#include "../tools/string_utils.h" + +namespace emp { + class CommentBox { + private: + web::Div box_element; + std::string box_base = box_element.GetID(); + web::Div triangle{emp::to_string(box_base, "_triangle")}; + web::Div all_content{emp::to_string(box_base, "_all_content")}; + web::Div desktop_content{emp::to_string(box_base, "_desktop_content")}; + web::Div mobile_content{emp::to_string(box_base, "_mobile_content")}; + public: + CommentBox(){ + box_element << triangle; + box_element << all_content; + all_content << desktop_content; + all_content << mobile_content; + //TODO: change class names to reflect comment box + triangle.SetAttr("class", "dropdown_triangle"); + all_content.SetAttr("class", "dropdown_content"); + mobile_content.SetAttr("class", "mobile_dropdown"); + } + template + void AddContent(T val){ + desktop_content << val; + } + template + void AddMobileContent(T val){ + mobile_content << val; + } + web::Div & GetDiv() {return box_element;} + }; +} + +#endif \ No newline at end of file diff --git a/source/prefab/ConfigPanel.h b/source/prefab/ConfigPanel.h index 813445f4bd..063d61eee5 100644 --- a/source/prefab/ConfigPanel.h +++ b/source/prefab/ConfigPanel.h @@ -11,6 +11,10 @@ #include "../tools/set_utils.h" #include "../tools/string_utils.h" +// Using prefab elements +// #include "Card.h" +#include "CommentBox.h" + namespace emp { class ConfigPanel { @@ -20,23 +24,19 @@ namespace emp { web::Div settings_div; std::set exclude; std::map group_divs; - std::map input_map; + std::map input_divs; std::function on_change_fun = [](const std::string & val){;}; std::function format_label_fun = [](std::string name){ emp::vector sliced = slice(name, '_'); return to_titlecase(join(sliced, " ")); }; void SyncForm(std::string val, std::string input1, std::string input2){ - std::cout << "Begin SyncForm" << std::endl; emp::web::Input div1(settings_div.Find(input1)); div1.Value(val); emp::web::Input div2(settings_div.Find(input2)); div2.Value(val); - std::cout << "SyncForm: after updating other two divs" << std::endl; - div1.Redraw(); div2.Redraw(); - std::cout << "SyncForm: after redraw" << std::endl; } public: ConfigPanel(Config & c, const std::string & div_name = "settings_div") @@ -89,7 +89,6 @@ namespace emp { } void Setup(const std::string & id_prefix = "settings_") { - for (auto group : config.GetGroupSet()) { // std::cout << "GROUP: " << group->GetName() << std::endl; std::string group_name = group->GetName(); @@ -101,27 +100,40 @@ namespace emp { group_divs[group_name] << card; web::Div card_header("card_header_" + group_name); card << card_header; -<<<<<<< HEAD - web::Element collapse_link("a"); - card_header << collapse_link; - collapse_link.SetAttr("data-toggle", "collapse").SetAttr("href", "#card_body_" + group_name); - collapse_link << "

" << group->GetDesc() << "

"; - -======= - web::Div inline_elements(group_name + "_inline"); + web::Div inline_elements(group_name + "_inline"); inline_elements.SetAttr("class", "clearfix"); card_header << inline_elements; web::Element collapse_name_link("button"); inline_elements << collapse_name_link; - collapse_name_link.SetAttr("data-toggle", "collapse").SetAttr("data-target", "#card_collapse_" + group_name); - collapse_name_link.SetAttr("class", "btn btn-link float-left collapse_toggle setting_heading").SetAttr("type", "button").SetAttr("aria-expanded", "true").SetAttr("aria-controls", "#card_body_" + group_name); + collapse_name_link.SetAttr( + "data-toggle", "collapse", + "data-target", "#card_collapse_" + group_name + ); + collapse_name_link.SetAttr( + "class", "btn btn-link float-left collapse_toggle setting_heading", + "type", "button", + "aria-expanded", "true", + "aria-controls", "#card_body_" + group_name + ); collapse_name_link << "

" << group->GetDesc() << "

"; web::Element collapse_icon_link("button"); inline_elements << collapse_icon_link; +<<<<<<< HEAD collapse_icon_link.SetAttr("data-toggle", "collapse").SetAttr("data-target", "#card_collapse_" + group_name); collapse_icon_link.SetAttr("class", "btn btn-link float-right collapse_toggle").SetAttr("type", "button").SetAttr("aria-expanded", "true").SetAttr("aria-controls", "#card_body_" + group_name); +======= + collapse_icon_link.SetAttr( + "data-toggle", "collapse", + "data-target", "#card_collapse_" + group_name, + "class", "btn btn-link float-right collapse_toggle", + "type", "button", + "aria-expanded", "true", + "aria-controls", "#card_body_" + group_name + ); + +>>>>>>> 1509465... added prefab module for comment box // Toggle Icons web::Element arrow_down("span"); collapse_icon_link << arrow_down; @@ -132,7 +144,11 @@ namespace emp { web::Div card_collapse("card_collapse_" + group_name); card << card_collapse; - card_collapse.SetAttr("class", "collapse show").SetAttr("data-parent", "card_" + group_name).SetAttr("aria-labelledby", "card_header_" + group_name); + card_collapse.SetAttr( + "class", "collapse show", + "data-parent", "card_" + group_name, + "aria-labelledby", "card_header_" + group_name + ); web::Div card_body("card_body_" + group_name); card_collapse << card_body; // make card true bootstrap cards @@ -163,8 +179,14 @@ namespace emp { web::Element title_span("span"); web::Element title("a"); setting_element << title_span << title; - title.SetAttr("data-toggle", "collapse").SetAttr("href", "#" + name + "_dropdown"); - title.SetAttr("class", "collapse_toggle").SetAttr("role", "button").SetAttr("aria-expanded", "false").SetAttr("aria-controls", "#" + name + "_dropdown"); + title.SetAttr( + "data-toggle", "collapse", + "href", "#" + name + "_dropdown", + "class", "collapse_toggle", + "role", "button", + "aria-expanded", "false", + "aria-controls", "#" + name + "_dropdown" + ); web::Element arrow_down_for_dropdown("span"); title << arrow_down_for_dropdown; arrow_down_for_dropdown.SetAttr("class", "fa fa-angle-double-right toggle_icon_left_margin"); @@ -174,23 +196,16 @@ namespace emp { title << format_label_fun(name); title_span.SetAttr("class", "title_area"); - // Dropdown bubble - // Should probably be modularlized in the future - web::Div drop_down(name + "_dropdown"); - input_divs[name] << drop_down; - web::Div triangle(name + "_triangle_up"); - drop_down << triangle; - triangle.SetAttr("class", "dropdown_triangle"); - web::Div content(name + "_content"); - drop_down << content; - content.SetAttr("class", "dropdown_content"); - content << group->GetEntry(i)->GetDescription(); - drop_down.SetAttr("class", "collapse"); - - // Portion of dropdown only visible on small screens - web::Div mobile_dropdown("mobile_dropdown_" + name); - content << mobile_dropdown; - mobile_dropdown.SetAttr("class", "mobile_dropdown"); + // This makes the Comment box toggle when title is clicked + // TODO: make a class to create a toggle for two elements? + web::Div dropdown_target(name + "_dropdown"); + input_divs[name] << dropdown_target; + dropdown_target.SetAttr("class", "collapse"); + + // Prefab Dropdown Box Version + emp::CommentBox box; + dropdown_target << box.GetDiv(); + box.AddContent(group->GetEntry(i)->GetDescription()); if (Has(numeric_types, type)) { // Seems more efficient to use web::Input, but it's not working @@ -233,29 +248,36 @@ namespace emp { std::cout << "empty mobile slider function" << std::endl; }, "range", NULL, name_input_mobile_slider +<<<<<<< HEAD ); mobile_dropdown << "
" << mobile_slider; +======= + ); + std::cout << name << " ---- adding mobile content" << std::endl; + box.AddMobileContent("
"); + box.AddMobileContent(mobile_slider); + std::cout << "BACK to config panel after adding mobile content" << std::endl; +>>>>>>> 1509465... added prefab module for comment box // Set onchange behavior for inputs slider.Callback( [this,name, name_input_number, name_input_mobile_slider](std::string val){ config.Set(name, val); - std::cout << "slider callback: after setting new value" << std::endl; - SyncForm(val, name_input_number, name_input_mobile_slider); }); number.Callback( [this,name, name_input_slider, name_input_mobile_slider](std::string val){ config.Set(name, val); +<<<<<<< HEAD std::cout << "slider callback: after setting new value" << std::endl; +======= +>>>>>>> 1509465... added prefab module for comment box SyncForm(val, name_input_slider, name_input_mobile_slider); }); mobile_slider.Callback( [this,name, name_input_number, name_input_slider](std::string val){ config.Set(name, val); - std::cout << "slider callback: after setting new value" << std::endl; - SyncForm(val, name_input_number, name_input_slider); }); // Set initial values @@ -296,6 +318,7 @@ namespace emp { SetDefaultRangeFixedPoint(number, emp::from_string(value)); SetDefaultRangeFixedPoint(mobile_slider, emp::from_string(value)); } + std::cout << "After calling set default range methods" << std::endl; } else if (type == "bool") { @@ -314,7 +337,10 @@ namespace emp { "text", NULL, name + "_input_textbox" ); setting_element << text_input; - text_input.SetAttr("class", "input_text").SetAttr("type", "text"); + text_input.SetAttr( + "class", "input_text", + "type", "text" + ); text_input.Value(config.Get(name)); } <<<<<<< HEAD From 4d599b349d37c1c4c609f206bee348826e4ea1d0 Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Tue, 16 Jun 2020 11:44:38 -0500 Subject: [PATCH 010/122] version of config panel that throws an exception --- source/prefab/CP_Bug.h | 254 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 source/prefab/CP_Bug.h diff --git a/source/prefab/CP_Bug.h b/source/prefab/CP_Bug.h new file mode 100644 index 0000000000..3e185bb1a9 --- /dev/null +++ b/source/prefab/CP_Bug.h @@ -0,0 +1,254 @@ +#ifndef EMP_CONFIG_PANEL_BUG_H +#define EMP_CONFIG_PANEL_BUG_H + +#include "../config/config.h" +#include "../web/Div.h" +#include "../web/Element.h" +#include "../web/Input.h" + +#include +#include +#include "../tools/set_utils.h" +#include "../tools/string_utils.h" + +// Using prefab elements +#include "CommentBox.h" + +/* +* This config panel will not render on the web. When setting the initial value for the first slider, +* it throws this exception: uncaught exception: abort(2). Build with -s ASSERTIONS=1 for more info. +* Emscripten notes on exception: https://emscripten.org/docs/porting/Debugging.html#debugging-assertions +* +* Methods called when setting value: Value -> UpdateValue -> DoChange -> callback -> SynchForm -> Value +* +* Note: this is not an issue when the prefab comment box element is added to the map of input_divs immediately +* after creation. (uncomment line 160 and comment line 239) +*/ + +namespace emp { + + class CP_Bug { + private: + inline static std::set numeric_types = {"int", "double", "float", "uint32_t", "uint64_t", "size_t"}; + Config & config; + web::Div settings_div; + std::set exclude; + std::map group_divs; + std::map input_divs; + std::function on_change_fun = [](const std::string & val){;}; + std::function format_label_fun = [](std::string name){ + emp::vector sliced = slice(name, '_'); + return to_titlecase(join(sliced, " ")); + }; + void SyncForm(std::string val, std::string input1, std::string input2){ + std::cout << "---- SyncForm() -----\n"; + emp::web::Input div1(settings_div.Find(input1)); + div1.Value(val); + emp::web::Input div2(settings_div.Find(input2)); + div2.Value(val); + div1.Redraw(); + div2.Redraw(); + std::cout << "END SyncForm()\n"; + } + public: + CP_Bug(Config & c, const std::string & div_name = "settings_div") + : config(c), settings_div(div_name) {;} + + void SetOnChangeFun(std::function fun) {on_change_fun = fun;} + + void ExcludeConfig(std::string setting) { + exclude.insert(setting); + } + + void Setup(const std::string & id_prefix = "settings_") { + for (auto group : config.GetGroupSet()) { + // std::cout << "GROUP: " << group->GetName() << std::endl; + std::string group_name = group->GetName(); + group_divs[group_name] = web::Div(id_prefix + group_name); + settings_div << group_divs[group_name]; + + // Setting card setup + web::Div card("card_" + group_name); + group_divs[group_name] << card; + web::Div card_header("card_header_" + group_name); + card << card_header; + web::Div inline_elements(group_name + "_inline"); + inline_elements.SetAttr("class", "clearfix"); + card_header << inline_elements; + web::Element collapse_name_link("button"); + inline_elements << collapse_name_link; + collapse_name_link.SetAttr( + "data-toggle", "collapse", + "data-target", "#card_collapse_" + group_name + ); + collapse_name_link.SetAttr( + "class", "btn btn-link float-left collapse_toggle setting_heading", + "type", "button", + "aria-expanded", "true", + "aria-controls", "#card_body_" + group_name + ); + collapse_name_link << "

" << group->GetDesc() << "

"; + web::Element collapse_icon_link("button"); + inline_elements << collapse_icon_link; + collapse_icon_link.SetAttr( + "data-toggle", "collapse", + "data-target", "#card_collapse_" + group_name, + "class", "btn btn-link float-right collapse_toggle", + "type", "button", + "aria-expanded", "true", + "aria-controls", "#card_body_" + group_name + ); + + // Toggle Icons + web::Element arrow_down("span"); + collapse_icon_link << arrow_down; + arrow_down.SetAttr("class", "fa fa-angle-double-down"); + web::Element arrow_up("span"); + collapse_icon_link << arrow_up; + arrow_up.SetAttr("class", "fa fa-angle-double-up"); + + web::Div card_collapse("card_collapse_" + group_name); + card << card_collapse; + card_collapse.SetAttr( + "class", "collapse show", + "data-parent", "card_" + group_name, + "aria-labelledby", "card_header_" + group_name + ); + web::Div card_body("card_body_" + group_name); + card_collapse << card_body; + // make card true bootstrap cards + card.SetAttr("class", "card"); + card_header.SetAttr("class", "card-header"); + card_body.SetAttr("class", "card-body"); + + + + for (size_t i = 0; i < group->GetSize(); i++) { + // std::cout << group->GetEntry(i)->GetType() << std::endl; + std::string name = group->GetEntry(i)->GetName(); + if (Has(exclude, name)) { + continue; + } + std::string type = group->GetEntry(i)->GetType(); + std::string value = group->GetEntry(i)->GetValue(); + + card_body << web::Element("form").SetCSS("width", "100%") << input_divs[name]; + + // Setting element label + web::Div setting_element(name + "_row"); + input_divs[name] << setting_element; + setting_element.SetAttr("class", "setting_element"); + web::Element title_span("span"); + web::Element title("a"); + setting_element << title_span << title; + title.SetAttr( + "data-toggle", "collapse", + "href", "#" + name + "_dropdown", + "class", "collapse_toggle", + "role", "button", + "aria-expanded", "false", + "aria-controls", "#" + name + "_dropdown" + ); + web::Element arrow_down_for_dropdown("span"); + title << arrow_down_for_dropdown; + arrow_down_for_dropdown.SetAttr("class", "fa fa-angle-double-right toggle_icon_left_margin"); + web::Element arrow_up_for_dropdown("span"); + title << arrow_up_for_dropdown; + arrow_up_for_dropdown.SetAttr("class", "fa fa-angle-double-up toggle_icon_left_margin"); + title << format_label_fun(name); + title_span.SetAttr("class", "title_area"); + + // Prefab Dropdown Box Version + emp::CommentBox box; + // input_divs[name] << box.GetDiv(); + box.AddContent(group->GetEntry(i)->GetDescription()); + + if (Has(numeric_types, type)) { + // Empty div to keep elements aligned in mobile view + web::Element spacer("span"); + setting_element << spacer; + spacer.SetAttr("class", "blank_div"); + + const std::string name_input_slider = name + "_input_slider"; + const std::string name_input_number = name + "_input_number"; + const std::string name_input_mobile_slider = name + "_input_mobile_slider"; + emp::web::Input slider( [](std::string x){ + std::cout << "empty slider function" << std::endl;}, + "range", NULL, name_input_slider + ); + setting_element << slider; + + emp::web::Input number([](std::string val){ + std::cout << "empty number function" << std::endl; + }, + "number", NULL, name_input_number + ); + setting_element << number; + emp::web::Input mobile_slider([](std::string val){ + std::cout << "empty mobile slider function" << std::endl; + }, + "range", NULL, name_input_mobile_slider + ); + std::cout << name << " ---- adding mobile content" << std::endl; + box.AddMobileContent("
"); + box.AddMobileContent(mobile_slider); + std::cout << "BACK to config panel after adding mobile content" << std::endl; + + // Set onchange behavior for inputs + slider.Callback( + [this,name, name_input_number, name_input_mobile_slider](std::string val){ + config.Set(name, val); + SyncForm(val, name_input_number, name_input_mobile_slider); + }); + number.Callback( + [this,name, name_input_slider, name_input_mobile_slider](std::string val){ + config.Set(name, val); + SyncForm(val, name_input_slider, name_input_mobile_slider); + }); + mobile_slider.Callback( + [this,name, name_input_number, name_input_slider](std::string val){ + config.Set(name, val); + SyncForm(val, name_input_number, name_input_slider); + }); + // Set initial values + slider.Value(config.Get(name)); // TODO: It never gets past this line! + number.Value(config.Get(name)); + mobile_slider.Value(config.Get(name)); + slider.SetAttr("class", "input_slider"); + number.SetAttr("class", "input_number"); + + } + else if (type == "bool") { + emp::web::Input bool_input( + [this, name](std::string val){config.Set(name, val); + on_change_fun(val);}, + "checkbox", NULL, name + "_input_checkbox" + ); + setting_element << bool_input; + + } else { + emp::web::Input text_input( + [this, name](std::string val){config.Set(name, val); + on_change_fun(val);}, + "text", NULL, name + "_input_textbox" + ); + setting_element << text_input; + text_input.SetAttr( + "class", "input_text", + "type", "text" + ); + text_input.Value(config.Get(name)); + } + input_divs[name] << box.GetDiv(); + } + } + + } + + web::Div & GetDiv() {return settings_div;} + + }; + +} + +#endif From 5368237de724a65cc85671daac667df60e323a8f Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Tue, 16 Jun 2020 14:21:33 -0500 Subject: [PATCH 011/122] added card element --- source/prefab/Card.h | 58 +++++++++++++++++++++++++++++++++++++ source/prefab/ConfigPanel.h | 45 ++++++++++++++++++++++++---- 2 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 source/prefab/Card.h diff --git a/source/prefab/Card.h b/source/prefab/Card.h new file mode 100644 index 0000000000..9843386e49 --- /dev/null +++ b/source/prefab/Card.h @@ -0,0 +1,58 @@ +#ifndef EMP_CARD_INTERFACE_H +#define EMP_CARD_INTERFACE_H + +#include "../web/Div.h" +#include "../tools/string_utils.h" + +namespace emp { + class Card { + private: + web::Div card; + std::string card_base = card.GetID(); + web::Div card_header{emp::to_string(card_base, "_card_header")}; + web::Div card_body{emp::to_string(card_base, "_card_body")}; + void AddBootstrap(){ + card.SetAttr("class", "card"); + card_header.SetAttr("class", "card-header"); + card_body.SetAttr("class", "card-body"); + } + public: + // Constructor for a plain card + Card(){ + card << card_header; + card << card_body; + AddBootstrap(); + } + // Constructor for a card with a collapsible body + // @param collapse_id (string) - the id for the data-target of the collapse link + // @param expanded (boolean) - true if collapse is open by default, false otherwise + Card(std::string collapse_id, bool expanded){ + card << card_header; + web::Div collapse(collapse_id); + std::cout << "created collapse div\n"; + collapse << card_body; + std::cout << "put card body in collapse div\n"; + card << collapse; + std::cout << "put collapse div in card\n"; + AddBootstrap(); + if (expanded){ + collapse.SetAttr("class", "collapse show"); + } + else{ + collapse.SetAttr("class", "collapse"); + } + } + template + void AddHeaderContent(T val){ + card_header << val; + } + template + void AddBodyContent(T val){ + card_body << val; + } + web::Div & GetDiv() {return card;} + web::Div GetBodyDiv() {return card_body;} + }; +} + +#endif \ No newline at end of file diff --git a/source/prefab/ConfigPanel.h b/source/prefab/ConfigPanel.h index 063d61eee5..eb47e703fd 100644 --- a/source/prefab/ConfigPanel.h +++ b/source/prefab/ConfigPanel.h @@ -11,8 +11,8 @@ #include "../tools/set_utils.h" #include "../tools/string_utils.h" -// Using prefab elements -// #include "Card.h" +// Prefab elements +#include "Card.h" #include "CommentBox.h" namespace emp { @@ -95,6 +95,7 @@ namespace emp { group_divs[group_name] = web::Div(id_prefix + group_name); settings_div << group_divs[group_name]; +<<<<<<< HEAD // Setting card setup web::Div card("card_" + group_name); group_divs[group_name] << card; @@ -102,19 +103,28 @@ namespace emp { card << card_header; web::Div inline_elements(group_name + "_inline"); +======= + // Prefab Card + emp::Card card("card_collapse_" + group_name, true); + group_divs[group_name] << card.GetDiv(); + // Header formatting + web::Div inline_elements(group_name + "_inline"); +>>>>>>> 0595c91... added card element inline_elements.SetAttr("class", "clearfix"); - card_header << inline_elements; + card.AddHeaderContent(inline_elements); + // Header content + // TODO: take care of toggle attribute in a class or function web::Element collapse_name_link("button"); inline_elements << collapse_name_link; collapse_name_link.SetAttr( "data-toggle", "collapse", - "data-target", "#card_collapse_" + group_name + "data-target", "#card_collapse_" + group_name // id passed to card constructor ); collapse_name_link.SetAttr( "class", "btn btn-link float-left collapse_toggle setting_heading", "type", "button", "aria-expanded", "true", - "aria-controls", "#card_body_" + group_name + "aria-controls", "#card_collapse_" + group_name // id passed to card constructor ); collapse_name_link << "

" << group->GetDesc() << "

"; web::Element collapse_icon_link("button"); @@ -130,7 +140,7 @@ namespace emp { "class", "btn btn-link float-right collapse_toggle", "type", "button", "aria-expanded", "true", - "aria-controls", "#card_body_" + group_name + "aria-controls", "#card_collapse_" + group_name // id passed to card constructor ); >>>>>>> 1509465... added prefab module for comment box @@ -142,6 +152,7 @@ namespace emp { collapse_icon_link << arrow_up; arrow_up.SetAttr("class", "fa fa-angle-double-up"); +<<<<<<< HEAD web::Div card_collapse("card_collapse_" + group_name); card << card_collapse; card_collapse.SetAttr( @@ -157,6 +168,17 @@ namespace emp { card_body.SetAttr("class", "card-body"); +======= + // this is taken care of in card element + // TODO: decide what to do with data-parent and aria-labelledby + // web::Div card_collapse("card_collapse_" + group_name); + // card_collapse.SetAttr( + // // "class", "collapse show", + // "data-parent", "card_" + group_name, + // "aria-labelledby", "card_header_" + group_name + // ); + +>>>>>>> 0595c91... added card element for (size_t i = 0; i < group->GetSize(); i++) { // std::cout << group->GetEntry(i)->GetType() << std::endl; @@ -166,8 +188,13 @@ namespace emp { } std::string type = group->GetEntry(i)->GetType(); std::string value = group->GetEntry(i)->GetValue(); +<<<<<<< HEAD card_body << web::Element("form").SetCSS("width", "100%") << input_divs[name]; +======= + + card.AddBodyContent(web::Element("form").SetCSS("width", "100%") << input_divs[name]); +>>>>>>> 0595c91... added card element web::Div mobile_dropdown("mobile_dropdown_" + name); mobile_dropdown.SetAttr("class", "d-md-none"); @@ -248,6 +275,7 @@ namespace emp { std::cout << "empty mobile slider function" << std::endl; }, "range", NULL, name_input_mobile_slider +<<<<<<< HEAD <<<<<<< HEAD ); mobile_dropdown << "
" << mobile_slider; @@ -258,6 +286,11 @@ namespace emp { box.AddMobileContent(mobile_slider); std::cout << "BACK to config panel after adding mobile content" << std::endl; >>>>>>> 1509465... added prefab module for comment box +======= + ); + box.AddMobileContent("
"); + box.AddMobileContent(mobile_slider); +>>>>>>> 0595c91... added card element // Set onchange behavior for inputs slider.Callback( From 968ea664bf4680ff28fda162848ecc9d492639c0 Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Tue, 16 Jun 2020 15:06:29 -0500 Subject: [PATCH 012/122] prefab element for font awesome icons --- source/prefab/ConfigPanel.h | 23 ++++++++++++++++------- source/prefab/FontAwesomeIcon.h | 22 ++++++++++++++++++++++ 2 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 source/prefab/FontAwesomeIcon.h diff --git a/source/prefab/ConfigPanel.h b/source/prefab/ConfigPanel.h index eb47e703fd..664c076884 100644 --- a/source/prefab/ConfigPanel.h +++ b/source/prefab/ConfigPanel.h @@ -14,6 +14,7 @@ // Prefab elements #include "Card.h" #include "CommentBox.h" +#include "FontAwesomeIcon.h" namespace emp { @@ -113,7 +114,7 @@ namespace emp { inline_elements.SetAttr("class", "clearfix"); card.AddHeaderContent(inline_elements); // Header content - // TODO: take care of toggle attribute in a class or function + // TODO: take care of toggle attribute in a class web::Element collapse_name_link("button"); inline_elements << collapse_name_link; collapse_name_link.SetAttr( @@ -142,6 +143,7 @@ namespace emp { "aria-expanded", "true", "aria-controls", "#card_collapse_" + group_name // id passed to card constructor ); +<<<<<<< HEAD >>>>>>> 1509465... added prefab module for comment box // Toggle Icons @@ -151,6 +153,14 @@ namespace emp { web::Element arrow_up("span"); collapse_icon_link << arrow_up; arrow_up.SetAttr("class", "fa fa-angle-double-up"); +======= + + // Prefab Icons + emp::FontAwesomeIcon arrow_down("fa-angle-double-down"); + collapse_icon_link << arrow_down.GetDiv(); + emp::FontAwesomeIcon arrow_up("fa-angle-double-up"); + collapse_icon_link << arrow_up.GetDiv(); +>>>>>>> c2cc336... prefab element for font awesome icons <<<<<<< HEAD web::Div card_collapse("card_collapse_" + group_name); @@ -214,12 +224,11 @@ namespace emp { "aria-expanded", "false", "aria-controls", "#" + name + "_dropdown" ); - web::Element arrow_down_for_dropdown("span"); - title << arrow_down_for_dropdown; - arrow_down_for_dropdown.SetAttr("class", "fa fa-angle-double-right toggle_icon_left_margin"); - web::Element arrow_up_for_dropdown("span"); - title << arrow_up_for_dropdown; - arrow_up_for_dropdown.SetAttr("class", "fa fa-angle-double-up toggle_icon_left_margin"); + + emp::FontAwesomeIcon arrow_right_for_dropdown("fa-angle-double-right toggle_icon_left_margin"); + title << arrow_right_for_dropdown.GetDiv(); + emp::FontAwesomeIcon arrow_up_for_dropdown("fa-angle-double-up toggle_icon_left_margin"); + title << arrow_up_for_dropdown.GetDiv(); title << format_label_fun(name); title_span.SetAttr("class", "title_area"); diff --git a/source/prefab/FontAwesomeIcon.h b/source/prefab/FontAwesomeIcon.h new file mode 100644 index 0000000000..3648ab42e7 --- /dev/null +++ b/source/prefab/FontAwesomeIcon.h @@ -0,0 +1,22 @@ +#ifndef EMP_FONT_AWESOME_ICON_H +#define EMP_FONT_AWESOME_ICON_H + +#include "../web/Element.h" +#include "../tools/string_utils.h" + +namespace emp { + class FontAwesomeIcon { + private: + web::Element icon{emp::to_string("span")}; + public: + // @param fa_name the font awesome class of the desired icon and any other necessary CSS class + FontAwesomeIcon(std::string fa_name){ + std::string full_class = emp::to_string("fa ", fa_name); + std::cout << full_class << std::endl; + icon.SetAttr("class", full_class); + } + web::Div & GetDiv() {return icon;} + }; +} + +#endif \ No newline at end of file From 6e39c1014e9bc977f8ae4bd1a18e2fa3b8b652c8 Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Tue, 16 Jun 2020 16:26:15 -0500 Subject: [PATCH 013/122] add prefab element to add collapibility to web elements --- source/prefab/Collapse.h | 66 +++++++++++++++++++++++++++++++++++++ source/prefab/ConfigPanel.h | 46 ++++++++++++++++++-------- 2 files changed, 99 insertions(+), 13 deletions(-) create mode 100644 source/prefab/Collapse.h diff --git a/source/prefab/Collapse.h b/source/prefab/Collapse.h new file mode 100644 index 0000000000..89c3c1607c --- /dev/null +++ b/source/prefab/Collapse.h @@ -0,0 +1,66 @@ +#ifndef EMP_COLLAPSE_H +#define EMP_COLLAPSE_H + +#include "../web/Div.h" +#include "../tools/string_utils.h" + +namespace emp { + class Collapse { + private: + web::Div link; + web::Div toggle; + public: + // Constructor used when both the link and toggle area need to be wrapped + // @param click - a web element that controls the collapsing area + // @param ref_toggle - a web element that will appear/disappear + // @param id - string representing a unique id used to allow communication between link and toggle divs + // @param expanded - true if collapse is open by default, false otherwise + template + Collapse(T click, S ref_toggle, std::string id, bool expanded){ + toggle = web::Div(id); + link << click; + toggle << ref_toggle; + link.SetAttr( + "data-toggle", "collapse", + "data-target", "#" + id, + "class", "collapse_toggle", + "role", "button", + "aria-controls", "#" + id + ); + if(expanded){ + link.SetAttr("aria-expanded", "true"); + toggle.SetAttr("class", "collapse show"); + } + else{ + link.SetAttr("aria-expanded", "false"); + toggle.SetAttr("class", "collapse"); + } + } + // Constructor used when only the link area needs to be wrapped + // i.e. there is more than one link to the same toggle area or when adding a link to collapse a card + // @param click - a web element that controls the collapsing area + // @param id - string representing a unique id used to allow communication between link and toggle divs + // @param expanded - true if collapse is open by default, false otherwise + template + Collapse(T click, std::string id, bool expanded){ + link << click; + link.SetAttr( + "data-toggle", "collapse", + "data-target", "#" + id, + "class", "collapse_toggle", + "role", "button", + "aria-controls", "#" + id + ); + if(expanded){ + link.SetAttr("aria-expanded", "true"); + } + else{ + link.SetAttr("aria-expanded", "false"); + } + } + web::Div & GetLinkDiv() {return link;} + web::Div & GetToggleDiv() {return toggle;} + }; +} + +#endif \ No newline at end of file diff --git a/source/prefab/ConfigPanel.h b/source/prefab/ConfigPanel.h index 664c076884..784d3d8bdf 100644 --- a/source/prefab/ConfigPanel.h +++ b/source/prefab/ConfigPanel.h @@ -15,6 +15,7 @@ #include "Card.h" #include "CommentBox.h" #include "FontAwesomeIcon.h" +#include "Collapse.h" namespace emp { @@ -113,22 +114,17 @@ namespace emp { >>>>>>> 0595c91... added card element inline_elements.SetAttr("class", "clearfix"); card.AddHeaderContent(inline_elements); + // Header content - // TODO: take care of toggle attribute in a class web::Element collapse_name_link("button"); - inline_elements << collapse_name_link; - collapse_name_link.SetAttr( - "data-toggle", "collapse", - "data-target", "#card_collapse_" + group_name // id passed to card constructor - ); - collapse_name_link.SetAttr( - "class", "btn btn-link float-left collapse_toggle setting_heading", - "type", "button", - "aria-expanded", "true", - "aria-controls", "#card_collapse_" + group_name // id passed to card constructor - ); + emp::Collapse header_title_toggle(collapse_name_link, "card_collapse_" + group_name, true); + inline_elements << header_title_toggle.GetLinkDiv(); + collapse_name_link.SetAttr("class", "btn btn-link float-left collapse_toggle setting_heading"); + + // Prefab Collapse/toggle for card collapse_name_link << "

" << group->GetDesc() << "

"; web::Element collapse_icon_link("button"); +<<<<<<< HEAD inline_elements << collapse_icon_link; <<<<<<< HEAD collapse_icon_link.SetAttr("data-toggle", "collapse").SetAttr("data-target", "#card_collapse_" + group_name); @@ -154,6 +150,11 @@ namespace emp { collapse_icon_link << arrow_up; arrow_up.SetAttr("class", "fa fa-angle-double-up"); ======= +======= + emp::Collapse header_icon_toggle(collapse_icon_link, "card_collapse_" + group_name, true); + inline_elements << header_icon_toggle.GetLinkDiv(); + collapse_icon_link.SetAttr("class", "btn btn-link float-right collapse_toggle"); +>>>>>>> 5f848a8... add prefab element to add collapibility to web elements // Prefab Icons emp::FontAwesomeIcon arrow_down("fa-angle-double-down"); @@ -178,6 +179,7 @@ namespace emp { card_body.SetAttr("class", "card-body"); +<<<<<<< HEAD ======= // this is taken care of in card element // TODO: decide what to do with data-parent and aria-labelledby @@ -190,6 +192,8 @@ namespace emp { >>>>>>> 0595c91... added card element +======= +>>>>>>> 5f848a8... add prefab element to add collapibility to web elements for (size_t i = 0; i < group->GetSize(); i++) { // std::cout << group->GetEntry(i)->GetType() << std::endl; std::string name = group->GetEntry(i)->GetName(); @@ -214,6 +218,7 @@ namespace emp { input_divs[name] << setting_element; setting_element.SetAttr("class", "setting_element"); web::Element title_span("span"); +<<<<<<< HEAD web::Element title("a"); setting_element << title_span << title; title.SetAttr( @@ -224,6 +229,11 @@ namespace emp { "aria-expanded", "false", "aria-controls", "#" + name + "_dropdown" ); +======= + setting_element << title_span; + web::Element title("button"); + title.SetAttr("class", "btn btn-link"); +>>>>>>> 5f848a8... add prefab element to add collapibility to web elements emp::FontAwesomeIcon arrow_right_for_dropdown("fa-angle-double-right toggle_icon_left_margin"); title << arrow_right_for_dropdown.GetDiv(); @@ -231,6 +241,7 @@ namespace emp { title << arrow_up_for_dropdown.GetDiv(); title << format_label_fun(name); title_span.SetAttr("class", "title_area"); +<<<<<<< HEAD // This makes the Comment box toggle when title is clicked // TODO: make a class to create a toggle for two elements? @@ -239,10 +250,19 @@ namespace emp { dropdown_target.SetAttr("class", "collapse"); // Prefab Dropdown Box Version +======= + + // Prefab Dropdown Box Version +>>>>>>> 5f848a8... add prefab element to add collapibility to web elements emp::CommentBox box; - dropdown_target << box.GetDiv(); box.AddContent(group->GetEntry(i)->GetDescription()); + // Prefab Collapse/toggle for setting element + emp::Collapse title_toggle(title, box.GetDiv(), name + "_dropdown", false); + input_divs[name] << title_toggle.GetToggleDiv(); + title_span << title_toggle.GetLinkDiv(); + + if (Has(numeric_types, type)) { // Seems more efficient to use web::Input, but it's not working // TODO: need to define on change function to use built in Input From d98a2216679490d76f906a13aa4fe08ced9a8af7 Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Thu, 18 Jun 2020 09:59:39 -0500 Subject: [PATCH 014/122] made card header the collapse link for card --- source/prefab/Card.h | 66 +++++++++++++++-------- source/prefab/DefaultConfigPanelStyle.css | 4 ++ 2 files changed, 47 insertions(+), 23 deletions(-) diff --git a/source/prefab/Card.h b/source/prefab/Card.h index 9843386e49..8e4a19c05b 100644 --- a/source/prefab/Card.h +++ b/source/prefab/Card.h @@ -3,11 +3,15 @@ #include "../web/Div.h" #include "../tools/string_utils.h" +#include "Collapse.h" +#include "FontAwesomeIcon.h" namespace emp { class Card { private: web::Div card; + web::Div collapse_link; + web::Div collapse_body; std::string card_base = card.GetID(); web::Div card_header{emp::to_string(card_base, "_card_header")}; web::Div card_body{emp::to_string(card_base, "_card_body")}; @@ -17,34 +21,50 @@ namespace emp { card_body.SetAttr("class", "card-body"); } public: - // Constructor for a plain card - Card(){ - card << card_header; - card << card_body; - AddBootstrap(); + enum Collapse {none, open, closed}; // collapse options for constructing a card + Card(Collapse state=none, bool showGlyphs=true){ + if(state != none){ // if card is collapsible, make the collapse link the head of the card + if(state == open){ + emp::Collapse accordion(card_header, card_body, emp::to_string(card_base + "_card_collapse"), true); + collapse_link = accordion.GetLinkDiv(); + collapse_body = accordion.GetToggleDiv(); + } + else{ + emp::Collapse accordion(card_header, card_body, emp::to_string(card_base + "_card_collapse"), false); + collapse_link = accordion.GetLinkDiv(); + collapse_body = accordion.GetToggleDiv(); + } + if(showGlyphs){ // by default add glyphs to a collapsible card + emp::FontAwesomeIcon up("fa-angle-double-up float-right collapse_toggle btn-link"); + emp::FontAwesomeIcon down("fa-angle-double-down float-right collapse_toggle btn-link"); + card_header << up.GetDiv(); + card_header << down.GetDiv(); + + } + card << collapse_link; + card << collapse_body; + } + else{ // plain card with no toggle enabled + card << card_header; + card << card_body; } - // Constructor for a card with a collapsible body - // @param collapse_id (string) - the id for the data-target of the collapse link - // @param expanded (boolean) - true if collapse is open by default, false otherwise - Card(std::string collapse_id, bool expanded){ - card << card_header; - web::Div collapse(collapse_id); - std::cout << "created collapse div\n"; - collapse << card_body; - std::cout << "put card body in collapse div\n"; - card << collapse; - std::cout << "put collapse div in card\n"; AddBootstrap(); - if (expanded){ - collapse.SetAttr("class", "collapse show"); + } + template + void AddHeaderContent(T val, bool link_content=false){ + if(link_content){ + // add bootstrap link properities to content (hover, underline, etc.), + // but does not have a target or href because it is assumed that + // this content will control the card collapse, which is done in the + // constructor. If you want the content to link somewhere else, + // specify that in the web element/div param val {and set link_content=true TODO: verify this}. + web::Div btn_link; + btn_link.SetAttr("class", "btn-link"); + card_header << btn_link << val; } else{ - collapse.SetAttr("class", "collapse"); - } + card_header << val; } - template - void AddHeaderContent(T val){ - card_header << val; } template void AddBodyContent(T val){ diff --git a/source/prefab/DefaultConfigPanelStyle.css b/source/prefab/DefaultConfigPanelStyle.css index f9fa1a73d2..a3b2fd8ab3 100644 --- a/source/prefab/DefaultConfigPanelStyle.css +++ b/source/prefab/DefaultConfigPanelStyle.css @@ -20,6 +20,10 @@ .setting_heading:hover{ color: #0275d8 /* Bootstrap default pirmary color */ } +/* Lower opacity of card body when hovering over collapsible header */ +.collapse_toggle:hover + .collapse .card-body{ + opacity: .6; +} /* Card Body */ .setting_element { From 598b47e10cbe59e3236d3dbd4f2b5a8228ead2fd Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Thu, 18 Jun 2020 16:24:01 -0500 Subject: [PATCH 015/122] examples for prefab components --- examples/prefab/Card.cc | 34 ++++++++++++++++++++++ examples/prefab/Card.html | 31 ++++++++++++++++++++ examples/prefab/Collapse.cc | 42 +++++++++++++++++++++++++++ examples/prefab/Collapse.html | 26 +++++++++++++++++ examples/prefab/CommentBox.cc | 28 ++++++++++++++++++ examples/prefab/CommentBox.html | 29 +++++++++++++++++++ examples/prefab/ConfigPanel.cc | 43 ++++++++++++++++++++++++++++ examples/prefab/ConfigPanel.html | 32 +++++++++++++++++++++ examples/prefab/FontAwesomeIcon.cc | 42 +++++++++++++++++++++++++++ examples/prefab/FontAwesomeIcon.html | 29 +++++++++++++++++++ examples/prefab/SampleConfig.h | 41 ++++++++++++++++++++++++++ 11 files changed, 377 insertions(+) create mode 100644 examples/prefab/Card.cc create mode 100644 examples/prefab/Card.html create mode 100644 examples/prefab/Collapse.cc create mode 100644 examples/prefab/Collapse.html create mode 100644 examples/prefab/CommentBox.cc create mode 100644 examples/prefab/CommentBox.html create mode 100644 examples/prefab/ConfigPanel.cc create mode 100644 examples/prefab/ConfigPanel.html create mode 100644 examples/prefab/FontAwesomeIcon.cc create mode 100644 examples/prefab/FontAwesomeIcon.html create mode 100644 examples/prefab/SampleConfig.h diff --git a/examples/prefab/Card.cc b/examples/prefab/Card.cc new file mode 100644 index 0000000000..caa4d288f1 --- /dev/null +++ b/examples/prefab/Card.cc @@ -0,0 +1,34 @@ +// This file is part of Empirical, https://github.com/devosoft/Empirical +// Copyright (C) Michigan State University, 2020. +// Released under the MIT Software license; see doc/LICENSE + +#include + +#include "web/web.h" +#include "prefab/Card.h" + +namespace UI = emp::web; + +UI::Document doc("emp_base"); + +int main() +{ + // Plain Card + emp::Card pCard(emp::Card::Collapse::none); + pCard.AddHeaderContent("Plain card"); + pCard.AddBodyContent("Plain body content"); + doc << pCard.GetDiv(); + + // Collapsible Card, default open + emp::Card openCard(emp::Card::Collapse::open, true); + // Header content with bootstrap link properties + openCard.AddHeaderContent("Open card", true); + openCard.AddBodyContent("Open body content
Glyphs
Linked title"); + doc << openCard.GetDiv(); + + // Collapsible Card, default closed + emp::Card closedCard(emp::Card::Collapse::closed, false); + closedCard.AddHeaderContent("Closed card"); + closedCard.AddBodyContent("Closed body content
No Glyphs
Plain title"); + doc << closedCard.GetDiv(); +} diff --git a/examples/prefab/Card.html b/examples/prefab/Card.html new file mode 100644 index 0000000000..8c42628fb3 --- /dev/null +++ b/examples/prefab/Card.html @@ -0,0 +1,31 @@ + + + + + + + + + + + + +Card Examples + + + +
+

Card Examples

+
+ +
+
+
+ + + + + + + + diff --git a/examples/prefab/Collapse.cc b/examples/prefab/Collapse.cc new file mode 100644 index 0000000000..a5932cb197 --- /dev/null +++ b/examples/prefab/Collapse.cc @@ -0,0 +1,42 @@ +// This file is part of Empirical, https://github.com/devosoft/Empirical +// Copyright (C) Michigan State University, 2020. +// Released under the MIT Software license; see doc/LICENSE + +#include + +#include "web/web.h" +#include "web/Div.h" +#include "prefab/Collapse.h" + +namespace UI = emp::web; + +UI::Document doc("emp_base"); + +int main() +{ + UI::Div btn1; + UI::Div content1; + + emp::Collapse collapse1(btn1, content1, true, "my_collapse"); + doc << collapse1.GetLinkDiv(); + doc << collapse1.GetToggleDiv(); + + btn1.SetAttr("class", "btn btn-primary"); + btn1 << "Click me 1"; + content1 << "This content starts out open and has an id of 'my_collapse'.
"; + content1 << "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; + + doc << "

"; + + UI::Div btn2; + UI::Div content2; + emp::Collapse collapse2(btn2, content2, false); + doc << collapse2.GetLinkDiv(); + doc << collapse2.GetToggleDiv(); + + btn2.SetAttr("class", "btn btn-primary"); + btn2 << "Click me 2"; + content2 << "This content starts out closed and has an emscripten generated id.
"; + content2 << "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; + +} diff --git a/examples/prefab/Collapse.html b/examples/prefab/Collapse.html new file mode 100644 index 0000000000..5eaece95aa --- /dev/null +++ b/examples/prefab/Collapse.html @@ -0,0 +1,26 @@ + + + + + + + +Collapse Examples + + + +
+

Collapse Examples

+
+ +
+
+
+ + + + + + + + diff --git a/examples/prefab/CommentBox.cc b/examples/prefab/CommentBox.cc new file mode 100644 index 0000000000..7d238333d7 --- /dev/null +++ b/examples/prefab/CommentBox.cc @@ -0,0 +1,28 @@ +// This file is part of Empirical, https://github.com/devosoft/Empirical +// Copyright (C) Michigan State University, 2020. +// Released under the MIT Software license; see doc/LICENSE + +#include + +#include "web/web.h" +#include "web/Div.h" +#include "web/Element.h" +#include "prefab/CommentBox.h" + +namespace UI = emp::web; + +UI::Document doc("emp_base"); + +int main() +{ + emp::CommentBox box; + UI::Div title("desktop_content"); + title << "

Content that shows on all screen sizes

"; + box.AddContent(title); + UI::Element mobile("span"); + mobile << "

Content that only shows on small screens
Web conponents can be added as content

"; + mobile << "
"; + box.AddMobileContent(mobile); + box.AddMobileContent("String literals can also be added to box content!"); + doc << box.GetDiv(); +} diff --git a/examples/prefab/CommentBox.html b/examples/prefab/CommentBox.html new file mode 100644 index 0000000000..f54c8dc51b --- /dev/null +++ b/examples/prefab/CommentBox.html @@ -0,0 +1,29 @@ + + + + + + + + + + +Comment Box Example + + + +
+

Comment Box Example

+
+ +
+
+
+ + + + + + + + diff --git a/examples/prefab/ConfigPanel.cc b/examples/prefab/ConfigPanel.cc new file mode 100644 index 0000000000..3d1c1a3d17 --- /dev/null +++ b/examples/prefab/ConfigPanel.cc @@ -0,0 +1,43 @@ +// This file is part of Config Panel App +// Copyright (C) Matthew Andres Moreno, 2020. +// Released under MIT license; see LICENSE + +#include + +#include "config/command_line.h" +#include "config/ArgManager.h" +#include "prefab/ConfigPanel.h" +#include "web/web.h" +#include "web/UrlParams.h" + +#include "SampleConfig.h" + +namespace UI = emp::web; + +UI::Document doc("emp_base"); + +Config cfg; + +emp::ConfigPanel config_panel(cfg); + +int main() +{ + // apply configuration query params and config files to Config + auto specs = emp::ArgManager::make_builtin_specs(&cfg); + emp::ArgManager am(emp::web::GetUrlParams(), specs); + // cfg.Read("config.cfg"); + am.UseCallbacks(); + if (am.HasUnused()) std::exit(EXIT_FAILURE); + + // log configuraiton settings + std::cout << "==============================" << std::endl; + std::cout << "| How am I configured? |" << std::endl; + std::cout << "==============================" << std::endl; + cfg.Write(std::cout); + std::cout << "==============================\n" << std::endl; + + // setup configuration panel + config_panel.Setup(); + doc << config_panel.GetDiv(); + +} diff --git a/examples/prefab/ConfigPanel.html b/examples/prefab/ConfigPanel.html new file mode 100644 index 0000000000..e7f8ae5258 --- /dev/null +++ b/examples/prefab/ConfigPanel.html @@ -0,0 +1,32 @@ + + + + + + + + + + + + +Config Panel App + + + +
+

Config Panel App

+

source: github.com/mmore500/config-panel-app

+
+ +
+
+
+ + + + + + + + diff --git a/examples/prefab/FontAwesomeIcon.cc b/examples/prefab/FontAwesomeIcon.cc new file mode 100644 index 0000000000..9927acbdc5 --- /dev/null +++ b/examples/prefab/FontAwesomeIcon.cc @@ -0,0 +1,42 @@ +// This file is part of Empirical, https://github.com/devosoft/Empirical +// Copyright (C) Michigan State University, 2020. +// Released under the MIT Software license; see doc/LICENSE + +#include + +#include "web/web.h" +#include "web/Div.h" +#include "prefab/FontAwesomeIcon.h" + +namespace UI = emp::web; + +UI::Document doc("emp_base"); + +int main() +{ + UI::Div toggleIcons; + doc << toggleIcons; + toggleIcons << "

Collapse Icons

"; + emp::FontAwesomeIcon up("fa-angle-double-up"); + toggleIcons << up.GetDiv(); + toggleIcons << "
"; + emp::FontAwesomeIcon down("fa-angle-double-down"); + toggleIcons << down.GetDiv(); + toggleIcons << "
"; + emp::FontAwesomeIcon right("fa-angle-double-right"); + toggleIcons << right.GetDiv(); + + doc << "


"; + + UI::Div infoIcons; + doc << infoIcons; + infoIcons << "

Circle icons

"; + emp::FontAwesomeIcon i_circle("fa-info-circle"); + infoIcons << i_circle.GetDiv(); + infoIcons << "
"; + emp::FontAwesomeIcon question_circle("fa-question-circle-o"); + infoIcons << question_circle.GetDiv(); + infoIcons << "
"; + emp::FontAwesomeIcon plus_circle("fa-plus-circle"); + infoIcons << plus_circle.GetDiv(); +} diff --git a/examples/prefab/FontAwesomeIcon.html b/examples/prefab/FontAwesomeIcon.html new file mode 100644 index 0000000000..0d4d5a1a07 --- /dev/null +++ b/examples/prefab/FontAwesomeIcon.html @@ -0,0 +1,29 @@ + + + + + + + + + +Font Awesome Examples + + + +
+

Font Awesome Examples

+

View Font Awesome icon library: https://fontawesome.com/v4.7.0/icons/

+
+ +
+
+
+ + + + + + + + diff --git a/examples/prefab/SampleConfig.h b/examples/prefab/SampleConfig.h new file mode 100644 index 0000000000..f407a0e6ee --- /dev/null +++ b/examples/prefab/SampleConfig.h @@ -0,0 +1,41 @@ +#pragma once + +#include "config/config.h" + +EMP_BUILD_CONFIG( Config, + GROUP(MAIN, "Global settings"), + VALUE(BOOL_EX, bool, true, "example description"), + VALUE(SEED, int, -1, "Random number generator seed"), + VALUE(TIME_STEPS, int, 1000, "Number of time steps to run for"), + VALUE(PLATE_LENGTH, double, 10.0, "Length of plate in mm"), + VALUE(PLATE_WIDTH, double, 6.0, "Width of plate in mm"), + VALUE(PLATE_DEPTH, double, 1.45, "Depth of plate in mm"), + VALUE(CELL_DIAMETER, double, 20.0, "Cell length and width in microns"), + VALUE(INIT_POP_SIZE, int, 100, "Number of cells to seed population with"), + VALUE(DATA_RESOLUTION, int, 10, "How many updates between printing data?"), + + GROUP(CELL, "Cell settings"), + VALUE(NEUTRAL_MUTATION_RATE, double, .05, "Probability of a neutral mutation (only relevant for phylogenetic signature)"), + VALUE(ASYMMETRIC_DIVISION_PROB, double, 0, "Probability of a change in stemness"), + VALUE(MITOSIS_PROB, double, .5, "Probability of mitosis"), + VALUE(HYPOXIA_DEATH_PROB, double, .25, "Probability of dieing, given hypoxic conditions"), + VALUE(AGE_LIMIT, int, 100, "Age over which non-stem cells die"), + VALUE(BASAL_OXYGEN_CONSUMPTION, double, .00075, "Base oxygen consumption rate"), + VALUE(OXYGEN_CONSUMPTION_DIVISION, double, .00075*5, "Amount of oxygen a cell consumes on division"), + + GROUP(OXYGEN, "Oxygen settings"), + VALUE(INITIAL_OXYGEN_LEVEL, double, .5, "Initial oxygen level (will be placed in all cells)"), + VALUE(OXYGEN_DIFFUSION_COEFFICIENT, double, .1, "Oxygen diffusion coefficient"), + VALUE(DIFFUSION_STEPS_PER_TIME_STEP, int, 100, "Rate at which diffusion is calculated relative to rest of model"), + VALUE(OXYGEN_THRESHOLD, double, .1, "How much oxygen do cells need to survive?"), + VALUE(KM, double, 0.01, "Michaelis-Menten kinetic parameter"), + + GROUP(TREATMENT, "Treatment settings"), + VALUE(RADIATION_DOSES, int, 1, "Number of radiation doses to apply (for use in web interface - use a radiation prescription file for command-line)"), + VALUE(RADIATION_DOSE_SIZE, double, 2, "Dose size (Gy) (for use in web interface - use a radiation prescription file for command-line)"), + VALUE(RADIATION_PRESCRIPTION_FILE, std::string, "none", "File containing radiation prescription"), + VALUE(K_OER, double, 3.28, "Effective OER constant"), + VALUE(OER_MIN, double, 1, "OER min constant"), + VALUE(OER_ALPHA_MAX, double, 1.75, "OER alpha max constant"), + VALUE(OER_BETA_MAX, double, 3.25, "OER alpha (? this is what the paper says but I feel like it's supposed to be beta) max constant"), +); From 58cf96c221e139183a67a0f49d2e3ecd7e51cf08 Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Fri, 19 Jun 2020 15:01:13 -0500 Subject: [PATCH 016/122] can add classes to a widget using SetAttr multiple times --- source/web/Attributes.h | 16 ++++++++++++++-- source/web/Widget.h | 11 ++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/source/web/Attributes.h b/source/web/Attributes.h index a2a2f1a254..9f0596c9a9 100644 --- a/source/web/Attributes.h +++ b/source/web/Attributes.h @@ -39,10 +39,22 @@ namespace web { int GetSize() const { return (int) settings.size(); } Attributes & DoSet(const std::string & in_set, const std::string & in_val) { - settings[in_set] = in_val; + if(in_set.compare("class")==0 && Has(in_set)){ + // Append new class to classes already assigned to attribute + std::string classes = settings[in_set]; + classes += " " + in_val; + settings[in_set] = classes; + } + else{ + settings[in_set] = in_val; + } return *this; } + std::string GetAttrValue(const std::string & in_set){ + return settings[in_set]; + } + /// Record that attribute "a" is set to value "v" (converted to string) and return this object. template Attributes & Set(const std::string & s, SET_TYPE v) { @@ -106,7 +118,7 @@ namespace web { } } - /// Apply onlay a SPECIFIC attributes setting from the setting library to widget_id. + /// Apply only a SPECIFIC attributes setting from the setting library to widget_id. void Apply(const std::string & widget_id, const std::string & setting) { emp_assert(Has(setting)); diff --git a/source/web/Widget.h b/source/web/Widget.h index 8c31103356..fb0f278689 100644 --- a/source/web/Widget.h +++ b/source/web/Widget.h @@ -577,7 +577,12 @@ namespace web { /// By default DoAttr will track the new information and apply it (if active) to the widget. virtual void DoAttr(const std::string & setting, const std::string & value) { info->extras.attr.DoSet(setting, value); - if (IsActive()) Attributes::Apply(info->id, setting, value); + std::string updated_val = value; + if(setting.compare("class")==0){ + // apply new class (value) and any previously added classes + updated_val = info->extras.attr.GetAttrValue(setting); + } + if (IsActive()) Attributes::Apply(info->id, setting, updated_val); } /// Listener options may be overridden in derived classes that have multiple listen targets. /// By default DoListen will track new listens and set them up immediately, if active. @@ -614,6 +619,10 @@ namespace web { return SetCSS(setting2, val2, others...); // Recurse to the others. } + // TODO: AddClass ->extras ->attributes + // Now when you call SetAttr for class more than once, new class is added to list, doen't replace other classes + // Should we add a separate function instead? in addition to? + /// Multiple Attributes can be provided simultaneously. template return_t & SetAttr(const std::string & setting1, T1 && val1, From b19a89f672a8cdaf209c6007a93bfee71a11adf0 Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Wed, 24 Jun 2020 10:20:27 -0500 Subject: [PATCH 017/122] AddClass is it's own method now --- source/web/Attributes.h | 20 ++++++++++++-------- source/web/Widget.h | 22 +++++++++++++--------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/source/web/Attributes.h b/source/web/Attributes.h index 9f0596c9a9..415269605f 100644 --- a/source/web/Attributes.h +++ b/source/web/Attributes.h @@ -16,6 +16,7 @@ #endif #include "../tools/string_utils.h" +#include "../base/errors.h" #include #include @@ -39,15 +40,18 @@ namespace web { int GetSize() const { return (int) settings.size(); } Attributes & DoSet(const std::string & in_set, const std::string & in_val) { - if(in_set.compare("class")==0 && Has(in_set)){ - // Append new class to classes already assigned to attribute - std::string classes = settings[in_set]; - classes += " " + in_val; - settings[in_set] = classes; - } - else{ - settings[in_set] = in_val; + settings[in_set] = in_val; + return *this; + } + + Attributes & DoAddClass(const std::string & in_val) { + if (!Has("class")){ + emp::LibraryWarning("AddClass should be used after SetAttr has been used to set the first class \nEx: SetAttr(\"class\", \""+in_val+"\")"); } + // Eventhough warning is given, in_val is added as a class in any case + std::string classes = settings["class"]; + classes += " " + in_val; + settings["class"] = classes; return *this; } diff --git a/source/web/Widget.h b/source/web/Widget.h index fb0f278689..1eaaab6caf 100644 --- a/source/web/Widget.h +++ b/source/web/Widget.h @@ -577,12 +577,12 @@ namespace web { /// By default DoAttr will track the new information and apply it (if active) to the widget. virtual void DoAttr(const std::string & setting, const std::string & value) { info->extras.attr.DoSet(setting, value); - std::string updated_val = value; - if(setting.compare("class")==0){ - // apply new class (value) and any previously added classes - updated_val = info->extras.attr.GetAttrValue(setting); - } - if (IsActive()) Attributes::Apply(info->id, setting, updated_val); + if (IsActive()) Attributes::Apply(info->id, setting, value); + } + /// New class will be appended to any existing classes for this widget, not overridden. + virtual void DoClass(const std::string & value){ + info->extras.attr.DoAddClass(value); + if (IsActive()) Attributes::Apply(info->id, "class", info->extras.attr.GetAttrValue("class")); } /// Listener options may be overridden in derived classes that have multiple listen targets. /// By default DoListen will track new listens and set them up immediately, if active. @@ -619,9 +619,13 @@ namespace web { return SetCSS(setting2, val2, others...); // Recurse to the others. } - // TODO: AddClass ->extras ->attributes - // Now when you call SetAttr for class more than once, new class is added to list, doen't replace other classes - // Should we add a separate function instead? in addition to? + /// Add more than one class to this widget. + template + return_t & AddClass(SETTING_TYPE && value){ + emp_assert(info != nullptr); + DoClass(emp::to_string(value)); + return (return_t &) *this; + } /// Multiple Attributes can be provided simultaneously. template From 9d93cfa4869ea44df8676cad5650c632c268c69e Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Wed, 24 Jun 2020 10:54:42 -0500 Subject: [PATCH 018/122] change namespace to emp::prefab and inherit from web components for some prefab components --- source/prefab/CP_Bug.h | 102 ++++++------------------- source/prefab/Card.h | 127 +++++++++++++++++--------------- source/prefab/Collapse.h | 100 ++++++++++++------------- source/prefab/CommentBox.h | 83 +++++++++++++-------- source/prefab/ConfigPanel.h | 43 ++++++++--- source/prefab/FontAwesomeIcon.h | 25 ++++--- 6 files changed, 232 insertions(+), 248 deletions(-) diff --git a/source/prefab/CP_Bug.h b/source/prefab/CP_Bug.h index 3e185bb1a9..5b97b17fb1 100644 --- a/source/prefab/CP_Bug.h +++ b/source/prefab/CP_Bug.h @@ -13,16 +13,20 @@ // Using prefab elements #include "CommentBox.h" +#include "Card.h" +#include "Collapse.h" +#include "FontAwesomeIcon.h" -/* +/** * This config panel will not render on the web. When setting the initial value for the first slider, * it throws this exception: uncaught exception: abort(2). Build with -s ASSERTIONS=1 for more info. * Emscripten notes on exception: https://emscripten.org/docs/porting/Debugging.html#debugging-assertions * * Methods called when setting value: Value -> UpdateValue -> DoChange -> callback -> SynchForm -> Value * -* Note: this is not an issue when the prefab comment box element is added to the map of input_divs immediately -* after creation. (uncomment line 160 and comment line 239) +* Note: This is not an issue when the prefab comment box element is added to the map of input_divs immediately +* after creation. (uncomment line 109 and comment line 188) +* All description boxes will be expanded. */ namespace emp { @@ -67,61 +71,15 @@ namespace emp { group_divs[group_name] = web::Div(id_prefix + group_name); settings_div << group_divs[group_name]; - // Setting card setup - web::Div card("card_" + group_name); + // Prefab Card + prefab::Card card(prefab::Card::Collapse::OPEN); group_divs[group_name] << card; - web::Div card_header("card_header_" + group_name); - card << card_header; - web::Div inline_elements(group_name + "_inline"); - inline_elements.SetAttr("class", "clearfix"); - card_header << inline_elements; - web::Element collapse_name_link("button"); - inline_elements << collapse_name_link; - collapse_name_link.SetAttr( - "data-toggle", "collapse", - "data-target", "#card_collapse_" + group_name - ); - collapse_name_link.SetAttr( - "class", "btn btn-link float-left collapse_toggle setting_heading", - "type", "button", - "aria-expanded", "true", - "aria-controls", "#card_body_" + group_name - ); - collapse_name_link << "

" << group->GetDesc() << "

"; - web::Element collapse_icon_link("button"); - inline_elements << collapse_icon_link; - collapse_icon_link.SetAttr( - "data-toggle", "collapse", - "data-target", "#card_collapse_" + group_name, - "class", "btn btn-link float-right collapse_toggle", - "type", "button", - "aria-expanded", "true", - "aria-controls", "#card_body_" + group_name - ); - - // Toggle Icons - web::Element arrow_down("span"); - collapse_icon_link << arrow_down; - arrow_down.SetAttr("class", "fa fa-angle-double-down"); - web::Element arrow_up("span"); - collapse_icon_link << arrow_up; - arrow_up.SetAttr("class", "fa fa-angle-double-up"); - - web::Div card_collapse("card_collapse_" + group_name); - card << card_collapse; - card_collapse.SetAttr( - "class", "collapse show", - "data-parent", "card_" + group_name, - "aria-labelledby", "card_header_" + group_name - ); - web::Div card_body("card_body_" + group_name); - card_collapse << card_body; - // make card true bootstrap cards - card.SetAttr("class", "card"); - card_header.SetAttr("class", "card-header"); - card_body.SetAttr("class", "card-body"); - - + + // Card header content + web::Div setting_heading; + card.AddHeaderContent(setting_heading); + setting_heading << "

" + group->GetDesc() + "

"; + setting_heading.SetAttr("class", "setting_heading"); for (size_t i = 0; i < group->GetSize(); i++) { // std::cout << group->GetEntry(i)->GetType() << std::endl; @@ -132,35 +90,23 @@ namespace emp { std::string type = group->GetEntry(i)->GetType(); std::string value = group->GetEntry(i)->GetValue(); - card_body << web::Element("form").SetCSS("width", "100%") << input_divs[name]; + card.AddBodyContent(web::Element("form").SetCSS("width", "100%") << input_divs[name]); // Setting element label web::Div setting_element(name + "_row"); input_divs[name] << setting_element; setting_element.SetAttr("class", "setting_element"); web::Element title_span("span"); - web::Element title("a"); - setting_element << title_span << title; - title.SetAttr( - "data-toggle", "collapse", - "href", "#" + name + "_dropdown", - "class", "collapse_toggle", - "role", "button", - "aria-expanded", "false", - "aria-controls", "#" + name + "_dropdown" - ); - web::Element arrow_down_for_dropdown("span"); - title << arrow_down_for_dropdown; - arrow_down_for_dropdown.SetAttr("class", "fa fa-angle-double-right toggle_icon_left_margin"); - web::Element arrow_up_for_dropdown("span"); - title << arrow_up_for_dropdown; - arrow_up_for_dropdown.SetAttr("class", "fa fa-angle-double-up toggle_icon_left_margin"); + setting_element << title_span; + web::Element title("button"); + title_span << title; + title.SetAttr("class", "btn btn-link"); title << format_label_fun(name); title_span.SetAttr("class", "title_area"); - // Prefab Dropdown Box Version - emp::CommentBox box; - // input_divs[name] << box.GetDiv(); + // Prefab Dropdown Box + prefab::CommentBox box; + // input_divs[name] << box; // TODO: uncomment this line box.AddContent(group->GetEntry(i)->GetDescription()); if (Has(numeric_types, type)) { @@ -239,7 +185,7 @@ namespace emp { ); text_input.Value(config.Get(name)); } - input_divs[name] << box.GetDiv(); + input_divs[name] << box; // TODO: Comment this line } } diff --git a/source/prefab/Card.h b/source/prefab/Card.h index 8e4a19c05b..a29a38c18e 100644 --- a/source/prefab/Card.h +++ b/source/prefab/Card.h @@ -7,72 +7,77 @@ #include "FontAwesomeIcon.h" namespace emp { - class Card { - private: - web::Div card; - web::Div collapse_link; - web::Div collapse_body; - std::string card_base = card.GetID(); - web::Div card_header{emp::to_string(card_base, "_card_header")}; - web::Div card_body{emp::to_string(card_base, "_card_body")}; - void AddBootstrap(){ - card.SetAttr("class", "card"); - card_header.SetAttr("class", "card-header"); - card_body.SetAttr("class", "card-body"); - } - public: - enum Collapse {none, open, closed}; // collapse options for constructing a card - Card(Collapse state=none, bool showGlyphs=true){ - if(state != none){ // if card is collapsible, make the collapse link the head of the card - if(state == open){ - emp::Collapse accordion(card_header, card_body, emp::to_string(card_base + "_card_collapse"), true); - collapse_link = accordion.GetLinkDiv(); - collapse_body = accordion.GetToggleDiv(); - } - else{ - emp::Collapse accordion(card_header, card_body, emp::to_string(card_base + "_card_collapse"), false); - collapse_link = accordion.GetLinkDiv(); - collapse_body = accordion.GetToggleDiv(); - } - if(showGlyphs){ // by default add glyphs to a collapsible card - emp::FontAwesomeIcon up("fa-angle-double-up float-right collapse_toggle btn-link"); - emp::FontAwesomeIcon down("fa-angle-double-down float-right collapse_toggle btn-link"); - card_header << up.GetDiv(); - card_header << down.GetDiv(); + namespace prefab{ + class Card : public web::Div{ + private: + web::Div collapse_link; + web::Div collapse_body; + std::string card_base = this->GetID(); + web::Div card_header{emp::to_string(card_base, "_card_header")}; + web::Div card_body{emp::to_string(card_base, "_card_body")}; + void AddBootstrap(){ + this->SetAttr("class", "card"); + card_header.SetAttr("class", "card-header"); + card_body.SetAttr("class", "card-body"); + card_header.AddClass("collapse_toggle_card_header"); + } + public: + enum Collapse {NONE, OPEN, CLOSED}; // collapse options for constructing a card + Card(Collapse state=NONE, bool showGlyphs=true, const std::string & in_name=""): web::Div(in_name){ + if(state != NONE){ // if card is collapsible, make the collapse link the head of the card + if(state == OPEN){ + prefab::Collapse accordion(card_header, card_body, true, emp::to_string(card_base+ "_card_collapse")); + collapse_link = accordion.GetLinkDiv(); + collapse_body = accordion.GetToggleDiv(); + } + else{ + prefab::Collapse accordion(card_header, card_body, false, emp::to_string(card_base + "_card_collapse")); + collapse_link = accordion.GetLinkDiv(); + collapse_body = accordion.GetToggleDiv(); + } + if(showGlyphs){ // by default add glyphs to a collapsible card + // TODO: Don't use float, just set it to align to the right (need to make icon decend from div first) + prefab::FontAwesomeIcon up("fa-angle-double-up"); + prefab::FontAwesomeIcon down("fa-angle-double-down"); + card_header << up; + card_header << down; + up.AddClass("float-right btn-link collapse_toggle collapse_toggle_card_header setting_heading"); + down.AddClass("float-right btn-link collapse_toggle collapse_toggle_card_header setting_heading"); + } + *this << collapse_link; + *this << collapse_body; } - card << collapse_link; - card << collapse_body; - } - else{ // plain card with no toggle enabled - card << card_header; - card << card_body; + else{ // plain card with no toggle enabled + *this << card_header; + *this << card_body; + } + AddBootstrap(); } - AddBootstrap(); - } - template - void AddHeaderContent(T val, bool link_content=false){ - if(link_content){ - // add bootstrap link properities to content (hover, underline, etc.), - // but does not have a target or href because it is assumed that - // this content will control the card collapse, which is done in the - // constructor. If you want the content to link somewhere else, - // specify that in the web element/div param val {and set link_content=true TODO: verify this}. - web::Div btn_link; - btn_link.SetAttr("class", "btn-link"); - card_header << btn_link << val; + template + void AddHeaderContent(T val, bool link_content=false){ + if(link_content){ + // add bootstrap link properities to content (hover, underline, etc.), + // but does not have a target or href because it is assumed that + // this content will control the card collapse, which is done in the + // constructor. If you want the content to link somewhere else, + // specify that in the web element/div param val {and set link_content=true TODO: verify this}. + web::Div btn_link; + btn_link.SetAttr("class", "btn-link"); + card_header << btn_link << val; + } + else{ + card_header << val; + } } - else{ - card_header << val; + template + void AddBodyContent(T val){ + card_body << val; } - } - template - void AddBodyContent(T val){ - card_body << val; - } - web::Div & GetDiv() {return card;} - web::Div GetBodyDiv() {return card_body;} - }; + // TODO: override operator<< so that it streams into body content + web::Div GetBodyDiv() {return card_body;} + }; + } } #endif \ No newline at end of file diff --git a/source/prefab/Collapse.h b/source/prefab/Collapse.h index 89c3c1607c..164fcefa9e 100644 --- a/source/prefab/Collapse.h +++ b/source/prefab/Collapse.h @@ -5,62 +5,54 @@ #include "../tools/string_utils.h" namespace emp { - class Collapse { - private: - web::Div link; - web::Div toggle; - public: - // Constructor used when both the link and toggle area need to be wrapped - // @param click - a web element that controls the collapsing area - // @param ref_toggle - a web element that will appear/disappear - // @param id - string representing a unique id used to allow communication between link and toggle divs - // @param expanded - true if collapse is open by default, false otherwise - template - Collapse(T click, S ref_toggle, std::string id, bool expanded){ - toggle = web::Div(id); - link << click; - toggle << ref_toggle; - link.SetAttr( - "data-toggle", "collapse", - "data-target", "#" + id, - "class", "collapse_toggle", - "role", "button", - "aria-controls", "#" + id - ); - if(expanded){ - link.SetAttr("aria-expanded", "true"); - toggle.SetAttr("class", "collapse show"); + namespace prefab{ + class Collapse { + private: + web::Div link; + web::Div toggle; + public: + // Constructor used when both the link and toggle area need to be wrapped + // @param click - a web element that controls the collapsing area + // @param ref_toggle - a web element that will appear/disappear + // @param id - string representing a unique id used to allow communication between link and toggle divs + // @param expanded - true if collapse is open by default, false otherwise + template + Collapse(T click, S ref_toggle, bool expanded=false, std::string id="") + : Collapse(click, id, expanded){ + toggle << ref_toggle; + if(expanded){ + toggle.SetAttr("class", "collapse show"); + } + else{ + toggle.SetAttr("class", "collapse"); + } } - else{ - link.SetAttr("aria-expanded", "false"); - toggle.SetAttr("class", "collapse"); + // Constructor used when only the link area needs to be wrapped + // i.e. there is more than one link to the same toggle area or when adding a link to collapse a card + // @param click - a web element that controls the collapsing area + // @param id - string representing a unique id used to allow communication between link and toggle divs + // @param expanded - true if collapse is open by default, false otherwise + template + Collapse(T click, std::string id, bool expanded): toggle(id){ + link << click; + link.SetAttr( + "data-toggle", "collapse", + "data-target", "#" + toggle.GetID(), + "class", "collapse_toggle", + "role", "button", + "aria-controls", "#" + toggle.GetID() + ); + if(expanded){ + link.SetAttr("aria-expanded", "true"); + } + else{ + link.SetAttr("aria-expanded", "false"); + } } - } - // Constructor used when only the link area needs to be wrapped - // i.e. there is more than one link to the same toggle area or when adding a link to collapse a card - // @param click - a web element that controls the collapsing area - // @param id - string representing a unique id used to allow communication between link and toggle divs - // @param expanded - true if collapse is open by default, false otherwise - template - Collapse(T click, std::string id, bool expanded){ - link << click; - link.SetAttr( - "data-toggle", "collapse", - "data-target", "#" + id, - "class", "collapse_toggle", - "role", "button", - "aria-controls", "#" + id - ); - if(expanded){ - link.SetAttr("aria-expanded", "true"); - } - else{ - link.SetAttr("aria-expanded", "false"); - } - } - web::Div & GetLinkDiv() {return link;} - web::Div & GetToggleDiv() {return toggle;} - }; + web::Div & GetLinkDiv() {return link;} + web::Div & GetToggleDiv() {return toggle;} + }; + } } #endif \ No newline at end of file diff --git a/source/prefab/CommentBox.h b/source/prefab/CommentBox.h index 7631616498..d07b5a01de 100644 --- a/source/prefab/CommentBox.h +++ b/source/prefab/CommentBox.h @@ -1,42 +1,63 @@ #ifndef EMP_COMMENT_BOX_H #define EMP_COMMENT_BOX_H -#include "../config/config.h" #include "../web/Div.h" -#include "../web/Element.h" -#include "../web/Input.h" #include "../tools/string_utils.h" +/* Notes for how to use + +include "prefab/CommentBox.h" + +for (int i=0; i < 2; i++){ + emp::CommentBox box; + box.AddContent("Box "); + box.AddContent(i); + doc << box.GetDiv(); + } + +emp::CommentBox box; +UI::Div title("desktop_content"); +title << "

Shows in Desktop view

"; +UI::Element mobile("span"); +mobile << "

Here is hidden info

"; +mobile << "
"; +box.AddContent(title); +box.AddMobileContent(mobile); +box.AddMobileContent("Even more hidden info!"); +doc << box.GetDiv(); + +*/ + namespace emp { - class CommentBox { - private: - web::Div box_element; - std::string box_base = box_element.GetID(); - web::Div triangle{emp::to_string(box_base, "_triangle")}; - web::Div all_content{emp::to_string(box_base, "_all_content")}; - web::Div desktop_content{emp::to_string(box_base, "_desktop_content")}; - web::Div mobile_content{emp::to_string(box_base, "_mobile_content")}; - public: - CommentBox(){ - box_element << triangle; - box_element << all_content; - all_content << desktop_content; - all_content << mobile_content; - //TODO: change class names to reflect comment box - triangle.SetAttr("class", "dropdown_triangle"); - all_content.SetAttr("class", "dropdown_content"); - mobile_content.SetAttr("class", "mobile_dropdown"); + namespace prefab{ + class CommentBox: public web::Div { + private: + std::string box_base = this->GetID(); + web::Div triangle{emp::to_string(box_base, "_triangle")}; + web::Div all_content{emp::to_string(box_base, "_all_content")}; + web::Div desktop_content{emp::to_string(box_base, "_desktop_content")}; + web::Div mobile_content{emp::to_string(box_base, "_mobile_content")}; + public: + CommentBox(std::string id=""): web::Div(id){ + *this << triangle; + *this << all_content; + all_content << desktop_content; + all_content << mobile_content; + //TODO: change class names to reflect comment box + triangle.SetAttr("class", "dropdown_triangle"); + all_content.SetAttr("class", "dropdown_content"); + mobile_content.SetAttr("class", "mobile_dropdown"); + } + template + void AddContent(T val){ + desktop_content << val; + } + template + void AddMobileContent(T val){ + mobile_content << val; } - template - void AddContent(T val){ - desktop_content << val; - } - template - void AddMobileContent(T val){ - mobile_content << val; - } - web::Div & GetDiv() {return box_element;} - }; + }; + } } #endif \ No newline at end of file diff --git a/source/prefab/ConfigPanel.h b/source/prefab/ConfigPanel.h index 784d3d8bdf..c8e240578b 100644 --- a/source/prefab/ConfigPanel.h +++ b/source/prefab/ConfigPanel.h @@ -18,7 +18,7 @@ #include "Collapse.h" namespace emp { - + namespace prefab{ class ConfigPanel { private: inline static std::set numeric_types = {"int", "double", "float", "uint32_t", "uint64_t", "size_t"}; @@ -107,6 +107,7 @@ namespace emp { web::Div inline_elements(group_name + "_inline"); ======= // Prefab Card +<<<<<<< HEAD emp::Card card("card_collapse_" + group_name, true); group_divs[group_name] << card.GetDiv(); // Header formatting @@ -178,6 +179,16 @@ namespace emp { card_header.SetAttr("class", "card-header"); card_body.SetAttr("class", "card-body"); +======= + prefab::Card card(prefab::Card::Collapse::OPEN); + group_divs[group_name] << card; + + // Header content + web::Div setting_heading; + card.AddHeaderContent(setting_heading); + setting_heading << "

" + group->GetDesc() + "

"; + setting_heading.SetAttr("class", "setting_heading"); +>>>>>>> 3305a14... change namespace to emp::prefab and inherit from web components for some prefab components <<<<<<< HEAD ======= @@ -235,12 +246,13 @@ namespace emp { title.SetAttr("class", "btn btn-link"); >>>>>>> 5f848a8... add prefab element to add collapibility to web elements - emp::FontAwesomeIcon arrow_right_for_dropdown("fa-angle-double-right toggle_icon_left_margin"); - title << arrow_right_for_dropdown.GetDiv(); - emp::FontAwesomeIcon arrow_up_for_dropdown("fa-angle-double-up toggle_icon_left_margin"); - title << arrow_up_for_dropdown.GetDiv(); + prefab::FontAwesomeIcon arrow_right_for_dropdown("fa-angle-double-right"); + title << arrow_right_for_dropdown; + prefab::FontAwesomeIcon arrow_up_for_dropdown("fa-angle-double-up"); + title << arrow_up_for_dropdown; title << format_label_fun(name); title_span.SetAttr("class", "title_area"); +<<<<<<< HEAD <<<<<<< HEAD // This makes the Comment box toggle when title is clicked @@ -255,10 +267,17 @@ namespace emp { // Prefab Dropdown Box Version >>>>>>> 5f848a8... add prefab element to add collapibility to web elements emp::CommentBox box; +======= + arrow_right_for_dropdown.AddClass("toggle_icon_left_margin"); + arrow_up_for_dropdown.AddClass("toggle_icon_left_margin"); + + // Prefab Dropdown Box + prefab::CommentBox box; +>>>>>>> 3305a14... change namespace to emp::prefab and inherit from web components for some prefab components box.AddContent(group->GetEntry(i)->GetDescription()); // Prefab Collapse/toggle for setting element - emp::Collapse title_toggle(title, box.GetDiv(), name + "_dropdown", false); + prefab::Collapse title_toggle(title, box, false, name + "_dropdown"); input_divs[name] << title_toggle.GetToggleDiv(); title_span << title_toggle.GetLinkDiv(); @@ -288,19 +307,19 @@ namespace emp { const std::string name_input_slider = name + "_input_slider"; const std::string name_input_number = name + "_input_number"; const std::string name_input_mobile_slider = name + "_input_mobile_slider"; - emp::web::Input slider( [](std::string x){ + web::Input slider( [](std::string x){ std::cout << "empty slider function" << std::endl;}, "range", NULL, name_input_slider ); setting_element << slider; - emp::web::Input number([](std::string val){ + web::Input number([](std::string val){ std::cout << "empty number function" << std::endl; }, "number", NULL, name_input_number ); setting_element << number; - emp::web::Input mobile_slider([](std::string val){ + web::Input mobile_slider([](std::string val){ std::cout << "empty mobile slider function" << std::endl; }, "range", NULL, name_input_mobile_slider @@ -384,7 +403,7 @@ namespace emp { } else if (type == "bool") { - emp::web::Input bool_input( + web::Input bool_input( [this, name](std::string val){config.Set(name, val); on_change_fun(val);}, "checkbox", NULL, name + "_input_checkbox" @@ -393,7 +412,7 @@ namespace emp { >>>>>>> 9738447... display appropriate setting descriptions and synchronize form when one input is changed } else { - emp::web::Input text_input( + web::Input text_input( [this, name](std::string val){config.Set(name, val); on_change_fun(val);}, "text", NULL, name + "_input_textbox" @@ -444,7 +463,7 @@ namespace emp { web::Div & GetDiv() {return settings_div;} }; - + } } #endif diff --git a/source/prefab/FontAwesomeIcon.h b/source/prefab/FontAwesomeIcon.h index 3648ab42e7..00c37bf55a 100644 --- a/source/prefab/FontAwesomeIcon.h +++ b/source/prefab/FontAwesomeIcon.h @@ -2,21 +2,22 @@ #define EMP_FONT_AWESOME_ICON_H #include "../web/Element.h" +#include "../web/Div.h" +#include "../web/Widget.h" #include "../tools/string_utils.h" namespace emp { - class FontAwesomeIcon { - private: - web::Element icon{emp::to_string("span")}; - public: - // @param fa_name the font awesome class of the desired icon and any other necessary CSS class - FontAwesomeIcon(std::string fa_name){ - std::string full_class = emp::to_string("fa ", fa_name); - std::cout << full_class << std::endl; - icon.SetAttr("class", full_class); - } - web::Div & GetDiv() {return icon;} - }; + namespace prefab { + class FontAwesomeIcon: public web::Element { + public: + // @param fa_name the font awesome class of the desired icon + FontAwesomeIcon(std::string fa_name, const std::string & in_name=""): web::Element("span", in_name){ + std::string full_class = emp::to_string("fa ", fa_name); + std::cout << full_class << std::endl; + this->SetAttr("class", full_class); + } + }; + } } #endif \ No newline at end of file From 9a7aacf186141a36a9165f1af68a27a35c84a2d4 Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Wed, 24 Jun 2020 10:59:10 -0500 Subject: [PATCH 019/122] change card header color on hover --- source/prefab/DefaultConfigPanelStyle.css | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/source/prefab/DefaultConfigPanelStyle.css b/source/prefab/DefaultConfigPanelStyle.css index a3b2fd8ab3..cef9299352 100644 --- a/source/prefab/DefaultConfigPanelStyle.css +++ b/source/prefab/DefaultConfigPanelStyle.css @@ -14,15 +14,14 @@ /* Card Header */ .setting_heading{ - color: black; - text-decoration: underline; + color: rgb(58, 57, 57); } .setting_heading:hover{ - color: #0275d8 /* Bootstrap default pirmary color */ + color: rgb(116, 114, 114); } -/* Lower opacity of card body when hovering over collapsible header */ -.collapse_toggle:hover + .collapse .card-body{ - opacity: .6; +/* Change background of card header on hover to convey collapsibility */ +.collapse_toggle_card_header:hover { + background-color: #C0C0C0; } /* Card Body */ From 1eb2b57b1b250a53158350a41243cf35ab81d2d0 Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Thu, 25 Jun 2020 10:22:27 -0500 Subject: [PATCH 020/122] fixed error in adding settings to card body --- source/prefab/CP_Bug.h | 2 +- source/prefab/ConfigPanel.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/source/prefab/CP_Bug.h b/source/prefab/CP_Bug.h index 5b97b17fb1..0843553e09 100644 --- a/source/prefab/CP_Bug.h +++ b/source/prefab/CP_Bug.h @@ -90,7 +90,7 @@ namespace emp { std::string type = group->GetEntry(i)->GetType(); std::string value = group->GetEntry(i)->GetValue(); - card.AddBodyContent(web::Element("form").SetCSS("width", "100%") << input_divs[name]); + card.AddBodyContent(input_divs[name]); // Setting element label web::Div setting_element(name + "_row"); diff --git a/source/prefab/ConfigPanel.h b/source/prefab/ConfigPanel.h index c8e240578b..59e60f8aae 100644 --- a/source/prefab/ConfigPanel.h +++ b/source/prefab/ConfigPanel.h @@ -218,11 +218,15 @@ namespace emp { card_body << web::Element("form").SetCSS("width", "100%") << input_divs[name]; ======= +<<<<<<< HEAD card.AddBodyContent(web::Element("form").SetCSS("width", "100%") << input_divs[name]); >>>>>>> 0595c91... added card element web::Div mobile_dropdown("mobile_dropdown_" + name); mobile_dropdown.SetAttr("class", "d-md-none"); +======= + card.AddBodyContent(input_divs[name]); +>>>>>>> 6ccbb1f... fixed error in adding settings to card body // Setting element label web::Div setting_element(name + "_row"); From ad558726caad5752964b175dccf3530f8298f3e9 Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Thu, 25 Jun 2020 17:33:15 -0500 Subject: [PATCH 021/122] prefab rst documentation --- doc/library/prefab/prefab.rst | 124 ++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 doc/library/prefab/prefab.rst diff --git a/doc/library/prefab/prefab.rst b/doc/library/prefab/prefab.rst new file mode 100644 index 0000000000..9075cb90c9 --- /dev/null +++ b/doc/library/prefab/prefab.rst @@ -0,0 +1,124 @@ +Prefabricated Web Tools (for use with Emscripten) +================================================= + +These prefabricated tools were created to help you quickly create interesting +web applicications without being overwhelmed with the underlying HTML, CSS, and +Bootstrap classes required. These tools use Empirical's web tools to provide +structure for the site, and many of the prefab tools inherit from web tools so you can add your +own styling and stream them into other web components in a similar way. + +You can view these tools in action `here `_. + +Card +~~~~ +The Card class allows you to define a Bootstrap style card into your +project. A card can be collapsible if it's state parameter it set to OPEN or CLOSED. +By default, if a card is collapsible, it will have toggle icons in the header, +but this can be overridden by setting the showGlyphs parameter to false. + +Since this class inherits from web::Div, you can set styling and attributes +with SetCSS and SetAttr respectively. You can also stream your Card into other web +components with the << operator. + +Example: + +.. code-block:: c++ + #include "prefab/Card.h" + + emp::prefab::Card my_card(emp::prefab::Card::Collapse::NONE); + my_card.AddHeaderContent("Title"); + my_card.AddBodyContent("Content for the card's body"); + // Web components can also be passed as parameters to AddHeaderContent and AddBodyContent + +Collapse +~~~~~~~~ +The Collapse class is used to create collapsible elements in the document. It requires a web +component to be the element that controls the expaning and collapsing of the another element on +the page. The element that will expand and collapse can be passed to the constructor if it is not +controlled by another linking element already. Otherwise, only providing the linking element and +the id of the collapseing element is necessary. + +By default, the toggle element will be closed, but this can be set to open by passing true for the +expanded parameter. + +Since the linking and collapsing element will not necessarily be neighboring on the page, call +GetLinkDiv() to obtain the HTML for the link element and GetToggleDiv() to obtain the HTML +for the toggle element. + +Example: + +.. code-block:: c++ + #include "prefab/Collapse.h" + #include "web/Div.h" + + // Fill these divs with content + emp::web::Div link_ele; + emp::web::Div toggle_ele; + + emp::prefab::Collapse my_collapse(link_ele, toggle_ele, true); + +CommentBox +~~~~~~~~~~ +A CommentBox is a simple grey comment bubble. Content can be added to it using +the AddContent method. If there is data you only want to be visible on mobile +devices, used the AddMobileContent method. + +Since this class inherits from web::Div, you can set styling and attributes +with SetCSS and SetAttr respectively. You can also stream your CommentBox into other web +components with the << operator. + +Example: + +.. code-block:: c++ + #include "prefab/CommentBox.h" + + emp::prefab::CommentBox my_box; + my_box.AddContent("

Content that shows on all screen sizes

"); + my_box.AddMobileContent("
Content that only shows on small screens"); + // Web components can also be passed as parameters to AddContent and AddMobileContent + +ConfigPanel +~~~~~~~~~~~ +Using the ConfigPanel class, a configuration panel is constructed when passed a Config file. It uses other +Prefabricated components to add styling and structure to the panel. Use the GetDiv +method to stream this component into another web component or document. + +Example: + +.. code-block:: c++ + #include "prefab/ConfigPanel.h" + #include "config/ArgManager.h" + #include "web/web.h" + + #include "SampleConfig.h" // Config file + + Config cfg; + + emp::prefab::ConfigPanel config_panel(cfg); + + // apply configuration query params and config files to Config + auto specs = emp::ArgManager::make_builtin_specs(&cfg); + emp::ArgManager am(emp::web::GetUrlParams(), specs); + // cfg.Read("config.cfg"); + am.UseCallbacks(); + if (am.HasUnused()) std::exit(EXIT_FAILURE); + + // setup configuration panel + config_panel.Setup(); + +FontAwesomeIcon +~~~~~~~~~~~~~~~ +`FontAwesome `__ is a free library of icons. This class, find +the icon you want to use from the `icons page `___. +Pass "fa-" + *icon name* as a parameter to the constructor. + +Since this class inherits from web::Element, you can set styling and attributes +with SetCSS and SetAttr respectively. You can also stream your FontAwesomeIcon into other web +components with the << operator. + +Example: + +.. code-block:: c++ + #include "prefab/FontAwesomeIcon.h" + + emp::prefab::FontAwesomeIcon my_icon("fa-paw"); \ No newline at end of file From a24b6dbe4b4e2afd14e6d01f4d0098d343636452 Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Thu, 25 Jun 2020 17:34:19 -0500 Subject: [PATCH 022/122] update namespace for prefab components --- examples/prefab/Card.cc | 12 ++++++------ examples/prefab/Collapse.cc | 4 ++-- examples/prefab/CommentBox.cc | 4 ++-- examples/prefab/ConfigPanel.cc | 2 +- examples/prefab/FontAwesomeIcon.cc | 24 ++++++++++++------------ 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/examples/prefab/Card.cc b/examples/prefab/Card.cc index caa4d288f1..4c2e2cb1f4 100644 --- a/examples/prefab/Card.cc +++ b/examples/prefab/Card.cc @@ -14,21 +14,21 @@ UI::Document doc("emp_base"); int main() { // Plain Card - emp::Card pCard(emp::Card::Collapse::none); + emp::prefab::Card pCard(emp::prefab::Card::Collapse::NONE); pCard.AddHeaderContent("Plain card"); pCard.AddBodyContent("Plain body content"); - doc << pCard.GetDiv(); + doc << pCard; // Collapsible Card, default open - emp::Card openCard(emp::Card::Collapse::open, true); + emp::prefab::Card openCard(emp::prefab::Card::Collapse::OPEN, true); // Header content with bootstrap link properties openCard.AddHeaderContent("Open card", true); openCard.AddBodyContent("Open body content
Glyphs
Linked title"); - doc << openCard.GetDiv(); + doc << openCard; // Collapsible Card, default closed - emp::Card closedCard(emp::Card::Collapse::closed, false); + emp::prefab::Card closedCard(emp::prefab::Card::Collapse::CLOSED, false); closedCard.AddHeaderContent("Closed card"); closedCard.AddBodyContent("Closed body content
No Glyphs
Plain title"); - doc << closedCard.GetDiv(); + doc << closedCard; } diff --git a/examples/prefab/Collapse.cc b/examples/prefab/Collapse.cc index a5932cb197..5ada56c2f9 100644 --- a/examples/prefab/Collapse.cc +++ b/examples/prefab/Collapse.cc @@ -17,7 +17,7 @@ int main() UI::Div btn1; UI::Div content1; - emp::Collapse collapse1(btn1, content1, true, "my_collapse"); + emp::prefab::Collapse collapse1(btn1, content1, true, "my_collapse"); doc << collapse1.GetLinkDiv(); doc << collapse1.GetToggleDiv(); @@ -30,7 +30,7 @@ int main() UI::Div btn2; UI::Div content2; - emp::Collapse collapse2(btn2, content2, false); + emp::prefab::Collapse collapse2(btn2, content2, false); doc << collapse2.GetLinkDiv(); doc << collapse2.GetToggleDiv(); diff --git a/examples/prefab/CommentBox.cc b/examples/prefab/CommentBox.cc index 7d238333d7..5c12550fc9 100644 --- a/examples/prefab/CommentBox.cc +++ b/examples/prefab/CommentBox.cc @@ -15,7 +15,7 @@ UI::Document doc("emp_base"); int main() { - emp::CommentBox box; + emp::prefab::CommentBox box; UI::Div title("desktop_content"); title << "

Content that shows on all screen sizes

"; box.AddContent(title); @@ -24,5 +24,5 @@ int main() mobile << "
"; box.AddMobileContent(mobile); box.AddMobileContent("String literals can also be added to box content!"); - doc << box.GetDiv(); + doc << box; } diff --git a/examples/prefab/ConfigPanel.cc b/examples/prefab/ConfigPanel.cc index 3d1c1a3d17..ec00bb8053 100644 --- a/examples/prefab/ConfigPanel.cc +++ b/examples/prefab/ConfigPanel.cc @@ -18,7 +18,7 @@ UI::Document doc("emp_base"); Config cfg; -emp::ConfigPanel config_panel(cfg); +emp::prefab::ConfigPanel config_panel(cfg); int main() { diff --git a/examples/prefab/FontAwesomeIcon.cc b/examples/prefab/FontAwesomeIcon.cc index 9927acbdc5..68609c0bdc 100644 --- a/examples/prefab/FontAwesomeIcon.cc +++ b/examples/prefab/FontAwesomeIcon.cc @@ -17,26 +17,26 @@ int main() UI::Div toggleIcons; doc << toggleIcons; toggleIcons << "

Collapse Icons

"; - emp::FontAwesomeIcon up("fa-angle-double-up"); - toggleIcons << up.GetDiv(); + emp::prefab::FontAwesomeIcon up("fa-angle-double-up"); + toggleIcons << up; toggleIcons << "
"; - emp::FontAwesomeIcon down("fa-angle-double-down"); - toggleIcons << down.GetDiv(); + emp::prefab::FontAwesomeIcon down("fa-angle-double-down"); + toggleIcons << down; toggleIcons << "
"; - emp::FontAwesomeIcon right("fa-angle-double-right"); - toggleIcons << right.GetDiv(); + emp::prefab::FontAwesomeIcon right("fa-angle-double-right"); + toggleIcons << right; doc << "


"; UI::Div infoIcons; doc << infoIcons; infoIcons << "

Circle icons

"; - emp::FontAwesomeIcon i_circle("fa-info-circle"); - infoIcons << i_circle.GetDiv(); + emp::prefab::FontAwesomeIcon i_circle("fa-info-circle"); + infoIcons << i_circle; infoIcons << "
"; - emp::FontAwesomeIcon question_circle("fa-question-circle-o"); - infoIcons << question_circle.GetDiv(); + emp::prefab::FontAwesomeIcon question_circle("fa-question-circle-o"); + infoIcons << question_circle; infoIcons << "
"; - emp::FontAwesomeIcon plus_circle("fa-plus-circle"); - infoIcons << plus_circle.GetDiv(); + emp::prefab::FontAwesomeIcon plus_circle("fa-plus-circle"); + infoIcons << plus_circle; } From 30b37545b077369d185d13a3b457a1628339d176 Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Mon, 29 Jun 2020 09:35:54 -0500 Subject: [PATCH 023/122] added CodeBlock element with highlightjs --- examples/prefab/CodeBlock.cc | 23 +++++++++++++++++++++++ examples/prefab/CodeBlock.html | 34 ++++++++++++++++++++++++++++++++++ source/prefab/CodeBlock.h | 32 ++++++++++++++++++++++++++++++++ source/web/Div.h | 2 ++ source/web/Widget.h | 19 +++++++++++++++++-- 5 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 examples/prefab/CodeBlock.cc create mode 100644 examples/prefab/CodeBlock.html create mode 100644 source/prefab/CodeBlock.h diff --git a/examples/prefab/CodeBlock.cc b/examples/prefab/CodeBlock.cc new file mode 100644 index 0000000000..1a0a32ec33 --- /dev/null +++ b/examples/prefab/CodeBlock.cc @@ -0,0 +1,23 @@ +// This file is part of Empirical, https://github.com/devosoft/Empirical +// Copyright (C) Michigan State University, 2020. +// Released under the MIT Software license; see doc/LICENSE + +#include + +#include "web/web.h" +#include "prefab/CodeBlock.h" + +emp::web::Document doc("emp_base"); + +int main() +{ + std::cout << "entering main\n"; + std::string my_code = + R"( + int num = 9; + std::cout << num << " is a square number" << std::endl; + )"; + + emp::prefab::CodeBlock code_block(my_code, "c++"); + doc << code_block; +} diff --git a/examples/prefab/CodeBlock.html b/examples/prefab/CodeBlock.html new file mode 100644 index 0000000000..3be39a2be5 --- /dev/null +++ b/examples/prefab/CodeBlock.html @@ -0,0 +1,34 @@ + + + + + + + + + + +Code Block Examplep + + + +
+

Code Block Example

+
+ +
+
+
+ + + + + + + + + + + + + diff --git a/source/prefab/CodeBlock.h b/source/prefab/CodeBlock.h new file mode 100644 index 0000000000..c5aa90c05d --- /dev/null +++ b/source/prefab/CodeBlock.h @@ -0,0 +1,32 @@ +#ifndef EMP_CODE_BLOCK_H +#define EMP_CODE_BLOCK_H + +#include "../web/Element.h" +#include "../web/Widget.h" +#include "../tools/string_utils.h" +#include "../base/errors.h" + +namespace emp { + namespace prefab { + class CodeBlock: public web::Element { + private: + web::Element code{emp::to_string("code")}; + public: + CodeBlock(const std::string code_str, const std::string lang, const std::string & in_name=""): web::Element("pre", in_name){ + this->SetAttr("class", lang); + this->DoUpdateJS([](){ + emscripten_run_script("hljs.initHighlighting.called = false; hljs.initHighlighting();"); + }); + code << code_str; + *this << code; + } + // TODO: << operator throw error + // template + // void operator<<(T invalid){ + // emp::LibraryError("Not allowed to add code to the code block after construction due to JavaScript callback order"); + // } + }; + } +} + +#endif \ No newline at end of file diff --git a/source/web/Div.h b/source/web/Div.h index c4fc10e301..a82972eb59 100644 --- a/source/web/Div.h +++ b/source/web/Div.h @@ -288,6 +288,8 @@ namespace web { // cycle_obj.innerHTML = "   Cycles Used = " + $2; // }, ss.str().c_str(), scroll_frac, hardware->GetExeCount()); + internal::WidgetInfo::TriggerJS(); + } public: diff --git a/source/web/Widget.h b/source/web/Widget.h index 1eaaab6caf..631250d2e7 100644 --- a/source/web/Widget.h +++ b/source/web/Widget.h @@ -38,6 +38,7 @@ #include "../base/vector.h" #include "../base/errors.h" #include "../tools/mem_track.h" +#include "../control/Signal.h" #include "events.h" #include "Font.h" @@ -221,6 +222,7 @@ namespace web { emp::vector dependants; ///< Widgets to be refreshed if this one is triggered Widget::ActivityState state; ///< Is this element active in DOM? + emp::Signal on_update_js_signal; /// Signal for JavaScript functions to be called with TriggerJS() /// WidgetInfo cannot be built unless within derived class, so constructor is protected WidgetInfo(const std::string & in_id="") @@ -332,7 +334,14 @@ namespace web { virtual void GetHTML(std::stringstream & ss) = 0; // Derived widgets may also provide JavaScript code to be run on redraw. - virtual void TriggerJS() { ; } + virtual void TriggerJS() { + on_update_js_signal.Trigger(); + } + + // Add JS function to be executed when TriggerJS() is called + SignalKey DoUpdateJS(const std::function &fun){ + return on_update_js_signal.AddAction(fun); + } // Assume that the associated ID exists and replace it with the current HTML code. virtual void ReplaceHTML() { @@ -354,7 +363,8 @@ namespace web { // If active update style, trigger JS, and recurse to children! if (state == Widget::ACTIVE) { extras.Apply(id); // Update the attributes, style, and listeners. - TriggerJS(); // Run associated Javascript code, if any (e.g., to fill out a canvas) + // commented this out when testing HightlightJS, called in protected section of DivInfo instead + // TriggerJS(); // Run associated Javascript code, if any (e.g., to fill out a canvas) } } @@ -902,6 +912,11 @@ namespace web { return (return_t &) *this; } + // Add JS function to on_update_js_sig + SignalKey DoUpdateJS(const std::function & fun){ + return info->DoUpdateJS(fun); + } + }; } From caafe4fba57e14e5fc1e2077e534f1846ff970ea Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Mon, 29 Jun 2020 12:07:01 -0500 Subject: [PATCH 024/122] added LoadingIcon and ToggleSwitch elements --- doc/library/prefab/prefab.rst | 173 ++++++++++++++++++++++++++++-- examples/prefab/LoadingIcon.cc | 18 ++++ examples/prefab/LoadingIcon.html | 28 +++++ examples/prefab/ToggleSwitch.cc | 30 ++++++ examples/prefab/ToggleSwitch.html | 29 +++++ source/prefab/LoadingIcon.h | 33 ++++++ source/prefab/ToggleSwitch.h | 43 ++++++++ 7 files changed, 343 insertions(+), 11 deletions(-) create mode 100644 examples/prefab/LoadingIcon.cc create mode 100644 examples/prefab/LoadingIcon.html create mode 100644 examples/prefab/ToggleSwitch.cc create mode 100644 examples/prefab/ToggleSwitch.html create mode 100644 source/prefab/LoadingIcon.h create mode 100644 source/prefab/ToggleSwitch.h diff --git a/doc/library/prefab/prefab.rst b/doc/library/prefab/prefab.rst index 9075cb90c9..02d1345aa8 100644 --- a/doc/library/prefab/prefab.rst +++ b/doc/library/prefab/prefab.rst @@ -21,15 +21,69 @@ with SetCSS and SetAttr respectively. You can also stream your Card into other w components with the << operator. Example: - +******** .. code-block:: c++ + + #include "web/web.h" #include "prefab/Card.h" + emp::web::Document doc("emp_base"); + emp::prefab::Card my_card(emp::prefab::Card::Collapse::NONE); + doc << my_card; + my_card.AddHeaderContent("Title"); my_card.AddBodyContent("Content for the card's body"); // Web components can also be passed as parameters to AddHeaderContent and AddBodyContent + +**Note**: The toggle icons that are avalible for collapsible cards use the `FontAwesome`_ library. +You will need to add the CSS file for this library to the head of your HTML file: + +.. code-block:: html + + + +CodeBlock +~~~~~~~~~ +The CardBlock class is an interface for `highlightjs`_ which allows you to display code on +web pages with language specific highlighting. You can find a list of `all languages`_ on +their GitHub page. +To use this class you need to pass the code you want displayed and the programming language +to the constructor. + +Since this class inherits from web::Element, you can stream your CodeBlock into other web +components with the << operator. + +Example: +******** +.. code-block:: c++ + + #include "web/web.h" + #include "prefab/CodeBlock.h" + + emp::web::Document doc("emp_base"); + + std::string code_str = + R"( + int num = 9; + std::cout << num << " is a square number" << std::endl; + )"; + emp::prefab::CodeBlock code_block(code_str, "c++"); + + doc << code_block; + +**Note**: You will also need to add the following code to the bottom of the body section of your HTML file: + +.. code-block:: html + + + + + +.. _highlightjs: https://highlightjs.org/ +.. _all languages: https://github.com/highlightjs/highlight.js/blob/master/SUPPORTED_LANGUAGES.md + Collapse ~~~~~~~~ The Collapse class is used to create collapsible elements in the document. It requires a web @@ -46,10 +100,14 @@ GetLinkDiv() to obtain the HTML for the link element and GetToggleDiv() to obtai for the toggle element. Example: +******** +.. code-block:: cpp -.. code-block:: c++ - #include "prefab/Collapse.h" + #include "web/web.h" #include "web/Div.h" + #include "prefab/Collapse.h" + + emp::web::Document doc("emp_base"); // Fill these divs with content emp::web::Div link_ele; @@ -57,6 +115,9 @@ Example: emp::prefab::Collapse my_collapse(link_ele, toggle_ele, true); + doc << my_collapse.GetLinkDiv(); + doc << my_collapse.GetToggleDiv(); + CommentBox ~~~~~~~~~~ A CommentBox is a simple grey comment bubble. Content can be added to it using @@ -68,11 +129,17 @@ with SetCSS and SetAttr respectively. You can also stream your CommentBox into o components with the << operator. Example: +******** +.. code-block:: cpp -.. code-block:: c++ + #include "web/web.h" #include "prefab/CommentBox.h" + emp::web::Document doc("emp_base"); + emp::prefab::CommentBox my_box; + doc << my_box; + my_box.AddContent("

Content that shows on all screen sizes

"); my_box.AddMobileContent("
Content that only shows on small screens"); // Web components can also be passed as parameters to AddContent and AddMobileContent @@ -84,14 +151,16 @@ Prefabricated components to add styling and structure to the panel. Use the GetD method to stream this component into another web component or document. Example: +******** +.. code-block:: cpp -.. code-block:: c++ + #include "web/web.h" #include "prefab/ConfigPanel.h" #include "config/ArgManager.h" - #include "web/web.h" #include "SampleConfig.h" // Config file + emp::web::Document doc("emp_base"); Config cfg; emp::prefab::ConfigPanel config_panel(cfg); @@ -105,20 +174,102 @@ Example: // setup configuration panel config_panel.Setup(); + doc << config_panel.GetDiv(); FontAwesomeIcon ~~~~~~~~~~~~~~~ -`FontAwesome `__ is a free library of icons. This class, find -the icon you want to use from the `icons page `___. -Pass "fa-" + *icon name* as a parameter to the constructor. +`FontAwesome`_ is a free library of icons that can be used in web pages. + +To use this class: + +1. Find the icon you wish to use in the `FontAwesome library`_ +2. Pass "fa-" + *icon name* as a parameter to the constructor. +3. Add the following CSS file to the head of your HTML document. +.. code-block:: html + + + Since this class inherits from web::Element, you can set styling and attributes with SetCSS and SetAttr respectively. You can also stream your FontAwesomeIcon into other web components with the << operator. Example: +******** +.. code-block:: cpp -.. code-block:: c++ + #include "web/web.h" #include "prefab/FontAwesomeIcon.h" - emp::prefab::FontAwesomeIcon my_icon("fa-paw"); \ No newline at end of file + emp::web::Document doc("emp_base"); + + emp::prefab::FontAwesomeIcon my_icon("fa-paw"); + doc << my_icon; + + my_icon.AddClass("custom_class"); + +.. _FontAwesome: https://fontawesome.com/v4.7.0/ +.. _FontAwesome library: https://fontawesome.com/v4.7.0/icons/ + +LoadingIcon +~~~~~~~~~~~ +The LoadingIcon class is used to add an animated loading icon. One possible use +for this icon is to be displayed while the contents of a web page is loading. The icon +is provided by `FontAwesome`_, so you will need to add its CSS to your HTML file to use +this class. + +.. code-block:: html + + + +Since this class inherits from web::Element, you can set styling and attributes +with SetCSS and SetAttr respectively. You can also stream your LoadingIcon into other web +components with the << operator. + +Example: +******** +.. code-block:: cpp + + #include "web/web.h" + #include "prefab/LoadingIcon.h" + + emp::web::Document doc("emp_base"); + + emp::prefab::LoadingIcon spinner; + doc << spinner; + +ToggleSwitch +~~~~~~~~~~~~ +This class is a wrapper for a checkbox input. It uses Bootstrap 4.5.0 to create a +custom toggle switch. To create a ToggleSwitch instance, an Input widget must be +passed as a parameter. If you need to add a CSS class to the Input, do it after the creating +the ToggleSwitch instance with AddClass(). + + +Since this class inherits from web::Element, you can set styling and attributes +with SetCSS and SetAttr respectively. You can also stream your ToggleSwitch into other web +components with the << operator. + +Example: +******** +.. code-block:: cpp + + #include "web/web.h" + #include "web/Input.h" + #include "prefab/ToggleSwitch.h" + + emp::web::Document doc("emp_base"); + + emp::web::Input input_element( + [](std::string str){;}, + "checkbox", NULL, "input_id" + ); + emp::prefab::ToggleSwitch my_switch(input_element); + doc << my_switch; + + my_switch.AddLabel("Switch Label"); + +Add the link to Bootstrap in the head of your HTML file: +.. code-block:: html + + diff --git a/examples/prefab/LoadingIcon.cc b/examples/prefab/LoadingIcon.cc new file mode 100644 index 0000000000..c4b8a5dbbf --- /dev/null +++ b/examples/prefab/LoadingIcon.cc @@ -0,0 +1,18 @@ +// This file is part of Empirical, https://github.com/devosoft/Empirical +// Copyright (C) Michigan State University, 2020. +// Released under the MIT Software license; see doc/LICENSE + +#include + +#include "web/web.h" +#include "prefab/LoadingIcon.h" + +namespace UI = emp::web; + +UI::Document doc("emp_base"); + +int main() +{ + emp::prefab::LoadingIcon spinner; + doc << spinner; +} diff --git a/examples/prefab/LoadingIcon.html b/examples/prefab/LoadingIcon.html new file mode 100644 index 0000000000..2f37b16bf9 --- /dev/null +++ b/examples/prefab/LoadingIcon.html @@ -0,0 +1,28 @@ + + + + + + + + + +Loading Icon Example + + + +
+

Loading Icon Example

+
+ +
+
+
+ + + + + + + + diff --git a/examples/prefab/ToggleSwitch.cc b/examples/prefab/ToggleSwitch.cc new file mode 100644 index 0000000000..ac26a1add9 --- /dev/null +++ b/examples/prefab/ToggleSwitch.cc @@ -0,0 +1,30 @@ +// This file is part of Empirical, https://github.com/devosoft/Empirical +// Copyright (C) Michigan State University, 2020. +// Released under the MIT Software license; see doc/LICENSE + +#include + +#include "web/web.h" +#include "web/Div.h" +#include "web/Input.h" +#include "prefab/ToggleSwitch.h" + +namespace UI = emp::web; + +UI::Document doc("emp_base"); + +int main() +{ + UI::Input input_element( + [](std::string str){;}, + "checkbox", NULL, "input_id" + ); + emp::prefab::ToggleSwitch my_switch(input_element); + doc << my_switch; + + UI::Div title; + title << "Switch Label"; + my_switch.AddLabel(title); + + std::cout << "end of main... !" << std::endl; +} diff --git a/examples/prefab/ToggleSwitch.html b/examples/prefab/ToggleSwitch.html new file mode 100644 index 0000000000..0a48fe4e70 --- /dev/null +++ b/examples/prefab/ToggleSwitch.html @@ -0,0 +1,29 @@ + + + + + + + + + + +Toggle Switch Example + + + +
+

Toggle Switch Example

+
+ +
+
+
+ + + + + + + + diff --git a/source/prefab/LoadingIcon.h b/source/prefab/LoadingIcon.h new file mode 100644 index 0000000000..4a4680dbab --- /dev/null +++ b/source/prefab/LoadingIcon.h @@ -0,0 +1,33 @@ +#ifndef EMP_LOADING_ICON_H +#define EMP_LOADING_ICON_H + +#include "../web/Element.h" +#include "../web/Div.h" +#include "../web/Widget.h" +#include "../tools/string_utils.h" +#include "../base/errors.h" + +namespace emp { + namespace prefab { + class LoadingIcon: public web::Element { + private: + web::Element icon{emp::to_string("span")}; + web::Element text{emp::to_string("span")}; + public: + LoadingIcon(const std::string & in_name=""): web::Element("span", in_name){ + *this << icon; + *this << text; + icon.SetAttr("class", "fa fa-spinner fa-pulse fa-3x fa-fw"); + text.SetAttr("class", "sr-only"); + text << "Loading..."; + } + // TODO: << operator throw error + // template + // void operator<<(T invalid){ + // emp::LibraryError("Not allowed to add code to the loading icon"); + // } + }; + } +} + +#endif \ No newline at end of file diff --git a/source/prefab/ToggleSwitch.h b/source/prefab/ToggleSwitch.h new file mode 100644 index 0000000000..307c6b1828 --- /dev/null +++ b/source/prefab/ToggleSwitch.h @@ -0,0 +1,43 @@ +#ifndef EMP_TOGGLE_SWITCH_H +#define EMP_TOGGLE_SWITCH_H + +#include "../web/Element.h" +#include "../web/Input.h" +#include "../web/Widget.h" +#include "../tools/string_utils.h" + +// NOTE: Need to link to Bootstrap 4.5.0 or newer to view the stylized toggle switch +// + +namespace emp { + namespace prefab { + class ToggleSwitch: public web::Element { + private: + web::Element label{emp::to_string("label")}; + public: + // @param fa_name the font awesome class of the desired icon + ToggleSwitch(emp::web::Input & checkbox, const std::string & in_name=""): web::Element("span", in_name){ + *this << checkbox; + *this << label; + // NOTE: If you added a class to the input before you called this constructor, + // it will be overridden here. Instead add the class after creating this object + checkbox.SetAttr("class", "custom-control-input"); + this->SetAttr("class", "custom-control custom-switch"); + this->SetCSS( + "clear", "none", + "display", "inline" + ); + label.SetAttr( + "class", "custom-control-label", + "for", checkbox.GetID() + ); + } + template + void AddLabel(const T usr_label){ + label << usr_label; + } + }; + } +} + +#endif \ No newline at end of file From 5924ac963b3d6c3dc2f57c919e02376126d9c42c Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Mon, 29 Jun 2020 12:08:13 -0500 Subject: [PATCH 025/122] updated classes --- source/prefab/CommentBox.h | 32 +++----------------- source/prefab/ConfigPanel.h | 14 +++++++-- source/prefab/DefaultConfigPanelStyle.css | 37 +++++++++++++---------- source/prefab/FontAwesomeIcon.h | 1 - 4 files changed, 37 insertions(+), 47 deletions(-) diff --git a/source/prefab/CommentBox.h b/source/prefab/CommentBox.h index d07b5a01de..7f5cdeb1cb 100644 --- a/source/prefab/CommentBox.h +++ b/source/prefab/CommentBox.h @@ -4,30 +4,6 @@ #include "../web/Div.h" #include "../tools/string_utils.h" -/* Notes for how to use - -include "prefab/CommentBox.h" - -for (int i=0; i < 2; i++){ - emp::CommentBox box; - box.AddContent("Box "); - box.AddContent(i); - doc << box.GetDiv(); - } - -emp::CommentBox box; -UI::Div title("desktop_content"); -title << "

Shows in Desktop view

"; -UI::Element mobile("span"); -mobile << "

Here is hidden info

"; -mobile << "
"; -box.AddContent(title); -box.AddMobileContent(mobile); -box.AddMobileContent("Even more hidden info!"); -doc << box.GetDiv(); - -*/ - namespace emp { namespace prefab{ class CommentBox: public web::Div { @@ -43,10 +19,10 @@ namespace emp { *this << all_content; all_content << desktop_content; all_content << mobile_content; - //TODO: change class names to reflect comment box - triangle.SetAttr("class", "dropdown_triangle"); - all_content.SetAttr("class", "dropdown_content"); - mobile_content.SetAttr("class", "mobile_dropdown"); + + triangle.SetAttr("class", "commentbox_triangle"); + all_content.SetAttr("class", "commentbox_content"); + mobile_content.SetAttr("class", "mobile_commentbox"); } template void AddContent(T val){ diff --git a/source/prefab/ConfigPanel.h b/source/prefab/ConfigPanel.h index 59e60f8aae..d29e490a8f 100644 --- a/source/prefab/ConfigPanel.h +++ b/source/prefab/ConfigPanel.h @@ -16,6 +16,7 @@ #include "CommentBox.h" #include "FontAwesomeIcon.h" #include "Collapse.h" +#include "ToggleSwitch.h" namespace emp { namespace prefab{ @@ -287,6 +288,7 @@ namespace emp { if (Has(numeric_types, type)) { +<<<<<<< HEAD // Seems more efficient to use web::Input, but it's not working // TODO: need to define on change function to use built in Input // emp::web::Input slider([this, name](std::string val){ @@ -308,6 +310,8 @@ namespace emp { setting_element << spacer; spacer.SetAttr("class", "blank_div"); +======= +>>>>>>> b7cb8b4... updated classes const std::string name_input_slider = name + "_input_slider"; const std::string name_input_number = name + "_input_number"; const std::string name_input_mobile_slider = name + "_input_mobile_slider"; @@ -403,7 +407,6 @@ namespace emp { SetDefaultRangeFixedPoint(number, emp::from_string(value)); SetDefaultRangeFixedPoint(mobile_slider, emp::from_string(value)); } - std::cout << "After calling set default range methods" << std::endl; } else if (type == "bool") { @@ -412,7 +415,14 @@ namespace emp { on_change_fun(val);}, "checkbox", NULL, name + "_input_checkbox" ); - setting_element << bool_input; + // Default checkbox + // setting_element << bool_input; + // bool_input.SetAttr("class", "input_bool"); + + // Bootstrap Toggle Switch (need at least v4.5.0) + emp::prefab::ToggleSwitch toggle_switch(bool_input); + setting_element << toggle_switch; + toggle_switch.AddClass("input_bool"); >>>>>>> 9738447... display appropriate setting descriptions and synchronize form when one input is changed } else { diff --git a/source/prefab/DefaultConfigPanelStyle.css b/source/prefab/DefaultConfigPanelStyle.css index cef9299352..1699ca77c5 100644 --- a/source/prefab/DefaultConfigPanelStyle.css +++ b/source/prefab/DefaultConfigPanelStyle.css @@ -28,29 +28,32 @@ .setting_element { width: 100%; } -.title_area{ +.title_area { width: 38%; display: inline-block; } -.blank_div{ - width: 38%; - display: none; +.btn { + text-align: left; } /* Form Inputs */ -.input_slider{ +.input_slider { width: 38%; margin-right: 10px; } -.input_number{ +.input_number { width: 18%; right: 10px; } -.input_text{ +.input_text { width: 57%; } +.input_bool { + width: 12%; + float: right; +} /* Dropdown Bubble */ -.dropdown_triangle{ +.commentbox_triangle { width: 0; height: 0; border-left: 12px solid transparent; @@ -59,28 +62,30 @@ border-bottom: 12px solid #ede9e8; margin-left: 15px; } -.dropdown_content{ - font-style: italic; +.commentbox_content { padding: 10px; background-color: #ede9e8; border-radius: 5px; margin-bottom: 10px; width: 95%; } -.mobile_dropdown{ +.mobile_commentbox { display: none; } /* Mobile Version */ @media screen and (max-width: 992px) { - .blank_div{ - display: inline-block; - } - .input_slider{ + .input_slider { display: none; } /* Dropdown Bubble */ - .mobile_dropdown{ + .mobile_commentbox { display: inline; } + .title_area { + width: 80%; + } + .input_bool { + width: 18%; + } } \ No newline at end of file diff --git a/source/prefab/FontAwesomeIcon.h b/source/prefab/FontAwesomeIcon.h index 00c37bf55a..8111ab7b5f 100644 --- a/source/prefab/FontAwesomeIcon.h +++ b/source/prefab/FontAwesomeIcon.h @@ -13,7 +13,6 @@ namespace emp { // @param fa_name the font awesome class of the desired icon FontAwesomeIcon(std::string fa_name, const std::string & in_name=""): web::Element("span", in_name){ std::string full_class = emp::to_string("fa ", fa_name); - std::cout << full_class << std::endl; this->SetAttr("class", full_class); } }; From 0772cea5daa1a8a7ed1dc2c39ccbf3ba669fea91 Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Tue, 30 Jun 2020 14:00:22 -0500 Subject: [PATCH 026/122] uncommented trigger js call --- source/web/Widget.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/web/Widget.h b/source/web/Widget.h index 631250d2e7..7b19696838 100644 --- a/source/web/Widget.h +++ b/source/web/Widget.h @@ -364,7 +364,7 @@ namespace web { if (state == Widget::ACTIVE) { extras.Apply(id); // Update the attributes, style, and listeners. // commented this out when testing HightlightJS, called in protected section of DivInfo instead - // TriggerJS(); // Run associated Javascript code, if any (e.g., to fill out a canvas) + TriggerJS(); // Run associated Javascript code, if any (e.g., to fill out a canvas) } } From 6413d216507893336104021a7bf23b0c2a16e519 Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Mon, 6 Jul 2020 15:47:57 -0500 Subject: [PATCH 027/122] added loading and regular modal tools --- source/prefab/DefaultConfigPanelStyle.css | 13 +++ source/prefab/LoadingModal.h | 26 ++++++ source/prefab/LoadingModal.js | 32 +++++++ source/prefab/Modal.h | 100 ++++++++++++++++++++++ source/web/Widget.h | 5 ++ 5 files changed, 176 insertions(+) create mode 100644 source/prefab/LoadingModal.h create mode 100644 source/prefab/LoadingModal.js create mode 100644 source/prefab/Modal.h diff --git a/source/prefab/DefaultConfigPanelStyle.css b/source/prefab/DefaultConfigPanelStyle.css index 1699ca77c5..c230766eb1 100644 --- a/source/prefab/DefaultConfigPanelStyle.css +++ b/source/prefab/DefaultConfigPanelStyle.css @@ -73,6 +73,19 @@ display: none; } +/* Loading Modal */ +.bd-example-modal-lg .modal-dialog { + display: table; + position: relative; + margin: 0 auto; + top: calc(50% - 24px); +} + +.bd-example-modal-lg .modal-dialog .modal-content { + background-color: transparent; + border: none; +} + /* Mobile Version */ @media screen and (max-width: 992px) { .input_slider { diff --git a/source/prefab/LoadingModal.h b/source/prefab/LoadingModal.h new file mode 100644 index 0000000000..688ec8614e --- /dev/null +++ b/source/prefab/LoadingModal.h @@ -0,0 +1,26 @@ +#ifndef EMP_LOADING_MODAL_H +#define EMP_LOADING_MODAL_H + +#include "../web/Element.h" +#include "../web/Div.h" +#include "../web/Widget.h" +#include "../tools/string_utils.h" + +namespace emp { + namespace prefab{ + void CloseLoadingModal(){ + emscripten_run_script("CloseLoadingModal();"); + } + } +} + +#endif + +// Turn on +// $('.modal').modal('show'); +// setTimeout(function () { +// $('.modal').modal('hide'); +// }, 10000); + +// Turn off +// emscripten_run_script("$('.modal').modal('hide');"); \ No newline at end of file diff --git a/source/prefab/LoadingModal.js b/source/prefab/LoadingModal.js new file mode 100644 index 0000000000..e4064cce00 --- /dev/null +++ b/source/prefab/LoadingModal.js @@ -0,0 +1,32 @@ +// inject modal html and start it +var modal_html = ')"; + web::Div modal_dialog; + web::Div modal_content; + web::Div modal_header; + web::Div modal_body; + web::Div modal_footer; + private: + public: + Modal(const std::string & in_name=""): web::Div(in_name){ + *this << modal_dialog; + modal_dialog << modal_content; + modal_content << modal_header; + modal_content << modal_body; + modal_content << modal_footer; + this->SetAttr( + "class", "modal", + "id", this->GetID(), + "data-backdrop", "static", + "data-keyboard", "false", + "tabindex", "-1" + ); + modal_dialog.SetAttr("class", "modal-dialog"); + modal_content.SetAttr("class", "modal-content"); + modal_header.SetAttr("class", "modal-header"); + modal_body.SetAttr("class", "modal-body"); + modal_footer.SetAttr("class", "modal-footer"); + } + template + void AddHeaderContent(T val){ + modal_header << val; + } + template + void AddBodyContent(T val){ + modal_body << val; + } + template + void AddFooterContent(T val){ + modal_footer << val; + } + // Adds an X button in the upper right corner of the modal so user can close it + // Should be called after all desired header content is added + // Best practice is to call this method, unless a close button is added somewhere + // else in the modal using AddButton() + void AddClosingX(){ + web::Button close_btn([](){;}, "x"); + modal_header << close_btn; + close_btn.SetAttr( + "class", "close float-right", + "data-dismiss", "modal", + "aria-label", "Close" + ); + } + void AddButton(web::Button & btn){ + btn.SetAttr( + "data-toggle", "modal", + "data-target", "#" + this->GetID() + ); + } + void SetBackground(const std::string color){ + modal_content.SetBackground(color); + std::cout << "Override background function" << std::endl; + } + }; + } +} +// TODO: +// [*] add x to header +// [] make generic class so you can add your own content +// [] test where you can place modal (stream into a nested div?) +// [] add test modal button for 2 seconds for demo +// [] allow user to change background options for modal +#endif \ No newline at end of file diff --git a/source/web/Widget.h b/source/web/Widget.h index 7b19696838..6110ba1297 100644 --- a/source/web/Widget.h +++ b/source/web/Widget.h @@ -604,6 +604,11 @@ namespace web { public: using return_t = RETURN_TYPE; + std::string GetHTML(){ + std::stringstream ss; + info->GetHTML(ss); + return ss.str(); + } /// Set a specific CSS value for this widget. template return_t & SetCSS(const std::string & setting, SETTING_TYPE && value) { From c0c9f228356c6303a582ebaa5f21234f668aa270 Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Mon, 6 Jul 2020 18:25:34 -0500 Subject: [PATCH 028/122] adding widget edits back in --- source/web/Widget.h | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/source/web/Widget.h b/source/web/Widget.h index 6110ba1297..bb4f58a5bd 100644 --- a/source/web/Widget.h +++ b/source/web/Widget.h @@ -36,7 +36,6 @@ #include #include "../base/vector.h" -#include "../base/errors.h" #include "../tools/mem_track.h" #include "../control/Signal.h" @@ -79,10 +78,13 @@ namespace web { /// Widget is effectively a smart pointer to a WidgetInfo object, plus some basic accessors. class Widget { friend internal::WidgetInfo; friend internal::DivInfo; friend internal::TableInfo; - public: + protected: using WidgetInfo = internal::WidgetInfo; WidgetInfo * info; ///< Information associated with this widget. + /// If an Append doesn't work with current class, forward it to the parent and try there. + template Widget & ForwardAppend(FWD_TYPE && arg); + /// Set the information associated with this widget. Widget & SetInfo(WidgetInfo * in_info); @@ -689,16 +691,6 @@ namespace web { DoListen(event_name, fun_id); return (return_t &) *this; } - - /// Provide an event and a function that will be called when that event is triggered. - /// In this case, the function takes a keyboard event as an argument, with full info about keyboard. - return_t & On(const std::string & event_name, - const std::function & fun) { - emp_assert(info != nullptr); - size_t fun_id = JSWrap(fun); - DoListen(event_name, fun_id); - return (return_t &) *this; - } /// Provide an event and a function that will be called when that event is triggered. /// In this case, the function takes two doubles which will be filled in with mouse coordinates. @@ -904,11 +896,6 @@ namespace web { // switch out parent's existing child for wrapper parent_info->RemoveChild((return_t &) *this); parent_info->AddChild(wrapper); - } else if (Info(wrapper)->ptr_count == 1) { - emp::LibraryWarning( - "Only one reference held to wrapper. ", - "It will be destroyed when it goes out of scope." - ); } // put this Widget inside of the wrapper From df0c94386130f439355b25de5a66e19461197916 Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Tue, 7 Jul 2020 12:11:14 -0500 Subject: [PATCH 029/122] users can now set the default state of checkboxes and toggle switches to be on or off --- doc/library/prefab/prefab.rst | 15 ++++++--------- examples/prefab/ToggleSwitch.cc | 20 ++++++++------------ source/prefab/ConfigPanel.h | 13 +++---------- source/prefab/ToggleSwitch.h | 12 +++++++++--- source/web/Input.h | 6 +++++- 5 files changed, 31 insertions(+), 35 deletions(-) diff --git a/doc/library/prefab/prefab.rst b/doc/library/prefab/prefab.rst index 02d1345aa8..5f8ec0b730 100644 --- a/doc/library/prefab/prefab.rst +++ b/doc/library/prefab/prefab.rst @@ -255,19 +255,16 @@ Example: .. code-block:: cpp #include "web/web.h" - #include "web/Input.h" #include "prefab/ToggleSwitch.h" - emp::web::Document doc("emp_base"); + emp::prefab::ToggleSwitch on_switch([](std::string val){}, "checkbox", "Switch Defult On", true, "user_defined_switch_id"); + doc << on_switch; - emp::web::Input input_element( - [](std::string str){;}, - "checkbox", NULL, "input_id" - ); - emp::prefab::ToggleSwitch my_switch(input_element); - doc << my_switch; + doc << "
"; - my_switch.AddLabel("Switch Label"); + emp::prefab::ToggleSwitch off_switch([](std::string val){}, "checkbox", NULL, false); + doc << off_switch; + off_switch.AddLabel("Switch Defult Off"); Add the link to Bootstrap in the head of your HTML file: .. code-block:: html diff --git a/examples/prefab/ToggleSwitch.cc b/examples/prefab/ToggleSwitch.cc index ac26a1add9..14da9bf36b 100644 --- a/examples/prefab/ToggleSwitch.cc +++ b/examples/prefab/ToggleSwitch.cc @@ -5,8 +5,6 @@ #include #include "web/web.h" -#include "web/Div.h" -#include "web/Input.h" #include "prefab/ToggleSwitch.h" namespace UI = emp::web; @@ -15,16 +13,14 @@ UI::Document doc("emp_base"); int main() { - UI::Input input_element( - [](std::string str){;}, - "checkbox", NULL, "input_id" - ); - emp::prefab::ToggleSwitch my_switch(input_element); - doc << my_switch; - - UI::Div title; - title << "Switch Label"; - my_switch.AddLabel(title); + emp::prefab::ToggleSwitch on_switch([](std::string val){}, "checkbox", "Switch Defult On", true, "user_defined_switch_id"); + doc << on_switch; + + doc << "
"; + + emp::prefab::ToggleSwitch off_switch([](std::string val){}, "checkbox", NULL, false); + doc << off_switch; + off_switch.AddLabel("Switch Defult Off"); std::cout << "end of main... !" << std::endl; } diff --git a/source/prefab/ConfigPanel.h b/source/prefab/ConfigPanel.h index d29e490a8f..106a730360 100644 --- a/source/prefab/ConfigPanel.h +++ b/source/prefab/ConfigPanel.h @@ -410,17 +410,10 @@ namespace emp { } else if (type == "bool") { - web::Input bool_input( - [this, name](std::string val){config.Set(name, val); - on_change_fun(val);}, - "checkbox", NULL, name + "_input_checkbox" - ); - // Default checkbox - // setting_element << bool_input; - // bool_input.SetAttr("class", "input_bool"); - // Bootstrap Toggle Switch (need at least v4.5.0) - emp::prefab::ToggleSwitch toggle_switch(bool_input); + emp::prefab::ToggleSwitch toggle_switch([this, name](std::string val){config.Set(name, val); + on_change_fun(val);}, + "checkbox", NULL, emp::from_string(value), name + "_input_checkbox"); setting_element << toggle_switch; toggle_switch.AddClass("input_bool"); diff --git a/source/prefab/ToggleSwitch.h b/source/prefab/ToggleSwitch.h index 307c6b1828..9f90b65dc3 100644 --- a/source/prefab/ToggleSwitch.h +++ b/source/prefab/ToggleSwitch.h @@ -15,12 +15,18 @@ namespace emp { private: web::Element label{emp::to_string("label")}; public: - // @param fa_name the font awesome class of the desired icon - ToggleSwitch(emp::web::Input & checkbox, const std::string & in_name=""): web::Element("span", in_name){ + ToggleSwitch(const std::function & in_cb, const std::string & in_type, + const std::string & in_label, bool is_checked=false, const std::string & t_switch_id=""): web::Element("span", t_switch_id){ + // When constructing checkbox input, do not use built in label + // functionality because for toggle switch classes to work, + // the label element must come after input element. Label element is + // placed before input element in Input constructor. + web::Input checkbox(in_cb, in_type, NULL, "", false, is_checked); *this << checkbox; *this << label; + label << in_label; // NOTE: If you added a class to the input before you called this constructor, - // it will be overridden here. Instead add the class after creating this object + // it will be overridden here. Instead, use AddClass after creating this object checkbox.SetAttr("class", "custom-control-input"); this->SetAttr("class", "custom-control custom-switch"); this->SetCSS( diff --git a/source/web/Input.h b/source/web/Input.h index 993d918386..b62581bde9 100644 --- a/source/web/Input.h +++ b/source/web/Input.h @@ -177,7 +177,7 @@ namespace web { /// @param in_label The label that should appear on the Input. /// @param in_id The HTML ID to use for this Input (leave blank for auto-generated) Input(const std::function & in_cb, const std::string & in_type, - const std::string & in_label, const std::string & in_id="") + const std::string & in_label, const std::string & in_id="", bool show_value=false, bool is_checked=false) : WidgetFacet(in_id) { info = new InputInfo(in_id); @@ -191,6 +191,10 @@ namespace web { InputInfo * b_info = Info(); Info()->callback_id = JSWrap( std::function( [b_info](std::string new_val){b_info->DoChange(new_val);} ) ); Info()->onchange_info = emp::to_string("emp.Callback(", Info()->callback_id, ", ['checkbox', 'radio'].includes(this.type) ? this.checked.toString() : this.value);"); + // Allows user to set the checkbox to start out on/checked + if (in_type.compare("checkbox") == 0 && is_checked){ + this->SetAttr("checked", "true"); + } } /// Link to an existing Input. From 54e92226dc27696a545ca3b1af723ae2fe3b8c76 Mon Sep 17 00:00:00 2001 From: kayakingCellist Date: Tue, 7 Jul 2020 12:36:11 -0500 Subject: [PATCH 030/122] added purge script for static files --- source/prefab/DefaultConfigPanelStyle.css | 5 +++++ source/prefab/LoadingModal.js | 5 ++++- source/prefab/purge_script.sh | 27 +++++++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 source/prefab/purge_script.sh diff --git a/source/prefab/DefaultConfigPanelStyle.css b/source/prefab/DefaultConfigPanelStyle.css index c230766eb1..32b6e2bb23 100644 --- a/source/prefab/DefaultConfigPanelStyle.css +++ b/source/prefab/DefaultConfigPanelStyle.css @@ -1,3 +1,8 @@ +/* + NOTE: If you modify this file, run the purge_script.sh script + to see your changes take effect in the browser +*/ + /* Glyphicon Toggle */ .collapse_toggle[aria-expanded=true] .fa-angle-double-down{ display: none; diff --git a/source/prefab/LoadingModal.js b/source/prefab/LoadingModal.js index e4064cce00..78268e0edd 100644 --- a/source/prefab/LoadingModal.js +++ b/source/prefab/LoadingModal.js @@ -1,4 +1,7 @@ -// inject modal html and start it +// NOTE: If you modify this file, run the purge_script.sh script +// to see your changes take effect in the browser + +// inject loading modal html and start it var modal_html = '