svghmi/gen_index_xhtml.xslt
branchsvghmi
changeset 3092 96ffd8b1b016
parent 3091 f475f39713aa
child 3094 3e184f1e1012
equal deleted inserted replaced
3091:f475f39713aa 3092:96ffd8b1b016
  3082 </xsl:text>
  3082 </xsl:text>
  3083     <xsl:text>            // Save original size of rectangle
  3083     <xsl:text>            // Save original size of rectangle
  3084 </xsl:text>
  3084 </xsl:text>
  3085     <xsl:text>            this.box_bbox = this.box_elt.getBBox()
  3085     <xsl:text>            this.box_bbox = this.box_elt.getBBox()
  3086 </xsl:text>
  3086 </xsl:text>
       
  3087     <xsl:text>            this.highlight_bbox = this.highlight_elt.getBBox()
       
  3088 </xsl:text>
       
  3089     <xsl:text>            this.highlight_elt.style.visibility = "hidden";
       
  3090 </xsl:text>
  3087     <xsl:text>
  3091     <xsl:text>
  3088 </xsl:text>
  3092 </xsl:text>
  3089     <xsl:text>            // Compute margins
  3093     <xsl:text>            // Compute margins
  3090 </xsl:text>
  3094 </xsl:text>
  3091     <xsl:text>            this.text_bbox = this.text_elt.getBBox();
  3095     <xsl:text>            this.text_bbox = this.text_elt.getBBox();
  3226 </xsl:text>
  3230 </xsl:text>
  3227     <xsl:text>                    // in case of overflow at the bottom, lift up one row
  3231     <xsl:text>                    // in case of overflow at the bottom, lift up one row
  3228 </xsl:text>
  3232 </xsl:text>
  3229     <xsl:text>                    let backup = first.getAttribute("dy");
  3233     <xsl:text>                    let backup = first.getAttribute("dy");
  3230 </xsl:text>
  3234 </xsl:text>
  3231     <xsl:text>                    // apply lift asr a dy added too first span (y attrib stays)
  3235     <xsl:text>                    // apply lift as a dy added too first span (y attrib stays)
  3232 </xsl:text>
  3236 </xsl:text>
  3233     <xsl:text>                    first.setAttribute("dy", "-"+String((this.lift+1)*1.1)+"em");
  3237     <xsl:text>                    first.setAttribute("dy", "-"+String((this.lift+1)*1.1)+"em");
  3234 </xsl:text>
  3238 </xsl:text>
  3235     <xsl:text>                    rect = txt.getBoundingClientRect();
  3239     <xsl:text>                    rect = txt.getBoundingClientRect();
  3236 </xsl:text>
  3240 </xsl:text>
  3304 </xsl:text>
  3308 </xsl:text>
  3305     <xsl:text>            this.reset_clickables();
  3309     <xsl:text>            this.reset_clickables();
  3306 </xsl:text>
  3310 </xsl:text>
  3307     <xsl:text>            this.reset_box();
  3311     <xsl:text>            this.reset_box();
  3308 </xsl:text>
  3312 </xsl:text>
       
  3313     <xsl:text>            this.reset_highlight();
       
  3314 </xsl:text>
  3309     <xsl:text>            // Put the button back in place
  3315     <xsl:text>            // Put the button back in place
  3310 </xsl:text>
  3316 </xsl:text>
  3311     <xsl:text>            this.element.appendChild(this.button_elt);
  3317     <xsl:text>            this.element.appendChild(this.button_elt);
  3312 </xsl:text>
  3318 </xsl:text>
  3313     <xsl:text>            // Mark as closed (to allow dispatch)
  3319     <xsl:text>            // Mark as closed (to allow dispatch)
  3324 </xsl:text>
  3330 </xsl:text>
  3325     <xsl:text>        make_clickable(span, func) {
  3331     <xsl:text>        make_clickable(span, func) {
  3326 </xsl:text>
  3332 </xsl:text>
  3327     <xsl:text>            let txt = this.text_elt;
  3333     <xsl:text>            let txt = this.text_elt;
  3328 </xsl:text>
  3334 </xsl:text>
       
  3335     <xsl:text>            let original_text_y = this.text_bbox.y;
       
  3336 </xsl:text>
       
  3337     <xsl:text>            let highlight = this.highlight_elt;
       
  3338 </xsl:text>
       
  3339     <xsl:text>            let original_h_y = this.highlight_bbox.y;
       
  3340 </xsl:text>
       
  3341     <xsl:text>            let clickable = highlight.cloneNode();
       
  3342 </xsl:text>
       
  3343     <xsl:text>            let yoffset = span.getBBox().y - original_text_y;
       
  3344 </xsl:text>
       
  3345     <xsl:text>            clickable.y.baseVal.value = original_h_y + yoffset;
       
  3346 </xsl:text>
       
  3347     <xsl:text>            clickable.style.pointerEvents = "bounding-box";
       
  3348 </xsl:text>
       
  3349     <xsl:text>            //clickable.style.visibility = "hidden";
       
  3350 </xsl:text>
       
  3351     <xsl:text>            //clickable.onclick = () =&gt; alert("love JS");
       
  3352 </xsl:text>
       
  3353     <xsl:text>            clickable.onclick = func;
       
  3354 </xsl:text>
       
  3355     <xsl:text>            this.element.appendChild(clickable);
       
  3356 </xsl:text>
       
  3357     <xsl:text>            this.clickables.push(clickable)
       
  3358 </xsl:text>
       
  3359     <xsl:text>        }
       
  3360 </xsl:text>
       
  3361     <xsl:text>        reset_clickables() {
       
  3362 </xsl:text>
       
  3363     <xsl:text>            while(this.clickables.length){
       
  3364 </xsl:text>
       
  3365     <xsl:text>                this.element.removeChild(this.clickables.pop());
       
  3366 </xsl:text>
       
  3367     <xsl:text>            }
       
  3368 </xsl:text>
       
  3369     <xsl:text>        }
       
  3370 </xsl:text>
       
  3371     <xsl:text>        // Set text content when content is smaller than menu (no scrolling)
       
  3372 </xsl:text>
       
  3373     <xsl:text>        set_complete_text(){
       
  3374 </xsl:text>
       
  3375     <xsl:text>            let spans = this.text_elt.children;
       
  3376 </xsl:text>
       
  3377     <xsl:text>            let c = 0;
       
  3378 </xsl:text>
       
  3379     <xsl:text>            for(let item of this.content){
       
  3380 </xsl:text>
       
  3381     <xsl:text>                let span=spans[c];
       
  3382 </xsl:text>
       
  3383     <xsl:text>                span.textContent = item;
       
  3384 </xsl:text>
       
  3385     <xsl:text>                let sel = c;
       
  3386 </xsl:text>
       
  3387     <xsl:text>                this.make_clickable(span, (evt) =&gt; this.bound_on_selection_click(sel));
       
  3388 </xsl:text>
       
  3389     <xsl:text>                c++;
       
  3390 </xsl:text>
       
  3391     <xsl:text>            }
       
  3392 </xsl:text>
       
  3393     <xsl:text>        }
       
  3394 </xsl:text>
       
  3395     <xsl:text>        // Move partial view :
       
  3396 </xsl:text>
       
  3397     <xsl:text>        // false : upward, lower value
       
  3398 </xsl:text>
       
  3399     <xsl:text>        // true  : downward, higher value
       
  3400 </xsl:text>
       
  3401     <xsl:text>        scroll(forward){
       
  3402 </xsl:text>
       
  3403     <xsl:text>            let contentlength = this.content.length;
       
  3404 </xsl:text>
       
  3405     <xsl:text>            let spans = this.text_elt.children;
       
  3406 </xsl:text>
       
  3407     <xsl:text>            let spanslength = spans.length;
       
  3408 </xsl:text>
       
  3409     <xsl:text>            // reduce accounted menu size according to prsence of scroll buttons
       
  3410 </xsl:text>
       
  3411     <xsl:text>            // since we scroll there is necessarly one button
       
  3412 </xsl:text>
       
  3413     <xsl:text>            spanslength--;
       
  3414 </xsl:text>
       
  3415     <xsl:text>            if(forward){
       
  3416 </xsl:text>
       
  3417     <xsl:text>                // reduce accounted menu size because of back button
       
  3418 </xsl:text>
       
  3419     <xsl:text>                if(this.menu_offset != 0) spanslength--;
       
  3420 </xsl:text>
       
  3421     <xsl:text>                this.menu_offset = Math.min(
       
  3422 </xsl:text>
       
  3423     <xsl:text>                    contentlength - spans.length + 1,
       
  3424 </xsl:text>
       
  3425     <xsl:text>                    this.menu_offset + spanslength);
       
  3426 </xsl:text>
       
  3427     <xsl:text>            }else{
       
  3428 </xsl:text>
       
  3429     <xsl:text>                if(this.menu_offset - spanslength &gt; 0) spanslength--;
       
  3430 </xsl:text>
       
  3431     <xsl:text>                this.menu_offset = Math.max(
       
  3432 </xsl:text>
       
  3433     <xsl:text>                    0,
       
  3434 </xsl:text>
       
  3435     <xsl:text>                    this.menu_offset - spanslength);
       
  3436 </xsl:text>
       
  3437     <xsl:text>            }
       
  3438 </xsl:text>
       
  3439     <xsl:text>            if(this.menu_offset == 1)
       
  3440 </xsl:text>
       
  3441     <xsl:text>                this.menu_offset = 0;
       
  3442 </xsl:text>
       
  3443     <xsl:text>
       
  3444 </xsl:text>
       
  3445     <xsl:text>            this.reset_highlight();
       
  3446 </xsl:text>
       
  3447     <xsl:text>
       
  3448 </xsl:text>
       
  3449     <xsl:text>            this.reset_clickables();
       
  3450 </xsl:text>
       
  3451     <xsl:text>            this.set_partial_text();
       
  3452 </xsl:text>
       
  3453     <xsl:text>
       
  3454 </xsl:text>
       
  3455     <xsl:text>            this.highlight_selection();
       
  3456 </xsl:text>
       
  3457     <xsl:text>        }
       
  3458 </xsl:text>
       
  3459     <xsl:text>        // Setup partial view text content
       
  3460 </xsl:text>
       
  3461     <xsl:text>        // with jumps at first and last entry when appropriate
       
  3462 </xsl:text>
       
  3463     <xsl:text>        set_partial_text(){
       
  3464 </xsl:text>
       
  3465     <xsl:text>            let spans = this.text_elt.children;
       
  3466 </xsl:text>
       
  3467     <xsl:text>            let contentlength = this.content.length;
       
  3468 </xsl:text>
       
  3469     <xsl:text>            let spanslength = spans.length;
       
  3470 </xsl:text>
       
  3471     <xsl:text>            let i = this.menu_offset, c = 0;
       
  3472 </xsl:text>
       
  3473     <xsl:text>            let m = this.box_bbox;
       
  3474 </xsl:text>
       
  3475     <xsl:text>            while(c &lt; spanslength){
       
  3476 </xsl:text>
       
  3477     <xsl:text>                let span=spans[c];
       
  3478 </xsl:text>
       
  3479     <xsl:text>                let onclickfunc;
       
  3480 </xsl:text>
       
  3481     <xsl:text>                // backward jump only present if not exactly at start
       
  3482 </xsl:text>
       
  3483     <xsl:text>                if(c == 0 &amp;&amp; i != 0){
       
  3484 </xsl:text>
       
  3485     <xsl:text>                    span.textContent = "&#x25B2;";
       
  3486 </xsl:text>
       
  3487     <xsl:text>                    onclickfunc = this.bound_on_backward_click;
       
  3488 </xsl:text>
       
  3489     <xsl:text>                    let o = span.getBBox();
       
  3490 </xsl:text>
       
  3491     <xsl:text>                    span.setAttribute("dx", (m.width - o.width)/2);
       
  3492 </xsl:text>
       
  3493     <xsl:text>                // presence of forward jump when not right at the end
       
  3494 </xsl:text>
       
  3495     <xsl:text>                }else if(c == spanslength-1 &amp;&amp; i &lt; contentlength - 1){
       
  3496 </xsl:text>
       
  3497     <xsl:text>                    span.textContent = "&#x25BC;";
       
  3498 </xsl:text>
       
  3499     <xsl:text>                    onclickfunc = this.bound_on_forward_click;
       
  3500 </xsl:text>
       
  3501     <xsl:text>                    let o = span.getBBox();
       
  3502 </xsl:text>
       
  3503     <xsl:text>                    span.setAttribute("dx", (m.width - o.width)/2);
       
  3504 </xsl:text>
       
  3505     <xsl:text>                // otherwise normal content
       
  3506 </xsl:text>
       
  3507     <xsl:text>                }else{
       
  3508 </xsl:text>
       
  3509     <xsl:text>                    span.textContent = this.content[i];
       
  3510 </xsl:text>
       
  3511     <xsl:text>                    let sel = i;
       
  3512 </xsl:text>
       
  3513     <xsl:text>                    onclickfunc = (evt) =&gt; this.bound_on_selection_click(sel);
       
  3514 </xsl:text>
       
  3515     <xsl:text>                    span.removeAttribute("dx");
       
  3516 </xsl:text>
       
  3517     <xsl:text>                    i++;
       
  3518 </xsl:text>
       
  3519     <xsl:text>                }
       
  3520 </xsl:text>
       
  3521     <xsl:text>                this.make_clickable(span, onclickfunc);
       
  3522 </xsl:text>
       
  3523     <xsl:text>                c++;
       
  3524 </xsl:text>
       
  3525     <xsl:text>            }
       
  3526 </xsl:text>
       
  3527     <xsl:text>        }
       
  3528 </xsl:text>
       
  3529     <xsl:text>        open(){
       
  3530 </xsl:text>
       
  3531     <xsl:text>            let length = this.content.length;
       
  3532 </xsl:text>
       
  3533     <xsl:text>            // systematically reset text, to strip eventual whitespace spans
       
  3534 </xsl:text>
       
  3535     <xsl:text>            this.reset_text();
       
  3536 </xsl:text>
       
  3537     <xsl:text>            // grow as much as needed or possible
       
  3538 </xsl:text>
       
  3539     <xsl:text>            let slots = this.grow_text(length);
       
  3540 </xsl:text>
       
  3541     <xsl:text>            // Depending on final size
       
  3542 </xsl:text>
       
  3543     <xsl:text>            if(slots == length) {
       
  3544 </xsl:text>
       
  3545     <xsl:text>                // show all at once
       
  3546 </xsl:text>
       
  3547     <xsl:text>                this.set_complete_text();
       
  3548 </xsl:text>
       
  3549     <xsl:text>            } else {
       
  3550 </xsl:text>
       
  3551     <xsl:text>                // eventualy align menu to current selection, compensating for lift
       
  3552 </xsl:text>
       
  3553     <xsl:text>                let offset = this.last_selection - this.lift;
       
  3554 </xsl:text>
       
  3555     <xsl:text>                if(offset &gt; 0)
       
  3556 </xsl:text>
       
  3557     <xsl:text>                    this.menu_offset = Math.min(offset + 1, length - slots + 1);
       
  3558 </xsl:text>
       
  3559     <xsl:text>                else
       
  3560 </xsl:text>
       
  3561     <xsl:text>                    this.menu_offset = 0;
       
  3562 </xsl:text>
       
  3563     <xsl:text>                // show surrounding values
       
  3564 </xsl:text>
       
  3565     <xsl:text>                this.set_partial_text();
       
  3566 </xsl:text>
       
  3567     <xsl:text>            }
       
  3568 </xsl:text>
       
  3569     <xsl:text>            // Now that text size is known, we can set the box around it
       
  3570 </xsl:text>
       
  3571     <xsl:text>            this.adjust_box_to_text();
       
  3572 </xsl:text>
       
  3573     <xsl:text>            // Take button out until menu closed
       
  3574 </xsl:text>
       
  3575     <xsl:text>            this.element.removeChild(this.button_elt);
       
  3576 </xsl:text>
       
  3577     <xsl:text>            // Rise widget to top by moving it to last position among siblings
       
  3578 </xsl:text>
       
  3579     <xsl:text>            this.element.parentNode.appendChild(this.element.parentNode.removeChild(this.element));
       
  3580 </xsl:text>
       
  3581     <xsl:text>            // disable interaction with background
       
  3582 </xsl:text>
       
  3583     <xsl:text>            svg_root.addEventListener("pointerdown", numb_event, true);
       
  3584 </xsl:text>
       
  3585     <xsl:text>            svg_root.addEventListener("pointerup", numb_event, true);
       
  3586 </xsl:text>
       
  3587     <xsl:text>            svg_root.addEventListener("click", this.bound_close_on_click_elsewhere, true);
       
  3588 </xsl:text>
       
  3589     <xsl:text>            this.highlight_selection();
       
  3590 </xsl:text>
       
  3591     <xsl:text>
       
  3592 </xsl:text>
       
  3593     <xsl:text>            // mark as open
       
  3594 </xsl:text>
       
  3595     <xsl:text>            this.opened = true;
       
  3596 </xsl:text>
       
  3597     <xsl:text>        }
       
  3598 </xsl:text>
       
  3599     <xsl:text>        // Put text element in normalized state
       
  3600 </xsl:text>
       
  3601     <xsl:text>        reset_text(){
       
  3602 </xsl:text>
       
  3603     <xsl:text>            let txt = this.text_elt;
       
  3604 </xsl:text>
  3329     <xsl:text>            let first = txt.firstElementChild;
  3605     <xsl:text>            let first = txt.firstElementChild;
  3330 </xsl:text>
  3606 </xsl:text>
       
  3607     <xsl:text>            // remove attribute eventually added to first text line while opening
       
  3608 </xsl:text>
       
  3609     <xsl:text>            first.onclick = null;
       
  3610 </xsl:text>
       
  3611     <xsl:text>            first.removeAttribute("dy");
       
  3612 </xsl:text>
       
  3613     <xsl:text>            first.removeAttribute("dx");
       
  3614 </xsl:text>
       
  3615     <xsl:text>            // keep only the first line of text
       
  3616 </xsl:text>
       
  3617     <xsl:text>            for(let span of Array.from(txt.children).slice(1)){
       
  3618 </xsl:text>
       
  3619     <xsl:text>                txt.removeChild(span)
       
  3620 </xsl:text>
       
  3621     <xsl:text>            }
       
  3622 </xsl:text>
       
  3623     <xsl:text>        }
       
  3624 </xsl:text>
       
  3625     <xsl:text>        // Put rectangle element in saved original state
       
  3626 </xsl:text>
       
  3627     <xsl:text>        reset_box(){
       
  3628 </xsl:text>
       
  3629     <xsl:text>            let m = this.box_bbox;
       
  3630 </xsl:text>
       
  3631     <xsl:text>            let b = this.box_elt;
       
  3632 </xsl:text>
       
  3633     <xsl:text>            b.x.baseVal.value = m.x;
       
  3634 </xsl:text>
       
  3635     <xsl:text>            b.y.baseVal.value = m.y;
       
  3636 </xsl:text>
       
  3637     <xsl:text>            b.width.baseVal.value = m.width;
       
  3638 </xsl:text>
       
  3639     <xsl:text>            b.height.baseVal.value = m.height;
       
  3640 </xsl:text>
       
  3641     <xsl:text>        }
       
  3642 </xsl:text>
       
  3643     <xsl:text>        highlight_selection(){
       
  3644 </xsl:text>
       
  3645     <xsl:text>            let highlighted_row = this.last_selection - this.menu_offset;
       
  3646 </xsl:text>
       
  3647     <xsl:text>            if(highlighted_row &lt; 0) return;
       
  3648 </xsl:text>
       
  3649     <xsl:text>            let spans = this.text_elt.children;
       
  3650 </xsl:text>
       
  3651     <xsl:text>            let spanslength = spans.length;
       
  3652 </xsl:text>
       
  3653     <xsl:text>            let contentlength = this.content.length;
       
  3654 </xsl:text>
       
  3655     <xsl:text>            if(this.menu_offset != 0) {
       
  3656 </xsl:text>
       
  3657     <xsl:text>                spanslength--;
       
  3658 </xsl:text>
       
  3659     <xsl:text>                highlighted_row++;
       
  3660 </xsl:text>
       
  3661     <xsl:text>            }
       
  3662 </xsl:text>
       
  3663     <xsl:text>            if(this.menu_offset + spanslength &lt; contentlength - 1) spanslength--;
       
  3664 </xsl:text>
       
  3665     <xsl:text>            if(highlighted_row &gt; spanslength) return;
       
  3666 </xsl:text>
  3331     <xsl:text>            let original_text_y = this.text_bbox.y;
  3667     <xsl:text>            let original_text_y = this.text_bbox.y;
  3332 </xsl:text>
  3668 </xsl:text>
  3333     <xsl:text>            let highlight = this.highlight_elt;
  3669     <xsl:text>            let highlight = this.highlight_elt;
  3334 </xsl:text>
  3670 </xsl:text>
  3335     <xsl:text>            let original_h_y = highlight.getBBox().y;
  3671     <xsl:text>            let span = spans[highlighted_row];
  3336 </xsl:text>
       
  3337     <xsl:text>            let clickable = highlight.cloneNode();
       
  3338 </xsl:text>
  3672 </xsl:text>
  3339     <xsl:text>            let yoffset = span.getBBox().y - original_text_y;
  3673     <xsl:text>            let yoffset = span.getBBox().y - original_text_y;
  3340 </xsl:text>
  3674 </xsl:text>
  3341     <xsl:text>            clickable.setAttribute("y", original_h_y + yoffset); 
  3675     <xsl:text>            highlight.y.baseVal.value = this.highlight_bbox.y + yoffset;
  3342 </xsl:text>
  3676 </xsl:text>
  3343     <xsl:text>            clickable.style.pointerEvents = "bounding-box";
  3677     <xsl:text>            highlight.style.visibility = "visible";
  3344 </xsl:text>
  3678 </xsl:text>
  3345     <xsl:text>            clickable.style.visibility = "hidden";
  3679     <xsl:text>        }
  3346 </xsl:text>
  3680 </xsl:text>
  3347     <xsl:text>            //clickable.onclick = () =&gt; alert("love JS");
  3681     <xsl:text>        reset_highlight(){
  3348 </xsl:text>
  3682 </xsl:text>
  3349     <xsl:text>            clickable.onclick = func;
  3683     <xsl:text>            let highlight = this.highlight_elt;
  3350 </xsl:text>
  3684 </xsl:text>
  3351     <xsl:text>            this.element.appendChild(clickable);
  3685     <xsl:text>            highlight.y.baseVal.value = this.highlight_bbox.y;
  3352 </xsl:text>
  3686 </xsl:text>
  3353     <xsl:text>            this.clickables.push(clickable)
  3687     <xsl:text>            highlight.style.visibility = "hidden";
  3354 </xsl:text>
       
  3355     <xsl:text>        }
       
  3356 </xsl:text>
       
  3357     <xsl:text>        reset_clickables() {
       
  3358 </xsl:text>
       
  3359     <xsl:text>            while(this.clickables.length){
       
  3360 </xsl:text>
       
  3361     <xsl:text>                this.element.removeChild(this.clickables.pop());
       
  3362 </xsl:text>
       
  3363     <xsl:text>            }
       
  3364 </xsl:text>
       
  3365     <xsl:text>        }
       
  3366 </xsl:text>
       
  3367     <xsl:text>        // Set text content when content is smaller than menu (no scrolling)
       
  3368 </xsl:text>
       
  3369     <xsl:text>        set_complete_text(){
       
  3370 </xsl:text>
       
  3371     <xsl:text>            let spans = this.text_elt.children;
       
  3372 </xsl:text>
       
  3373     <xsl:text>            let c = 0;
       
  3374 </xsl:text>
       
  3375     <xsl:text>            for(let item of this.content){
       
  3376 </xsl:text>
       
  3377     <xsl:text>                let span=spans[c];
       
  3378 </xsl:text>
       
  3379     <xsl:text>                span.textContent = item;
       
  3380 </xsl:text>
       
  3381     <xsl:text>                let sel = c;
       
  3382 </xsl:text>
       
  3383     <xsl:text>                this.make_clickable(span, (evt) =&gt; this.bound_on_selection_click(sel));
       
  3384 </xsl:text>
       
  3385     <xsl:text>                c++;
       
  3386 </xsl:text>
       
  3387     <xsl:text>            }
       
  3388 </xsl:text>
       
  3389     <xsl:text>        }
       
  3390 </xsl:text>
       
  3391     <xsl:text>        // Move partial view :
       
  3392 </xsl:text>
       
  3393     <xsl:text>        // false : upward, lower value
       
  3394 </xsl:text>
       
  3395     <xsl:text>        // true  : downward, higher value
       
  3396 </xsl:text>
       
  3397     <xsl:text>        scroll(forward){
       
  3398 </xsl:text>
       
  3399     <xsl:text>            let contentlength = this.content.length;
       
  3400 </xsl:text>
       
  3401     <xsl:text>            let spans = this.text_elt.children;
       
  3402 </xsl:text>
       
  3403     <xsl:text>            let spanslength = spans.length;
       
  3404 </xsl:text>
       
  3405     <xsl:text>            // reduce accounted menu size according to jumps
       
  3406 </xsl:text>
       
  3407     <xsl:text>            if(this.menu_offset != 0) spanslength--;
       
  3408 </xsl:text>
       
  3409     <xsl:text>            if(this.menu_offset &lt; contentlength - 1) spanslength--;
       
  3410 </xsl:text>
       
  3411     <xsl:text>            if(forward){
       
  3412 </xsl:text>
       
  3413     <xsl:text>                this.menu_offset = Math.min(
       
  3414 </xsl:text>
       
  3415     <xsl:text>                    contentlength - spans.length + 1,
       
  3416 </xsl:text>
       
  3417     <xsl:text>                    this.menu_offset + spanslength);
       
  3418 </xsl:text>
       
  3419     <xsl:text>            }else{
       
  3420 </xsl:text>
       
  3421     <xsl:text>                this.menu_offset = Math.max(
       
  3422 </xsl:text>
       
  3423     <xsl:text>                    0,
       
  3424 </xsl:text>
       
  3425     <xsl:text>                    this.menu_offset - spanslength);
       
  3426 </xsl:text>
       
  3427     <xsl:text>            }
       
  3428 </xsl:text>
       
  3429     <xsl:text>            this.reset_clickables();
       
  3430 </xsl:text>
       
  3431     <xsl:text>            this.set_partial_text();
       
  3432 </xsl:text>
       
  3433     <xsl:text>        }
       
  3434 </xsl:text>
       
  3435     <xsl:text>        // Setup partial view text content
       
  3436 </xsl:text>
       
  3437     <xsl:text>        // with jumps at first and last entry when appropriate
       
  3438 </xsl:text>
       
  3439     <xsl:text>        set_partial_text(){
       
  3440 </xsl:text>
       
  3441     <xsl:text>            let spans = this.text_elt.children;
       
  3442 </xsl:text>
       
  3443     <xsl:text>            let contentlength = this.content.length;
       
  3444 </xsl:text>
       
  3445     <xsl:text>            let spanslength = spans.length;
       
  3446 </xsl:text>
       
  3447     <xsl:text>            let i = this.menu_offset, c = 0;
       
  3448 </xsl:text>
       
  3449     <xsl:text>            let m = this.box_bbox;
       
  3450 </xsl:text>
       
  3451     <xsl:text>            while(c &lt; spanslength){
       
  3452 </xsl:text>
       
  3453     <xsl:text>                let span=spans[c];
       
  3454 </xsl:text>
       
  3455     <xsl:text>                let onclickfunc;
       
  3456 </xsl:text>
       
  3457     <xsl:text>                // backward jump only present if not exactly at start
       
  3458 </xsl:text>
       
  3459     <xsl:text>                if(c == 0 &amp;&amp; i != 0){
       
  3460 </xsl:text>
       
  3461     <xsl:text>                    span.textContent = "&#x25B2;";
       
  3462 </xsl:text>
       
  3463     <xsl:text>                    onclickfunc = this.bound_on_backward_click;
       
  3464 </xsl:text>
       
  3465     <xsl:text>                    let o = span.getBBox();
       
  3466 </xsl:text>
       
  3467     <xsl:text>                    span.setAttribute("dx", (m.width - o.width)/2);
       
  3468 </xsl:text>
       
  3469     <xsl:text>                // presence of forward jump when not right at the end
       
  3470 </xsl:text>
       
  3471     <xsl:text>                }else if(c == spanslength-1 &amp;&amp; i &lt; contentlength - 1){
       
  3472 </xsl:text>
       
  3473     <xsl:text>                    span.textContent = "&#x25BC;";
       
  3474 </xsl:text>
       
  3475     <xsl:text>                    onclickfunc = this.bound_on_forward_click;
       
  3476 </xsl:text>
       
  3477     <xsl:text>                    let o = span.getBBox();
       
  3478 </xsl:text>
       
  3479     <xsl:text>                    span.setAttribute("dx", (m.width - o.width)/2);
       
  3480 </xsl:text>
       
  3481     <xsl:text>                // otherwise normal content
       
  3482 </xsl:text>
       
  3483     <xsl:text>                }else{
       
  3484 </xsl:text>
       
  3485     <xsl:text>                    span.textContent = this.content[i];
       
  3486 </xsl:text>
       
  3487     <xsl:text>                    let sel = i;
       
  3488 </xsl:text>
       
  3489     <xsl:text>                    onclickfunc = (evt) =&gt; this.bound_on_selection_click(sel);
       
  3490 </xsl:text>
       
  3491     <xsl:text>                    span.removeAttribute("dx");
       
  3492 </xsl:text>
       
  3493     <xsl:text>                    i++;
       
  3494 </xsl:text>
       
  3495     <xsl:text>                }
       
  3496 </xsl:text>
       
  3497     <xsl:text>                this.make_clickable(span, onclickfunc);
       
  3498 </xsl:text>
       
  3499     <xsl:text>                c++;
       
  3500 </xsl:text>
       
  3501     <xsl:text>            }
       
  3502 </xsl:text>
       
  3503     <xsl:text>        }
       
  3504 </xsl:text>
       
  3505     <xsl:text>        open(){
       
  3506 </xsl:text>
       
  3507     <xsl:text>            let length = this.content.length;
       
  3508 </xsl:text>
       
  3509     <xsl:text>            // systematically reset text, to strip eventual whitespace spans
       
  3510 </xsl:text>
       
  3511     <xsl:text>            this.reset_text();
       
  3512 </xsl:text>
       
  3513     <xsl:text>            // grow as much as needed or possible
       
  3514 </xsl:text>
       
  3515     <xsl:text>            let slots = this.grow_text(length);
       
  3516 </xsl:text>
       
  3517     <xsl:text>            // Depending on final size
       
  3518 </xsl:text>
       
  3519     <xsl:text>            if(slots == length) {
       
  3520 </xsl:text>
       
  3521     <xsl:text>                // show all at once
       
  3522 </xsl:text>
       
  3523     <xsl:text>                this.set_complete_text();
       
  3524 </xsl:text>
       
  3525     <xsl:text>            } else {
       
  3526 </xsl:text>
       
  3527     <xsl:text>                // eventualy align menu to current selection, compensating for lift
       
  3528 </xsl:text>
       
  3529     <xsl:text>                let offset = this.last_selection - this.lift;
       
  3530 </xsl:text>
       
  3531     <xsl:text>                if(offset &gt; 0)
       
  3532 </xsl:text>
       
  3533     <xsl:text>                    this.menu_offset = Math.min(offset + 1, length - slots + 1);
       
  3534 </xsl:text>
       
  3535     <xsl:text>                else
       
  3536 </xsl:text>
       
  3537     <xsl:text>                    this.menu_offset = 0;
       
  3538 </xsl:text>
       
  3539     <xsl:text>                // show surrounding values
       
  3540 </xsl:text>
       
  3541     <xsl:text>                this.set_partial_text();
       
  3542 </xsl:text>
       
  3543     <xsl:text>            }
       
  3544 </xsl:text>
       
  3545     <xsl:text>            // Now that text size is known, we can set the box around it
       
  3546 </xsl:text>
       
  3547     <xsl:text>            this.adjust_box_to_text();
       
  3548 </xsl:text>
       
  3549     <xsl:text>            // Take button out until menu closed
       
  3550 </xsl:text>
       
  3551     <xsl:text>            this.element.removeChild(this.button_elt);
       
  3552 </xsl:text>
       
  3553     <xsl:text>            // Rise widget to top by moving it to last position among siblings
       
  3554 </xsl:text>
       
  3555     <xsl:text>            this.element.parentNode.appendChild(this.element.parentNode.removeChild(this.element));
       
  3556 </xsl:text>
       
  3557     <xsl:text>            // disable interaction with background
       
  3558 </xsl:text>
       
  3559     <xsl:text>            svg_root.addEventListener("pointerdown", numb_event, true);
       
  3560 </xsl:text>
       
  3561     <xsl:text>            svg_root.addEventListener("pointerup", numb_event, true);
       
  3562 </xsl:text>
       
  3563     <xsl:text>            svg_root.addEventListener("click", this.bound_close_on_click_elsewhere, true);
       
  3564 </xsl:text>
       
  3565     <xsl:text>            // mark as open
       
  3566 </xsl:text>
       
  3567     <xsl:text>            this.opened = true;
       
  3568 </xsl:text>
       
  3569     <xsl:text>        }
       
  3570 </xsl:text>
       
  3571     <xsl:text>        // Put text element in normalized state
       
  3572 </xsl:text>
       
  3573     <xsl:text>        reset_text(){
       
  3574 </xsl:text>
       
  3575     <xsl:text>            let txt = this.text_elt;
       
  3576 </xsl:text>
       
  3577     <xsl:text>            let first = txt.firstElementChild;
       
  3578 </xsl:text>
       
  3579     <xsl:text>            // remove attribute eventually added to first text line while opening
       
  3580 </xsl:text>
       
  3581     <xsl:text>            first.onclick = null;
       
  3582 </xsl:text>
       
  3583     <xsl:text>            first.removeAttribute("dy");
       
  3584 </xsl:text>
       
  3585     <xsl:text>            first.removeAttribute("dx");
       
  3586 </xsl:text>
       
  3587     <xsl:text>            // keep only the first line of text
       
  3588 </xsl:text>
       
  3589     <xsl:text>            for(let span of Array.from(txt.children).slice(1)){
       
  3590 </xsl:text>
       
  3591     <xsl:text>                txt.removeChild(span)
       
  3592 </xsl:text>
       
  3593     <xsl:text>            }
       
  3594 </xsl:text>
       
  3595     <xsl:text>        }
       
  3596 </xsl:text>
       
  3597     <xsl:text>        // Put rectangle element in saved original state
       
  3598 </xsl:text>
       
  3599     <xsl:text>        reset_box(){
       
  3600 </xsl:text>
       
  3601     <xsl:text>            let m = this.box_bbox;
       
  3602 </xsl:text>
       
  3603     <xsl:text>            let b = this.box_elt;
       
  3604 </xsl:text>
       
  3605     <xsl:text>            b.x.baseVal.value = m.x;
       
  3606 </xsl:text>
       
  3607     <xsl:text>            b.y.baseVal.value = m.y;
       
  3608 </xsl:text>
       
  3609     <xsl:text>            b.width.baseVal.value = m.width;
       
  3610 </xsl:text>
       
  3611     <xsl:text>            b.height.baseVal.value = m.height;
       
  3612 </xsl:text>
  3688 </xsl:text>
  3613     <xsl:text>        }
  3689     <xsl:text>        }
  3614 </xsl:text>
  3690 </xsl:text>
  3615     <xsl:text>        // Use margin and text size to compute box size
  3691     <xsl:text>        // Use margin and text size to compute box size
  3616 </xsl:text>
  3692 </xsl:text>