<commit_before>/** Markers **/
/**
 * Formats the marker labels.
 * @param {Object} obj - Marker value Object {x:..,y:..}
 * @return {String} Formatted marker string
 */
(function () {

Flotr.defaultMarkerFormatter = function(obj){
  return (Math.round(obj.y*100)/100)+'';
};

Flotr.addType('markers', {
  options: {
    show: false,           // => setting to true will show markers, false will hide
    lineWidth: 1,          // => line width of the rectangle around the marker
    color: '#000000',      // => text color
    fill: false,           // => fill or not the marekers' rectangles
    fillColor: "#FFFFFF",  // => fill color
    fillOpacity: 0.4,      // => fill opacity
    stroke: false,         // => draw the rectangle around the markers
    position: 'ct',        // => the markers position (vertical align: b, m, t, horizontal align: l, c, r)
    labelFormatter: Flotr.defaultMarkerFormatter,
    fontSize: Flotr.defaultOptions.fontSize,
    stacked: false,        // => true if markers should be stacked
    stackingType: 'b',     // => define staching behavior, (b- bars like, a - area like) (see Issue 125 for details)
    horizontal: false      // => true if markers should be horizontal (For now only in a case on horizontal stacked bars, stacks should be calculated horizontaly)
  },

  // TODO test stacked markers.
  stack : {
      positive : [],
      negative : [],
      values : []
  },

  draw : function (options) {

    var
      data            = options.data,
      context         = options.context,
      stack           = options.stacked ? options.stack : false,
      stackType       = options.stackingType,
      stackOffsetNeg,
      stackOffsetPos,
      stackOffset,
      i, x, y, label;

    context.save();
    context.lineJoin = 'round';
    context.lineWidth = options.lineWidth;
    context.strokeStyle = 'rgba(0,0,0,0.5)';
    context.fillStyle = options.fillStyle;

    function stackPos (a, b) {
      stackOffsetPos = stack.negative[a] || 0;
      stackOffsetNeg = stack.positive[a] || 0;
      if (b > 0) {
        stack.positive[a] = stackOffsetPos + b;
        return stackOffsetPos + b;
      } else {
        stack.negative[a] = stackOffsetNeg + b;
        return stackOffsetNeg + b;
      }
    }

    for (i = 0; i < data.length; ++i) {

      x = data[i][0];
      y = data[i][1];

      if (stack) {
        if (stackType == 'b') {
          if (options.horizontal) y = stackPos(y, x);
          else x = stackPos(x, y);
        } else if (stackType == 'a') {
          stackOffset = stack.values[x] || 0;
          stack.values[x] = stackOffset + y;
          y = stackOffset + y;
        }
      }

      label = options.labelFormatter({x: x, y: y, index: i, data : data});
      this.plot(options.xScale(x), options.yScale(y), label, options);
    }
    context.restore();
  },
  plot: function(x, y, label, options) {
    var context = options.context;
    if (isImage(label) && !label.complete) {
      throw 'Marker image not loaded.';
    } else {
      this._plot(x, y, label, options);
    }
  },

  _plot: function(x, y, label, options) {
    var context = options.context,
        margin = 2,
        left = x,
        top = y,
        dim;

    if (isImage(label))
      dim = {height : label.height, width: label.width};
    else
      dim = options.text.canvas(label);

    dim.width = Math.floor(dim.width+margin*2);
    dim.height = Math.floor(dim.height+margin*2);

         if (options.position.indexOf('c') != -1) left -= dim.width/2 + margin;
    else if (options.position.indexOf('l') != -1) left -= dim.width;

         if (options.position.indexOf('m') != -1) top -= dim.height/2 + margin;
    else if (options.position.indexOf('t') != -1) top -= dim.height;

    left = Math.floor(left)+0.5;
    top = Math.floor(top)+0.5;

    if(options.fill)
      context.fillRect(left, top, dim.width, dim.height);

    if(options.stroke)
      context.strokeRect(left, top, dim.width, dim.height);

    if (isImage(label))
      context.drawImage(label, left+margin, top+margin);
    else
      Flotr.drawText(context, label, left+margin, top+margin, {textBaseline: 'top', textAlign: 'left', size: options.fontSize, color: options.color});
  }
});

function isImage (i) {
  return typeof i === 'object' && i.constructor && (Image ? true : i.constructor === Image);
}

})();
<commit_msg>added a new config option called verticalMargin so that if you are showing points of varying sizes, the label can be moved above or below the point.<commit_after>/** Markers **/
/**
 * Formats the marker labels.
 * @param {Object} obj - Marker value Object {x:..,y:..}
 * @return {String} Formatted marker string
 */
(function () {

Flotr.defaultMarkerFormatter = function(obj){
  return (Math.round(obj.y*100)/100)+'';
};

Flotr.addType('markers', {
  options: {
    show: false,           // => setting to true will show markers, false will hide
    lineWidth: 1,          // => line width of the rectangle around the marker
    color: '#000000',      // => text color
    fill: false,           // => fill or not the marekers' rectangles
    fillColor: "#FFFFFF",  // => fill color
    fillOpacity: 0.4,      // => fill opacity
    stroke: false,         // => draw the rectangle around the markers
    position: 'ct',        // => the markers position (vertical align: b, m, t, horizontal align: l, c, r)
    verticalMargin: 2,     // => the margin between the point and the text.
    labelFormatter: Flotr.defaultMarkerFormatter,
    fontSize: Flotr.defaultOptions.fontSize,
    stacked: false,        // => true if markers should be stacked
    stackingType: 'b',     // => define staching behavior, (b- bars like, a - area like) (see Issue 125 for details)
    horizontal: false      // => true if markers should be horizontal (For now only in a case on horizontal stacked bars, stacks should be calculated horizontaly)
  },

  // TODO test stacked markers.
  stack : {
      positive : [],
      negative : [],
      values : []
  },

  draw : function (options) {

    var
      data            = options.data,
      context         = options.context,
      stack           = options.stacked ? options.stack : false,
      stackType       = options.stackingType,
      stackOffsetNeg,
      stackOffsetPos,
      stackOffset,
      i, x, y, label;

    context.save();
    context.lineJoin = 'round';
    context.lineWidth = options.lineWidth;
    context.strokeStyle = 'rgba(0,0,0,0.5)';
    context.fillStyle = options.fillStyle;

    function stackPos (a, b) {
      stackOffsetPos = stack.negative[a] || 0;
      stackOffsetNeg = stack.positive[a] || 0;
      if (b > 0) {
        stack.positive[a] = stackOffsetPos + b;
        return stackOffsetPos + b;
      } else {
        stack.negative[a] = stackOffsetNeg + b;
        return stackOffsetNeg + b;
      }
    }

    for (i = 0; i < data.length; ++i) {

      x = data[i][0];
      y = data[i][1];

      if (stack) {
        if (stackType == 'b') {
          if (options.horizontal) y = stackPos(y, x);
          else x = stackPos(x, y);
        } else if (stackType == 'a') {
          stackOffset = stack.values[x] || 0;
          stack.values[x] = stackOffset + y;
          y = stackOffset + y;
        }
      }

      label = options.labelFormatter({x: x, y: y, index: i, data : data});
      this.plot(options.xScale(x), options.yScale(y), label, options);
    }
    context.restore();
  },
  plot: function(x, y, label, options) {
    var context = options.context;
    if (isImage(label) && !label.complete) {
      throw 'Marker image not loaded.';
    } else {
      this._plot(x, y, label, options);
    }
  },

  _plot: function(x, y, label, options) {
    var context = options.context,
        margin = 2,
        left = x,
        top = y,
        dim;

    if (isImage(label))
      dim = {height : label.height, width: label.width};
    else
      dim = options.text.canvas(label);

    dim.width = Math.floor(dim.width+margin*2);
    dim.height = Math.floor(dim.height+margin*2);

         if (options.position.indexOf('c') != -1) left -= dim.width/2 + margin;
    else if (options.position.indexOf('l') != -1) left -= dim.width;

         if (options.position.indexOf('m') != -1) top -= dim.height/2 + margin;
    else if (options.position.indexOf('t') != -1) top -= dim.height + options.verticalMargin;
    else top += options.verticalMargin;

    left = Math.floor(left)+0.5;
    top = Math.floor(top)+0.5;

    if(options.fill)
      context.fillRect(left, top, dim.width, dim.height);

    if(options.stroke)
      context.strokeRect(left, top, dim.width, dim.height);

    if (isImage(label))
      context.drawImage(label, left+margin, top+margin);
    else
      Flotr.drawText(context, label, left+margin, top+margin, {textBaseline: 'top', textAlign: 'left', size: options.fontSize, color: options.color});
  }
});

function isImage (i) {
  return typeof i === 'object' && i.constructor && (Image ? true : i.constructor === Image);
}

})();
<|endoftext|>


<commit_before>/*
 Copyright 2017 Credential Engine and other contributing parties.

 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*/

var framework = null;
var selectedCompetency = null;
var selectedRelation = null;
//For keyboard controls
var frameworkSelectionIndex = null;
var competencySelectionIndex = null;
var competencyEditScreenActive = false;

fetchFailure = function (failure) {
    this.fetches--;
    error(failure);
    if (this.fetches == 0) {
        if ($("#tree").html() == "")
            $("#tree").html("

This framework is empty.
");
        afterRefresh(true);
    }
};

var treeTop = 0;
populateFramework = function () {
    var me = this;
    treeTop = $("#tree").scrollTop();
    $("#tree").html("");
    me.fetches = 0;
    $("#editFrameworkSection #frameworkName").text(framework.getName());
    if (framework.competency == null)
        framework.competency = [];
    if (framework.relation == null)
        framework.relation = [];
    if (framework.level == null)
        framework.level = [];
    var fun = function (success) {
        if (framework.competency.length == 0) {
            if ($("#tree").html() == "")
                $("#tree").html("

This framework is empty.
");
            showPage("#editFrameworkSection", framework);
        } else {
            me.fetches += framework.competency.length;
            for (var i = 0; i < framework.competency.length; i++) {
                EcCompetency.get(framework.competency[i], refreshCompetency, fetchFailure);
            }
            me.fetches += framework.level.length;
            for (var i = 0; i < framework.level.length; i++) {
                EcLevel.get(framework.level[i], refreshCompetency, fetchFailure);
            }
        }
    };
    repo.precache(framework.competency.concat(framework.relation), fun, fun);
}

function afterRefresh(level) {
    if (level == null) {
        this.fetches += framework.level.length;
        for (var i = 0; i < framework.level.length; i++) {
            EcLevel.get(framework.level[i], refreshCompetency, fetchFailure);
        }
        if (framework.level.length == 0)
            showPage("#editFrameworkSection", framework);
    } else
        showPage("#editFrameworkSection", framework);
    $("#tree").scrollTop(treeTop);
}

$("body").on("click", ".collapse", null, function (evt) {
    $(this).parent().children("ul").slideToggle();

    if ($(this).hasClass('collapsed')) {
        $(this).removeClass('collapsed');
        $(this).html(' ');
    } else {
        $(this).addClass('collapsed');
        $(this).html(' ');
    }
});

$("body").on("click", ".competency", null, function (evt) {
    var me = $(this);
    if (!$(this).hasClass("competency"))
        me = $(this).parents("competency");

    $('.competency').removeClass('selected');
    me.addClass('selected');

    selectedCompetency = EcCompetency.getBlocking(me.attr("id"));
    if (selectedCompetency == null)
        selectedCompetency = EcLevel.getBlocking(me.attr("id"));
    var relationId = me.attr("relationid");
    if (relationId != null && relationId != "")
        selectedRelation = EcAlignment.getBlocking(me.attr("relationid"));
    else
        selectedRelation = null;
    refreshSidebar();
    evt.stopPropagation();
});

$('body').on('dragover', '.competency', function(evt) {
    $(this).addClass('selected');
});

$('body').on('dragleave', '.competency', function(evt) {
    $(this).removeClass('selected');
});

$('html').keydown(function(evt) {
    if (!$('input').is(':focus')) {
        //If we're on the framework selection screen
        if ($('#frameworksSection').css('display') === 'block') {
            var frameworkElementArray = document.getElementById('frameworks').children;
            if (frameworkSelectionIndex === null) {
                frameworkSelectionIndex = 0;
                $('#frameworks').find('p.selected').each(function() {
                    $(this).removeClass('selected');
                });
                frameworkElementArray[frameworkSelectionIndex].classList.add('selected');
                return;
            }
            //On Down arrow
            if (evt.which === 40) {
                if (frameworkSelectionIndex < frameworkElementArray.length)
                    frameworkSelectionIndex++;
                //clear any existing selected
                $('#frameworks').find('p.selected').each(function() {
                    $(this).removeClass('selected');
                });
                frameworkElementArray[frameworkSelectionIndex].classList.add('selected');
            }
            //On Up arrow
            else if (evt.which === 38) {
                if (frameworkSelectionIndex > 0)
                    frameworkSelectionIndex--;
                $('#frameworks').find('p.selected').each(function() {
                    $(this).removeClass('selected');
                });
                frameworkElementArray[frameworkSelectionIndex].classList.add('selected');
            }
            //On enter
            else if (evt.which === 13) {
                $(frameworkElementArray[frameworkSelectionIndex]).click();
                frameworkSelectionIndex = null;
            }
        }
        //If we're on the editFrameworks section
        else if ($('#editFrameworkSection').css('display') === 'block') {
            var competencyElementArray = $('#tree').find('.competency:visible');
            if (competencySelectionIndex === null) {
                competencySelectionIndex = 0;
                $('#tree').find('.competency.selected').each(function() {
                    $(this).removeClass('selected');
                });
                competencyElementArray[competencySelectionIndex].classList.add('selected');
            }

            if (evt.which === 40) {
                if (competencySelectionIndex < competencyElementArray.length)
                    competencySelectionIndex++;
                if (competencyElementArray[competencySelectionIndex])
                $('#tree').find('.competency.selected').each(function() {
                    $(this).removeClass('selected');
                });
                competencyElementArray[competencySelectionIndex].classList.add('selected');
            } else if (evt.which === 38) {
                if (competencySelectionIndex > 0)
                    competencySelectionIndex--;
                $('#tree').find('.competency.selected').each(function() {
                    $(this).removeClass('selected');
                });
                competencyElementArray[competencySelectionIndex].classList.add('selected');
            } else if (evt.which === 13) {
                $(competencyElementArray[competencySelectionIndex]).click();
            } else if (evt.which === 39) {
                $(competencyElementArray[competencySelectionIndex]).find('.collapse').click();
            } else if (evt.which === 37) {
                $(competencyElementArray[competencySelectionIndex]).find('.collapse').click();
            }
        }
    }
});

function refreshCompetency(col, level) {
    var me = this;
    me.fetches--;
    var treeNode = null;
    if ($("[id='" + col.shortId() + "']").length > 0) {
        treeNode = $("[id='" + col.shortId() + "']").before("

");
        var tn = treeNode.prev();
        treeNode.remove();
        treeNode = tn;
    } else
        treeNode = $("#tree").append("

").children().last();
    treeNode.attr("id", col.shortId());
    if (col.description != null && col.description != "NULL" && col.description != col.name)
        treeNode.children().first().prepend("").children().first().addClass("competencyDescription").text(col.getDescription());
    treeNode.children().first().prepend("").children().first().addClass("competencyName").text(col.getName());
    if (col.competency != null) {
        level = true;
        $(".competency[id=\"" + col.competency + "\"]").children().last().append($(".competency[id=\"" + col.shortId() + "\"]"));
        treeNode.children().first().append(" (Performance Level)");
        if (!$(".competency[id=\"" + col.competency + "\"]").hasClass("expandable"))
            $(".competency[id=\"" + col.competency + "\"]").addClass("expandable").prepend("").children().first().addClass("collapse").html(' ');
    }
    if (queryParams.link == "true")
        treeNode.prepend(" 🔗").children().first().attr("href", col.shortId());
    if (me.fetches == 0) {
        if (framework.relation != undefined && framework.relation.length > 0) {
            me.fetches += framework.relation.length;
            for (var i = 0; i < framework.relation.length; i++) {
                EcAlignment.get(framework.relation[i], function (relation) {
                    me.fetches--;
                    if (relation.source !== undefined && relation.target !== undefined && relation.source != null && relation.target != null) {
                        if (relation.relationType == "narrows") {
                            if ($(".competency[relationid=\"" + relation.shortId() + "\"]").length == 0) {
                                $(".competency[id=\"" + relation.target + "\"]").children().last().append($(".competency[id=\"" + relation.source + "\"]").outerHTML()).children().last().attr("relationid", relation.shortId());
                                if ($(".competency[id=\"" + relation.target + "\"]").length > 0)
                                    $("#tree>.competency[id=\"" + relation.source + "\"]").remove();
                                if (!$(".competency[id=\"" + relation.target + "\"]").hasClass("expandable"))
                                    $(".competency[id=\"" + relation.target + "\"]").addClass("expandable").prepend("").children().first().addClass("collapse").html(' ');
                            }
                        }
                    }
                    if (me.fetches == 0) {
                        me.fetches += framework.relation.length;
                        for (var i = 0; i < framework.relation.length; i++) {
                            EcAlignment.get(framework.relation[i], function (relation) {
                                me.fetches--;
                                if (relation.source !== undefined) {
                                    if (relation.relationType == "requires") {
                                        if ($(".competency[id=\"" + relation.target + "\"]").prevAll(".competency[id=\"" + relation.source + "\"]").length > 0)
                                            $(".competency[id=\"" + relation.target + "\"]").insertBefore($(".competency[id=\"" + relation.source + "\"]"));
                                    }
                                }
                                if (me.fetches == 0) {
                                    if ($("#tree").html() == "")
                                        $("#tree").html("

This framework is empty.
");
                                    afterRefresh(level);
                                }
                            }, fetchFailure);
                        }
                    }
                }, fetchFailure);
            }
        } else {
            if ($("#tree").html() == "")
                $("#tree").html("

This framework is empty.
");
            afterRefresh(level);
        }
    }
}

refreshSidebar = function () {
    $('#detailSlider').show();

    var thing = framework;
    if (selectedCompetency != null)
        thing = selectedCompetency;
    $("sidebarFeedback").text("");
    $("#editFrameworkSection").find("button,input,textarea,select").prop('disabled', false);
    $("#editFrameworkSection .viewMode").show();
    $("#editFrameworkSection .editMode").hide();
    $("#editFrameworkSection #sidebarName").text(thing.getName());
    $("#editFrameworkSection #sidebarNameInput").val(thing.getName());
    $("#editFrameworkSection #sidebarDescription").text(thing.getDescription());
    $("#editFrameworkSection #sidebarDescriptionInput").val(thing.getDescription());

    if (framework == thing) {
        $("#sidebarVersion").hide();
        $("#sidebarAddLevels").hide();
    }

    if (thing == selectedCompetency)
        if (EcArray.has(framework.competency.concat(framework.level), thing.shortId()))
            $("#sidebarVersion option").prop('selected', false).first().prop('selected', true);
        else {
            if (EcArray.has(framework.competency.concat(framework.level), thing.id))
                $("#sidebarVersion option").prop('selected', false).last().prop('selected', true);
            else
                console.log("Error. Version not certain.");
        }

    if (new EcLevel().isA(thing.getFullType())) {
        $("#sidebarAddCompetencies").hide();
        $("#sidebarAddLevels").hide();
    }

    if (thing.id == thing.shortId()) {
        $("#sidebarVersion").hide();
    }

    if (!framework.canEditAny(EcIdentityManager.getMyPks())) {
        $("#sidebarVersion").prop('disabled', true);
        $("#sidebarAddCompetencies").prop('disabled', true);
        $("#sidebarAddLevels").prop('disabled', true);
        $("#sidebarFeedback").html("Some edit options are limited:
You do not own this framework.
 ");
    } else
        $("#sidebarFeedback").html("");

}

editSidebar = function () {
    $("#editFrameworkSection .viewMode").hide();
    $("#editFrameworkSection .editMode").show();

    var thing = framework;
    if (selectedCompetency != null)
        thing = selectedCompetency;

    $("sidebarFeedback").text("");
    if (!framework.canEditAny(EcIdentityManager.getMyPks()))
        if (selectedCompetency != null && framework.competency != null)
            if (EcArray.has(framework.competency.concat(framework.level), selectedCompetency.shortId())) {
                $("#sidebarSave").prop('disabled', true);
                $("#sidebarRemove").prop('disabled', true);
                $("#sidebarDelete").prop('disabled', true);
                $("#sidebarFeedback").html("Some edit options are limited:
You do not own this framework.
 ");
            }

    if (!thing.canEditAny(EcIdentityManager.getMyPks())) {
        $("#sidebarNameInput").prop('disabled', true);
        $("#sidebarDescriptionInput").prop('disabled', true);
        $("#sidebarSave").prop('disabled', true);
        $("#sidebarDelete").prop('disabled', true);
        if (thing == framework) {
            $("#sidebarFeedback").html("Some edit options are limited:
You do not own this framework.
 ");
        } else
            $("#sidebarFeedback").append("
You do not own this competency.
 ");
    }

    if (thing == framework) {
        $("#sidebarUnlink").hide();
        $("#sidebarRemove").hide();
    }

    if (selectedRelation == null) {
        $("#sidebarUnlink").prop('disabled', true);
    }
}
<commit_msg>Added backspace key command to go back to frameworks search, added escape key command to leave input focus<commit_after>/*
 Copyright 2017 Credential Engine and other contributing parties.

 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*/

var framework = null;
var selectedCompetency = null;
var selectedRelation = null;
//For keyboard controls
var frameworkSelectionIndex = null;
var competencySelectionIndex = null;
var competencyEditScreenActive = false;

fetchFailure = function (failure) {
    this.fetches--;
    error(failure);
    if (this.fetches == 0) {
        if ($("#tree").html() == "")
            $("#tree").html("

This framework is empty.
");
        afterRefresh(true);
    }
};

var treeTop = 0;
populateFramework = function () {
    var me = this;
    treeTop = $("#tree").scrollTop();
    $("#tree").html("");
    me.fetches = 0;
    $("#editFrameworkSection #frameworkName").text(framework.getName());
    if (framework.competency == null)
        framework.competency = [];
    if (framework.relation == null)
        framework.relation = [];
    if (framework.level == null)
        framework.level = [];
    var fun = function (success) {
        if (framework.competency.length == 0) {
            if ($("#tree").html() == "")
                $("#tree").html("

This framework is empty.
");
            showPage("#editFrameworkSection", framework);
        } else {
            me.fetches += framework.competency.length;
            for (var i = 0; i < framework.competency.length; i++) {
                EcCompetency.get(framework.competency[i], refreshCompetency, fetchFailure);
            }
            me.fetches += framework.level.length;
            for (var i = 0; i < framework.level.length; i++) {
                EcLevel.get(framework.level[i], refreshCompetency, fetchFailure);
            }
        }
    };
    repo.precache(framework.competency.concat(framework.relation), fun, fun);
}

function afterRefresh(level) {
    if (level == null) {
        this.fetches += framework.level.length;
        for (var i = 0; i < framework.level.length; i++) {
            EcLevel.get(framework.level[i], refreshCompetency, fetchFailure);
        }
        if (framework.level.length == 0)
            showPage("#editFrameworkSection", framework);
    } else
        showPage("#editFrameworkSection", framework);
    $("#tree").scrollTop(treeTop);
}

$("body").on("click", ".collapse", null, function (evt) {
    $(this).parent().children("ul").slideToggle();

    if ($(this).hasClass('collapsed')) {
        $(this).removeClass('collapsed');
        $(this).html(' ');
    } else {
        $(this).addClass('collapsed');
        $(this).html(' ');
    }
});

$("body").on("click", ".competency", null, function (evt) {
    var me = $(this);
    if (!$(this).hasClass("competency"))
        me = $(this).parents("competency");

    $('.competency').removeClass('selected');
    me.addClass('selected');

    selectedCompetency = EcCompetency.getBlocking(me.attr("id"));
    if (selectedCompetency == null)
        selectedCompetency = EcLevel.getBlocking(me.attr("id"));
    var relationId = me.attr("relationid");
    if (relationId != null && relationId != "")
        selectedRelation = EcAlignment.getBlocking(me.attr("relationid"));
    else
        selectedRelation = null;
    refreshSidebar();
    evt.stopPropagation();
});

$('body').on('dragover', '.competency', function(evt) {
    $(this).addClass('selected');
});

$('body').on('dragleave', '.competency', function(evt) {
    $(this).removeClass('selected');
});

$('html').keydown(function(evt) {
    if (!$('input').is(':focus')) {
        //If we're on the framework selection screen
        if ($('#frameworksSection').css('display') === 'block') {
            var frameworkElementArray = document.getElementById('frameworks').children;
            if (frameworkSelectionIndex === null) {
                frameworkSelectionIndex = 0;
                $('#frameworks').find('p.selected').each(function() {
                    $(this).removeClass('selected');
                });
                frameworkElementArray[frameworkSelectionIndex].classList.add('selected');
                return;
            }
            //On Down arrow
            if (evt.which === 40) {
                if (frameworkSelectionIndex < frameworkElementArray.length)
                    frameworkSelectionIndex++;
                //clear any existing selected
                $('#frameworks').find('p.selected').each(function() {
                    $(this).removeClass('selected');
                });
                frameworkElementArray[frameworkSelectionIndex].classList.add('selected');
            }
            //On Up arrow
            else if (evt.which === 38) {
                if (frameworkSelectionIndex > 0)
                    frameworkSelectionIndex--;
                $('#frameworks').find('p.selected').each(function() {
                    $(this).removeClass('selected');
                });
                frameworkElementArray[frameworkSelectionIndex].classList.add('selected');
            }
            //On enter
            else if (evt.which === 13) {
                $(frameworkElementArray[frameworkSelectionIndex]).click();
                frameworkSelectionIndex = null;
            }
        }
        //If we're on the editFrameworks section
        else if ($('#editFrameworkSection').css('display') === 'block') {
            var competencyElementArray = $('#tree').find('.competency:visible');
            if (competencySelectionIndex === null) {
                competencySelectionIndex = 0;
                $('#tree').find('.competency.selected').each(function() {
                    $(this).removeClass('selected');
                });
                competencyElementArray[competencySelectionIndex].classList.add('selected');
            }
            //On down arrow
            if (evt.which === 40) {
                if (competencySelectionIndex < competencyElementArray.length)
                    competencySelectionIndex++;
                if (competencyElementArray[competencySelectionIndex])
                $('#tree').find('.competency.selected').each(function() {
                    $(this).removeClass('selected');
                });
                competencyElementArray[competencySelectionIndex].classList.add('selected');
            }
            //On up arrow
            else if (evt.which === 38) {
                if (competencySelectionIndex > 0)
                    competencySelectionIndex--;
                $('#tree').find('.competency.selected').each(function() {
                    $(this).removeClass('selected');
                });
                competencyElementArray[competencySelectionIndex].classList.add('selected');
            }
            //On enter
            else if (evt.which === 13) {
                $(competencyElementArray[competencySelectionIndex]).click();
            }
            //On left and right arrows
            else if (evt.which === 39) {
                $(competencyElementArray[competencySelectionIndex]).find('.collapse').click();
            }
            else if (evt.which === 37) {
                $(competencyElementArray[competencySelectionIndex]).find('.collapse').click();
            }
            //On Backspace
            else if (evt.which === 8) {
                $('#editFrameworkBack').click();
            }
        }
    } else {
        //On escape
        if (evt.which === 27) {
            $('input').blur();
        }
    }
});

function refreshCompetency(col, level) {
    var me = this;
    me.fetches--;
    var treeNode = null;
    if ($("[id='" + col.shortId() + "']").length > 0) {
        treeNode = $("[id='" + col.shortId() + "']").before("

");
        var tn = treeNode.prev();
        treeNode.remove();
        treeNode = tn;
    } else
        treeNode = $("#tree").append("

").children().last();
    treeNode.attr("id", col.shortId());
    if (col.description != null && col.description != "NULL" && col.description != col.name)
        treeNode.children().first().prepend("").children().first().addClass("competencyDescription").text(col.getDescription());
    treeNode.children().first().prepend("").children().first().addClass("competencyName").text(col.getName());
    if (col.competency != null) {
        level = true;
        $(".competency[id=\"" + col.competency + "\"]").children().last().append($(".competency[id=\"" + col.shortId() + "\"]"));
        treeNode.children().first().append(" (Performance Level)");
        if (!$(".competency[id=\"" + col.competency + "\"]").hasClass("expandable"))
            $(".competency[id=\"" + col.competency + "\"]").addClass("expandable").prepend("").children().first().addClass("collapse").html(' ');
    }
    if (queryParams.link == "true")
        treeNode.prepend(" 🔗").children().first().attr("href", col.shortId());
    if (me.fetches == 0) {
        if (framework.relation != undefined && framework.relation.length > 0) {
            me.fetches += framework.relation.length;
            for (var i = 0; i < framework.relation.length; i++) {
                EcAlignment.get(framework.relation[i], function (relation) {
                    me.fetches--;
                    if (relation.source !== undefined && relation.target !== undefined && relation.source != null && relation.target != null) {
                        if (relation.relationType == "narrows") {
                            if ($(".competency[relationid=\"" + relation.shortId() + "\"]").length == 0) {
                                $(".competency[id=\"" + relation.target + "\"]").children().last().append($(".competency[id=\"" + relation.source + "\"]").outerHTML()).children().last().attr("relationid", relation.shortId());
                                if ($(".competency[id=\"" + relation.target + "\"]").length > 0)
                                    $("#tree>.competency[id=\"" + relation.source + "\"]").remove();
                                if (!$(".competency[id=\"" + relation.target + "\"]").hasClass("expandable"))
                                    $(".competency[id=\"" + relation.target + "\"]").addClass("expandable").prepend("").children().first().addClass("collapse").html(' ');
                            }
                        }
                    }
                    if (me.fetches == 0) {
                        me.fetches += framework.relation.length;
                        for (var i = 0; i < framework.relation.length; i++) {
                            EcAlignment.get(framework.relation[i], function (relation) {
                                me.fetches--;
                                if (relation.source !== undefined) {
                                    if (relation.relationType == "requires") {
                                        if ($(".competency[id=\"" + relation.target + "\"]").prevAll(".competency[id=\"" + relation.source + "\"]").length > 0)
                                            $(".competency[id=\"" + relation.target + "\"]").insertBefore($(".competency[id=\"" + relation.source + "\"]"));
                                    }
                                }
                                if (me.fetches == 0) {
                                    if ($("#tree").html() == "")
                                        $("#tree").html("

This framework is empty.
");
                                    afterRefresh(level);
                                }
                            }, fetchFailure);
                        }
                    }
                }, fetchFailure);
            }
        } else {
            if ($("#tree").html() == "")
                $("#tree").html("

This framework is empty.
");
            afterRefresh(level);
        }
    }
}

refreshSidebar = function () {
    $('#detailSlider').show();

    var thing = framework;
    if (selectedCompetency != null)
        thing = selectedCompetency;
    $("sidebarFeedback").text("");
    $("#editFrameworkSection").find("button,input,textarea,select").prop('disabled', false);
    $("#editFrameworkSection .viewMode").show();
    $("#editFrameworkSection .editMode").hide();
    $("#editFrameworkSection #sidebarName").text(thing.getName());
    $("#editFrameworkSection #sidebarNameInput").val(thing.getName());
    $("#editFrameworkSection #sidebarDescription").text(thing.getDescription());
    $("#editFrameworkSection #sidebarDescriptionInput").val(thing.getDescription());

    if (framework == thing) {
        $("#sidebarVersion").hide();
        $("#sidebarAddLevels").hide();
    }

    if (thing == selectedCompetency)
        if (EcArray.has(framework.competency.concat(framework.level), thing.shortId()))
            $("#sidebarVersion option").prop('selected', false).first().prop('selected', true);
        else {
            if (EcArray.has(framework.competency.concat(framework.level), thing.id))
                $("#sidebarVersion option").prop('selected', false).last().prop('selected', true);
            else
                console.log("Error. Version not certain.");
        }

    if (new EcLevel().isA(thing.getFullType())) {
        $("#sidebarAddCompetencies").hide();
        $("#sidebarAddLevels").hide();
    }

    if (thing.id == thing.shortId()) {
        $("#sidebarVersion").hide();
    }

    if (!framework.canEditAny(EcIdentityManager.getMyPks())) {
        $("#sidebarVersion").prop('disabled', true);
        $("#sidebarAddCompetencies").prop('disabled', true);
        $("#sidebarAddLevels").prop('disabled', true);
        $("#sidebarFeedback").html("Some edit options are limited:
You do not own this framework.
 ");
    } else
        $("#sidebarFeedback").html("");

}

editSidebar = function () {
    $("#editFrameworkSection .viewMode").hide();
    $("#editFrameworkSection .editMode").show();

    var thing = framework;
    if (selectedCompetency != null)
        thing = selectedCompetency;

    $("sidebarFeedback").text("");
    if (!framework.canEditAny(EcIdentityManager.getMyPks()))
        if (selectedCompetency != null && framework.competency != null)
            if (EcArray.has(framework.competency.concat(framework.level), selectedCompetency.shortId())) {
                $("#sidebarSave").prop('disabled', true);
                $("#sidebarRemove").prop('disabled', true);
                $("#sidebarDelete").prop('disabled', true);
                $("#sidebarFeedback").html("Some edit options are limited:
You do not own this framework.
 ");
            }

    if (!thing.canEditAny(EcIdentityManager.getMyPks())) {
        $("#sidebarNameInput").prop('disabled', true);
        $("#sidebarDescriptionInput").prop('disabled', true);
        $("#sidebarSave").prop('disabled', true);
        $("#sidebarDelete").prop('disabled', true);
        if (thing == framework) {
            $("#sidebarFeedback").html("Some edit options are limited:
You do not own this framework.
 ");
        } else
            $("#sidebarFeedback").append("
You do not own this competency.
 ");
    }

    if (thing == framework) {
        $("#sidebarUnlink").hide();
        $("#sidebarRemove").hide();
    }

    if (selectedRelation == null) {
        $("#sidebarUnlink").prop('disabled', true);
    }
}
<|endoftext|>


<commit_before>define(function(require) {

  var $ = require('jquery');
  var _ = require('underscore');
  var Backbone = require('backbone');
  var entriesTemplate = require('text!templates/entries.html');
  var docs = require('collections/docs');
  var settings = require('models/settings');

  var EntriesView = Backbone.View.extend({

    el: '#entries',

    initialize: function() {
      this.template = _.template(entriesTemplate);
      this.render();

      docs
        .on('add', this.render, this)
        .on('reset', this.render, this)
        .on('change:title', this.updateTitle, this)
        .on('destroy', this.removeItem, this);

      settings.on('change:openDocId', this.selectOpenDoc, this);
    },

    render: function() {
      this.$el.html(
        this.template({ docs: docs.toJSON() })
      );

      this.selectOpenDoc();
    },

    $itemById: function(id) {
      return this.$('.item[data-id=' + id + ']');
    },

    updateTitle: function(doc) {
      this.$itemById(doc.id).find('a').html( doc.get('title') );
    },

    removeItem: function(doc) {
      this.$itemById(doc.id).remove();
    },

    selectOpenDoc: function() {
      if (this.$selected) {
        this.$selected.removeClass('selected');
      }
      this.$selected = this.$itemById( settings.get('openDocId') )
        .addClass('selected');
    },

    events: {
      'click .item': 'openDoc'
    },

    openDoc: function(e) {
      e.preventDefault();

      settings.save('openDocId', this.$(e.currentTarget).attr('data-id'));
    }

  });

  return EntriesView;
});<commit_msg>removed duplicated observer.<commit_after>define(function(require) {

  var $ = require('jquery');
  var _ = require('underscore');
  var Backbone = require('backbone');
  var entriesTemplate = require('text!templates/entries.html');
  var docs = require('collections/docs');
  var settings = require('models/settings');

  var EntriesView = Backbone.View.extend({

    el: '#entries',

    initialize: function() {
      this.template = _.template(entriesTemplate);
      this.render();

      docs
        .on('reset', this.render, this)
        .on('change:title', this.updateTitle, this)
        .on('destroy', this.removeItem, this);

      settings.on('change:openDocId', this.selectOpenDoc, this);
    },

    render: function() {
      this.$el.html(
        this.template({ docs: docs.toJSON() })
      );

      this.selectOpenDoc();
    },

    $itemById: function(id) {
      return this.$('.item[data-id=' + id + ']');
    },

    updateTitle: function(doc) {
      this.$itemById(doc.id).find('a').html( doc.get('title') );
    },

    removeItem: function(doc) {
      this.$itemById(doc.id).remove();
    },

    selectOpenDoc: function() {
      if (this.$selected) {
        this.$selected.removeClass('selected');
      }
      this.$selected = this.$itemById( settings.get('openDocId') )
        .addClass('selected');
    },

    events: {
      'click .item': 'openDoc'
    },

    openDoc: function(e) {
      e.preventDefault();

      settings.save('openDocId', this.$(e.currentTarget).attr('data-id'));
    }

  });

  return EntriesView;
});<|endoftext|>


<commit_before>/**
/**
 * @author dmarcos / https://github.com/dmarcos
 * @author hawksley / https://github.com/hawksley (added support for many more forms of control)
 */

THREE.VRControls = function ( camera, speed, done ) {
	this.phoneVR = new PhoneVR();

	this.speed = speed || 1; // 3 is just a good default speed multiplier

	//---game controller stuff---
	this.haveEvents = 'ongamepadconnected' in window;
	this.controllers = {};

	this._camera = camera;

	this._init = function () {
		var self = this;

		//hold down keys to do rotations and stuff
		function key(event, sign) {
			var control = self.manualControls[event.keyCode];

			if (typeof control === 'undefined' || sign === 1 && control.active || sign === -1 && !control.active) {
				return;
			}

			control.active = (sign === 1);
			if (self.isWASD && control.index <= 2){
				self.manualRotateRate[control.index] += sign * control.sign;
			} else if (self.isArrows && control.index <= 5) {
				self.manualMoveRate[control.index - 3] += sign * control.sign;
			}
		}

		document.addEventListener('keydown', function(event) { key(event, 1); }, false);
		document.addEventListener('keyup', function(event) { key(event, -1); }, false);

		function connecthandler(e) {
			addgamepad(e.gamepad);
		}

		function addgamepad(gamepad) {
			self.controllers[gamepad.index] = gamepad;
		}

		function disconnecthandler(e) {
			removegamepad(e.gamepad);
		}

		function removegamepad(gamepad) {
			delete self.controllers[gamepad.index];
		}

		function scangamepads() {
			var gamepads = navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads() : []);
			for (var i = 0; i < gamepads.length; i++) {
				if (gamepads[i]) {
					if (gamepads[i].index in self.controllers) {
						self.controllers[gamepads[i].index] = gamepads[i];
					} else {
						addgamepad(gamepads[i]);
					}
				}
			}
		}

		window.addEventListener("gamepadconnected", connecthandler);
		window.addEventListener("gamepaddisconnected", disconnecthandler);
		if (!self.haveEvents) {
			setInterval(scangamepads, 500);
		}

		if ( !navigator.mozGetVRDevices && !navigator.getVRDevices ) {
			if ( done ) {
				done("Your browser is not VR Ready");
			}
			return;
		}

		if ( navigator.getVRDevices ) {
			navigator.getVRDevices().then( gotVRDevices );
		} else {
			navigator.mozGetVRDevices( gotVRDevices );
		}

		function gotVRDevices( devices ) {
			var vrInput;
			var error;
			for ( var i = 0; i < devices.length; ++i ) {
				if ( devices[i] instanceof PositionSensorVRDevice ) {
					vrInput = devices[i]
					self._vrInput = vrInput;
					break; // We keep the first we encounter
				}
			}
			if ( done ) {
				if ( !vrInput ) {
				 error = 'HMD not available';
				}
				done( error );
			}
		}
	};

	this._init();

	this.manualRotation = new THREE.Quaternion();

	this.manualControls = {
		65 : {index: 1, sign: 1, active: 0},  // a
		68 : {index: 1, sign: -1, active: 0}, // d
		87 : {index: 0, sign: 1, active: 0},  // w
		83 : {index: 0, sign: -1, active: 0}, // s
		81 : {index: 2, sign: -1, active: 0}, // q
		69 : {index: 2, sign: 1, active: 0},  // e

		38 : {index: 3, sign: -1, active: 0},  // up
		40 : {index: 3, sign: 1, active: 0}, // down
		37 : {index: 4, sign: 1, active: 0}, // left
		39 : {index: 4, sign: -1, active: 0},   // right
		191 : {index: 5, sign: 1, active: 0}, // fwd slash
		222 : {index: 5, sign: -1, active: 0}   // single quote
  };

	this.manualRotateRate = new Float32Array([0, 0, 0]);
	this.manualMoveRate = new Float32Array([0, 0, 0]);
	this.updateTime = 0;

	this.isGamepad = true;
	this.isArrows = true;
	this.isWASD = true;

	// the Rift SDK returns the position in meters
	// this scale factor allows the user to define how meters
	// are converted to scene units.
	this.scale = 1;

	this.enableGamepad = function(isGamepad) {
		this.isGamepad = isGamepad;
	}

	this.enableArrows = function(isArrows) {
		this.isArrows = isArrows;
	}

	this.enableWASD = function(isWASD) {
		this.isWASD = isWASD;
	}

	this.update = function() {
		var camera = this._camera;
		var vrState = this.getVRState();
		var vrInput = this._vrInput;
		var manualRotation = this.manualRotation;
		var oldTime = this.updateTime;
		var newTime = Date.now();
		this.updateTime = newTime;

		/*
		Get controller button info
		*/
		// if (this.isGamepad) {
			var j;

			for (j in this.controllers) {
				var controller = this.controllers[j];

				this.manualMoveRate[1] = -1 * Math.round(controller.axes[0]);
				this.manualMoveRate[0] = Math.round(controller.axes[1]);
				this.manualRotateRate[1] = -1 * Math.round(controller.axes[3]);
				this.manualRotateRate[0] = -1 * Math.round(controller.axes[4]);
			}
		// }

		// if (this.isGamepad || this.isWASD) {
		  var interval = (newTime - oldTime) * 0.001;
		  var update = new THREE.Quaternion(this.manualRotateRate[0] * interval,
		                               this.manualRotateRate[1] * interval,
		                               this.manualRotateRate[2] * interval, 1.0);
		  update.normalize();
			manualRotation.multiplyQuaternions(manualRotation, update);
		// }

		// if (this.isGamepad || this.isArrows) {
			var offset = new THREE.Vector3();
			if (this.manualMoveRate[0] != 0 || this.manualMoveRate[1] != 0 || this.manualMoveRate[2] != 0){
					offset = getFwdVector().multiplyScalar( interval * this.speed * this.manualMoveRate[0])
							.add(getRightVector().multiplyScalar( interval * this.speed * this.manualMoveRate[1]))
							.add(getUpVector().multiplyScalar( interval * this.speed * this.manualMoveRate[2]));
			}

		// }

		if ( camera ) {
			if ( !vrState ) {
				camera.quaternion.copy(manualRotation);
				camera.position = camera.position.add(offset);
				return;
			}

			// Applies head rotation from sensors data.
			var totalRotation = new THREE.Quaternion();
			var state = vrInput.getState();
      if (state.orientation !== null) {
					var vrStateRotation = new THREE.Quaternion(state.orientation.x, state.orientation.y, state.orientation.z, state.orientation.w);
	        totalRotation.multiplyQuaternions(manualRotation, vrStateRotation);
      } else {
        	totalRotation = manualRotation;
      }

			camera.quaternion.copy(totalRotation);

			if (state.position !== null) {
				camera.position.copy( state.position ).multiplyScalar( this.scale );
			}
		}
	};

	this.resetSensor = function() {
		var vrInput = this._vrInput;
		if (!vrInput) {
			return null;
		}
		vrInput.resetSensor();
	};

	this.getRotation = function() {
		if ( typeof vrState == "undefined" || !vrState ) {
			return this.manualRotation;
		}

		var totalRotation = new THREE.Quaternion();
		var state = vrState.hmd.rotation;
		if (vrState.hmd.rotation[0] !== 0 ||
				vrState.hmd.rotation[1] !== 0 ||
				vrState.hmd.rotation[2] !== 0 ||
				vrState.hmd.rotation[3] !== 0) {
				var vrStateRotation = new THREE.Quaternion(state[0], state[1], state[2], state[3]);
				totalRotation.multiplyQuaternions(manualRotation, vrStateRotation);
		} else {
				totalRotation = manualRotation;
		}

		return totalRotation;
	};

	this.getVRState = function() {
		var vrInput = this._vrInput;
		var orientation;
		var vrState;

		if ( vrInput ) {
			orientation	= vrInput.getState().orientation;
		} else if (this.phoneVR.rotationQuat()) {
			orientation = this.phoneVR.rotationQuat();
		} else {
			return null;
		}

		if (orientation == null) {
			return null;
		}
		vrState = {
			hmd : {
				rotation : [
					orientation.x,
					orientation.y,
					orientation.z,
					orientation.w
				]
			}
		};
		return vrState;
	};

	function getFwdVector() {
		return new THREE.Vector3(0,0,1).applyQuaternion(camera.quaternion);
	}

	function getRightVector() {
		return new THREE.Vector3(-1,0,0).applyQuaternion(camera.quaternion);
	}

	function getUpVector() {
		return new THREE.Vector3(0,-1,0).applyQuaternion(camera.quaternion);
	}
};
<commit_msg>start work on vrcontrols<commit_after>/**
/**
 * @author dmarcos / https://github.com/dmarcos
 * @author hawksley / https://github.com/hawksley (added support for many more forms of control)
 */

THREE.VRControls = function ( camera, speed, done ) {
	this.phoneVR = new PhoneVR();

	this.speed = speed || 1; // 3 is just a good default speed multiplier

	//---game controller stuff---
	this.haveEvents = 'ongamepadconnected' in window;
	this.controllers = {};

	this._camera = camera;

	this._init = function () {
		var self = this;

		//hold down keys to do rotations and stuff
		function key(event, sign) {
			var control = self.manualControls[event.keyCode];

			if (typeof control === 'undefined' || sign === 1 && control.active || sign === -1 && !control.active) {
				return;
			}

			control.active = (sign === 1);
			if (self.isWASD && control.index <= 2){
				self.manualRotateRate[control.index] += sign * control.sign;
			} else if (self.isArrows && control.index <= 5) {
				self.manualMoveRate[control.index - 3] += sign * control.sign;
			}
		}

		document.addEventListener('keydown', function(event) { key(event, 1); }, false);
		document.addEventListener('keyup', function(event) { key(event, -1); }, false);

		function connecthandler(e) {
			addgamepad(e.gamepad);
		}

		function addgamepad(gamepad) {
			self.controllers[gamepad.index] = gamepad;
		}

		function disconnecthandler(e) {
			removegamepad(e.gamepad);
		}

		function removegamepad(gamepad) {
			delete self.controllers[gamepad.index];
		}

		function scangamepads() {
			var gamepads = navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads() : []);
			for (var i = 0; i < gamepads.length; i++) {
				if (gamepads[i]) {
					if (gamepads[i].index in self.controllers) {
						self.controllers[gamepads[i].index] = gamepads[i];
					} else {
						addgamepad(gamepads[i]);
					}
				}
			}
		}

		window.addEventListener("gamepadconnected", connecthandler);
		window.addEventListener("gamepaddisconnected", disconnecthandler);
		if (!self.haveEvents) {
			setInterval(scangamepads, 500);
		}

		if (!navigator.getVRDisplays && !navigator.mozGetVRDevices && !navigator.getVRDevices) {
			if ( done ) {
				done("Your browser is not VR Ready");
			}
			return;
		}
		if (navigator.getVRDisplays) {
			navigator.getVRDisplays().then( gotVRDisplay );
		}else if ( navigator.getVRDevices ) {
			navigator.getVRDevices().then( gotVRDevices );
		} else {
			navigator.mozGetVRDevices( gotVRDevices );
		}

		function gotVRDisplay( devices) {
			var vrInput;
			var error;
			for ( var i = 0; i < devices.length; ++i ) {
				if ( devices[i] instanceof VRDisplay ) {
					vrInput = devices[i]
					self._vrInput = vrInput;
					break; // We keep the first we encounter
				}
			}
			if ( done ) {
				if ( !vrInput ) {
				 error = 'HMD not available';
				}
				done( error );
			}
		}

		function gotVRDevices( devices ) {
			var vrInput;
			var error;
			for ( var i = 0; i < devices.length; ++i ) {
				if ( devices[i] instanceof PositionSensorVRDevice ) {
					vrInput = devices[i]
					self._vrInput = vrInput;
					break; // We keep the first we encounter
				}
			}
			if ( done ) {
				if ( !vrInput ) {
				 error = 'HMD not available';
				}
				done( error );
			}
		}
	};

	this._init();

	this.manualRotation = new THREE.Quaternion();

	this.manualControls = {
		65 : {index: 1, sign: 1, active: 0},  // a
		68 : {index: 1, sign: -1, active: 0}, // d
		87 : {index: 0, sign: 1, active: 0},  // w
		83 : {index: 0, sign: -1, active: 0}, // s
		81 : {index: 2, sign: -1, active: 0}, // q
		69 : {index: 2, sign: 1, active: 0},  // e

		38 : {index: 3, sign: -1, active: 0},  // up
		40 : {index: 3, sign: 1, active: 0}, // down
		37 : {index: 4, sign: 1, active: 0}, // left
		39 : {index: 4, sign: -1, active: 0},   // right
		191 : {index: 5, sign: 1, active: 0}, // fwd slash
		222 : {index: 5, sign: -1, active: 0}   // single quote
  };

	this.manualRotateRate = new Float32Array([0, 0, 0]);
	this.manualMoveRate = new Float32Array([0, 0, 0]);
	this.updateTime = 0;

	this.isGamepad = true;
	this.isArrows = true;
	this.isWASD = true;

	// the Rift SDK returns the position in meters
	// this scale factor allows the user to define how meters
	// are converted to scene units.
	this.scale = 1;

	this.enableGamepad = function(isGamepad) {
		this.isGamepad = isGamepad;
	}

	this.enableArrows = function(isArrows) {
		this.isArrows = isArrows;
	}

	this.enableWASD = function(isWASD) {
		this.isWASD = isWASD;
	}

	this.update = function() {
		var camera = this._camera;
		var vrState = this.getVRState();
		var vrInput = this._vrInput;
		var manualRotation = this.manualRotation;
		var oldTime = this.updateTime;
		var newTime = Date.now();
		this.updateTime = newTime;

		/*
		Get controller button info
		*/
		// if (this.isGamepad) {
			var j;

			for (j in this.controllers) {
				var controller = this.controllers[j];

				this.manualMoveRate[1] = -1 * Math.round(controller.axes[0]);
				this.manualMoveRate[0] = Math.round(controller.axes[1]);
				this.manualRotateRate[1] = -1 * Math.round(controller.axes[3]);
				this.manualRotateRate[0] = -1 * Math.round(controller.axes[4]);
			}
		// }

		// if (this.isGamepad || this.isWASD) {
		  var interval = (newTime - oldTime) * 0.001;
		  var update = new THREE.Quaternion(this.manualRotateRate[0] * interval,
		                               this.manualRotateRate[1] * interval,
		                               this.manualRotateRate[2] * interval, 1.0);
		  update.normalize();
			manualRotation.multiplyQuaternions(manualRotation, update);
		// }

		// if (this.isGamepad || this.isArrows) {
			var offset = new THREE.Vector3();
			if (this.manualMoveRate[0] != 0 || this.manualMoveRate[1] != 0 || this.manualMoveRate[2] != 0){
					offset = getFwdVector().multiplyScalar( interval * this.speed * this.manualMoveRate[0])
							.add(getRightVector().multiplyScalar( interval * this.speed * this.manualMoveRate[1]))
							.add(getUpVector().multiplyScalar( interval * this.speed * this.manualMoveRate[2]));
			}

		// }

		if ( camera ) {
			if ( !vrState ) {
				camera.quaternion.copy(manualRotation);
				camera.position = camera.position.add(offset);
				return;
			}

			// Applies head rotation from sensors data.
			var totalRotation = new THREE.Quaternion();
			var state = vrInput.getState();
      if (state.orientation !== null) {
					var vrStateRotation = new THREE.Quaternion(state.orientation.x, state.orientation.y, state.orientation.z, state.orientation.w);
	        totalRotation.multiplyQuaternions(manualRotation, vrStateRotation);
      } else {
        	totalRotation = manualRotation;
      }

			camera.quaternion.copy(totalRotation);

			if (state.position !== null) {
				camera.position.copy( state.position ).multiplyScalar( this.scale );
			}
		}
	};

	this.resetSensor = function() {
		var vrInput = this._vrInput;
		if (!vrInput) {
			return null;
		}
		vrInput.resetSensor();
	};

	this.getRotation = function() {
		if ( typeof vrState == "undefined" || !vrState ) {
			return this.manualRotation;
		}

		var totalRotation = new THREE.Quaternion();
		var state = vrState.hmd.rotation;
		if (vrState.hmd.rotation[0] !== 0 ||
				vrState.hmd.rotation[1] !== 0 ||
				vrState.hmd.rotation[2] !== 0 ||
				vrState.hmd.rotation[3] !== 0) {
				var vrStateRotation = new THREE.Quaternion(state[0], state[1], state[2], state[3]);
				totalRotation.multiplyQuaternions(manualRotation, vrStateRotation);
		} else {
				totalRotation = manualRotation;
		}

		return totalRotation;
	};

	this.getVRState = function() {
		var vrInput = this._vrInput;
		var orientation;
		var vrState;

		if ( vrInput ) {
			orientation	= vrInput.getState().orientation;
		} else if (this.phoneVR.rotationQuat()) {
			orientation = this.phoneVR.rotationQuat();
		} else {
			return null;
		}

		if (orientation == null) {
			return null;
		}
		vrState = {
			hmd : {
				rotation : [
					orientation.x,
					orientation.y,
					orientation.z,
					orientation.w
				]
			}
		};
		return vrState;
	};

	function getFwdVector() {
		return new THREE.Vector3(0,0,1).applyQuaternion(camera.quaternion);
	}

	function getRightVector() {
		return new THREE.Vector3(-1,0,0).applyQuaternion(camera.quaternion);
	}

	function getUpVector() {
		return new THREE.Vector3(0,-1,0).applyQuaternion(camera.quaternion);
	}
};
<|endoftext|>


<commit_before>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Responsive presentation and behavior for HTML data panels
//>>label: Panel
//>>group: Widgets
//>>css.structure: ../css/structure/jquery.mobile.panel.css
//>>css.theme: ../css/themes/default/jquery.mobile.theme.css

define( [ "jquery", "../jquery.mobile.widget", "./page", "./page.sections" ], function( $ ) {
//>>excludeEnd("jqmBuildExclude");
(function( $, undefined ) {

$.widget( "mobile.panel", $.mobile.widget, {
	options: {
		classes: {
			panel: "ui-panel",
			panelOpen: "ui-panel-open",
			panelClosed: "ui-panel-closed",
			modal: "ui-panel-dismiss",
			modalOpen: "ui-panel-dismiss-open",
			openComplete: "ui-panel-open-complete",
			contentWrap: "ui-panel-content-wrap",
			contentWrapOpen: "ui-panel-content-wrap-open",
			contentWrapClosed: "ui-panel-content-wrap-closed",
			panelUnfixed: "ui-panel-unfixed",
			contentWrapOpenComplete: "ui-panel-content-wrap-open-complete",
			pageBlock: "ui-panel-page-block",
			pagePanel: "ui-page-panel",
			pageChildAnimations: "ui-page-panel-animate"
		},
		animate: true,
		theme: null,
		position: "left",
		dismissible: true,
		display: "overlay", //accepts reveal, push, overlay
		initSelector: ":jqmData(role='panel')",
		swipeClose: true
	},

	_panelID: null,
	_closeLink: null,
	_page: null,
	_modal: null,
	_wrapper: null,

	_create: function() {
		var self = this,
			$el = self.element,
			_getWrapper = function(){
				var $wrapper = self._page.find( "." + self.options.classes.contentWrap );
				if( $wrapper.length === 0 ){
					$wrapper = self._page.find( ".ui-header, .ui-content, .ui-footer" ).wrapAll( '
' ).parent();
				}
				return $wrapper;
			};

		// expose some private props to other methods
		self._panelID = $el.attr( "id" );
		self._closeLink = $el.find( ":jqmData(rel='close')" );
		self._page = $el.closest( ":jqmData(role='page')" );
		self._wrapper = _getWrapper();
		self._addPanelClasses();
		self._wrapper.addClass( this.options.classes.contentWrapClosed );

		// if animating, add the class to do so
		if ( $.support.cssTransform3d && self.options.animate ) {
			this.element.add( self._wrapper ).addClass( "ui-panel-animate" );
			self._page.addClass( this.options.classes.pageChildAnimations );
		}

		self._bindCloseEvents();
		self._bindLinkListeners();
		self._bindPageEvents();

		if( self.options.dismissible ){
			self._createModal();
		}

	},

	_createModal: function( options ){
		var self = this;
		self._modal = $( "

" )
			.on( "mousedown" , function(){
				self.close();
			})
			.appendTo( this._page );
	},

	_getPosDisplayClasses: function( prefix ){
		return prefix + "-position-" + this.options.position + " " + prefix + "-display-" + this.options.display;
	},

	_getPanelClasses: function(){
		var panelClasses = this.options.classes.panel +
						" " + this._getPosDisplayClasses( this.options.classes.panel ) +
						" " + this.options.classes.panelClosed;

		if( this.options.theme ){
			panelClasses += " ui-body-" + this.options.theme;
		}

		if( $.support.cssTransform3d ){
			panelClasses += " ui-panel-3dtransforms";
		}
		return panelClasses;
	},

	_addPanelClasses: function(){
		this.element.addClass( this._getPanelClasses() );
	},

	_bindCloseEvents: function(){
		var self = this;
		self._closeLink.on( "click.panel" , function( e ){
			e.preventDefault();
			self.close();
			return false;
		});
	},

	_positionPanel: function(){
		if( this.element.height() > $.mobile.getScreenHeight() ){
			this._unfixPanel();
			this._scrollIntoView();
		}
		else {
			this._fixPanel();
		}
	},

	_scrollIntoView: function(){
		if( $(window).scrollTop() > $.mobile.getScreenHeight() ){
			window.scrollTo( 0, 0);
		}
	},

	_bindFixListener: function(){
		this._on( $( window ), { "throttledresize": "_positionPanel" });
	},

	_unbindFixListener: function(){
		this._off( $( window ), "throttledresize" );
	},

	_unfixPanel: function(){
		this.element.addClass( this.options.classes.panelUnfixed );
	},

	_fixPanel: function(){
		this.element.removeClass( this.options.classes.panelUnfixed );
	},

	_bindLinkListeners: function(){
		var self = this;

		this._page.on( "click.panel" , "a", function( e ) {
			if( this.href.split( "#" )[ 1 ] === self._panelID ){
				e.preventDefault();
				var $link = $( this );
				$link.addClass( $.mobile.activeBtnClass );
				self.element.one( "panelopen panelclose", function(){
					$link.removeClass( $.mobile.activeBtnClass );
				});
				self.toggle();
				return false;
			}
		});
	},

	_bindPageEvents: function(){
		var self = this;
		if(this.option.swipeClose){
			self.element
				// on swipe, close the panel (should swipe open too?)
				.on( "swipe.panel" , function( e ){
					self.close( true );
				});
		}
		self._page
			// Close immediately if another panel on the page opens
			.on( "panelbeforeopen", function( e ){
				if( self._open && e.target !== self.element[ 0 ] ){
					self.close( true );
				}
			})
			// clean up open panels after page hide
			.on(  "pagebeforehide", function( e ) {
				if( self._open ){
					self.close( true );
				}
			})
			// on escape, close? might need to have a target check too...
			.on( "keyup.panel", function( e ) {
				if( e.keyCode === 27 && self._open ){
					self.close( true );
				}
			});
	},

	// state storage of open or closed
	_open: false,

	_contentWrapOpenClasses: null,
	_modalOpenClasses: null,

	open: function( options ){
		var self = this,
			o = self.options,
			complete = function(){
				self.element.add( self._wrapper ).unbind( self._transitionEndEvents , complete );
				self.element.addClass( o.classes.openComplete );
				self._wrapper.addClass( o.classes.contentWrapOpenComplete );
				self._positionPanel();
				self._bindFixListener();
				self._trigger( "open" );
			};

		self._trigger( "beforeopen" );

		if ( $.support.cssTransitions && o.animate ) {
			self.element.add( self._wrapper ).on( self._transitionEndEvents , complete );
		} else{
			setTimeout( complete , 0 );
		}
		self._page.addClass( self.options.classes.pageBlock );
		self.element.removeClass( o.classes.panelClosed );
		self.element.addClass( o.classes.panelOpen );
		self._contentWrapOpenClasses = self._getPosDisplayClasses( o.classes.contentWrap );
		self._wrapper.removeClass( o.classes.contentWrapClosed );
		self._wrapper.addClass( self._contentWrapOpenClasses + " " + o.classes.contentWrapOpen );
		self._modalOpenClasses = self._getPosDisplayClasses( o.classes.modal ) + " " + o.classes.modalOpen;
		self._modal.addClass( self._modalOpenClasses );

		self._open = true;

	},

	close: function( immediate ){
		var o = this.options,
			self = this,
			complete = function(){
				self.element.add( self._wrapper ).unbind( self._transitionEndEvents , complete );
				self.element.addClass( o.classes.panelClosed );
				self._wrapper.removeClass( self._contentWrapOpenClasses );
				self._wrapper.addClass( o.classes.contentWrapClosed );
				self._page.removeClass( self.options.classes.pageBlock );
				self._fixPanel();
				self._unbindFixListener();
				self._trigger( "close" );
			};

		self._trigger( "beforeclose" );

		if ( $.support.cssTransform3d && o.animate ) {
			self.element.add( self._wrapper ).on( self._transitionEndEvents , complete );
		} else{
			setTimeout( complete , 0 );
		}

		self.element.removeClass( o.classes.panelOpen + " " + o.classes.openComplete );
		self._modal.removeClass( self._modalOpenClasses );
		self._wrapper.removeClass( o.classes.contentWrapOpen + " " + o.classes.contentWrapOpenComplete );

		self._open = false;
	},

	toggle: function( options ){
		this[ this._open ? "close" : "open" ]();
	},

	_transitionEndEvents: "webkitTransitionEnd oTransitionEnd otransitionend transitionend msTransitionEnd",

	_destroy: function(){
		var classes = this.options.classes,
			hasOtherSiblingPanels = this.element.siblings( "." + classes.panel ).length;

		// create
		if( !hasOtherSiblingPanels ) {
			this._wrapper.children().unwrap();
			this._page.removeClass( classes.pageChildAnimations )
				.find( "a" ).unbind( "panelopen panelclose" );
		} else if( this._open ) {
			this._wrapper.removeClass( [ classes.contentWrapOpen, classes.contentWrapOpenComplete ].join( " " ) );
		}

		this.element.removeClass( [ this._getPanelClasses(), classes.panelAnimate ].join( " " ) )
			.off( "swipe.panel" )
			.off( "panelbeforeopen" )
			.off( "panelbeforehide" )
			.off( "keyup.panel" );

		this._closeLink.off( "click.panel" );

		if( this._modal ) {
			this._modal.remove();
		}

		// open and close
		this.element.off( this._transitionEndEvents )
			.removeClass( [ classes.openComplete, classes.panelUnfixed, classes.panelClosed, classes.panelOpen ].join( " " ) );
		this._page.removeClass( classes.pageBlock );
	}
});

//auto self-init widgets
$( document ).bind( "pagecreate create", function( e ) {
	$.mobile.panel.prototype.enhanceWithin( e.target );
});

})( jQuery );
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");

<commit_msg>Panel: open and close should do nothing if it is already opened / closed. calling close on a closed panel causes the transition to never complete until open which causes the panel to close again.<commit_after>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Responsive presentation and behavior for HTML data panels
//>>label: Panel
//>>group: Widgets
//>>css.structure: ../css/structure/jquery.mobile.panel.css
//>>css.theme: ../css/themes/default/jquery.mobile.theme.css

define( [ "jquery", "../jquery.mobile.widget", "./page", "./page.sections" ], function( $ ) {
//>>excludeEnd("jqmBuildExclude");
(function( $, undefined ) {

$.widget( "mobile.panel", $.mobile.widget, {
	options: {
		classes: {
			panel: "ui-panel",
			panelOpen: "ui-panel-open",
			panelClosed: "ui-panel-closed",
			modal: "ui-panel-dismiss",
			modalOpen: "ui-panel-dismiss-open",
			openComplete: "ui-panel-open-complete",
			contentWrap: "ui-panel-content-wrap",
			contentWrapOpen: "ui-panel-content-wrap-open",
			contentWrapClosed: "ui-panel-content-wrap-closed",
			panelUnfixed: "ui-panel-unfixed",
			contentWrapOpenComplete: "ui-panel-content-wrap-open-complete",
			pageBlock: "ui-panel-page-block",
			pagePanel: "ui-page-panel",
			pageChildAnimations: "ui-page-panel-animate"
		},
		animate: true,
		theme: null,
		position: "left",
		dismissible: true,
		display: "overlay", //accepts reveal, push, overlay
		initSelector: ":jqmData(role='panel')",
		swipeClose: true
	},

	_panelID: null,
	_closeLink: null,
	_page: null,
	_modal: null,
	_wrapper: null,

	_create: function() {
		var self = this,
			$el = self.element,
			_getWrapper = function(){
				var $wrapper = self._page.find( "." + self.options.classes.contentWrap );
				if( $wrapper.length === 0 ){
					$wrapper = self._page.find( ".ui-header, .ui-content, .ui-footer" ).wrapAll( '
' ).parent();
				}
				return $wrapper;
			};

		// expose some private props to other methods
		self._panelID = $el.attr( "id" );
		self._closeLink = $el.find( ":jqmData(rel='close')" );
		self._page = $el.closest( ":jqmData(role='page')" );
		self._wrapper = _getWrapper();
		self._addPanelClasses();
		self._wrapper.addClass( this.options.classes.contentWrapClosed );

		// if animating, add the class to do so
		if ( $.support.cssTransform3d && self.options.animate ) {
			this.element.add( self._wrapper ).addClass( "ui-panel-animate" );
			self._page.addClass( this.options.classes.pageChildAnimations );
		}

		self._bindCloseEvents();
		self._bindLinkListeners();
		self._bindPageEvents();

		if( self.options.dismissible ){
			self._createModal();
		}

	},

	_createModal: function( options ){
		var self = this;
		self._modal = $( "

" )
			.on( "mousedown" , function(){
				self.close();
			})
			.appendTo( this._page );
	},

	_getPosDisplayClasses: function( prefix ){
		return prefix + "-position-" + this.options.position + " " + prefix + "-display-" + this.options.display;
	},

	_getPanelClasses: function(){
		var panelClasses = this.options.classes.panel +
						" " + this._getPosDisplayClasses( this.options.classes.panel ) +
						" " + this.options.classes.panelClosed;

		if( this.options.theme ){
			panelClasses += " ui-body-" + this.options.theme;
		}

		if( $.support.cssTransform3d ){
			panelClasses += " ui-panel-3dtransforms";
		}
		return panelClasses;
	},

	_addPanelClasses: function(){
		this.element.addClass( this._getPanelClasses() );
	},

	_bindCloseEvents: function(){
		var self = this;
		self._closeLink.on( "click.panel" , function( e ){
			e.preventDefault();
			self.close();
			return false;
		});
	},

	_positionPanel: function(){
		if( this.element.height() > $.mobile.getScreenHeight() ){
			this._unfixPanel();
			this._scrollIntoView();
		}
		else {
			this._fixPanel();
		}
	},

	_scrollIntoView: function(){
		if( $(window).scrollTop() > $.mobile.getScreenHeight() ){
			window.scrollTo( 0, 0);
		}
	},

	_bindFixListener: function(){
		this._on( $( window ), { "throttledresize": "_positionPanel" });
	},

	_unbindFixListener: function(){
		this._off( $( window ), "throttledresize" );
	},

	_unfixPanel: function(){
		this.element.addClass( this.options.classes.panelUnfixed );
	},

	_fixPanel: function(){
		this.element.removeClass( this.options.classes.panelUnfixed );
	},

	_bindLinkListeners: function(){
		var self = this;

		this._page.on( "click.panel" , "a", function( e ) {
			if( this.href.split( "#" )[ 1 ] === self._panelID ){
				e.preventDefault();
				var $link = $( this );
				$link.addClass( $.mobile.activeBtnClass );
				self.element.one( "panelopen panelclose", function(){
					$link.removeClass( $.mobile.activeBtnClass );
				});
				self.toggle();
				return false;
			}
		});
	},

	_bindPageEvents: function(){
		var self = this;
		if( this.option.swipeClose ){
			self.element
				// on swipe, close the panel (should swipe open too?)
				.on( "swipe.panel" , function( e ){
					self.close( true );
				});
		}
		self._page
			// Close immediately if another panel on the page opens
			.on( "panelbeforeopen", function( e ){
				if( self._open && e.target !== self.element[ 0 ] ){
					self.close( true );
				}
			})
			// clean up open panels after page hide
			.on(  "pagebeforehide", function( e ) {
				if( self._open ){
					self.close( true );
				}
			})
			// on escape, close? might need to have a target check too...
			.on( "keyup.panel", function( e ) {
				if( e.keyCode === 27 && self._open ){
					self.close( true );
				}
			});
	},

	// state storage of open or closed
	_open: false,

	_contentWrapOpenClasses: null,
	_modalOpenClasses: null,

	open: function( options ){
		if( !this._open ){
			var self = this,
				o = self.options,
				complete = function(){
					self.element.add( self._wrapper ).unbind( self._transitionEndEvents , complete );
					self.element.addClass( o.classes.openComplete );
					self._wrapper.addClass( o.classes.contentWrapOpenComplete );
					self._positionPanel();
					self._bindFixListener();
					self._trigger( "open" );
				};

			self._trigger( "beforeopen" );

			if ( $.support.cssTransitions && o.animate ) {
				self.element.add( self._wrapper ).on( self._transitionEndEvents , complete );
			} else{
				setTimeout( complete , 0 );
			}
			self._page.addClass( self.options.classes.pageBlock );
			self.element.removeClass( o.classes.panelClosed );
			self.element.addClass( o.classes.panelOpen );
			self._contentWrapOpenClasses = self._getPosDisplayClasses( o.classes.contentWrap );
			self._wrapper.removeClass( o.classes.contentWrapClosed );
			self._wrapper.addClass( self._contentWrapOpenClasses + " " + o.classes.contentWrapOpen );
			self._modalOpenClasses = self._getPosDisplayClasses( o.classes.modal ) + " " + o.classes.modalOpen;
			self._modal.addClass( self._modalOpenClasses );

			self._open = true;
		}
	},

	close: function( immediate ){
		if( this._open ){
			var o = this.options,
				self = this,
				complete = function(){
					self.element.add( self._wrapper ).unbind( self._transitionEndEvents , complete );
					self.element.addClass( o.classes.panelClosed );
					self._wrapper.removeClass( self._contentWrapOpenClasses );
					self._wrapper.addClass( o.classes.contentWrapClosed );
					self._page.removeClass( self.options.classes.pageBlock );
					self._fixPanel();
					self._unbindFixListener();
					self._trigger( "close" );
				};

			self._trigger( "beforeclose" );

			if ( $.support.cssTransform3d && o.animate ) {
				self.element.add( self._wrapper ).on( self._transitionEndEvents , complete );
			} else{
				setTimeout( complete , 0 );
			}

			self.element.removeClass( o.classes.panelOpen + " " + o.classes.openComplete );
			self._modal.removeClass( self._modalOpenClasses );
			self._wrapper.removeClass( o.classes.contentWrapOpen + " " + o.classes.contentWrapOpenComplete );

			self._open = false;
		}
	},

	toggle: function( options ){
		this[ this._open ? "close" : "open" ]();
	},

	_transitionEndEvents: "webkitTransitionEnd oTransitionEnd otransitionend transitionend msTransitionEnd",

	_destroy: function(){
		var classes = this.options.classes,
			hasOtherSiblingPanels = this.element.siblings( "." + classes.panel ).length;

		// create
		if( !hasOtherSiblingPanels ) {
			this._wrapper.children().unwrap();
			this._page.removeClass( classes.pageChildAnimations )
				.find( "a" ).unbind( "panelopen panelclose" );
		} else if( this._open ) {
			this._wrapper.removeClass( [ classes.contentWrapOpen, classes.contentWrapOpenComplete ].join( " " ) );
		}

		this.element.removeClass( [ this._getPanelClasses(), classes.panelAnimate ].join( " " ) )
			.off( "swipe.panel" )
			.off( "panelbeforeopen" )
			.off( "panelbeforehide" )
			.off( "keyup.panel" );

		this._closeLink.off( "click.panel" );

		if( this._modal ) {
			this._modal.remove();
		}

		// open and close
		this.element.off( this._transitionEndEvents )
			.removeClass( [ classes.openComplete, classes.panelUnfixed, classes.panelClosed, classes.panelOpen ].join( " " ) );
		this._page.removeClass( classes.pageBlock );
	}
});

//auto self-init widgets
$( document ).bind( "pagecreate create", function( e ) {
	$.mobile.panel.prototype.enhanceWithin( e.target );
});

})( jQuery );
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");

<|endoftext|>


<commit_before>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Responsive presentation and behavior for HTML data panels
//>>label: Panel
//>>group: Widgets
//>>css.structure: ../css/structure/jquery.mobile.panel.css
//>>css.theme: ../css/themes/default/jquery.mobile.theme.css

define( [ "jquery", "../jquery.mobile.widget", "./page", "./page.sections" ], function( $ ) {
//>>excludeEnd("jqmBuildExclude");
(function( $, undefined ) {

$.widget( "mobile.panel", $.mobile.widget, {
	options: {
		classes: {
			panel: "ui-panel",
			panelOpen: "ui-panel-open",
			panelClosed: "ui-panel-closed",
			modal: "ui-panel-dismiss",
			modalOpen: "ui-panel-dismiss-open",
			openComplete: "ui-panel-open-complete",
			contentWrap: "ui-panel-content-wrap",
			contentWrapOpen: "ui-panel-content-wrap-open",
			panelUnfixed: "ui-panel-unfixed",
			contentWrapOpenComplete: "ui-panel-content-wrap-open-complete",
			pageBlock: "ui-panel-page-block",
			pagePanel: "ui-page-panel",
			pageChildAnimations: "ui-page-panel-animate"
		},
		animate: true,
		theme: null,
		position: "left",
		dismissible: true,
		display: "overlay", //accepts reveal, push, overlay
		initSelector: ":jqmData(role='panel')"
	},

	_panelID: null,
	_closeLink: null,
	_page: null,
	_modal: null,
	_wrapper: null,

	_create: function() {
		var self = this,
			$el = self.element,
			_getWrapper = function(){
				var $wrapper = self._page.find( "." + self.options.classes.contentWrap );
				if( $wrapper.length === 0 ){
					$wrapper = self._page.find( ".ui-header, .ui-content, .ui-footer" ).wrapAll( '
' ).parent();
				}
				return $wrapper;
			};

		// expose some private props to other methods
		self._panelID = $el.attr( "id" );
		self._closeLink = $el.find( ":jqmData(rel='close')" );
		self._page = $el.closest( ":jqmData(role='page')" );
		self._wrapper = _getWrapper();
		self._addPanelClasses();

		// if animating, add the class to do so
		if ( $.support.cssTransitions && self.options.animate ) {
			this.element.add( self._wrapper ).addClass( "ui-panel-animate" );
			self._page.addClass( this.options.classes.pageChildAnimations );
		}

		self._bindCloseEvents();
		self._bindLinkListeners();
		self._bindPageEvents();

		if( self.options.dismissible ){
			self._createModal();
		}

		// move the panel to the right place in the DOM
		self.element[ this.options.position === "left" ? "insertBefore" : "insertAfter" ]( self._wrapper );

		self._trigger( "create" );
	},

	_createModal: function( options ){
		var self = this;
		self._modal = $( "

" )
			.on( "mousedown" , function(){
				self.close();
			})
			.appendTo( this._page );
	},

	_getPosDisplayClasses: function( prefix ){
		return prefix + "-position-" + this.options.position + " " + prefix + "-display-" + this.options.display;
	},

	_addPanelClasses: function(){
		var panelClasses = this.options.classes.panel +
						" " + this._getPosDisplayClasses( this.options.classes.panel ) +
						" " + this.options.classes.panelClosed;

		if( this.options.theme ){
			panelClasses += " ui-body-" + this.options.theme;
		}

		this.element.addClass( panelClasses );
	},

	_bindCloseEvents: function(){
		var self = this;
		self._closeLink.on( "vclick" , function( e ){
			e.preventDefault();
			self.close();
			return false;
		});
	},

	_positionPanel: function(){
		if( this.element.height() > $.mobile.getScreenHeight() ){
			this._unfixPanel();
		}
		else {
			this._fixPanel();
		}
	},

	_bindFixListener: function(){
		var self = this;
		$( window ).on( "throttledresize.panel", function(){
			self._positionPanel();
		} );
	},

	_unbindFixListener: function(){
		$( window ).off( "throttledresize.panel" );
	},

	_unfixPanel: function(){
		this.element.addClass( this.options.classes.panelUnfixed );
	},

	_fixPanel: function(){
		this.element.removeClass( this.options.classes.panelUnfixed );
	},

	_bindLinkListeners: function(){
		var self = this;

		$( document ).on( "vclick" , "a", function( e ) {
			if( this.href.split( "#" )[ 1 ] === self._panelID ){
				e.preventDefault();
				var $link = $( this );
				$link.addClass( $.mobile.activeBtnClass );
				self.element.one( "panelopen panelclose", function(){
					$link.removeClass( $.mobile.activeBtnClass );
				});
				self.toggle();
				return false;
			}
		});
	},

	_bindPageEvents: function(){
		var self = this;

		$( window )
			// on swipe, close the panel (should swipe open too?)
			.on( "swipe" , function( e ){
				self.close( true );
			});

		self._page
			// Close immediately if another panel on the page opens
			.on( "panelbeforeopen", function( e ){
				if( self._open && e.target !== self.element ){
					self.close( true );
				}
			})
			// clean up open panels after page hide
			.on(  "panelbeforehide", function( e ) {
				self.close( true );
			})
			// on escape, close? might need to have a target check too...
			.on( "keyup", function( e ) {
				if( e.keyCode === 27 && self._open ){
					self.close( true );
				}
			});
	},

	// state storage of open or closed
	_open: false,

	_contentWrapOpenClasses: null,
	_modalOpenClasses: null,

	open: function( options ){
		var self = this,
			o = self.options,
			complete = function(){
				self.element.add( self._wrapper ).unbind( self._transitionEndEvents , complete );
				self.element.addClass( o.classes.openComplete );
				self._wrapper.addClass( o.classes.contentWrapOpenComplete );
				self._positionPanel();
				self._bindFixListener();
				self._trigger( "open" );
			};

		self._trigger( "beforeopen" );

		if ( $.support.cssTransitions && o.animate ) {
			self.element.add( self._wrapper ).on( self._transitionEndEvents , complete );
		} else{
			setTimeout( complete , 0 );
		}
		self._page.addClass( self.options.classes.pageBlock );
		self.element.removeClass( o.classes.panelClosed );
		self.element.addClass( o.classes.panelOpen );
		self._contentWrapOpenClasses = self._getPosDisplayClasses( o.classes.contentWrap );
		self._wrapper.addClass( self._contentWrapOpenClasses + " " + o.classes.contentWrapOpen );
		self._modalOpenClasses = self._getPosDisplayClasses( o.classes.modal ) + " " + o.classes.modalOpen;
		self._modal.addClass( self._modalOpenClasses );

		self._open = true;

	},

	close: function( immediate ){
		var o = this.options,
			self = this,
			complete = function(){
				self.element.add( self._wrapper ).unbind( self._transitionEndEvents , complete );
				self.element.addClass( o.classes.panelClosed );
				self._wrapper.removeClass( self._contentWrapOpenClasses );
				self._page.removeClass( self.options.classes.pageBlock );
				self._fixPanel();
				self._unbindFixListener();
				self._trigger( "close" );
				complete = null;
			};

		self._trigger( "beforeclose" );

		if ( $.support.cssTransitions && o.animate ) {
			self.element.add( self._wrapper ).on( self._transitionEndEvents , complete );
		} else{
			setTimeout( complete , 0 );
		}

		self.element.removeClass( o.classes.panelOpen + " " + o.classes.openComplete );
		self._modal.removeClass( self._modalOpenClasses );
		self._wrapper.removeClass( o.classes.contentWrapOpen + " " + o.classes.contentWrapOpenComplete );

		self._open = false;
	},

	toggle: function( options ){
		this[ this._open ? "close" : "open" ]();
	},

	_transitionEndEvents: "webkitTransitionEnd oTransitionEnd otransitionend transitionend msTransitionEnd",

	destroy: function(){
		// unbind events, remove generated elements, remove classes, remove data
	}
});

//auto self-init widgets
$( document ).bind( "pagecreate create", function( e ) {
	$.mobile.panel.prototype.enhanceWithin( e.target );
});

})( jQuery );
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");

<commit_msg>fixed a comparison in the check for whether a panelbeforeopen event is this panel or not<commit_after>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Responsive presentation and behavior for HTML data panels
//>>label: Panel
//>>group: Widgets
//>>css.structure: ../css/structure/jquery.mobile.panel.css
//>>css.theme: ../css/themes/default/jquery.mobile.theme.css

define( [ "jquery", "../jquery.mobile.widget", "./page", "./page.sections" ], function( $ ) {
//>>excludeEnd("jqmBuildExclude");
(function( $, undefined ) {

$.widget( "mobile.panel", $.mobile.widget, {
	options: {
		classes: {
			panel: "ui-panel",
			panelOpen: "ui-panel-open",
			panelClosed: "ui-panel-closed",
			modal: "ui-panel-dismiss",
			modalOpen: "ui-panel-dismiss-open",
			openComplete: "ui-panel-open-complete",
			contentWrap: "ui-panel-content-wrap",
			contentWrapOpen: "ui-panel-content-wrap-open",
			panelUnfixed: "ui-panel-unfixed",
			contentWrapOpenComplete: "ui-panel-content-wrap-open-complete",
			pageBlock: "ui-panel-page-block",
			pagePanel: "ui-page-panel",
			pageChildAnimations: "ui-page-panel-animate"
		},
		animate: true,
		theme: null,
		position: "left",
		dismissible: true,
		display: "overlay", //accepts reveal, push, overlay
		initSelector: ":jqmData(role='panel')"
	},

	_panelID: null,
	_closeLink: null,
	_page: null,
	_modal: null,
	_wrapper: null,

	_create: function() {
		var self = this,
			$el = self.element,
			_getWrapper = function(){
				var $wrapper = self._page.find( "." + self.options.classes.contentWrap );
				if( $wrapper.length === 0 ){
					$wrapper = self._page.find( ".ui-header, .ui-content, .ui-footer" ).wrapAll( '
' ).parent();
				}
				return $wrapper;
			};

		// expose some private props to other methods
		self._panelID = $el.attr( "id" );
		self._closeLink = $el.find( ":jqmData(rel='close')" );
		self._page = $el.closest( ":jqmData(role='page')" );
		self._wrapper = _getWrapper();
		self._addPanelClasses();

		// if animating, add the class to do so
		if ( $.support.cssTransitions && self.options.animate ) {
			this.element.add( self._wrapper ).addClass( "ui-panel-animate" );
			self._page.addClass( this.options.classes.pageChildAnimations );
		}

		self._bindCloseEvents();
		self._bindLinkListeners();
		self._bindPageEvents();

		if( self.options.dismissible ){
			self._createModal();
		}

		// move the panel to the right place in the DOM
		self.element[ this.options.position === "left" ? "insertBefore" : "insertAfter" ]( self._wrapper );

		self._trigger( "create" );
	},

	_createModal: function( options ){
		var self = this;
		self._modal = $( "

" )
			.on( "mousedown" , function(){
				self.close();
			})
			.appendTo( this._page );
	},

	_getPosDisplayClasses: function( prefix ){
		return prefix + "-position-" + this.options.position + " " + prefix + "-display-" + this.options.display;
	},

	_addPanelClasses: function(){
		var panelClasses = this.options.classes.panel +
						" " + this._getPosDisplayClasses( this.options.classes.panel ) +
						" " + this.options.classes.panelClosed;

		if( this.options.theme ){
			panelClasses += " ui-body-" + this.options.theme;
		}

		this.element.addClass( panelClasses );
	},

	_bindCloseEvents: function(){
		var self = this;
		self._closeLink.on( "vclick" , function( e ){
			e.preventDefault();
			self.close();
			return false;
		});
	},

	_positionPanel: function(){
		if( this.element.height() > $.mobile.getScreenHeight() ){
			this._unfixPanel();
		}
		else {
			this._fixPanel();
		}
	},

	_bindFixListener: function(){
		var self = this;
		$( window ).on( "throttledresize.panel", function(){
			self._positionPanel();
		} );
	},

	_unbindFixListener: function(){
		$( window ).off( "throttledresize.panel" );
	},

	_unfixPanel: function(){
		this.element.addClass( this.options.classes.panelUnfixed );
	},

	_fixPanel: function(){
		this.element.removeClass( this.options.classes.panelUnfixed );
	},

	_bindLinkListeners: function(){
		var self = this;

		$( document ).on( "vclick" , "a", function( e ) {
			if( this.href.split( "#" )[ 1 ] === self._panelID ){
				e.preventDefault();
				var $link = $( this );
				$link.addClass( $.mobile.activeBtnClass );
				self.element.one( "panelopen panelclose", function(){
					$link.removeClass( $.mobile.activeBtnClass );
				});
				self.toggle();
				return false;
			}
		});
	},

	_bindPageEvents: function(){
		var self = this;

		$( window )
			// on swipe, close the panel (should swipe open too?)
			.on( "swipe" , function( e ){
				self.close( true );
			});

		self._page
			// Close immediately if another panel on the page opens
			.on( "panelbeforeopen", function( e ){
				if( self._open && e.target !== self.element[ 0 ] ){
					self.close( true );
				}
			})
			// clean up open panels after page hide
			.on(  "panelbeforehide", function( e ) {
				self.close( true );
			})
			// on escape, close? might need to have a target check too...
			.on( "keyup", function( e ) {
				if( e.keyCode === 27 && self._open ){
					self.close( true );
				}
			});
	},

	// state storage of open or closed
	_open: false,

	_contentWrapOpenClasses: null,
	_modalOpenClasses: null,

	open: function( options ){
		var self = this,
			o = self.options,
			complete = function(){
				self.element.add( self._wrapper ).unbind( self._transitionEndEvents , complete );
				self.element.addClass( o.classes.openComplete );
				self._wrapper.addClass( o.classes.contentWrapOpenComplete );
				self._positionPanel();
				self._bindFixListener();
				self._trigger( "open" );
			};

		self._trigger( "beforeopen" );

		if ( $.support.cssTransitions && o.animate ) {
			self.element.add( self._wrapper ).on( self._transitionEndEvents , complete );
		} else{
			setTimeout( complete , 0 );
		}
		self._page.addClass( self.options.classes.pageBlock );
		self.element.removeClass( o.classes.panelClosed );
		self.element.addClass( o.classes.panelOpen );
		self._contentWrapOpenClasses = self._getPosDisplayClasses( o.classes.contentWrap );
		self._wrapper.addClass( self._contentWrapOpenClasses + " " + o.classes.contentWrapOpen );
		self._modalOpenClasses = self._getPosDisplayClasses( o.classes.modal ) + " " + o.classes.modalOpen;
		self._modal.addClass( self._modalOpenClasses );

		self._open = true;

	},

	close: function( immediate ){
		var o = this.options,
			self = this,
			complete = function(){
				self.element.add( self._wrapper ).unbind( self._transitionEndEvents , complete );
				self.element.addClass( o.classes.panelClosed );
				self._wrapper.removeClass( self._contentWrapOpenClasses );
				self._page.removeClass( self.options.classes.pageBlock );
				self._fixPanel();
				self._unbindFixListener();
				self._trigger( "close" );
				complete = null;
			};

		self._trigger( "beforeclose" );

		if ( $.support.cssTransitions && o.animate ) {
			self.element.add( self._wrapper ).on( self._transitionEndEvents , complete );
		} else{
			setTimeout( complete , 0 );
		}

		self.element.removeClass( o.classes.panelOpen + " " + o.classes.openComplete );
		self._modal.removeClass( self._modalOpenClasses );
		self._wrapper.removeClass( o.classes.contentWrapOpen + " " + o.classes.contentWrapOpenComplete );

		self._open = false;
	},

	toggle: function( options ){
		this[ this._open ? "close" : "open" ]();
	},

	_transitionEndEvents: "webkitTransitionEnd oTransitionEnd otransitionend transitionend msTransitionEnd",

	destroy: function(){
		// unbind events, remove generated elements, remove classes, remove data
	}
});

//auto self-init widgets
$( document ).bind( "pagecreate create", function( e ) {
	$.mobile.panel.prototype.enhanceWithin( e.target );
});

})( jQuery );
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");

<|endoftext|>