/* TODO: update action button
 * TODO: commit select pre-enhancement
 * TODO: switch from table wrapper slots to controlbar and use table as-is
 * TODO: commit table-pre-enhancement
 * TODO: update collapsible-tabs to latest code
 */
/* ========================= CARSOUSEL ================================== */
(function( $, undefined ) {

$.widget( "mobile.carousel", $.extend( {

  options: {
    enhanced: false,
    handles: true,
    barrel: null,
    bullets: true,
    bulletsPos: "bottom",
    transition: "slide"
  },

  _create: function () {
    this.refresh( true );
  },

  refresh: function ( create ) {
    var $inputs, $items, i,
      el = this.element,
      o = this.options;

    if ( !o.thumbnails ) {
      if ( !o.enhanced ) {

        // clear barrel on refesh
        if ( !create ) {
          $( "#ui-carousel-barrel-" + this.uuid ).remove();
        }
        this._enhance( el, o );
        el.parent()[ o.bulletsPos === "top" ? "prepend" : "append" ]( this._barrel );
      } else {
        this._barrel = $( "#" + o.barrel );
      }

      $inputs =  this._barrel.find( "input" );
      $items = this._items = this._getItems( "li" );
      this._len = $items.length;
      this._direction = "";

      // set reference on radio buttons
      for (i = 0; i < this._len; i += 1) {
        $inputs.eq( i ).data( "reference", $items.eq( i ) );
      }

      this._on( $inputs, {
        "click": "_change"
      });

      this._on( el, {
        "keydown": "_onKeyPress",
        "swipeleft": function () { this.jump( 1 ); },
        "swiperight": function () { this.jump( -1 ); }
      });
    } else {
      this._enhance( el, o );
    }

    if ( o.handles ) {
      this._on( el.parent().find( "a.ui-carousel-handle" ), {
        "click": function ( event ) {
          this.jump( $( event.target ).is( "ui-carousel-handle-left" ) ? -1 : 1 );
        }
      });
    }
  },

  _onKeyPress: function ( e ) {
    switch (e.keyCode) {
      case $.mobile.keyCode.LEFT: this.jump( -1 ); break;
      case $.mobile.keyCode.RIGHT: this.jump( 1 ); break;
    }
  },

  _change: function ( e ) {
    var el = this.element,
      kids = el.children(),
      current = kids.filter( ".ui-carousel-active" ),
      next = $( e.target ).data( "reference" );

    // click on active
    if ( next.hasClass( "ui-carousel-active" ) ) {
      el.focus();
      return;
    }
    this._direction = kids.index( current ) > kids.index( next ) ? " reverse " : "";
    this._transition( current, next );
    el.focus();
  },

  _getItems: function ( selector ) {
    return this.element.find( selector );
  },

  jump: function ( increment ) {
    var len = this._len,
      go = this._items.index( this._getItems( "li.ui-carousel-active" ) ) + increment;

    // allow rotation
    switch ( true ) {
      case go < 0: go = len - 1; break;
      case go > len - 1: go = 0; break;
    }
    this._direction = increment > 0 ? "" : " reverse ";

    // provide hook to modify slide
    if ( this._trigger( "beforejump" ) === false ) {
      return false;
    }

    this._barrel.find( "input" ).eq( go ).trigger( "click" ).checkboxradio( "refresh" );
  },

  _transition: function ( currentActive, nextActive ) {
    var transition = $.mobile._maybeDegradeTransition( this.options.transition ),
      bound = transition + this._direction;

    currentActive.addClass( bound + " out " );
    nextActive
      .addClass( bound + " in ui-carousel-active" )
      .animationComplete( function () {
        currentActive.removeClass( bound + " ui-carousel-active out" );
        nextActive.removeClass( bound + " in ");
      });
  }
}, $.mobile.behaviors.addFirstLastClasses ) );

})( jQuery );

(function( $, undefined ) {

$.widget( "mobile.carousel", $.mobile.carousel, {
  options: {
    corners: false,
    captions: false,
    captionpos: "top",
    captiontheme: "a",
    heading: "h1,h2,h3,h4,h5,h6,legend",
    inset: false,
    shadow: false,
    thumbnails: false
  },

  _addButton: function ( inset, left ) {
    var arr = left ? ["Left", "left", "l"] : ["Right", "right", "r"];

    return $( '<a class="ui-carousel-handle ui-carousel-handle-' + arr[1] +
      ' ui-btn ui-btn-icon-notext ui-corner-all ui-icon-carat-' + arr[2] +
          ' ui-shadow ' + ( inset ? 'ui-carousel-handle-inset' : '' ) +
          '" href="#">' + arr[0] + '</a>');
  },

  _enhance: function ( el, o ) {
    var i, item, radio, label, barrel, containsLink, $selector,
      id = this.uuid,
      items = el.children(),
      len = items.length,
      carouselClasses = "ui-carousel ",
      fragment = document.createDocumentFragment(),
      prefix = 'radio-' + id,
      emptyString = "";

    // handlers
    if ( o.handles && len > 0 ) {
      carouselClasses += " ui-carousel-handles";
      el.after( this._addButton( o.inset ) )
        .after( this._addButton( o.inset, true ) );
    }

    // thumbnails
    if ( o.thumbnails ) {
      carouselClasses += " ui-carousel-thumbnails";
    } else {
      for ( i = 0; i < len; i += 1 ) {
        item = items[i];

        // captions
        if ( o.captions ) {
          containsLink = item.children[ 0 ].tagName === "A";
          $selector = containsLink ? $( item ).find( "a" )  : $( item );

          $selector
            .addClass( "ui-carousel-selector" )
            .children()
            .not( "img" )
            .wrap( "<p class='ui-carousel-captions-content ui-bar-" +
                o.captiontheme + " ui-carousel-captions-" +
                    o.captionpos + "'></p>")
            .parent()
            .prependTo( $selector )
              .find( o.heading )
              .addClass( "ui-carousel-captions-heading" );
        }

        // radios bullets
        if ( o.bullets ) {
          label = $( "<label data-" + $.mobile.ns + "iconpos='notext'></label>" );
          radio = $( "<input type='radio' name='" + prefix + "' id='" +
              prefix + "-" + i + "' value='" + i + "'/>" );

          if ( i === 0 ) {
            radio.attr( "checked", true );
            $( item ).addClass( "ui-carousel-active" );
          }
          label.append( radio );
          fragment.appendChild( label[0] );
        }
      }
    }

    carouselClasses += o.captions ? " ui-carousel-captions" : emptyString;
    carouselClasses += o.inset ? " ui-carousel-inset" : emptyString;

    if ( !!o.inset ) {
      carouselClasses += o.corners ? " ui-corner-all" : emptyString;
      carouselClasses += o.shadow ? " ui-shadow" : emptyString;
    }

    if ( o.bullets && !o.thumbnails ) {
      carouselClasses += " ui-carousel-bullets";
      barrel = $( "<div id='ui-carousel-barrel-" + id + "' class='" +
          "ui-carousel-controls ui-carousel-controls-" + o.bulletsPos +
              "'></div>");
      this._barrel = barrel.append( fragment ).enhanceWithin();
    }
    // setting tabindex -1 allows to focus programmatically
    el.addClass( carouselClasses ).attr("tabindex", -1);
  }
});

})( jQuery );
/* ========================= ACTION BUTTON EXTENSION ==================== */
(function () {

  $.widget("mobile.textinput", $.mobile.textinput, {

    options: {
      actionBtn: false,
      actionBtnText: "Search",
      actionBtnIcon: "search",
      actionBtnI18n: null,
      actionBtnPop: false,
      actionBtnPopId: null,
      actionBtnClass: null
    },

    _create: function () {
      this._super();
      if (!!this.options.actionBtn || this.isSearch) {
        this._addActionBtn();
      }
    },

    actionButton: function () {
      var o = this.options;
      return $("<a href='#" + (o.actionBtnPop ?
        (o.actionBtnPopId +
        "' data-rel='popup' data-position-to='window' " +
        "data-transition='pop'") : "'") +
        " tabindex='-1' class='ui-input-action ui-btn ui-icon-" +
        o.actionBtnIcon + " ui-btn-icon-notext ui-corner-all" + " " + o.actionBtnClass +
        "' title='" + o.actionBtnText + "'>" +
        o.actionBtnText + "</a>");
    },

    _addActionBtn: function () {

      if (!this.options.enhanced) {
        this._enhanceAction();
      }

      $.extend(this, {
        _actionBtn: this.widget().find("a.ui-input-action")
      });

    },

    _enhanceAction: function () {
      this.actionButton().appendTo(this.widget());
      this.widget().addClass(
        "ui-input-has-action ui-input-search-no-pseudo"
      );
    },

    _setOptions: function (options) {
      this._super(options);

      if (options.actionBtn !== undefined &&
          !this.element.is("textarea, :jqmData(type='range')")) {
        if (options.actionBtn) {
          this._addActionBtn();
        } else {
          this._destroyAction();
        }
      }

      if (options.clearBtnText !== undefined &&
          this._actionBtn !== undefined) {
        this._actionBtn.text(options.clearBtnText);
      }
    },

    _destroyAction: function () {
      this.element.removeClass("ui-input-has-clear");
      this._actionBtn.remove();
    },

    _destroy: function () {
      this._super();
      this._destroyAction();
    }

  });


}());


/* ============================= TABLE ====================================*/
(function( $, undefined ) {

$.widget( "mobile.table", {
  options: {
    classes: {
      table: "ui-table"
    },
    enhanced: false
  },

  _create: function() {
    if ( !this.options.enhanced ) {
      this.element.addClass( this.options.classes.table );
    }

    // extend here, assign on refresh > _setHeaders
    $.extend( this, {

      // Expose headers and allHeaders properties on the widget
      // headers references the THs within the first TR in the table
      headers: undefined,

      // allHeaders references headers, plus all THs in the thead, which may
      // include several rows, or not
      allHeaders: undefined
    });

    this._refresh( true );
  },

  _setHeaders: function() {
    var trs = this.element.find( "thead tr" );

    this.headers = this.element.find( "tr:eq(0)" ).children();
    this.allHeaders = this.headers.add( trs.children() );
  },

  refresh: function() {
    this._refresh();
  },

  rebuild: $.noop,

  _refresh: function( /* create */ ) {
    var table = this.element,
      trs = table.find( "thead tr" );

    // updating headers on refresh (fixes #5880)
    this._setHeaders();

    // Iterate over the trs
    trs.each( function() {
      var columnCount = 0;

      // Iterate over the children of the tr
      $( this ).children().each( function() {
        var span = parseInt( $.mobile.getAttribute( this, "colspan" ), 10 ),
          selector = ":nth-child(" + ( columnCount + 1 ) + ")",
          j;

        this.setAttribute( "data-" + $.mobile.ns + "colstart", columnCount + 1 );

        if ( span ) {
          for( j = 0; j < span - 1; j++ ) {
            columnCount++;
            selector += ", :nth-child(" + ( columnCount + 1 ) + ")";
          }
        }

        // Store "cells" data on header as a reference to all cells in the
        // same column as this TH
        $( this ).jqmData( "cells", table.find( "tr" ).not( trs.eq( 0 ) ).not( this ).children( selector ) );

        columnCount++;
      });
    });
  }
});

})( jQuery );


(function( $, undefined ) {

$.widget( "mobile.table", $.mobile.table, {
  options: {
    usePop: true,
    mode: "columntoggle",
    columnBtnShow: true,
    columnBtnTheme: null,
    columnPopupTheme: null,
    columnBtnText: "Columns...",
    columnBtnIcon: "Search",
    wrap: null,
    embedded: null,
    topGrid: null,
    bottomGrid: null,
    classes: $.extend( $.mobile.table.prototype.options.classes, {
      popup: "ui-table-columntoggle-popup",
      columnBtn: "ui-table-columntoggle-btn",
      priorityPrefix: "ui-table-priority-",
      columnToggleTable: "ui-table-columntoggle"
    })
  },

  _create: function() {
    var o = this.options;

    this._super();

    if( o.mode !== "columntoggle" ) {
      return;
    }
    $.extend( this, {
      _menu: null,
      _menuButton: null
    });

    if( o.usePop) {
      if( o.enhanced ) {
        this._menu = this.document.find( this._id() + "-popup" ).children().first();
      } else {
        this._menu = this._enhanceColToggle();
        this._setTableClasses();
      }

      this._setupEvents();

      this._setToggleState();
    } else {
      this._setTableClasses();

      // add responsive CSS
      this._addResponsiveClassAndLabel();
    }
    if (o.wrap) {
      this._wrapTable();
    }
  },

  _id: function() {
    return ( this.element.attr( "id" ) || ( this.widgetName + this.uuid ) );
  },

  _setTableClasses: function () {
    this.element.addClass( this.options.classes.columnToggleTable );
  },

  _setupEvents: function() {
    //NOTE: inputs are bound in bindToggles,
    // so it can be called on refresh, too

    // update column toggles on resize
    this._on( $.mobile.window, {
      throttledresize: "_setToggleState"
    });
  },

  _bindToggles: function( menu ) {
    var inputs = menu.find( "input" );

    this._on( inputs, {
      change: "_menuInputChange"
    });
  },

  _addResponsiveClassAndLabel: function ( keep ) {
    var o = this.options;

    this.headers.not( "td" ).each( function() {
      var header = $( this ),
        priority = $.mobile.getAttribute( this, "priority", true ),
        cells = header.add( header.jqmData( "cells" ) );

      if( priority ) {
        cells.addClass( o.classes.priorityPrefix + priority );
        if ( !keep && o.usePop ) {
          $("<label><input type='checkbox' checked />" + header.text() + "</label>" )
            .appendTo( menu )
            .children( 0 )
            .jqmData( "cells", cells )
            .checkboxradio( {
              theme: o.columnPopupTheme
            });
        }
      }
    });
  },

  _addToggles: function( menu, keep ) {
    var opts = this.options;

    // allow update of menu on refresh (fixes #5880)
    if ( !keep ) {
      menu.empty();
    }

    this._addResponsiveClassAndLabel(keep);

    // set bindings here
    if ( !keep ) {
      this._bindToggles( menu );
    }
  },

  _menuInputChange: function( evt ) {
    var input = $( evt.target ),
      checked = input[ 0 ].checked;

    input.jqmData( "cells" )
      .toggleClass( "ui-table-cell-hidden", !checked )
      .toggleClass( "ui-table-cell-visible", checked );

    if ( input[ 0 ].getAttribute( "locked" ) ) {
      input.removeAttr( "locked" );

      this._unlockCells( input.jqmData( "cells" ) );
    } else {
      input.attr( "locked", true );
    }
  },

  _unlockCells: function( cells ) {
    // allow hide/show via CSS only = remove all toggle-locks
    cells.removeClass( "ui-table-cell-hidden ui-table-cell-visible");
  },

  _toLetter: function (n) {
    return n.toString(26).replace(/./g, function( c ) {
      return String.fromCharCode( c.charCodeAt(0) + ( isNaN( +c ) ? 10 : 49 ));
    });
  },

  _generateWrapper: function ( grids ) {
    return $("<div class='ui-table-wrapper ui-table-wrapper-inset " +
        (this.options.embedded ? "" : "ui-corner-all") + "'>")
        .append(
          $.map(new Array( grids ), function(){
            return $("<div/>");
          })
        )
        .grid({ grid: grids > 1 ? this._toLetter(grids-2) : "solo" });
  },

  _enhanceColToggle: function() {
    var id, popup, menu,
      table = this.element,
      opts = this.options,
      ns = $.mobile.ns,
      fragment = this.document[ 0 ].createDocumentFragment();

    id = this._id() + "-popup";
    this._menuButton = $( "<a role='button' href='#" + id + "' " +
      "class='" + opts.classes.columnBtn + " ui-btn ui-btn-" + ( opts.columnBtnTheme || "a" ) + " ui-corner-all ui-shadow ui-mini ui-icon ui-btn-icon-left ui-icon-"+ opts.columnBtnIcon +"' " +
      "data-" + ns + "rel='popup' " +
      "data-" + ns + "icon='" + opts.columnBtnIcon + "' " +
      "data-" + ns + "mini='true'>" + opts.columnBtnText + "</a>" );
    popup = $( "<div data-" + ns + "role='popup' data-" + ns + "role='fieldcontain' class='" + opts.classes.popup + "' id='" + id + "'></div>" );
    menu = $( "<fieldset data-" + ns + "role='controlgroup'></fieldset>" );

    // set extension here, send "false" to trigger build/rebuild
    this._addToggles( menu, false );

    menu.appendTo( popup );

    fragment.appendChild( popup[ 0 ] );
    if (opts.columnBtnShow) {
      fragment.appendChild( this._menuButton[ 0 ] );
    }
    table.before( fragment );

    popup.popup().enhanceWithin();

    // always return the menu
    return menu;
  },


  // wrappers
  // TODO: not nice, should be possible to wrap top with 3 elements
  // and then where do you put the toggle button
  // TODO: also not nice, because no way to latch on the filter
  // TODO: also not nice, because data-slot-id is not used.
  _wrapTable: function () {
    var front, back, slots, fill, i, item,
      opts = this.options,
      table = this.element;

    fill = table.parent().find( "div[data-slot]" );

    if (opts.wrap === "both") {
      front = this._generateWrapper( opts.topGrid ).addClass("ui-table-wrapper-top");
      back = this._generateWrapper( opts.bottomGrid ).addClass("ui-table-wrapper-bottom");

      if (fill) {
        slots = front.add( back ).children("div");
        for (i = 0; i < fill.length; i += 1) {
          item = parseFloat(fill.eq(i).jqmData("slot-id"))-1;
          fill.eq(i)
            .find("label")
            .addClass("ui-hidden-accessible")
            .end()
          .appendTo(
            slots.eq( opts.usePop ? (item || (i === 2 ? 3 : i)) : item )
          );
        }
      }
      // move toggle button
      if (opts.columnBtnShow && this._menuButton) {
        front.children("div").last().append( this._menuButton[ 0 ] );
      }

      // not possible in one-go...
      table.before(front);
      table.after(back);

    } else {
      front = this._generateWrapper( opts.topGrid || opts.bottomGrid || 3).addClass("ui-table-wrapper-top");

      if (fill.length) {
        slots = front.children("div");

        for (i = 0; i < fill.length; i += 1) {
          fill.eq(i)
            .find("label")
            .addClass("ui-hidden-accessible")
            .end()
          // skip slot 2
          .appendTo( opts.usePop ? (slots.eq( i === 2 ? 3 : i )) : i );
        }
      }
      if (opts.columnBtnShow) {
        front.children("div").last().append( this._menuButton );
      }

      // not possible in one-go...
      table[ opts.wrap === "top" ? "before" : "after"](front)
    }
  },

  rebuild: function() {
    this._super();

    if ( this.options.mode === "columntoggle" ) {
      // NOTE: rebuild passes "false", while refresh passes "undefined"
      // both refresh the table, but inside addToggles, !false will be true,
      // so a rebuild call can be indentified
      this._refresh( false );
    }
  },

  _refresh: function( create ) {
    this._super( create );

    if ( !create && this.options.mode === "columntoggle" && this.options.usePop ) {
      // columns not being replaced must be cleared from input toggle-locks
      this._unlockCells( this.allHeaders );

      // update columntoggles and cells
      this._addToggles( this._menu, create );

      // check/uncheck
      this._setToggleState();
    }
  },

  _setToggleState: function() {
    this._menu.find( "input" ).each( function() {
      var checkbox = $( this );

      this.checked = checkbox.jqmData( "cells" ).eq( 0 ).css( "display" ) === "table-cell";
      checkbox.checkboxradio( "refresh" );
    });
  },

  _destroy: function() {
    this._super();
  }
});

})( jQuery );

(function( $, undefined ) {

$.widget( "mobile.table", $.mobile.table, {
  options: {
    mode: "reflow",
    classes: $.extend( $.mobile.table.prototype.options.classes, {
      reflowTable: "ui-table-reflow",
      cellLabels: "ui-table-cell-label"
    })
  },

  _create: function() {
    this._super();

    // If it's not reflow mode, return here.
    if( this.options.mode !== "reflow" ) {
      return;
    }

    if( !this.options.enhanced ) {
      this.element.addClass( this.options.classes.reflowTable );

      this._updateReflow();
    }
  },

  rebuild: function() {
    this._super();

    if ( this.options.mode === "reflow" ) {
      this._refresh( false );
    }
  },

  _refresh: function( create ) {
    this._super( create );
    if ( !create && this.options.mode === "reflow" ) {
      this._updateReflow( );
    }
  },

  _updateReflow: function() {
    var table = this,
      opts = this.options;

    // get headers in reverse order so that top-level headers are appended last
    $( table.allHeaders.get().reverse() ).each( function() {
      var cells = $( this ).jqmData( "cells" ),
        colstart = $.mobile.getAttribute( this, "colstart", true ),
        hierarchyClass = cells.not( this ).filter( "thead th" ).length && " ui-table-cell-label-top",
        text = $( this ).text(),
        iteration, filter;

        if ( text !== ""  ) {

          if( hierarchyClass ) {
            iteration = parseInt( this.getAttribute( "colspan" ), 10 );
            filter = "";

            if ( iteration ){
              filter = "td:nth-child("+ iteration +"n + " + ( colstart ) +")";
            }

            table._addLabels( cells.filter( filter ), opts.classes.cellLabels + hierarchyClass, text );
          } else {
            table._addLabels( cells, opts.classes.cellLabels, text );
          }

        }
    });
  },

  _addLabels: function( cells, label, text ) {
    // .not fixes #6006
    cells.not( ":has(b." + label + ")" ).prepend( "<b class='" + label + "'>" + text + "</b>"  );
  }
});

})( jQuery );
/* ====================================== COLLAPSIBLE =====================*/
(function( $, undefined ) {

var rInitialLetter = /([A-Z])/g;

$.widget( "mobile.collapsible", {
  options: {
    enhanced: false,
    expandCueText: null,
    collapseCueText: null,
    collapsed: true,
    heading: "h1,h2,h3,h4,h5,h6,legend",
    icon: null,
    collapsedIcon: null,
    expandedIcon: null,
    iconpos: null,
    theme: null,
    contentTheme: null,
    inset: null,
    corners: null,
    mini: null
  },

  _create: function() {
    var elem = this.element,
      ui = {
        accordion: elem
          .closest( ":jqmData(role='collapsible-set')" +
            ( $.mobile.collapsibleset ? ", :mobile-collapsibleset" : "" ) )
          .addClass( "ui-collapsible-set" )
      };

    $.extend( this, {
      _ui: ui
    });

    if ( this.options.enhanced ) {
      ui.heading = $( ".ui-collapsible-heading", this.element[ 0 ] );
      ui.content = ui.heading.next();
      ui.anchor = $( "a", ui.heading[ 0 ] ).first();
      ui.status = ui.anchor.children( ".ui-collapsible-heading-status" );
    } else {
      this._enhance( elem, ui );
    }

    this._on( ui.heading, {
      "tap": function() {
        ui.heading.find( "a" ).first().addClass( $.mobile.activeBtnClass );
      },

      "click": function( event ) {
        this._handleExpandCollapse( !ui.heading.hasClass( "ui-collapsible-heading-collapsed" ) );
        event.preventDefault();
        event.stopPropagation();
      }
    });
  },

  // Adjust the keys inside options for inherited values
  _getOptions: function( options ) {
    var key,
      accordion = this._ui.accordion,
      accordionWidget = this._ui.accordionWidget;

    // Copy options
    options = $.extend( {}, options );

    if ( accordion.length && !accordionWidget ) {
      this._ui.accordionWidget =
      accordionWidget = accordion.data( "mobile-collapsibleset" );
    }

    for ( key in options ) {

      // Retrieve the option value first from the options object passed in and, if
      // null, from the parent accordion or, if that's null too, or if there's no
      // parent accordion, then from the defaults.
      options[ key ] =
        ( options[ key ] != null ) ? options[ key ] :
        ( accordionWidget ) ? accordionWidget.options[ key ] :
        accordion.length ? $.mobile.getAttribute( accordion[ 0 ],
          key.replace( rInitialLetter, "-$1" ).toLowerCase(), true ):
        null;

      if ( null == options[ key ] ) {
        options[ key ] = $.mobile.collapsible.defaults[ key ];
      }
    }

    return options;
  },

  _themeClassFromOption: function( prefix, value ) {
    return ( value ? ( value === "none" ? "" : prefix + value ) : "" );
  },

  _enhance: function( elem, ui ) {
    var iconclass,
      opts = this._getOptions( this.options ),
      contentThemeClass = this._themeClassFromOption( "ui-body-", opts.contentTheme );

    elem.addClass( "ui-collapsible " +
      ( opts.inset ? "ui-collapsible-inset " : "" ) +
      ( opts.inset && opts.corners ? "ui-corner-all " : "" ) +
      ( contentThemeClass ? "ui-collapsible-themed-content " : "" ) );
    ui.originalHeading = elem.children( this.options.heading ).first(),
    ui.content = elem
      .wrapInner( "<div " +
        "class='ui-collapsible-content " +
        contentThemeClass + "'></div>" )
      .children( ".ui-collapsible-content" ),
    ui.heading = ui.originalHeading;

    // Replace collapsibleHeading if it's a legend
    if ( ui.heading.is( "legend" ) ) {
      ui.heading = $( "<div role='heading'>"+ ui.heading.html() +"</div>" );
      ui.placeholder = $( "<div><!-- placeholder for legend --></div>" ).insertBefore( ui.originalHeading );
      ui.originalHeading.remove();
    }

    iconclass = ( opts.icon === false ? "ui-collapsible-hide-icon " : "" ) +
      ( opts.collapsed ? ( opts.collapsedIcon ? "ui-icon-" + opts.collapsedIcon : "" ) :
      ( opts.expandedIcon ? "ui-icon-" + opts.expandedIcon : "" ));

    ui.status = $( "<span class='ui-collapsible-heading-status'></span>" );
    ui.anchor = ui.heading
      .detach()
      //modify markup & attributes
      .addClass( "ui-collapsible-heading" )
      .append( ui.status )
      .contents()
      .filter(function() {
        return this.nodeType === 3;
      })
      .wrap( "<a href='#' class='ui-collapsible-heading-toggle'></a>" )
      .parents(".ui-collapsible-heading")
      .find( "a" )
        .first()
        .addClass( "ui-btn " +
          ( iconclass ? iconclass + " " : "" ) +
          ( iconclass ? ( "ui-btn-icon-" +
            ( opts.iconpos === "right" ? "right" : "left" ) ) +
            " " : "" ) +
          this._themeClassFromOption( "ui-btn-", opts.theme ) + " " +
          ( opts.mini ? "ui-mini " : "" ) );

    //drop heading in before content
    ui.heading.insertBefore( ui.content );

    this._handleExpandCollapse( this.options.collapsed );

    return ui;
  },

  refresh: function() {
    var key, options = {};

    for ( key in $.mobile.collapsible.defaults ) {
      options[ key ] = this.options[ key ];
    }

    this._setOptions( options );
  },

  _setOptions: function( options ) {
    var isCollapsed, newTheme, oldTheme,
      elem = this.element,
      currentOpts = this.options,
      ui = this._ui,
      anchor = ui.anchor,
      status = ui.status,
      opts = this._getOptions( options );

    // First and foremost we need to make sure the collapsible is in the proper
    // state, in case somebody decided to change the collapsed option at the
    // same time as another option
    if ( options.collapsed !== undefined ) {
      this._handleExpandCollapse( options.collapsed );
    }

    isCollapsed = elem.hasClass( "ui-collapsible-collapsed" );

    // Only options referring to the current state need to be applied right away
    // It is enough to store options covering the alternate in this.options.
    if ( isCollapsed ) {
      if ( opts.expandCueText !== undefined ) {
        status.text( opts.expandCueText );
      }
      if ( opts.collapsedIcon !== undefined ) {
        if ( currentOpts.collapsedIcon ) {
          anchor.removeClass( "ui-icon-" + currentOpts.collapsedIcon );
        }
        if ( opts.collapsedIcon ) {
          anchor.addClass( "ui-icon-" + opts.collapsedIcon );
        }
      }
    } else {
      if ( opts.collapseCueText !== undefined ) {
        status.text( opts.collapseCueText );
      }
      if ( opts.expandedIcon !== undefined ) {
        if ( currentOpts.expandedIcon ) {
          anchor.removeClass( "ui-icon-" + currentOpts.expandedIcon );
        }
        if ( opts.expandedIcon ) {
          anchor.addClass( "ui-icon-" + opts.expandedIcon );
        }
      }
    }

    if ( opts.iconpos !== undefined ) {
      anchor.removeClass( "ui-btn-icon-" + ( currentOpts.iconPos === "right" ? "right" : "left" ) );
      anchor.addClass( "ui-btn-icon-" + ( opts.iconPos === "right" ? "right" : "left" ) );
    }

    if ( opts.theme !== undefined ) {
      oldTheme = this._themeClassFromOption( "ui-btn-", currentOpts.theme );
      newTheme = this._themeClassFromOption( "ui-btn-", opts.theme );
      anchor.removeClass( oldTheme ).addClass( newTheme );
    }

    if ( opts.contentTheme !== undefined ) {
      oldTheme = this._themeClassFromOption( "ui-body-", currentOpts.theme );
      newTheme = this._themeClassFromOption( "ui-body-", opts.theme );
      ui.content.removeClass( oldTheme ).addClass( newTheme );
    }

    // It is important to apply "inset" before corners, because the new value of
    // "inset" can affect whether we display corners or not. Note that setting
    // the "inset" option to false does not cause a change in the value of
    // this.options.corners - it merely causes a change in the interpretation of
    // the value of the "corners" option.
    if ( opts.inset !== undefined ) {
      elem.toggleClass( "ui-collapsible-inset", opts.inset );
      currentOpts.inset = opts.inset;
      if ( !opts.inset ) {
        opts.corners = false;
      }
    }

    if ( opts.corners !== undefined ) {
      elem.toggleClass( "ui-corner-all", currentOpts.inset && opts.corners );
    }

    if ( opts.mini !== undefined ) {
      anchor.toggleClass( "ui-mini", opts.mini );
    }

    this._super( options );
  },

  _handleExpandCollapse: function( isCollapse ) {
    var opts = this._getOptions( this.options ),
      ui = this._ui;

    if ( !this._trigger( isCollapse ? "beforecollapse" : "beforeexpand" ) ) {
      return;
    }
    ui.status.text( isCollapse ? opts.expandCueText : opts.collapseCueText );
    ui.heading
      .toggleClass( "ui-collapsible-heading-collapsed", isCollapse )
      .find( "a" ).first()
      .toggleClass( "ui-icon-" + opts.expandedIcon, !isCollapse )

      // logic or cause same icon for expanded/collapsed state would remove the ui-icon-class
      .toggleClass( "ui-icon-" + opts.collapsedIcon, ( isCollapse || opts.expandedIcon === opts.collapsedIcon ) )
      .removeClass( $.mobile.activeBtnClass );

    this.element.toggleClass( "ui-collapsible-collapsed", isCollapse );
    ui.content
      .toggleClass( "ui-collapsible-content-collapsed", isCollapse )
      .attr( "aria-hidden", isCollapse )
      .trigger( "updatelayout" );
    this.options.collapsed = isCollapse;
    this._trigger( isCollapse ? "collapse" : "expand" );
  },

  expand: function() {
    this._handleExpandCollapse( false );
  },

  collapse: function() {
    this._handleExpandCollapse( true );
  },

  _destroy: function() {
    var ui = this._ui,
      opts = this.options;

    if ( opts.enhanced ) {
      return;
    }

    if ( ui.placeholder ) {
      ui.originalHeading.insertBefore( ui.placeholder );
      ui.placeholder.remove();
      ui.heading.remove();
    } else {
      ui.status.remove();
      ui.heading
        .removeClass( "ui-collapsible-heading ui-collapsible-heading-collapsed" )
        .children()
          .contents()
            .unwrap();
    }

    ui.anchor.contents().unwrap();
    ui.content.contents().unwrap();
    this.element
      .removeClass( "ui-collapsible ui-collapsible-collapsed " +
        "ui-collapsible-themed-content ui-collapsible-inset ui-corner-all" );
  }
});

// Defaults to be used by all instances of collapsible if per-instance values
// are unset or if nothing is specified by way of inheritance from an accordion.
// Note that this hash does not contain options "collapsed" or "heading",
// because those are not inheritable.
$.mobile.collapsible.defaults = {
  expandCueText: " click to expand contents",
  collapseCueText: " click to collapse contents",
  collapsedIcon: "plus",
  expandedIcon: "minus",
  iconpos: "left",
  inset: true,
  corners: true,
  mini: false
};

})( jQuery );
/* ============================= before expand/collapse ================== */
/*
$.widget( "mobile.collapsible", $.mobile.collapsible, {
  _handleExpandCollapse: function( isCollapse ) {
    if ( this._trigger( "collapsiblebefore" +
      ( isCollapse ? "collapse" : "expand" ) ) ) {

      this._superApply( arguments );
    }
  }
});
*/
/* ============================= COLLAPSIBLE_SET =========================*/
(function( $, undefined ) {

var childCollapsiblesSelector = ":mobile-collapsible, " + $.mobile.collapsible.initSelector;

$.widget( "mobile.collapsibleset", $.extend( {

  // The initSelector is deprecated as of 1.4.0. In 1.5.0 we will use
  // :jqmData(role='collapsibleset') which will allow us to get rid of the line
  // below altogether, because the autoinit will generate such an initSelector
  initSelector: ":jqmData(role='collapsible-set'),:jqmData(role='collapsibleset')",

  options: $.extend( {
    enhanced: false,
    type: null
  }, $.mobile.collapsible.defaults ),

  _isSetAndClose: function ( parent, allClosed ) {

    if (allClosed) {
      return parent.children().length === parent.children(".ui-collapsible-collapsed").length;
    }
    return parent.is( ":mobile-collapsibleset, :jqmData(role='collapsible-set')" );
  },

  _handleCollapsibleExpand: function( event ) {
    var closestCollapsible = $( event.target ).closest( ".ui-collapsible" ),
      parentElement = closestCollapsible.parent();

    if ( this._isSetAndClose( parentElement ) ) {
      closestCollapsible
        .siblings( ".ui-collapsible:not(.ui-collapsible-collapsed)" )
        .collapsible( "collapse" );

    parentElement.toggleClass("ui-collapsible-set-all-closed", this._isSetAndClose( parentElement, true) );
    }
  },

  _handleCollapsibleCollapse: function ( event ) {
    var closestCollapsible = $( event.target ).closest( ".ui-collapsible" ),
      parentElement = closestCollapsible.parent();

    if ( this._isSetAndClose( parentElement ) ) {
      parentElement.toggleClass("ui-collapsible-set-all-closed", this._isSetAndClose( parentElement, true) );
    }
  },

  _create: function() {
    var elem = this.element,
      opts = this.options;

    $.extend( this, {
      _classes: ""
    });

    if ( !opts.enhanced ) {
      elem.addClass( "ui-collapsible-set " +
        this._themeClassFromOption( "ui-group-theme-", opts.theme ) + " " +
        ( opts.corners && opts.inset ? "ui-corner-all " : "" ) );
      // tabs
      if (opts.type) {
        elem.addClass( "ui-collapsible-tabs" );
      }
      this.element.find( $.mobile.collapsible.initSelector ).collapsible();
    }

    this._on( elem, {
      collapsibleexpand: "_handleCollapsibleExpand",
      collapsiblecollapse: "_handleCollapsibleCollapse"
    } );
  },

  _themeClassFromOption: function( prefix, value ) {
    return ( value ? ( value === "none" ? "" : prefix + value ) : "" );
  },

  _init: function() {
    this._refresh( true );

    // Because the corners are handled by the collapsible itself and the default state is collapsed
    // That was causing https://github.com/jquery/jquery-mobile/issues/4116
    this.element
      .children( childCollapsiblesSelector )
      .filter( ":jqmData(collapsed='false')" )
      .collapsible( "expand" );
  },

  _setOptions: function( options ) {
    var ret,
      elem = this.element,
      themeClass = this._themeClassFromOption( "ui-group-theme-", options.theme );

    if ( themeClass ) {
      elem
        .removeClass( this._themeClassFromOption( "ui-group-theme-", this.options.theme ) )
        .addClass( themeClass );
    }

    if ( options.corners !== undefined ) {
      elem.toggleClass( "ui-corner-all", options.corners );
    }

    ret = this._super( options );
    this.element.children( ":mobile-collapsible" ).collapsible( "refresh" );
    return ret;
  },

  _destroy: function() {
    var el = this.element;

    this._removeFirstLastClasses( el.children( childCollapsiblesSelector ) );
    el
      .removeClass( "ui-collapsible-set ui-corner-all " +
        this._themeClassFromOption( "ui-group-theme", this.options.theme ) )
      .children( ":mobile-collapsible" )
      .collapsible( "destroy" );
  },

  _refresh: function( create ) {
    var collapsiblesInSet = this.element.children( childCollapsiblesSelector );

    this.element.find( $.mobile.collapsible.initSelector ).not( ".ui-collapsible" ).collapsible();

    this._addFirstLastClasses( collapsiblesInSet, this._getVisibles( collapsiblesInSet, create ), create );
  },

  refresh: function() {
    this._refresh( false );
  }
}, $.mobile.behaviors.addFirstLastClasses ) );

})( jQuery );

