User:Yair rand/SWSelectBox.js

From Wikimedia Incubator

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
// SignWriting form element replacements
// Note: This script is only meant to be used in situations where the writing-mode is properly set to vertical.

mw.loader.using(["jquery.ui","mediawiki.ui.button"], function(){ $( document ).ready( function( $ ) {
  //$("select").replaceWith("<select><option>M538x518S15a21515x483S15a07463x482S15a01466x483S2a20c493x490</option><option>M521x543S19220500x474S1f720495x498S11920494x517S2a20c479x457</option><option>M511x538S1ce20489x463S14a20490x497S14720491x516</option><option>M515x560S18d20495x440S1f720495x469S11a20500x487S16d20498x521S11502485x545</option><option>M518x566S1f720492x435S14051483x451S11a20497x478S19220497x512S1dc20488x536</option><option>M514x534S18d20488x467S1f720488x497S19a20486x514</option><option>M521x559S19220500x458S2a20c479x441S11520500x480S11920494x513S14a20500x544</option><option>M521x563S19220500x455S2a20c479x438S11520500x477S1dc20491x511S19a20493x543</option><option>M515x534S1f720495x466S11520500x484S1f040486x519</option><option>M516x540S20320498x461S14a20498x480S14051485x495S1fb20498x521</option><option>M509x532S17620493x469S16d20492x489S1fb20494x513</option><option>M511x540S11920490x461S17620495x491S10e20496x510</option><option>M509x537S10120493x464S14a20494x498S16d20492x517</option></select>");

  mw.util.addCSS(".swSelect{ -webkit-writing-mode: vertical-lr; writing-mode: tb-lr; -ms-writing-mode: tb-lr; cursor: default; outline: none; display: inline-block; position: relative; vertical-align: middle; white-space: nowrap; color: #000000; }.swSelectSelected{border:#AAA 1px solid; }.swSelectList{border:#AAA 1px solid; max-width: 600px; overflow-x: scroll !important; overflow-y: hidden; position: absolute; z-index: 1; background-color: #FFF; }.swSelectList>div:hover{background-color: #EEEEEE; }.swSelectList>div:active {background-color: #E3E3E3; }.swSelect div.swSelectedOpt{background-color: #D8DDFF; background-color: Highlight; color: HighlightText; }.swSelect .signwritingtext{cursor: default; border-left-width: 0 !important; }body div.swSelectArrow{float: right; margin: 0; margin-top: -2px; background-color: #EEE; border: 1px solid #AAA; }.swSelectArrow>div{background-image: url(//upload.wikimedia.org/wikipedia/commons/4/41/MediaWiki_Vector_skin_right_arrow.png); background-repeat: no-repeat; background-position: 50% 50%; height: 100%; width: 100%; }.swSelectArrow>div>div{ position: relative; width: 100%; height: 0; cursor: default; }.ui-button .signwritingtext,.mw-ui-button .signwritingtext{cursor: inherit; }.mw-ui-button{border-radius:0 !important;}"); // todo: line breaks, merge with other relevant CSS.
  
  var scrollBarHeight = (function(){
    var testDiv = $("<div>").css("display", "inline-block").appendTo("#content"),
      height = -testDiv.height() + testDiv.css("overflow-x", "scroll").height();
    if( height === 0 ) {
      height = testDiv.height( 100 )[0].clientHeight - testDiv.css("overflow-x", "visible")[ 0 ].offsetHeight; // measure the scroll bar. can't think of a better way to do this...
    }
    testDiv.remove();
    return height;
  })();
  
  $( "select" ).each( function() { // every select needs doing, even if without any SW, so that writing-mode will work
    var $select = $( this ).hide(), $fS, $list, $selected, selectedIndex = $select.prop('selectedIndex'), $optSelected, $arrow, width = 0;
    $select.after( $fS = $( "<div>" ).attr( "tabindex", 0 ).addClass( "swSelect" ).append( $arrow = $("<div>").addClass( "swSelectArrow ui-button").height( Math.abs( scrollBarHeight ) - 1 ).append( $("<div>").append( $("<div>") ) ) ).append( $selected = $( "<div>" ).addClass("swSelectSelected") ).append( $list = $( "<div>" ).addClass( "swSelectList" ) ) )
    $select.find( "option" ).each( function( i ) {
      var $option = $( this ), optiontext = $option.text(), $opt = $( "<div>" ).text( optiontext );

      

      $list.append( $opt.on("click", function( e, fake ){
        $opt.clone().appendTo( $selected.empty() ).css("color", "#000000");
        $select.val( $option.val() ); // update the value of the original select box
        $optSelected && $optSelected.removeClass( "swSelectedOpt" );
        $optSelected = $opt.addClass( "swSelectedOpt" );
        // $arrow.width( $selected.width() );
        if( fake ) { // user didn't actually click the box
          e.preventDefault();
          return false;
        }
      } ));
      

      signwriting_styled( $opt[ 0 ] ); // activate signwriting
      
      if( $opt.width() > width ) { width = $opt.width(); }
      
      if( i == selectedIndex ){ // originally-selected option
        $opt.trigger( "click", true );
      }
      
    });
    
    var sH = $list.height();
    $selected
      .height( sH = sH - ( scrollBarHeight < 0 && scrollBarHeight ) ) // don't shrink as soon as the menu collapses
      .width( width ); // set to the width of the largest item, don't bob in and out when switching
    $list.hide(); //.css( "overflow-x", "auto" ); // absolute-positioned elements don't handle overflow well
    if( scrollBarHeight < 0 ) { // Safari scrollbars shrink the content instead of expanding the box
      $list.height( sH );
    }
    sH -= Math.abs( scrollBarHeight ) - 1;
    $arrow.width( width ).find(">div>div").css({ paddingTop: sH, top: -sH }); // extend the range of :hover-causing elements
    
    var w = false, hidden = true, mousePos = false;
    $fS.on( "focus blur keydown mouseup", function( e, fake ) {
      function updateScroll() {
        // $optSelected[ 0 ].scrollIntoView( false ); // doesn't work well in IE
        var l = $list[ 0 ], o = $optSelected[ 0 ], a = o.offsetLeft - l.scrollLeft, b = 0;
        if( a < 0 || a > ( b = 600 - o.offsetWidth ) ) {
          l.scrollLeft += a - b;
        }
      }
      // console.log( e.which );
      var t = e.type, key = e.which; 
      if( t === "mouseup" && ( mousePos === ( mousePos = false ) || e.target === $list[ 0 ] ) ) {
        return;
      }
      // console.log( t, "| hidden = "+hidden, "| w = "+w,"| fake = "+fake, "| mousePos = "+mousePos );
      // console.log( e.target );
      if( t === "blur" && $( document.activeElement ).closest( ".swSelectList" )[ 0 ] === $list[ 0 ] ) { // for IE
        // console.log("wierd blur");
        $fS.trigger( "focus", 2 ); // refocus it, but don't let the event handler do anything. 
        return;
      }
      if( fake === 2 ){ return; }
      if( t === "keydown" && key !== 13 ) {
        if( key === 37 || key === 39 || key === 36 || key === 35 ) { // left, right, home, end
          $optSelected[ ( { '39' : 'next', '37' : 'prev', '35' : 'nextAll', '36' : 'prevAll' } )[ key ] ]().last().trigger( "click", true );
          
          updateScroll();
          
          e.preventDefault();
        } // other non-enter keys do nothing, so far.
      } else if( 
        //!( e.target === $list[ 0 ] ) && 
        !( ( t === "blur" || t === "keydown" ) && hidden === true ) && // blur and enter key only toggle to hide
        !( t === "focus" && hidden === false ) // focus only toggles to show
      ) { 
        if( !w || t === "blur" || ( t === "focus" && fake != true ) ) { // only blur/realfocus get to interrupt an animation
          w && $list.stop();
          $list.animate({
            "width":"toggle","marginLeft":"toggle","marginRight":"toggle","paddingLeft":"toggle","paddingRight":"toggle"
            }, 150, function(){ w = false; });
          hidden = !hidden;
          updateScroll();
        }
        w = true;
      }
    }).on( "mousedown", function( e ) {
      // console.log("mousedown");
      mousePos = hidden === false;
      $fS.trigger( "focus", true );
      e.preventDefault();
      return false;
    });
    // TODO: relay events from the original select element to the new one, to deal with labels and such.
    // probably something like this:
    // $select.on( "focus blur keydown mouseup mousedown", function( e ) { $fS.trigger( e ) } );
    // also, the original select needs to be counted as existing by the browsers...
    // need to do thorough cross-browser testing
  });
  
  // Submit buttons
  $("input[type='submit']:not(.searchButton)")
    //.val("M546x525S2ff00482x483S16d10492x505S2e502519x502")
    .each(function()
  {
    var $t = $( this ).hide(), $s = $( "<div>" ).text( $t.val() || "Submit" ).attr( {"title" : $t.attr( "title" ), "tabindex" : $t.attr( "tabindex" ) || "0" } );
    $t.after( 
      $s.attr( "class", $t.hasClass( "mw-ui-button" ) ? $t.attr( "class" ) : "mw-ui-button" )
        .on( "click", function(){ $t.trigger( "click" ); } ) );
    signwriting_styled( $s[ 0 ] );
  });
}); });