edouard@2883: // widget_jump.ysl2
Edouard@2779: 
edouard@3241: widget_desc("Jump") {
edouard@3241:     longdesc
edouard@3241:     ||
Edouard@3595:     Jump widget brings focus to a different page. Mandatory first argument
edouard@3241:     gives name of the page.
edouard@3241: 
Edouard@3596:     If first path is pointint to HMI_NODE variable is used as new reference
Edouard@3595:     when jumping to a relative page.
edouard@3241: 
Edouard@3595:     Additional arguments are unordered options:
Edouard@3595: 
Edouard@3595:     - Absolute: force page jump to be not relative even if first path is of type HMI_NODE
Edouard@3595: 
Edouard@3597:     - name=value: Notify PLC about jump by setting variable with path having same name assigned
Edouard@3596: 
edouard@3241:     "active"+"inactive" labeled elements can be provided and reflect current
edouard@3241:     page being shown.
edouard@3241: 
Edouard@3595:     Exemples:
Edouard@3596: 
Edouard@3595:     Relative jump:
Edouard@3595: 
Edouard@3595:     HMI:Jump:RelativePage@/PUMP9
Edouard@3595:     HMI:Jump:RelativePage@/PUMP9@role=.userrole#role=="admin"
Edouard@3595: 
Edouard@3595:     Absolute jump:
Edouard@3595: 
Edouard@3595:     HMI:Jump:AbsolutePage
Edouard@3595:     HMI:Jump:AbsolutePage@role=.userrole#role=="admin"
Edouard@3595: 
Edouard@3595:     Forced absolute jump:
Edouard@3595: 
Edouard@3595:     HMI:Jump:AbsolutePage:Absolute@/PUMP9
Edouard@3595:     HMI:Jump:AbsolutePage:Absolute:notify=1@notify=/PUMP9
Edouard@3595: 
Edouard@3597:     Jump with feedback
Edouard@3597: 
Edouard@3597:     HMI:Jump:AbsolutePage:notify=1@notify=.did_jump
Edouard@3597: 
edouard@3241:     ||
edouard@3241: 
edouard@3241:     shortdesc > Jump to given page
edouard@3241: 
edouard@3241:     arg name="page" accepts="string" > name of page to jump to
edouard@3241: 
edouard@3241:     path name="reference" count="optional" accepts="HMI_NODE" > reference for relative jump
edouard@3241: }
edouard@3241: 
edouard@3232: widget_class("Jump") {
edouard@3107: ||
edouard@3107:         activable = false;
edouard@3107:         frequency = 2;
Edouard@3626:         target_page_is_current_page = false;
Edouard@3626:         button_beeing_pressed = false;
edouard@3107: 
Edouard@3626:         onmouseup(evt) {
Edouard@3626:             svg_root.removeEventListener("pointerup", this.bound_onmouseup, true);
Edouard@3626:             if(this.enable_state) {
Edouard@3626:                 const index =
Edouard@3626:                     (this.is_relative && this.indexes.length > 0) ?
Edouard@3626:                     this.indexes[0] + this.offset : undefined;
Edouard@3626:                 this.button_beeing_pressed = false;
Edouard@3626:                 this.activity_state = this.target_page_is_current_page || this.button_beeing_pressed;
Edouard@3626:                 fading_page_switch(this.args[0], index);
Edouard@3626:                 this.notify();
Edouard@3626:             }
Edouard@3626:         }
Edouard@3626: 
Edouard@3626:         onmousedown(){
Edouard@3626:             if(this.enable_state) {
Edouard@3626:                 svg_root.addEventListener("pointerup", this.bound_onmouseup, true);
Edouard@3626:                 this.button_beeing_pressed = true;
Edouard@3626:                 this.activity_state = true;
Edouard@3626:                 this.request_animate();
edouard@3107:             }
edouard@3107:         }
edouard@3107: 
edouard@3107:         notify_page_change(page_name, index) {
Edouard@3596:             // called from animate()
edouard@3107:             if(this.activable) {
edouard@3107:                 const ref_index = this.indexes.length > 0 ? this.indexes[0] + this.offset : undefined;
edouard@3107:                 const ref_name = this.args[0];
Edouard@3626:                 this.target_page_is_current_page = ((ref_name == undefined || ref_name == page_name) && index == ref_index);
Edouard@3626:                 this.activity_state = this.target_page_is_current_page || this.button_beeing_pressed;
Edouard@3596:                 // Since called from animate, update activity directly
Edouard@3596:                 if(this.enable_displayed_state && this.has_activity) {
Edouard@3596:                     this.animate_activity();
Edouard@3596:                 }
edouard@3107:             }
edouard@3107:         }
edouard@3107: ||
Edouard@2906: }
Edouard@2906: 
Edouard@3595: def "func:is_relative_jump" {
Edouard@3595:     param "widget";
Edouard@3595:     result "$widget/path and $widget/path[1]/@type='HMI_NODE' and not($widget/arg[position()>1 and @value = 'Absolute'])";
Edouard@3595: }
Edouard@3595: 
edouard@3232: widget_defs("Jump") {
Edouard@3595:     optional_activable();
edouard@3107: 
Edouard@3595:     const "jump_disability","$has_activity and $has_disability";
edouard@3107: 
edouard@2883:     |     init: function() {
Edouard@3626:     |         this.bound_onmouseup = this.onmouseup.bind(this);
Edouard@3626:     |         this.element.addEventListener("pointerdown", this.onmousedown.bind(this));
Edouard@3595:     if "$has_activity" {
edouard@3107:     |         this.activable = true;
Edouard@2903:     }
Edouard@3595: 
Edouard@3595:     >         this.is_relative = 
Edouard@3595:     choose{
Edouard@3595:         when "func:is_relative_jump(.)" > true
Edouard@3595:         otherwise > false
Edouard@2906:     }
Edouard@3240:     > ;\n
edouard@2883:     |     },
Edouard@3240: 
Edouard@3597:     |     notify: function() {
Edouard@3597:     const "paths","path";
Edouard@3597:     foreach "arg[position()>1 and contains(@value,'=')]"{
Edouard@3597:         const "name","substring-before(@value,'=')";
Edouard@3597:         const "value","substring-after(@value,'=')";
Edouard@3597:         const "index" foreach "$paths" if "@assign = $name" value "position()-1";
Edouard@3597:     |         // «@value»
Edouard@3597:     |         this.apply_hmi_value(«$index», «$value»);
Edouard@3597:     }
Edouard@3597:     |     },
Edouard@2753: }
Edouard@2901: 
edouard@3232: widget_page("Jump"){
Edouard@2901:     param "page_desc";
Edouard@3595:     /* jump is considered relative jump if first path points to HMI_NODE
Edouard@3595:        but a jump can be forced Absolute by adding a "Absolute" argument */
Edouard@3595:     if "func:is_relative_jump(.)" {
Edouard@3595:         /* if relative check that given path is compatible with page's reference path */
Edouard@3595: 
Edouard@2901:         /* when no page name provided, check for same page */
Edouard@2901:         const "target_page_name" choose {
Edouard@2901:             when "arg" value "arg[1]/@value";
Edouard@2901:             otherwise value "$page_desc/arg[1]/@value";
Edouard@2901:         }
Edouard@2901:         const "target_page_path" choose {
Edouard@3685:             when "arg" value "$hmi_pages_descs[arg[1]/@value = $target_page_name]/path[not(@assign)]/@value";
Edouard@3685:             otherwise value "$page_desc/path[not(@assign)]/@value";
Edouard@2901:         }
Edouard@2901: 
Edouard@2901:         if "not(func:same_class_paths($target_page_path, path[1]/@value))"
Edouard@2901:             error > Jump id="«@id»" to page "«$target_page_name»" with incompatible path "«path[1]/@value» (must be same class as "«$target_page_path»")
Edouard@3595: 
Edouard@2901:     }
Edouard@2901: }
edouard@2942: 
Edouard@3595: 
Edouard@3595: 
Edouard@3577: /* TODO: move to detachable pages ysl2 */
Edouard@3512: emit "cssdefs:jump"
Edouard@3512: ||
Edouard@3512: .fade-out-page {
Edouard@3553:     animation: cubic-bezier(0, 0.8, 0.6, 1) fadeOut 0.6s both;
Edouard@3512: }
Edouard@3512: 
Edouard@3512: @keyframes fadeOut {
Edouard@3512:     0% { opacity: 1; }
Edouard@3512:     100% { opacity: 0; }
Edouard@3512: }
Edouard@3512: 
Edouard@3512: ||
Edouard@3512: 
edouard@2943: emit "declarations:jump"
edouard@2942: ||
edouard@2942: var jumps_need_update = false;
edouard@2942: var jump_history = [[default_page, undefined]];
edouard@2942: 
edouard@2942: function update_jumps() {
Edouard@3596:     // called from animate()
edouard@2942:     page_desc[current_visible_page].jumps.map(w=>w.notify_page_change(current_visible_page,current_page_index));
edouard@2942:     jumps_need_update = false;
edouard@2942: };
edouard@2942: 
edouard@2942: ||
edouard@2942: