svghmi/gen_index_xhtml.xslt
branchsvghmi
changeset 2936 53fb11263ff1
parent 2934 ee483e8346f5
child 2938 1379cd5c69dd
equal deleted inserted replaced
2935:83d83aa0f085 2936:53fb11263ff1
   835 </xsl:text>
   835 </xsl:text>
   836     <xsl:text>        this.button_elt.setAttribute("onclick", "hmi_widgets['</xsl:text>
   836     <xsl:text>        this.button_elt.setAttribute("onclick", "hmi_widgets['</xsl:text>
   837     <xsl:value-of select="$hmi_element/@id"/>
   837     <xsl:value-of select="$hmi_element/@id"/>
   838     <xsl:text>'].on_button_click()");
   838     <xsl:text>'].on_button_click()");
   839 </xsl:text>
   839 </xsl:text>
   840     <xsl:text>        this.text_bbox = this.text_elt.getBBox()
   840     <xsl:text>        // Save original size of rectangle
   841 </xsl:text>
   841 </xsl:text>
   842     <xsl:text>        this.box_bbox = this.box_elt.getBBox()
   842     <xsl:text>        this.box_bbox = this.box_elt.getBBox()
   843 </xsl:text>
   843 </xsl:text>
   844     <xsl:text>        lmargin = this.text_bbox.x - this.box_bbox.x;
   844     <xsl:text>
   845 </xsl:text>
   845 </xsl:text>
   846     <xsl:text>        tmargin = this.text_bbox.y - this.box_bbox.y;
   846     <xsl:text>        // Compute margins
       
   847 </xsl:text>
       
   848     <xsl:text>        text_bbox = this.text_elt.getBBox()
       
   849 </xsl:text>
       
   850     <xsl:text>        lmargin = text_bbox.x - this.box_bbox.x;
       
   851 </xsl:text>
       
   852     <xsl:text>        tmargin = text_bbox.y - this.box_bbox.y;
   847 </xsl:text>
   853 </xsl:text>
   848     <xsl:text>        this.margins = [lmargin, tmargin].map(x =&gt; Math.max(x,0));
   854     <xsl:text>        this.margins = [lmargin, tmargin].map(x =&gt; Math.max(x,0));
   849 </xsl:text>
   855 </xsl:text>
   850     <xsl:text>        //this.content = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten",
   856     <xsl:text>
   851 </xsl:text>
   857 </xsl:text>
   852     <xsl:text>        //                "eleven", "twelve", "thirteen", "fourteen", "fifteen"];
   858     <xsl:text>        // It is assumed that list content conforms to Array interface.
   853 </xsl:text>
   859 </xsl:text>
   854     <xsl:text>        this.content = [
   860     <xsl:text>        this.content = [
   855 </xsl:text>
   861 </xsl:text>
   856     <xsl:for-each select="arg">
   862     <xsl:for-each select="arg">
   857       <xsl:text>"</xsl:text>
   863       <xsl:text>"</xsl:text>
   859       <xsl:text>",
   865       <xsl:text>",
   860 </xsl:text>
   866 </xsl:text>
   861     </xsl:for-each>
   867     </xsl:for-each>
   862     <xsl:text>        ];
   868     <xsl:text>        ];
   863 </xsl:text>
   869 </xsl:text>
       
   870     <xsl:text>
       
   871 </xsl:text>
       
   872     <xsl:text>        // Index of first visible element in the menu, when opened
       
   873 </xsl:text>
   864     <xsl:text>        this.menu_offset = 0;
   874     <xsl:text>        this.menu_offset = 0;
   865 </xsl:text>
   875 </xsl:text>
       
   876     <xsl:text>
       
   877 </xsl:text>
       
   878     <xsl:text>        // How mutch to lift the menu vertically so that it does not cross bottom border
       
   879 </xsl:text>
   866     <xsl:text>        this.lift = 0;
   880     <xsl:text>        this.lift = 0;
   867 </xsl:text>
   881 </xsl:text>
       
   882     <xsl:text>
       
   883 </xsl:text>
       
   884     <xsl:text>        // Event handlers cannot be object method ('this' is unknown)
       
   885 </xsl:text>
       
   886     <xsl:text>        // as a workaround, handler given to addEventListener is bound in advance.
       
   887 </xsl:text>
       
   888     <xsl:text>        this.bound_close_on_click_elsewhere = this.close_on_click_elsewhere.bind(this);
       
   889 </xsl:text>
       
   890     <xsl:text>
       
   891 </xsl:text>
   868     <xsl:text>        this.opened = false;
   892     <xsl:text>        this.opened = false;
   869 </xsl:text>
   893 </xsl:text>
   870     <xsl:text>        this.bound_close_on_click_elsewhere = this.close_on_click_elsewhere.bind(this);
   894     <xsl:text>    },
   871 </xsl:text>
   895 </xsl:text>
   872     <xsl:text>    },
   896     <xsl:text>    // Called when a menu entry is clicked
   873 </xsl:text>
   897 </xsl:text>
   874     <xsl:text>    on_selection_click: function(selection) {
   898     <xsl:text>    on_selection_click: function(selection) {
   875 </xsl:text>
   899 </xsl:text>
   876     <xsl:text>        console.log("selected "+selection);
       
   877 </xsl:text>
       
   878     <xsl:text>        this.close();
   900     <xsl:text>        this.close();
   879 </xsl:text>
   901 </xsl:text>
   880     <xsl:text>        let orig = this.indexes[0];
   902     <xsl:text>        let orig = this.indexes[0];
   881 </xsl:text>
   903 </xsl:text>
   882     <xsl:text>        let idx = this.offset ? orig - this.offset : orig;
   904     <xsl:text>        let idx = this.offset ? orig - this.offset : orig;
   889 </xsl:text>
   911 </xsl:text>
   890     <xsl:text>        this.open();
   912     <xsl:text>        this.open();
   891 </xsl:text>
   913 </xsl:text>
   892     <xsl:text>    },
   914     <xsl:text>    },
   893 </xsl:text>
   915 </xsl:text>
   894     <xsl:text>    on_backward_click:function(){
   916     <xsl:text>    on_backward_click: function(){
   895 </xsl:text>
   917 </xsl:text>
   896     <xsl:text>        this.move(false);
   918     <xsl:text>        this.scroll(false);
   897 </xsl:text>
   919 </xsl:text>
   898     <xsl:text>    },
   920     <xsl:text>    },
   899 </xsl:text>
   921 </xsl:text>
   900     <xsl:text>    on_forward_click:function(){
   922     <xsl:text>    on_forward_click:function(){
   901 </xsl:text>
   923 </xsl:text>
   902     <xsl:text>        this.move(true);
   924     <xsl:text>        this.scroll(true);
   903 </xsl:text>
   925 </xsl:text>
   904     <xsl:text>    },
   926     <xsl:text>    },
   905 </xsl:text>
   927 </xsl:text>
   906     <xsl:text>    set_selection: function(value) {
   928     <xsl:text>    set_selection: function(value) {
   907 </xsl:text>
   929 </xsl:text>
   908     <xsl:text>        let display_str;
   930     <xsl:text>        let display_str;
   909 </xsl:text>
   931 </xsl:text>
   910     <xsl:text>        if(value &gt;= 0 &amp;&amp; value &lt; this.content.length){
   932     <xsl:text>        if(value &gt;= 0 &amp;&amp; value &lt; this.content.length){
   911 </xsl:text>
   933 </xsl:text>
       
   934     <xsl:text>            // if valid selection resolve content
       
   935 </xsl:text>
   912     <xsl:text>            display_str = this.content[value];
   936     <xsl:text>            display_str = this.content[value];
   913 </xsl:text>
   937 </xsl:text>
   914     <xsl:text>            this.last_selection = value;
   938     <xsl:text>            this.last_selection = value;
   915 </xsl:text>
   939 </xsl:text>
   916     <xsl:text>        } else {
   940     <xsl:text>        } else {
   917 </xsl:text>
   941 </xsl:text>
       
   942     <xsl:text>            // otherwise show problem
       
   943 </xsl:text>
   918     <xsl:text>            display_str = "?"+String(value)+"?";
   944     <xsl:text>            display_str = "?"+String(value)+"?";
   919 </xsl:text>
   945 </xsl:text>
   920     <xsl:text>        }
   946     <xsl:text>        }
   921 </xsl:text>
   947 </xsl:text>
       
   948     <xsl:text>        // It is assumed that first span always stays,
       
   949 </xsl:text>
       
   950     <xsl:text>        // and contains selection when menu is closed
       
   951 </xsl:text>
   922     <xsl:text>        this.text_elt.firstElementChild.textContent = display_str;
   952     <xsl:text>        this.text_elt.firstElementChild.textContent = display_str;
   923 </xsl:text>
   953 </xsl:text>
   924     <xsl:text>    },
   954     <xsl:text>    },
   925 </xsl:text>
   955 </xsl:text>
   926     <xsl:text>    grow_text: function(up_to) {
   956     <xsl:text>    grow_text: function(up_to) {
   929 </xsl:text>
   959 </xsl:text>
   930     <xsl:text>        let txt = this.text_elt; 
   960     <xsl:text>        let txt = this.text_elt; 
   931 </xsl:text>
   961 </xsl:text>
   932     <xsl:text>        let first = txt.firstElementChild;
   962     <xsl:text>        let first = txt.firstElementChild;
   933 </xsl:text>
   963 </xsl:text>
       
   964     <xsl:text>        // Real world (pixels) boundaries of current page
       
   965 </xsl:text>
   934     <xsl:text>        let bounds = svg_root.getBoundingClientRect(); 
   966     <xsl:text>        let bounds = svg_root.getBoundingClientRect(); 
   935 </xsl:text>
   967 </xsl:text>
   936     <xsl:text>        this.lift = 0;
   968     <xsl:text>        this.lift = 0;
   937 </xsl:text>
   969 </xsl:text>
   938     <xsl:text>        while(count &lt; up_to) {
   970     <xsl:text>        while(count &lt; up_to) {
   939 </xsl:text>
   971 </xsl:text>
   940     <xsl:text>            let next = first.cloneNode();
   972     <xsl:text>            let next = first.cloneNode();
   941 </xsl:text>
   973 </xsl:text>
       
   974     <xsl:text>            // relative line by line text flow instead of absolute y coordinate
       
   975 </xsl:text>
   942     <xsl:text>            next.removeAttribute("y");
   976     <xsl:text>            next.removeAttribute("y");
   943 </xsl:text>
   977 </xsl:text>
   944     <xsl:text>            next.setAttribute("dy", "1.1em");
   978     <xsl:text>            next.setAttribute("dy", "1.1em");
   945 </xsl:text>
   979 </xsl:text>
       
   980     <xsl:text>            // default content to allow computing text element bbox
       
   981 </xsl:text>
   946     <xsl:text>            next.textContent = "...";
   982     <xsl:text>            next.textContent = "...";
   947 </xsl:text>
   983 </xsl:text>
       
   984     <xsl:text>            // append new span to text element
       
   985 </xsl:text>
   948     <xsl:text>            txt.appendChild(next);
   986     <xsl:text>            txt.appendChild(next);
   949 </xsl:text>
   987 </xsl:text>
       
   988     <xsl:text>            // now check if text extended by one row fits to page
       
   989 </xsl:text>
       
   990     <xsl:text>            // FIXME : exclude margins to be more accurate on box size
       
   991 </xsl:text>
   950     <xsl:text>            let rect = txt.getBoundingClientRect();
   992     <xsl:text>            let rect = txt.getBoundingClientRect();
   951 </xsl:text>
   993 </xsl:text>
   952     <xsl:text>            if(rect.bottom &gt; bounds.bottom){
   994     <xsl:text>            if(rect.bottom &gt; bounds.bottom){
   953 </xsl:text>
   995 </xsl:text>
       
   996     <xsl:text>                // in case of overflow at the bottom, lift up one row
       
   997 </xsl:text>
   954     <xsl:text>                let backup = first.getAttribute("dy");
   998     <xsl:text>                let backup = first.getAttribute("dy");
   955 </xsl:text>
   999 </xsl:text>
       
  1000     <xsl:text>                // apply lift asr a dy added too first span (y attrib stays)
       
  1001 </xsl:text>
   956     <xsl:text>                first.setAttribute("dy", "-"+String((this.lift+1)*1.1)+"em");
  1002     <xsl:text>                first.setAttribute("dy", "-"+String((this.lift+1)*1.1)+"em");
   957 </xsl:text>
  1003 </xsl:text>
   958     <xsl:text>                rect = txt.getBoundingClientRect();
  1004     <xsl:text>                rect = txt.getBoundingClientRect();
   959 </xsl:text>
  1005 </xsl:text>
   960     <xsl:text>                if(rect.top &gt; bounds.top){
  1006     <xsl:text>                if(rect.top &gt; bounds.top){
   961 </xsl:text>
  1007 </xsl:text>
   962     <xsl:text>                    this.lift += 1;
  1008     <xsl:text>                    this.lift += 1;
   963 </xsl:text>
  1009 </xsl:text>
   964     <xsl:text>                } else {
  1010     <xsl:text>                } else {
   965 </xsl:text>
  1011 </xsl:text>
       
  1012     <xsl:text>                    // if it goes over the top, then backtrack
       
  1013 </xsl:text>
       
  1014     <xsl:text>                    // restore dy attribute on first span
       
  1015 </xsl:text>
   966     <xsl:text>                    if(backup)
  1016     <xsl:text>                    if(backup)
   967 </xsl:text>
  1017 </xsl:text>
   968     <xsl:text>                        first.setAttribute("dy", backup);
  1018     <xsl:text>                        first.setAttribute("dy", backup);
   969 </xsl:text>
  1019 </xsl:text>
   970     <xsl:text>                    else
  1020     <xsl:text>                    else
   971 </xsl:text>
  1021 </xsl:text>
   972     <xsl:text>                        first.removeAttribute("dy");
  1022     <xsl:text>                        first.removeAttribute("dy");
   973 </xsl:text>
  1023 </xsl:text>
       
  1024     <xsl:text>                    // remove unwanted child
       
  1025 </xsl:text>
   974     <xsl:text>                    txt.removeChild(next);
  1026     <xsl:text>                    txt.removeChild(next);
   975 </xsl:text>
  1027 </xsl:text>
   976     <xsl:text>                    return count;
  1028     <xsl:text>                    return count;
   977 </xsl:text>
  1029 </xsl:text>
   978     <xsl:text>                }
  1030     <xsl:text>                }
   987 </xsl:text>
  1039 </xsl:text>
   988     <xsl:text>    },
  1040     <xsl:text>    },
   989 </xsl:text>
  1041 </xsl:text>
   990     <xsl:text>    close_on_click_elsewhere: function(e) {
  1042     <xsl:text>    close_on_click_elsewhere: function(e) {
   991 </xsl:text>
  1043 </xsl:text>
   992     <xsl:text>        console.log("inhibit", e);
  1044     <xsl:text>        // inhibit events not targetting spans (menu items)
   993 </xsl:text>
       
   994     <xsl:text>        console.log(e.target.parentNode, this.text_elt);
       
   995 </xsl:text>
  1045 </xsl:text>
   996     <xsl:text>        if(e.target.parentNode !== this.text_elt){
  1046     <xsl:text>        if(e.target.parentNode !== this.text_elt){
   997 </xsl:text>
  1047 </xsl:text>
   998     <xsl:text>            e.stopPropagation();
  1048     <xsl:text>            e.stopPropagation();
   999 </xsl:text>
  1049 </xsl:text>
       
  1050     <xsl:text>            // close menu in case click is outside box
       
  1051 </xsl:text>
  1000     <xsl:text>            if(e.target !== this.box_elt)
  1052     <xsl:text>            if(e.target !== this.box_elt)
  1001 </xsl:text>
  1053 </xsl:text>
  1002     <xsl:text>                this.close();
  1054     <xsl:text>                this.close();
  1003 </xsl:text>
  1055 </xsl:text>
  1004     <xsl:text>        }
  1056     <xsl:text>        }
  1005 </xsl:text>
  1057 </xsl:text>
  1006     <xsl:text>    },
  1058     <xsl:text>    },
  1007 </xsl:text>
  1059 </xsl:text>
  1008     <xsl:text>    close: function(){
  1060     <xsl:text>    close: function(){
  1009 </xsl:text>
  1061 </xsl:text>
  1010     <xsl:text>        document.removeEventListener("click", this.bound_close_on_click_elsewhere, true);
  1062     <xsl:text>        // Stop hogging all click events
       
  1063 </xsl:text>
       
  1064     <xsl:text>        svg_root.removeEventListener("click", this.bound_close_on_click_elsewhere, true);
       
  1065 </xsl:text>
       
  1066     <xsl:text>        // Restore position and sixe of widget elements
  1011 </xsl:text>
  1067 </xsl:text>
  1012     <xsl:text>        this.reset_text();
  1068     <xsl:text>        this.reset_text();
  1013 </xsl:text>
  1069 </xsl:text>
  1014     <xsl:text>        this.reset_box();
  1070     <xsl:text>        this.reset_box();
  1015 </xsl:text>
  1071 </xsl:text>
       
  1072     <xsl:text>        // Put the button back in place
       
  1073 </xsl:text>
  1016     <xsl:text>        this.element.appendChild(this.button_elt);
  1074     <xsl:text>        this.element.appendChild(this.button_elt);
  1017 </xsl:text>
  1075 </xsl:text>
       
  1076     <xsl:text>        // Mark as closed (to allow dispatch)
       
  1077 </xsl:text>
  1018     <xsl:text>        this.opened = false;
  1078     <xsl:text>        this.opened = false;
  1019 </xsl:text>
  1079 </xsl:text>
       
  1080     <xsl:text>        // Dispatch last cached value
       
  1081 </xsl:text>
  1020     <xsl:text>        this.apply_cache();
  1082     <xsl:text>        this.apply_cache();
  1021 </xsl:text>
  1083 </xsl:text>
  1022     <xsl:text>    },
  1084     <xsl:text>    },
       
  1085 </xsl:text>
       
  1086     <xsl:text>    // Set text content when content is smaller than menu (no scrolling)
  1023 </xsl:text>
  1087 </xsl:text>
  1024     <xsl:text>    set_complete_text: function(){
  1088     <xsl:text>    set_complete_text: function(){
  1025 </xsl:text>
  1089 </xsl:text>
  1026     <xsl:text>        let spans = this.text_elt.children; 
  1090     <xsl:text>        let spans = this.text_elt.children; 
  1027 </xsl:text>
  1091 </xsl:text>
  1041 </xsl:text>
  1105 </xsl:text>
  1042     <xsl:text>        }
  1106     <xsl:text>        }
  1043 </xsl:text>
  1107 </xsl:text>
  1044     <xsl:text>    },
  1108     <xsl:text>    },
  1045 </xsl:text>
  1109 </xsl:text>
  1046     <xsl:text>    move: function(forward){
  1110     <xsl:text>    // Move partial view :
       
  1111 </xsl:text>
       
  1112     <xsl:text>    // false : upward, lower value
       
  1113 </xsl:text>
       
  1114     <xsl:text>    // true  : downward, higher value
       
  1115 </xsl:text>
       
  1116     <xsl:text>    scroll: function(forward){
  1047 </xsl:text>
  1117 </xsl:text>
  1048     <xsl:text>        let contentlength = this.content.length;
  1118     <xsl:text>        let contentlength = this.content.length;
  1049 </xsl:text>
  1119 </xsl:text>
  1050     <xsl:text>        let spans = this.text_elt.children; 
  1120     <xsl:text>        let spans = this.text_elt.children; 
  1051 </xsl:text>
  1121 </xsl:text>
  1052     <xsl:text>        let spanslength = spans.length;
  1122     <xsl:text>        let spanslength = spans.length;
  1053 </xsl:text>
  1123 </xsl:text>
       
  1124     <xsl:text>        // reduce accounted menu size according to jumps
       
  1125 </xsl:text>
  1054     <xsl:text>        if(this.menu_offset != 0) spanslength--;
  1126     <xsl:text>        if(this.menu_offset != 0) spanslength--;
  1055 </xsl:text>
  1127 </xsl:text>
  1056     <xsl:text>        if(this.menu_offset &lt; contentlength - 1) spanslength--;
  1128     <xsl:text>        if(this.menu_offset &lt; contentlength - 1) spanslength--;
  1057 </xsl:text>
  1129 </xsl:text>
  1058     <xsl:text>        if(forward){
  1130     <xsl:text>        if(forward){
  1077 </xsl:text>
  1149 </xsl:text>
  1078     <xsl:text>        this.set_partial_text();
  1150     <xsl:text>        this.set_partial_text();
  1079 </xsl:text>
  1151 </xsl:text>
  1080     <xsl:text>    },
  1152     <xsl:text>    },
  1081 </xsl:text>
  1153 </xsl:text>
       
  1154     <xsl:text>    // Setup partial view text content
       
  1155 </xsl:text>
       
  1156     <xsl:text>    // with jumps at first and last entry when appropriate
       
  1157 </xsl:text>
  1082     <xsl:text>    set_partial_text: function(){
  1158     <xsl:text>    set_partial_text: function(){
  1083 </xsl:text>
  1159 </xsl:text>
  1084     <xsl:text>        let spans = this.text_elt.children; 
  1160     <xsl:text>        let spans = this.text_elt.children; 
  1085 </xsl:text>
  1161 </xsl:text>
  1086     <xsl:text>        let contentlength = this.content.length;
  1162     <xsl:text>        let contentlength = this.content.length;
  1090     <xsl:text>        let i = this.menu_offset, c = 0;
  1166     <xsl:text>        let i = this.menu_offset, c = 0;
  1091 </xsl:text>
  1167 </xsl:text>
  1092     <xsl:text>        while(c &lt; spanslength){
  1168     <xsl:text>        while(c &lt; spanslength){
  1093 </xsl:text>
  1169 </xsl:text>
  1094     <xsl:text>            let span=spans[c];
  1170     <xsl:text>            let span=spans[c];
       
  1171 </xsl:text>
       
  1172     <xsl:text>            // backward jump only present if not exactly at start
  1095 </xsl:text>
  1173 </xsl:text>
  1096     <xsl:text>            if(c == 0 &amp;&amp; i != 0){
  1174     <xsl:text>            if(c == 0 &amp;&amp; i != 0){
  1097 </xsl:text>
  1175 </xsl:text>
  1098     <xsl:text>                span.textContent = "&#x2191;  &#x2191;  &#x2191;";
  1176     <xsl:text>                span.textContent = "&#x2191;  &#x2191;  &#x2191;";
  1099 </xsl:text>
  1177 </xsl:text>
  1100     <xsl:text>                span.setAttribute("onclick", "hmi_widgets['</xsl:text>
  1178     <xsl:text>                span.setAttribute("onclick", "hmi_widgets['</xsl:text>
  1101     <xsl:value-of select="$hmi_element/@id"/>
  1179     <xsl:value-of select="$hmi_element/@id"/>
  1102     <xsl:text>'].on_backward_click()");
  1180     <xsl:text>'].on_backward_click()");
  1103 </xsl:text>
  1181 </xsl:text>
       
  1182     <xsl:text>            // presence of forward jump when not right at the end
       
  1183 </xsl:text>
  1104     <xsl:text>            }else if(c == spanslength-1 &amp;&amp; i &lt; contentlength - 1){
  1184     <xsl:text>            }else if(c == spanslength-1 &amp;&amp; i &lt; contentlength - 1){
  1105 </xsl:text>
  1185 </xsl:text>
  1106     <xsl:text>                span.textContent = "&#x2193;  &#x2193;  &#x2193;";
  1186     <xsl:text>                span.textContent = "&#x2193;  &#x2193;  &#x2193;";
  1107 </xsl:text>
  1187 </xsl:text>
  1108     <xsl:text>                span.setAttribute("onclick", "hmi_widgets['</xsl:text>
  1188     <xsl:text>                span.setAttribute("onclick", "hmi_widgets['</xsl:text>
  1109     <xsl:value-of select="$hmi_element/@id"/>
  1189     <xsl:value-of select="$hmi_element/@id"/>
  1110     <xsl:text>'].on_forward_click()");
  1190     <xsl:text>'].on_forward_click()");
  1111 </xsl:text>
  1191 </xsl:text>
       
  1192     <xsl:text>            // otherwise normal content
       
  1193 </xsl:text>
  1112     <xsl:text>            }else{
  1194     <xsl:text>            }else{
  1113 </xsl:text>
  1195 </xsl:text>
  1114     <xsl:text>                span.textContent = this.content[i];
  1196     <xsl:text>                span.textContent = this.content[i];
  1115 </xsl:text>
  1197 </xsl:text>
  1116     <xsl:text>                span.setAttribute("onclick", "hmi_widgets['</xsl:text>
  1198     <xsl:text>                span.setAttribute("onclick", "hmi_widgets['</xsl:text>
  1129 </xsl:text>
  1211 </xsl:text>
  1130     <xsl:text>    open: function(){
  1212     <xsl:text>    open: function(){
  1131 </xsl:text>
  1213 </xsl:text>
  1132     <xsl:text>        let length = this.content.length;
  1214     <xsl:text>        let length = this.content.length;
  1133 </xsl:text>
  1215 </xsl:text>
       
  1216     <xsl:text>        // systematically reset text, to strip eventual whitespace spans
       
  1217 </xsl:text>
  1134     <xsl:text>        this.reset_text();
  1218     <xsl:text>        this.reset_text();
  1135 </xsl:text>
  1219 </xsl:text>
       
  1220     <xsl:text>        // grow as much as needed or possible
       
  1221 </xsl:text>
  1136     <xsl:text>        let slots = this.grow_text(length);
  1222     <xsl:text>        let slots = this.grow_text(length);
  1137 </xsl:text>
  1223 </xsl:text>
       
  1224     <xsl:text>        // Depending on final size
       
  1225 </xsl:text>
  1138     <xsl:text>        if(slots == length) {
  1226     <xsl:text>        if(slots == length) {
  1139 </xsl:text>
  1227 </xsl:text>
       
  1228     <xsl:text>            // show all at once
       
  1229 </xsl:text>
  1140     <xsl:text>            this.set_complete_text();
  1230     <xsl:text>            this.set_complete_text();
  1141 </xsl:text>
  1231 </xsl:text>
  1142     <xsl:text>        } else {
  1232     <xsl:text>        } else {
  1143 </xsl:text>
  1233 </xsl:text>
  1144     <xsl:text>            // align to selection
  1234     <xsl:text>            // eventualy align menu to current selection, compensating for lift
  1145 </xsl:text>
  1235 </xsl:text>
  1146     <xsl:text>            let offset = this.last_selection - this.lift;
  1236     <xsl:text>            let offset = this.last_selection - this.lift;
  1147 </xsl:text>
  1237 </xsl:text>
  1148     <xsl:text>            if(offset &gt; 0)
  1238     <xsl:text>            if(offset &gt; 0)
  1149 </xsl:text>
  1239 </xsl:text>
  1151 </xsl:text>
  1241 </xsl:text>
  1152     <xsl:text>            else
  1242     <xsl:text>            else
  1153 </xsl:text>
  1243 </xsl:text>
  1154     <xsl:text>                this.menu_offset = 0;
  1244     <xsl:text>                this.menu_offset = 0;
  1155 </xsl:text>
  1245 </xsl:text>
       
  1246     <xsl:text>            // show surrounding values
       
  1247 </xsl:text>
  1156     <xsl:text>            this.set_partial_text();
  1248     <xsl:text>            this.set_partial_text();
  1157 </xsl:text>
  1249 </xsl:text>
  1158     <xsl:text>        }
  1250     <xsl:text>        }
  1159 </xsl:text>
  1251 </xsl:text>
       
  1252     <xsl:text>        // Now that text size is known, we can set the box around it
       
  1253 </xsl:text>
  1160     <xsl:text>        this.adjust_box_to_text();
  1254     <xsl:text>        this.adjust_box_to_text();
  1161 </xsl:text>
  1255 </xsl:text>
       
  1256     <xsl:text>        // Take button out until menu closed
       
  1257 </xsl:text>
  1162     <xsl:text>        this.element.removeChild(this.button_elt);
  1258     <xsl:text>        this.element.removeChild(this.button_elt);
  1163 </xsl:text>
  1259 </xsl:text>
       
  1260     <xsl:text>        // Rise widget to top by moving it to last position among siblings
       
  1261 </xsl:text>
  1164     <xsl:text>        this.element.parentNode.appendChild(this.element.parentNode.removeChild(this.element));
  1262     <xsl:text>        this.element.parentNode.appendChild(this.element.parentNode.removeChild(this.element));
  1165 </xsl:text>
  1263 </xsl:text>
  1166     <xsl:text>        // disable interaction with background
  1264     <xsl:text>        // disable interaction with background
  1167 </xsl:text>
  1265 </xsl:text>
  1168     <xsl:text>        document.addEventListener("click", this.bound_close_on_click_elsewhere, true);
  1266     <xsl:text>        svg_root.addEventListener("click", this.bound_close_on_click_elsewhere, true);
       
  1267 </xsl:text>
       
  1268     <xsl:text>        // mark as open
  1169 </xsl:text>
  1269 </xsl:text>
  1170     <xsl:text>        this.opened = true;
  1270     <xsl:text>        this.opened = true;
  1171 </xsl:text>
  1271 </xsl:text>
  1172     <xsl:text>    },
  1272     <xsl:text>    },
  1173 </xsl:text>
  1273 </xsl:text>
       
  1274     <xsl:text>    // Put text element in normalized state
       
  1275 </xsl:text>
  1174     <xsl:text>    reset_text: function(){
  1276     <xsl:text>    reset_text: function(){
  1175 </xsl:text>
  1277 </xsl:text>
  1176     <xsl:text>        let txt = this.text_elt; 
  1278     <xsl:text>        let txt = this.text_elt; 
  1177 </xsl:text>
  1279 </xsl:text>
  1178     <xsl:text>        let first = txt.firstElementChild;
  1280     <xsl:text>        let first = txt.firstElementChild;
  1179 </xsl:text>
  1281 </xsl:text>
       
  1282     <xsl:text>        // remove attribute eventually added to first text line while opening
       
  1283 </xsl:text>
  1180     <xsl:text>        first.removeAttribute("onclick");
  1284     <xsl:text>        first.removeAttribute("onclick");
  1181 </xsl:text>
  1285 </xsl:text>
  1182     <xsl:text>        first.removeAttribute("dy");
  1286     <xsl:text>        first.removeAttribute("dy");
  1183 </xsl:text>
  1287 </xsl:text>
       
  1288     <xsl:text>        // keep only the first line of text
       
  1289 </xsl:text>
  1184     <xsl:text>        for(let span of Array.from(txt.children).slice(1)){
  1290     <xsl:text>        for(let span of Array.from(txt.children).slice(1)){
  1185 </xsl:text>
  1291 </xsl:text>
  1186     <xsl:text>            txt.removeChild(span)
  1292     <xsl:text>            txt.removeChild(span)
  1187 </xsl:text>
  1293 </xsl:text>
  1188     <xsl:text>        }
  1294     <xsl:text>        }
  1189 </xsl:text>
  1295 </xsl:text>
  1190     <xsl:text>    },
  1296     <xsl:text>    },
  1191 </xsl:text>
  1297 </xsl:text>
       
  1298     <xsl:text>    // Put rectangle element in saved original state
       
  1299 </xsl:text>
  1192     <xsl:text>    reset_box: function(){
  1300     <xsl:text>    reset_box: function(){
  1193 </xsl:text>
  1301 </xsl:text>
  1194     <xsl:text>        let m = this.box_bbox;
  1302     <xsl:text>        let m = this.box_bbox;
  1195 </xsl:text>
  1303 </xsl:text>
  1196     <xsl:text>        let b = this.box_elt;
  1304     <xsl:text>        let b = this.box_elt;
  1202     <xsl:text>        b.width.baseVal.value = m.width;
  1310     <xsl:text>        b.width.baseVal.value = m.width;
  1203 </xsl:text>
  1311 </xsl:text>
  1204     <xsl:text>        b.height.baseVal.value = m.height;
  1312     <xsl:text>        b.height.baseVal.value = m.height;
  1205 </xsl:text>
  1313 </xsl:text>
  1206     <xsl:text>    },
  1314     <xsl:text>    },
       
  1315 </xsl:text>
       
  1316     <xsl:text>    // Use margin and text size to compute box size
  1207 </xsl:text>
  1317 </xsl:text>
  1208     <xsl:text>    adjust_box_to_text: function(){
  1318     <xsl:text>    adjust_box_to_text: function(){
  1209 </xsl:text>
  1319 </xsl:text>
  1210     <xsl:text>        let [lmargin, tmargin] = this.margins;
  1320     <xsl:text>        let [lmargin, tmargin] = this.margins;
  1211 </xsl:text>
  1321 </xsl:text>