<commit_before>/**
 * Created by andrew on 3/28/15.
 */
runEditWidget = function(truckId, locations, categories, options) {
  var lastStop, $editStop = $("#edit-stop"), locationEndpoint = '/admin/locations';
  options = options || {};

  if (options["vendorEndpoints"]) {
    locationEndpoint = '/locations';
  }

  var $startTimeInput = $("#startTimeInput"), $endTimeInput = $("#endTimeInput");

  $startTimeInput.blur(function (e) {
    var startTime = fromDate($startTimeInput.val()),
        endTime = fromDate($endTimeInput.val());
    if (startTime.getTime() >= endTime.getTime()) {
      var diff = startTime.getTime() + (60 * 60 * 2000);
      $endTimeInput.val(toDate(new Date(diff)));
    }
  });

  $editStop.keypress(function(e) {
    if (e.which == 13) {
      e.preventDefault();
      $("#saveButton").click();
    }
  });

  // Type-ahead related stuff
  var substringMatcher = function(strs) {
    return function findMatches(q, cb) {
      var matches, substrRegex;
      matches = [];
      substrRegex = new RegExp(q, 'i');
      $.each(strs, function(i, str) {
        if (substrRegex.test(str)) {
          matches.push({ value: str });
        }
      });
      cb(matches);
    };
  };

  $("#locationInput").typeahead({
    hint: true,
    highlight: true,
    minLength: 1
  },{ name: 'locations', displayKey: 'value', source: substringMatcher(locations)});

  $editStop.on("shown.bs.modal", function() {
    $startTimeInput.focus();
  });

  function populateDialog(stop) {
    $startTimeInput.val(stop.startTimeH);
    $endTimeInput.val( stop.endTimeH);
    $("#locationInput").val(stop.location.name);
    $("#lockStop").val( stop.locked);
  }

  function invokeEditDialog(stop, afterwards) {
    populateDialog(stop);
    $("#locationInputGroup").removeClass("has-error");
    $("#truck-schedule-alert").addClass("hidden");
    $("#edit-stop").modal({ show: true, keyboard: true, backdrop: true});
    var $saveButton = $("#saveButton");
    $saveButton.unbind('click');
    $saveButton.click(function (e) {
      e.preventDefault();
      var $btn = $(this).button('loading')
      stop.startTime =  $startTimeInput.val();
      stop.endTime =  $endTimeInput.val();
      var locationName = $("#locationInput").val();
      var oldLocation = stop.location;
      if (locationName != stop.location.name) {
        stop.locationName = locationName;
        delete stop.location;
      }
      stop.truckId = truckId;
      stop.locked = $("#lockStop").is(":checked");
      if(locationName.length == 0) {
        $("#locationInputGroup").addClass("has-error");
        $("#truck-schedule-error").html("No location specified");
        $btn.button('reset')
      } else {
        $.ajax({
          url: "/services/v2/stops",
          type: 'PUT',
          contentType: 'application/json',
          data: JSON.stringify(stop),
          complete: function () {
          },
          error: function(e) {
            var obj = JSON.parse(e.responseText);
            $("#truck-schedule-error").html(obj.error);
            $("#truck-schedule-alert").removeClass("hidden");
            if (/location/i.exec(obj.error)) {
              $("#locationInputGroup").addClass("has-error");
            }
            if (/start time/i.exec(obj.error)) {
              $("#startTimeInputGroup").addClass("has-error");
            }
            if (/end time/i.exec(obj.error)) {
              $("#endTimeInputGroup").addClass("has-error");
            }
            stop.location = oldLocation;
            $btn.button('reset')
          },
          success: function() {
            $("#edit-stop").modal('hide');
            $btn.button('reset');
            afterwards();
          }
        });
      }
    });
    var $cancelButton = $("#cancelButton");
    $cancelButton.unbind("click");
    $cancelButton.click(function (e) {
      e.preventDefault();
      $("#edit-stop").modal('hide');
    });
  }

  function pad(t) {
    t = String(t)
    if (t.length == 1) {
      return "0" + t;
    }
    return t;
  }

  function fromDate(dateString) {
    var year = parseInt(dateString.substring(0, 4)),
        month = parseInt(dateString.substring(5, 7))-1,
        day = parseInt(dateString.substring(8, 10)),
        hour = parseInt(dateString.substring(11, 13)),
        min = parseInt(dateString.substring(14, 16));
    return new Date(year, month, day, hour, min, 0, 0);
  }

  function toDate(d) {
    return (d.getFullYear()) + "-" + pad(d.getMonth()+1) + "-" + pad(d.getDate()) + "T" + pad(d.getHours()) + ":" + pad(d.getMinutes());
  }

  function refreshSchedule() {
    var scheduleTable = $("#scheduleTable");
    scheduleTable.empty();
    lastStop = null;
    var d = new Date();
    d.setHours(0);
    d.setMinutes(0);
    d.setSeconds(0);
    var tomorrow = d.getTime() + 86400000;

    $.ajax({
      url: '/services/v2/stops?truck=' + truckId,
      type: 'GET',
      dataType: 'json',
      success: function (schedule) {
        var now = new Date().getTime(), numStops = schedule.length;
        var prevHadStart = false;
        $.each(schedule, function (truckIndex, stop) {
          if (stop.startMillis < tomorrow) {
            lastStop = stop;
          }
          var labels = (stop.locked) ? " locked" :
              "";
          var crazyDuration = stop.durationMillis < 0 || stop.durationMillis > 43200000;
          var showControls = stop.startMillis < tomorrow || stop.origin != 'VENDORCAL';;
          labels += (stop.fromBeacon) ? " beacon" : "";
          var truckCountLink = stop.totalTruckCount < 2 ? "" : "" + stop.totalTruckCount + "";
          var buf = "
" + stop.startDate + "	" + stop.startTime + "	" + stop.endTime +
              "	" + stop.duration + "	" + stop.origin + "	"
              + stop.location.name + "" + labels + "	" + truckCountLink +"	";
          if (showControls) {
            if (!prevHadStart && now < stop.startMillis) {
              prevHadStart = true;
              buf = buf + "<button class='btn btn-default' id='truckStartNow" + truckIndex +
              "' class='btn success'>Start Now</button>"
            } else if (now >= stop.startMillis && now < stop.endMillis) {
              buf = buf + "<button class='btn btn-default' id='truckEndNow" + truckIndex +
              "' class='btn warning'>End Now</button>";
            }
          }
          buf += " 	";
          if (showControls) {
            buf = buf + "
<button class='btn btn-default' id='truckDelete" + truckIndex +
            "' class='btn '> Delete</button> <button class='btn btn-default' id='truckEdit" +
            truckIndex + "'> Edit</button>

";
          }
          scheduleTable.append(buf);
          $("#truckEdit" + truckIndex).click(function (e) {
            stop["startDate"] = toDate(new Date(stop["startMillis"]));
            stop["endDate"] = toDate(new Date(stop["endMillis"]));
            invokeEditDialog(stop, refreshSchedule);
          });

          function timeUpdateMaker(useStart) {
            return function (e) {
              e.preventDefault();
              if (useStart) {
                stop.startTime = toDate(new Date());
                stop["endTime"] = toDate(new Date(stop["endMillis"]));
              } else {
                stop.startTime = toDate(new Date(stop["startMillis"]));
                stop.endTime = toDate(new Date());
              }
              stop.truckId = truckId;
              $.ajax({
                url: "/services/v2/stops",
                type: 'PUT',
                contentType: 'application/json',
                data: JSON.stringify(stop),
                success: refreshSchedule
              });
            }
          }

          $("#truckStartNow" + truckIndex).click(timeUpdateMaker(true));
          $("#truckEndNow" + truckIndex).click(timeUpdateMaker(false));
          $("#truckDelete" + truckIndex).click(function (e) {
            e.preventDefault();
            $.ajax({
              url: "/services/v2/stops/" + stop.id,
              type: 'DELETE',
              complete: function () {
                refreshSchedule();
              }
            })
          });
        });
        $(function () {
          $('[data-toggle="popover"]').popover()
        });
      }
    });
  }

  function numStops() {
    return $("#scheduleTable").children().length;
  }

  function hasCategory(category) {
    return categories.indexOf(category) >= 0;
  }

  function newStop() {
    var now = new Date();
    if ((!hasCategory("Breakfast") && numStops() == 0) && now.getHours() < 10 ) {
      now.setHours(11);
      now.setMinutes(0);
    }
    if (numStops() > 0 && lastStop != null) {
      now = new Date(lastStop["endMillis"] + 60000)
    }
    var minutes = now.getMinutes();
    if (minutes != 0) {
      minutes = Math.ceil(minutes / 15) * 15;
      if (minutes <= 45) {
        now.setMinutes(minutes);
      } else {
        now = new Date(now.getTime() + (60 * 60 * 1000));
        now.setMinutes(0);
      }
    }
    var today = toDate(now), later = toDate(new Date(now.getTime() + (2*60*60*1000)));
    invokeEditDialog({truckId: truckId, locationName: "", location: { name: ""},
          startTimeH: today, endTimeH: later },
        refreshSchedule);
  }

  $("#addButton").click(function (e) {
    newStop();
  });

  $(document).keypress(function(e) {
    if (e.which == 110 && $editStop.css("display") == 'none') {
      e.preventDefault();
      newStop();
    }
  });

  refreshSchedule();
  var $offTheRoadButton = $("#offRoadButton");
  if (options["vendorEndpoints"]) {
    $offTheRoadButton.css("display", "none");
  }
  if (!options["hasCalendar"]) {
    $("#recacheButton").addClass("hidden");
  }
  if (options["truckName"]) {
    $("#truck-widget-header").html("Schedule for " + options["truckName"]);
  }
  $offTheRoadButton.click(function (evt) {
    $.ajax({
      url: "/admin/trucks/" + truckId + "/offtheroad",
      type: 'POST',
      context: document.body,
      dataType: 'json',
      complete: function (data) {
        refreshSchedule();
      }});
  });

  var $recacheButton = $("#recacheButton");
  $recacheButton.click(function (evt) {
    $recacheButton.empty();
    $recacheButton.append("Refreshing...")
    $.ajax({
      url: "/cron/recache?truck=" + truckId,
      context: document.body,
      dataType: 'json',
      complete: function () {
        $recacheButton.empty();
        $recacheButton.append("Refresh")
      },
      success: function (data) {
        refreshSchedule();
      }});
  });
};<commit_msg>Fix truck edit widget not escaping single quotes<commit_after>/**
 * Created by andrew on 3/28/15.
 */
runEditWidget = function(truckId, locations, categories, options) {
  var lastStop, $editStop = $("#edit-stop"), locationEndpoint = '/admin/locations';
  options = options || {};

  if (options["vendorEndpoints"]) {
    locationEndpoint = '/locations';
  }

  var $startTimeInput = $("#startTimeInput"), $endTimeInput = $("#endTimeInput");

  $startTimeInput.blur(function (e) {
    var startTime = fromDate($startTimeInput.val()),
        endTime = fromDate($endTimeInput.val());
    if (startTime.getTime() >= endTime.getTime()) {
      var diff = startTime.getTime() + (60 * 60 * 2000);
      $endTimeInput.val(toDate(new Date(diff)));
    }
  });

  $editStop.keypress(function(e) {
    if (e.which == 13) {
      e.preventDefault();
      $("#saveButton").click();
    }
  });

  // Type-ahead related stuff
  var substringMatcher = function(strs) {
    return function findMatches(q, cb) {
      var matches, substrRegex;
      matches = [];
      substrRegex = new RegExp(q, 'i');
      $.each(strs, function(i, str) {
        if (substrRegex.test(str)) {
          matches.push({ value: str });
        }
      });
      cb(matches);
    };
  };

  $("#locationInput").typeahead({
    hint: true,
    highlight: true,
    minLength: 1
  },{ name: 'locations', displayKey: 'value', source: substringMatcher(locations)});

  $editStop.on("shown.bs.modal", function() {
    $startTimeInput.focus();
  });

  function populateDialog(stop) {
    $startTimeInput.val(stop.startTimeH);
    $endTimeInput.val( stop.endTimeH);
    $("#locationInput").val(stop.location.name);
    $("#lockStop").val( stop.locked);
  }

  function invokeEditDialog(stop, afterwards) {
    populateDialog(stop);
    $("#locationInputGroup").removeClass("has-error");
    $("#truck-schedule-alert").addClass("hidden");
    $("#edit-stop").modal({ show: true, keyboard: true, backdrop: true});
    var $saveButton = $("#saveButton");
    $saveButton.unbind('click');
    $saveButton.click(function (e) {
      e.preventDefault();
      var $btn = $(this).button('loading')
      stop.startTime =  $startTimeInput.val();
      stop.endTime =  $endTimeInput.val();
      var locationName = $("#locationInput").val();
      var oldLocation = stop.location;
      if (locationName != stop.location.name) {
        stop.locationName = locationName;
        delete stop.location;
      }
      stop.truckId = truckId;
      stop.locked = $("#lockStop").is(":checked");
      if(locationName.length == 0) {
        $("#locationInputGroup").addClass("has-error");
        $("#truck-schedule-error").html("No location specified");
        $btn.button('reset')
      } else {
        $.ajax({
          url: "/services/v2/stops",
          type: 'PUT',
          contentType: 'application/json',
          data: JSON.stringify(stop),
          complete: function () {
          },
          error: function(e) {
            var obj = JSON.parse(e.responseText);
            $("#truck-schedule-error").html(obj.error);
            $("#truck-schedule-alert").removeClass("hidden");
            if (/location/i.exec(obj.error)) {
              $("#locationInputGroup").addClass("has-error");
            }
            if (/start time/i.exec(obj.error)) {
              $("#startTimeInputGroup").addClass("has-error");
            }
            if (/end time/i.exec(obj.error)) {
              $("#endTimeInputGroup").addClass("has-error");
            }
            stop.location = oldLocation;
            $btn.button('reset')
          },
          success: function() {
            $("#edit-stop").modal('hide');
            $btn.button('reset');
            afterwards();
          }
        });
      }
    });
    var $cancelButton = $("#cancelButton");
    $cancelButton.unbind("click");
    $cancelButton.click(function (e) {
      e.preventDefault();
      $("#edit-stop").modal('hide');
    });
  }

  function pad(t) {
    t = String(t)
    if (t.length == 1) {
      return "0" + t;
    }
    return t;
  }

  function fromDate(dateString) {
    var year = parseInt(dateString.substring(0, 4)),
        month = parseInt(dateString.substring(5, 7))-1,
        day = parseInt(dateString.substring(8, 10)),
        hour = parseInt(dateString.substring(11, 13)),
        min = parseInt(dateString.substring(14, 16));
    return new Date(year, month, day, hour, min, 0, 0);
  }

  function toDate(d) {
    return (d.getFullYear()) + "-" + pad(d.getMonth()+1) + "-" + pad(d.getDate()) + "T" + pad(d.getHours()) + ":" + pad(d.getMinutes());
  }

  function refreshSchedule() {
    var scheduleTable = $("#scheduleTable");
    scheduleTable.empty();
    lastStop = null;
    var d = new Date();
    d.setHours(0);
    d.setMinutes(0);
    d.setSeconds(0);
    var tomorrow = d.getTime() + 86400000;

    $.ajax({
      url: '/services/v2/stops?truck=' + truckId,
      type: 'GET',
      dataType: 'json',
      success: function (schedule) {
        var now = new Date().getTime(), numStops = schedule.length;
        var prevHadStart = false;
        $.each(schedule, function (truckIndex, stop) {
          if (stop.startMillis < tomorrow) {
            lastStop = stop;
          }
          var labels = (stop.locked) ? " locked" :
              "";
          var crazyDuration = stop.durationMillis < 0 || stop.durationMillis > 43200000;
          var showControls = stop.startMillis < tomorrow || stop.origin != 'VENDORCAL';
          var truckNames = stop.truckNames.replace(/\'/g, "");
          labels += (stop.fromBeacon) ? " beacon" : "";
          var truckCountLink = stop.totalTruckCount < 2 ? "" : "" + stop.totalTruckCount + "";
          var buf = "
" + stop.startDate + "	" + stop.startTime + "	" + stop.endTime +
              "	" + stop.duration + "	" + stop.origin + "	"
              + stop.location.name + "" + labels + "	" + truckCountLink +"	";
          if (showControls) {
            if (!prevHadStart && now < stop.startMillis) {
              prevHadStart = true;
              buf = buf + "<button class='btn btn-default' id='truckStartNow" + truckIndex +
              "' class='btn success'>Start Now</button>"
            } else if (now >= stop.startMillis && now < stop.endMillis) {
              buf = buf + "<button class='btn btn-default' id='truckEndNow" + truckIndex +
              "' class='btn warning'>End Now</button>";
            }
          }
          buf += " 	";
          if (showControls) {
            buf = buf + "
<button class='btn btn-default' id='truckDelete" + truckIndex +
            "' class='btn '> Delete</button> <button class='btn btn-default' id='truckEdit" +
            truckIndex + "'> Edit</button>

";
          }
          scheduleTable.append(buf);
          $("#truckEdit" + truckIndex).click(function (e) {
            stop["startDate"] = toDate(new Date(stop["startMillis"]));
            stop["endDate"] = toDate(new Date(stop["endMillis"]));
            invokeEditDialog(stop, refreshSchedule);
          });

          function timeUpdateMaker(useStart) {
            return function (e) {
              e.preventDefault();
              if (useStart) {
                stop.startTime = toDate(new Date());
                stop["endTime"] = toDate(new Date(stop["endMillis"]));
              } else {
                stop.startTime = toDate(new Date(stop["startMillis"]));
                stop.endTime = toDate(new Date());
              }
              stop.truckId = truckId;
              $.ajax({
                url: "/services/v2/stops",
                type: 'PUT',
                contentType: 'application/json',
                data: JSON.stringify(stop),
                success: refreshSchedule
              });
            }
          }

          $("#truckStartNow" + truckIndex).click(timeUpdateMaker(true));
          $("#truckEndNow" + truckIndex).click(timeUpdateMaker(false));
          $("#truckDelete" + truckIndex).click(function (e) {
            e.preventDefault();
            $.ajax({
              url: "/services/v2/stops/" + stop.id,
              type: 'DELETE',
              complete: function () {
                refreshSchedule();
              }
            })
          });
        });
        $(function () {
          $('[data-toggle="popover"]').popover()
        });
      }
    });
  }

  function numStops() {
    return $("#scheduleTable").children().length;
  }

  function hasCategory(category) {
    return categories.indexOf(category) >= 0;
  }

  function newStop() {
    var now = new Date();
    if ((!hasCategory("Breakfast") && numStops() == 0) && now.getHours() < 10 ) {
      now.setHours(11);
      now.setMinutes(0);
    }
    if (numStops() > 0 && lastStop != null) {
      now = new Date(lastStop["endMillis"] + 60000)
    }
    var minutes = now.getMinutes();
    if (minutes != 0) {
      minutes = Math.ceil(minutes / 15) * 15;
      if (minutes <= 45) {
        now.setMinutes(minutes);
      } else {
        now = new Date(now.getTime() + (60 * 60 * 1000));
        now.setMinutes(0);
      }
    }
    var today = toDate(now), later = toDate(new Date(now.getTime() + (2*60*60*1000)));
    invokeEditDialog({truckId: truckId, locationName: "", location: { name: ""},
          startTimeH: today, endTimeH: later },
        refreshSchedule);
  }

  $("#addButton").click(function (e) {
    newStop();
  });

  $(document).keypress(function(e) {
    if (e.which == 110 && $editStop.css("display") == 'none') {
      e.preventDefault();
      newStop();
    }
  });

  refreshSchedule();
  var $offTheRoadButton = $("#offRoadButton");
  if (options["vendorEndpoints"]) {
    $offTheRoadButton.css("display", "none");
  }
  if (!options["hasCalendar"]) {
    $("#recacheButton").addClass("hidden");
  }
  if (options["truckName"]) {
    $("#truck-widget-header").html("Schedule for " + options["truckName"]);
  }
  $offTheRoadButton.click(function (evt) {
    $.ajax({
      url: "/admin/trucks/" + truckId + "/offtheroad",
      type: 'POST',
      context: document.body,
      dataType: 'json',
      complete: function (data) {
        refreshSchedule();
      }});
  });

  var $recacheButton = $("#recacheButton");
  $recacheButton.click(function (evt) {
    $recacheButton.empty();
    $recacheButton.append("Refreshing...")
    $.ajax({
      url: "/cron/recache?truck=" + truckId,
      context: document.body,
      dataType: 'json',
      complete: function () {
        $recacheButton.empty();
        $recacheButton.append("Refresh")
      },
      success: function (data) {
        refreshSchedule();
      }});
  });
};<|endoftext|>


<commit_before>/** @param {HTMLCanvasElement} canvas
 *  @param {function(StateGL)} onload
 *  @constructor */
function StateGL(canvas, onload) {
    var gl = /** @type WebGLRenderingContext */ (canvas.getContext('webgl', {
        preserveDrawingBuffer: true
    }));
    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    gl.enable(gl.DEPTH_TEST);
    this.gl = gl;
    this.mkRenderToTextureObjects();
    var stategl = this;
    stategl.mkFXAAProgram(function() {
        onload(stategl);
    });
}

/** @type {boolean} */
StateGL.prototype.cached = false;

/** @type {WebGLProgram} */
StateGL.prototype.cachedSurfaceProgram = null;

/** @type {boolean} */
StateGL.prototype.clipping = false;

/** @type {boolean} */
StateGL.prototype.fxaa = true;

/** @type {WebGLProgram} */
StateGL.prototype.fxaaProgram = null;

/** @param {string} shaderId
 *  @param {function(Array<string>)} onload */
StateGL.getShaderSources = function(shaderId, onload) {
    var files = [shaderId + '-vs.glsl', shaderId + '-fs.glsl'];
    Misc.loadTextFiles(files, onload);
};

/** @type {WebGLRenderingContext} */
StateGL.prototype.gl = null;

/** @param {string} file
 *  @param {function()} onload */
StateGL.prototype.loadModel = function(file, onload) {
    var stategl = this;
    var req = new XMLHttpRequest();
    req.open("GET", file, true);
    req.responseType = "arraybuffer";
    req.onload = function() {
        var positions = /** @type {ArrayBuffer|null} */ (req.response);
        stategl.mkBuffer(positions);
        stategl.size = positions.byteLength / 16;
        stategl.mkCachedSurfaceProgram(onload);
    };
    req.send();
};

/** @param {ArrayBuffer} positions */
StateGL.prototype.mkBuffer = function(positions) {
    var gl = this.gl;
    gl.enableVertexAttribArray(0);
    this.positionsBuffer = /** @type {WebGLBuffer} */ (gl.createBuffer());
    this.positions = positions;
    gl.bindBuffer(gl.ARRAY_BUFFER, this.positionsBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.positions), gl.STATIC_DRAW);
    gl.vertexAttribPointer(0, 4, gl.FLOAT, false, 0, 0);
};

/** @param {function()} onload */
StateGL.prototype.mkCachedSurfaceProgram = function(onload) {
    var gl = this;
    StateGL.getShaderSources("cached-surface", function(sources) {
        gl.cachedSurfaceProgram = gl.mkProgram(sources);
        gl.cached = true;
        onload();
    });
};

/** @param {function()} onload */
StateGL.prototype.mkFXAAProgram = function(onload) {
    var gl = this;
    StateGL.getShaderSources("fxaa", function(sources) {
        gl.fxaaProgram = gl.mkProgram(sources);
        onload();
    });
};

/** @param {Array<string>} sources
 *  @return {WebGLProgram} */
StateGL.prototype.mkProgram = function(sources) {
    var gl = this.gl;
    var vertexShaderSource = sources[0],
        fragmentShaderSource = sources[1];
    var vertexShader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vertexShader, vertexShaderSource);
    gl.compileShader(vertexShader);
    if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS))
        console.log(gl.getShaderInfoLog(vertexShader));
    var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fragmentShader, fragmentShaderSource);
    gl.compileShader(fragmentShader);
    if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS))
        console.log(gl.getShaderInfoLog(fragmentShader));
    var shaderProgram = gl.createProgram();
    gl.attachShader(shaderProgram, vertexShader);
    gl.attachShader(shaderProgram, fragmentShader);
    gl.linkProgram(shaderProgram);
    if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS))
        console.log(gl.getProgramInfoLog(shaderProgram));
    gl.useProgram(shaderProgram);
    return shaderProgram;
};

StateGL.prototype.mkRenderToTextureObjects = function() {
    var gl = this.gl;

    this.rttArrayBuffer = /** @type {WebGLBuffer} */ (gl.createBuffer());
    gl.bindBuffer(gl.ARRAY_BUFFER, this.rttArrayBuffer);
    var vertices = [-1, -1, 3, -1, -1, 3];
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
    gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(0);

    this.rttFramebuffer = gl.createFramebuffer();
    gl.bindFramebuffer(gl.FRAMEBUFFER, this.rttFramebuffer);

    this.rttRenderbuffer = gl.createRenderbuffer();
    gl.bindRenderbuffer(gl.RENDERBUFFER, this.rttRenderbuffer);
    gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, 2048, 2048);
    gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this.rttRenderbuffer);

    this.rttTexture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, this.rttTexture);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2048, 2048, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.rttTexture, 0);

    gl.bindTexture(gl.TEXTURE_2D, null);
    gl.bindRenderbuffer(gl.RENDERBUFFER, null);
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    gl.bindBuffer(gl.ARRAY_BUFFER, null);
};

/** @param {State3D} st */
StateGL.prototype.renderSurface = function(st) {
    var gl = this.gl;
    var stategl = this;
    this.withOptionalFXAA(function() {
        gl.useProgram(stategl.cachedSurfaceProgram);
        stategl.updateClipping();
        stategl.updateModelViewProjectionMatrices(st);
        gl.bindBuffer(gl.ARRAY_BUFFER, stategl.positionsBuffer);
        gl.vertexAttribPointer(0, 4, gl.FLOAT, false, 0, 0);
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
        gl.drawArrays(gl.TRIANGLES, 0, stategl.size);
    });
};

/** @type {WebGLBuffer} */
StateGL.prototype.rttArrayBuffer = null;

/** @type {WebGLFramebuffer} */
StateGL.prototype.rttFramebuffer = null;

/** @type {WebGLRenderbuffer} */
StateGL.prototype.rttRenderbuffer = null;

/** @type {WebGLTexture} */
StateGL.prototype.rttTexture = null;

/** @type {number} */
StateGL.prototype.size = 0;

StateGL.prototype.toggleAntialiasing = function () {
    this.fxaa = !this.fxaa;
};

StateGL.prototype.toggleClipping = function () {
    this.clipping = !this.clipping;
};

StateGL.prototype.toggleTransparency = function () {
    var gl = this.gl;
    if (gl.getParameter(gl.BLEND)) {
        gl.disable(gl.BLEND);
        gl.enable(gl.DEPTH_TEST);
        gl.depthFunc(gl.LESS);
    } else {
        gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
        gl.enable(gl.BLEND);
        gl.disable(gl.DEPTH_TEST);
    }
};

StateGL.prototype.updateClipping = function () {
    var gl = this.gl;
    var loc = gl.getUniformLocation(this.cachedSurfaceProgram, "clipping");
    gl.uniform1f(loc, this.clipping);
};

/** @param {State3D} st */
StateGL.prototype.updateModelMatrix = function(st) {
    this.updateUniformMatrix("m", st.modelMatrix());
};

/** @param {State3D} st */
StateGL.prototype.updateModelViewProjectionMatrices = function(st) {
    this.updateModelMatrix(st);
    this.updateViewMatrix(st);
    this.updateProjectionMatrix(st);
};

/** @param {State3D} st */
StateGL.prototype.updateProjectionMatrix = function(st) {
    var gl = this.gl,
        vp = gl.getParameter(gl.VIEWPORT),
        w = vp[2],
        h = vp[3];
    this.updateUniformMatrix("p", st.projectionMatrix(w, h));
};

/** @param {string} i
 *  @param {Array<number>} ms */
StateGL.prototype.updateUniformMatrix = function(i, ms) {
    var gl = this.gl;
    var program = /** @type {WebGLProgram|null} */ (gl.getParameter(gl.CURRENT_PROGRAM));
    var loc = gl.getUniformLocation(program, i);
    gl.uniformMatrix4fv(loc, false, ms);
};

/** @param {State3D} st */
StateGL.prototype.updateViewMatrix = function(st) {
    this.updateUniformMatrix("v", st.viewMatrix());
};

/** @param {function()} action */
StateGL.prototype.withFXAA = function(action) {
    this.withRenderToTexture(action);
    var gl = this.gl;
    gl.useProgram(this.fxaaProgram);
    gl.bindBuffer(gl.ARRAY_BUFFER, this.rttArrayBuffer);
    gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, this.rttTexture);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.drawArrays(gl.TRIANGLES, 0, 3);
};

/** @param {function()} action */
StateGL.prototype.withOptionalFXAA = function(action) {
    if (this.fxaa)
        this.withFXAA(action);
    else
        action();
};

/** @param {function()} action */
StateGL.prototype.withRenderToTexture = function(action) {
    var gl = this.gl;
    gl.bindFramebuffer(gl.FRAMEBUFFER, this.rttFramebuffer);
    action();
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
};
<commit_msg>Fix type for update of boolean uniform<commit_after>/** @param {HTMLCanvasElement} canvas
 *  @param {function(StateGL)} onload
 *  @constructor */
function StateGL(canvas, onload) {
    var gl = /** @type WebGLRenderingContext */ (canvas.getContext('webgl', {
        preserveDrawingBuffer: true
    }));
    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    gl.enable(gl.DEPTH_TEST);
    this.gl = gl;
    this.mkRenderToTextureObjects();
    var stategl = this;
    stategl.mkFXAAProgram(function() {
        onload(stategl);
    });
}

/** @type {boolean} */
StateGL.prototype.cached = false;

/** @type {WebGLProgram} */
StateGL.prototype.cachedSurfaceProgram = null;

/** @type {boolean} */
StateGL.prototype.clipping = false;

/** @type {boolean} */
StateGL.prototype.fxaa = true;

/** @type {WebGLProgram} */
StateGL.prototype.fxaaProgram = null;

/** @param {string} shaderId
 *  @param {function(Array<string>)} onload */
StateGL.getShaderSources = function(shaderId, onload) {
    var files = [shaderId + '-vs.glsl', shaderId + '-fs.glsl'];
    Misc.loadTextFiles(files, onload);
};

/** @type {WebGLRenderingContext} */
StateGL.prototype.gl = null;

/** @param {string} file
 *  @param {function()} onload */
StateGL.prototype.loadModel = function(file, onload) {
    var stategl = this;
    var req = new XMLHttpRequest();
    req.open("GET", file, true);
    req.responseType = "arraybuffer";
    req.onload = function() {
        var positions = /** @type {ArrayBuffer|null} */ (req.response);
        stategl.mkBuffer(positions);
        stategl.size = positions.byteLength / 16;
        stategl.mkCachedSurfaceProgram(onload);
    };
    req.send();
};

/** @param {ArrayBuffer} positions */
StateGL.prototype.mkBuffer = function(positions) {
    var gl = this.gl;
    gl.enableVertexAttribArray(0);
    this.positionsBuffer = /** @type {WebGLBuffer} */ (gl.createBuffer());
    this.positions = positions;
    gl.bindBuffer(gl.ARRAY_BUFFER, this.positionsBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.positions), gl.STATIC_DRAW);
    gl.vertexAttribPointer(0, 4, gl.FLOAT, false, 0, 0);
};

/** @param {function()} onload */
StateGL.prototype.mkCachedSurfaceProgram = function(onload) {
    var gl = this;
    StateGL.getShaderSources("cached-surface", function(sources) {
        gl.cachedSurfaceProgram = gl.mkProgram(sources);
        gl.cached = true;
        onload();
    });
};

/** @param {function()} onload */
StateGL.prototype.mkFXAAProgram = function(onload) {
    var gl = this;
    StateGL.getShaderSources("fxaa", function(sources) {
        gl.fxaaProgram = gl.mkProgram(sources);
        onload();
    });
};

/** @param {Array<string>} sources
 *  @return {WebGLProgram} */
StateGL.prototype.mkProgram = function(sources) {
    var gl = this.gl;
    var vertexShaderSource = sources[0],
        fragmentShaderSource = sources[1];
    var vertexShader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vertexShader, vertexShaderSource);
    gl.compileShader(vertexShader);
    if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS))
        console.log(gl.getShaderInfoLog(vertexShader));
    var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fragmentShader, fragmentShaderSource);
    gl.compileShader(fragmentShader);
    if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS))
        console.log(gl.getShaderInfoLog(fragmentShader));
    var shaderProgram = gl.createProgram();
    gl.attachShader(shaderProgram, vertexShader);
    gl.attachShader(shaderProgram, fragmentShader);
    gl.linkProgram(shaderProgram);
    if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS))
        console.log(gl.getProgramInfoLog(shaderProgram));
    gl.useProgram(shaderProgram);
    return shaderProgram;
};

StateGL.prototype.mkRenderToTextureObjects = function() {
    var gl = this.gl;

    this.rttArrayBuffer = /** @type {WebGLBuffer} */ (gl.createBuffer());
    gl.bindBuffer(gl.ARRAY_BUFFER, this.rttArrayBuffer);
    var vertices = [-1, -1, 3, -1, -1, 3];
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
    gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(0);

    this.rttFramebuffer = gl.createFramebuffer();
    gl.bindFramebuffer(gl.FRAMEBUFFER, this.rttFramebuffer);

    this.rttRenderbuffer = gl.createRenderbuffer();
    gl.bindRenderbuffer(gl.RENDERBUFFER, this.rttRenderbuffer);
    gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, 2048, 2048);
    gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this.rttRenderbuffer);

    this.rttTexture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, this.rttTexture);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2048, 2048, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.rttTexture, 0);

    gl.bindTexture(gl.TEXTURE_2D, null);
    gl.bindRenderbuffer(gl.RENDERBUFFER, null);
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    gl.bindBuffer(gl.ARRAY_BUFFER, null);
};

/** @param {State3D} st */
StateGL.prototype.renderSurface = function(st) {
    var gl = this.gl;
    var stategl = this;
    this.withOptionalFXAA(function() {
        gl.useProgram(stategl.cachedSurfaceProgram);
        stategl.updateClipping();
        stategl.updateModelViewProjectionMatrices(st);
        gl.bindBuffer(gl.ARRAY_BUFFER, stategl.positionsBuffer);
        gl.vertexAttribPointer(0, 4, gl.FLOAT, false, 0, 0);
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
        gl.drawArrays(gl.TRIANGLES, 0, stategl.size);
    });
};

/** @type {WebGLBuffer} */
StateGL.prototype.rttArrayBuffer = null;

/** @type {WebGLFramebuffer} */
StateGL.prototype.rttFramebuffer = null;

/** @type {WebGLRenderbuffer} */
StateGL.prototype.rttRenderbuffer = null;

/** @type {WebGLTexture} */
StateGL.prototype.rttTexture = null;

/** @type {number} */
StateGL.prototype.size = 0;

StateGL.prototype.toggleAntialiasing = function () {
    this.fxaa = !this.fxaa;
};

StateGL.prototype.toggleClipping = function () {
    this.clipping = !this.clipping;
};

StateGL.prototype.toggleTransparency = function () {
    var gl = this.gl;
    if (gl.getParameter(gl.BLEND)) {
        gl.disable(gl.BLEND);
        gl.enable(gl.DEPTH_TEST);
        gl.depthFunc(gl.LESS);
    } else {
        gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
        gl.enable(gl.BLEND);
        gl.disable(gl.DEPTH_TEST);
    }
};

StateGL.prototype.updateClipping = function () {
    var gl = this.gl;
    var loc = gl.getUniformLocation(this.cachedSurfaceProgram, "clipping");
    gl.uniform1f(loc, this.clipping ? 1 : 0);
};

/** @param {State3D} st */
StateGL.prototype.updateModelMatrix = function(st) {
    this.updateUniformMatrix("m", st.modelMatrix());
};

/** @param {State3D} st */
StateGL.prototype.updateModelViewProjectionMatrices = function(st) {
    this.updateModelMatrix(st);
    this.updateViewMatrix(st);
    this.updateProjectionMatrix(st);
};

/** @param {State3D} st */
StateGL.prototype.updateProjectionMatrix = function(st) {
    var gl = this.gl,
        vp = gl.getParameter(gl.VIEWPORT),
        w = vp[2],
        h = vp[3];
    this.updateUniformMatrix("p", st.projectionMatrix(w, h));
};

/** @param {string} i
 *  @param {Array<number>} ms */
StateGL.prototype.updateUniformMatrix = function(i, ms) {
    var gl = this.gl;
    var program = /** @type {WebGLProgram|null} */ (gl.getParameter(gl.CURRENT_PROGRAM));
    var loc = gl.getUniformLocation(program, i);
    gl.uniformMatrix4fv(loc, false, ms);
};

/** @param {State3D} st */
StateGL.prototype.updateViewMatrix = function(st) {
    this.updateUniformMatrix("v", st.viewMatrix());
};

/** @param {function()} action */
StateGL.prototype.withFXAA = function(action) {
    this.withRenderToTexture(action);
    var gl = this.gl;
    gl.useProgram(this.fxaaProgram);
    gl.bindBuffer(gl.ARRAY_BUFFER, this.rttArrayBuffer);
    gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, this.rttTexture);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.drawArrays(gl.TRIANGLES, 0, 3);
};

/** @param {function()} action */
StateGL.prototype.withOptionalFXAA = function(action) {
    if (this.fxaa)
        this.withFXAA(action);
    else
        action();
};

/** @param {function()} action */
StateGL.prototype.withRenderToTexture = function(action) {
    var gl = this.gl;
    gl.bindFramebuffer(gl.FRAMEBUFFER, this.rttFramebuffer);
    action();
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
};
<|endoftext|>


<commit_before>angular.module('anol.urlmarkers')
/**
 * @ngdoc object
 * @name anol.urlmarkers.UrlMarkersServiceProvider
 */
.provider('UrlMarkersService', [function() {
    var _defaultSrs;
    var _propertiesDelimiter = '|';
    var _keyValueDelimiter = ':';
    var _style = {};
    var _usePopup = true;
    var _popupOffset = [0, 0];

    /**
     * @ngdoc method
     * @name setDefaultSrs
     * @methodOf anol.urlmarkers.UrlMarkersServiceProvider
     * @param {string} srs default EPSG code of marker coordinates in url
     */
    this.setDefaultSrs = function(srs) {
        _defaultSrs = srs;
    };

    /**
     * @ngdoc method
     * @name setPropertiesDelimiter
     * @methodOf anol.urlmarkers.UrlMarkersServiceProvider
     * @param {string} delimiter Delimiter separating marker properties
     */
    this.setPropertiesDelimiter = function(delimiter) {
        _propertiesDelimiter = delimiter || _propertiesDelimiter;
    };

    /**
     * @ngdoc method
     * @name setKeyValueDelimiter
     * @methodOf anol.urlmarkers.UrlMarkersServiceProvider
     * @param {string} delimiter Delimiter separating properties keys from values
     */
    this.setKeyValueDelimiter = function(delimiter) {
        _keyValueDelimiter = delimiter || _keyValueDelimiter;
    };

    /**
     * @ngdoc method
     * @name setMarkerStyle
     * @methodOf anol.urlmarkers.UrlMarkersServiceProvider
     * @param {object} style marker style
     */
    this.setMarkerStyle = function(style) {
        _style = style;
    };

    /**
     * @ngdoc method
     * @name setPopup
     * @methodOf anol.urlmarkers.UrlMarkersServiceProvider
     * @param {boolean} usePopup
     * @description When not using popup a label text is added. This can be styled by markerStyle
     */
    this.setUsePopup = function(usePopup) {
        _usePopup = usePopup === undefined ? _usePopup : usePopup;
    };

    /**
     * @ngdoc method
     * @name setPopupOffset
     * @methodOf anol.urlmarkers.UrlMarkersServiceProvider
     * @param {Array.<number>} popupOffset Offset of placed popup. First value is x- second value is y-offset in px
     */
    this.setPopupOffset = function(popupOffset) {
        _popupOffset = popupOffset === undefined ? _popupOffset : popupOffset;
    };

    this.$get = ['$rootScope', '$location', '$compile', '$document', 'MapService', 'LayersService', function($rootScope, $location, $compile, $document, MapService, LayersService) {
        /**
         * @ngdoc service
         * @name anol.urlmarkers.UrlMarkersService
         *
         * @description
         * Adds markers specified in url. A valid url marker looks like marker=color:ff0000|label:foobar|coord:8.21,53.15|srs:4326
         */
        var UrlMarkers = function(defaultSrs, propertiesDelimiter, keyValueDelimiter, style, usePopup, popupOffset) {
            var self = this;
            self.features = [];
            self.defaultSrs = defaultSrs || MapService.view.getProjection();
            self.propertiesDelimiter = propertiesDelimiter;
            self.keyValueDelimiter = keyValueDelimiter;
            self.style = style;
            self.usePopup = usePopup;
            self.popupOffset = popupOffset;

            self.extractFeaturesFromUrl();

            if(self.features.length === 0) {
                return;
            }

            self.layer = self.createLayer(self.features);

            LayersService.addSystemLayer(self.layer);

            if(self.usePopup) {
                self.overlays = self.createPopups(self.features);
            }
        };

        UrlMarkers.prototype.extractFeaturesFromUrl = function() {
            var self = this;
            var urlParams = $location.search();

            if(angular.isUndefined(urlParams.marker)) {
                return false;
            }

            var markers = angular.isArray(urlParams.marker) ? urlParams.marker : [urlParams.marker];
            angular.forEach(markers, function(_marker) {
                var params = _marker.split(self.propertiesDelimiter);
                if(params.length === 0) {
                    return;
                }

                var marker = {};
                var style = {};
                angular.forEach(params, function(kv) {
                    kv = kv.split(self.keyValueDelimiter);
                    if(kv[0] === 'coord') {
                        var coord = kv[1].split(',');
                        coord = [parseFloat(coord[0]), parseFloat(coord[1])];
                        marker.geometry = new ol.geom.Point(coord);
                    } else if (kv[0] === 'srs') {
                        marker.srs = 'EPSG:' + kv[1];
                    } else if (kv[0] === 'color') {
                        style = {
                            fillColor: '#' + kv[1],
                            strokeColor: '#' + kv[1],
                            graphicColor: '#' + kv[1]
                        };
                    }
                    else {
                        marker[kv[0]] = kv[1];
                    }
                });
                if(marker.geometry === undefined) {
                    return;
                }
                marker.geometry.transform(
                    marker.srs || self.defaultSrs,
                    MapService.view.getProjection()
                );
                marker.style = angular.merge({}, self.style, style);
                if(!self.usePopup && marker.label !== undefined) {
                    marker.style.text = marker.label;
                }
                self.features.push(new ol.Feature(marker));

            });
        };

        UrlMarkers.prototype.createLayer = function(features) {
            var layer = new anol.layer.Feature({
                name: 'markersLayer',
                olLayer: {
                    source: {
                        features: features
                  }
                }
            });

            var olLayerOptions = layer.olLayerOptions;
            olLayerOptions.source = new layer.OL_SOURCE_CLASS(layer.olSourceOptions);
            layer.setOlLayer(new layer.OL_LAYER_CLASS(olLayerOptions));

            return layer;
        };

        UrlMarkers.prototype.createPopups = function(features)  {
            var self = this;
            angular.forEach(features, function(feature) {
                var label = feature.get('label');
                if(label === undefined) {
                    return;
                }
                var coordinate = feature.getGeometry().getCoordinates();
                if(coordinate === undefined) {
                    return;
                }
                var template = '
{{ label }}
';
                var compiled = $compile(angular.element(template));
                var popupScope = $rootScope.$new();
                popupScope.coordinate = coordinate;
                popupScope.label = label;
                popupScope.layers = [self.layer];
                popupScope.offset = self.popupOffset;
                $document.find('body').append(compiled(popupScope));
            });

        };

        return new UrlMarkers(_defaultSrs, _propertiesDelimiter, _keyValueDelimiter, _style, _usePopup, _popupOffset);
    }];
}]);
<commit_msg>Set url marker popup not sticky<commit_after>angular.module('anol.urlmarkers')
/**
 * @ngdoc object
 * @name anol.urlmarkers.UrlMarkersServiceProvider
 */
.provider('UrlMarkersService', [function() {
    var _defaultSrs;
    var _propertiesDelimiter = '|';
    var _keyValueDelimiter = ':';
    var _style = {};
    var _usePopup = true;
    var _popupOffset = [0, 0];

    /**
     * @ngdoc method
     * @name setDefaultSrs
     * @methodOf anol.urlmarkers.UrlMarkersServiceProvider
     * @param {string} srs default EPSG code of marker coordinates in url
     */
    this.setDefaultSrs = function(srs) {
        _defaultSrs = srs;
    };

    /**
     * @ngdoc method
     * @name setPropertiesDelimiter
     * @methodOf anol.urlmarkers.UrlMarkersServiceProvider
     * @param {string} delimiter Delimiter separating marker properties
     */
    this.setPropertiesDelimiter = function(delimiter) {
        _propertiesDelimiter = delimiter || _propertiesDelimiter;
    };

    /**
     * @ngdoc method
     * @name setKeyValueDelimiter
     * @methodOf anol.urlmarkers.UrlMarkersServiceProvider
     * @param {string} delimiter Delimiter separating properties keys from values
     */
    this.setKeyValueDelimiter = function(delimiter) {
        _keyValueDelimiter = delimiter || _keyValueDelimiter;
    };

    /**
     * @ngdoc method
     * @name setMarkerStyle
     * @methodOf anol.urlmarkers.UrlMarkersServiceProvider
     * @param {object} style marker style
     */
    this.setMarkerStyle = function(style) {
        _style = style;
    };

    /**
     * @ngdoc method
     * @name setPopup
     * @methodOf anol.urlmarkers.UrlMarkersServiceProvider
     * @param {boolean} usePopup
     * @description When not using popup a label text is added. This can be styled by markerStyle
     */
    this.setUsePopup = function(usePopup) {
        _usePopup = usePopup === undefined ? _usePopup : usePopup;
    };

    /**
     * @ngdoc method
     * @name setPopupOffset
     * @methodOf anol.urlmarkers.UrlMarkersServiceProvider
     * @param {Array.<number>} popupOffset Offset of placed popup. First value is x- second value is y-offset in px
     */
    this.setPopupOffset = function(popupOffset) {
        _popupOffset = popupOffset === undefined ? _popupOffset : popupOffset;
    };

    this.$get = ['$rootScope', '$location', '$compile', '$document', 'MapService', 'LayersService', function($rootScope, $location, $compile, $document, MapService, LayersService) {
        /**
         * @ngdoc service
         * @name anol.urlmarkers.UrlMarkersService
         *
         * @description
         * Adds markers specified in url. A valid url marker looks like marker=color:ff0000|label:foobar|coord:8.21,53.15|srs:4326
         */
        var UrlMarkers = function(defaultSrs, propertiesDelimiter, keyValueDelimiter, style, usePopup, popupOffset) {
            var self = this;
            self.features = [];
            self.defaultSrs = defaultSrs || MapService.view.getProjection();
            self.propertiesDelimiter = propertiesDelimiter;
            self.keyValueDelimiter = keyValueDelimiter;
            self.style = style;
            self.usePopup = usePopup;
            self.popupOffset = popupOffset;

            self.extractFeaturesFromUrl();

            if(self.features.length === 0) {
                return;
            }

            self.layer = self.createLayer(self.features);

            LayersService.addSystemLayer(self.layer);

            if(self.usePopup) {
                self.overlays = self.createPopups(self.features);
            }
        };

        UrlMarkers.prototype.extractFeaturesFromUrl = function() {
            var self = this;
            var urlParams = $location.search();

            if(angular.isUndefined(urlParams.marker)) {
                return false;
            }

            var markers = angular.isArray(urlParams.marker) ? urlParams.marker : [urlParams.marker];
            angular.forEach(markers, function(_marker) {
                var params = _marker.split(self.propertiesDelimiter);
                if(params.length === 0) {
                    return;
                }

                var marker = {};
                var style = {};
                angular.forEach(params, function(kv) {
                    kv = kv.split(self.keyValueDelimiter);
                    if(kv[0] === 'coord') {
                        var coord = kv[1].split(',');
                        coord = [parseFloat(coord[0]), parseFloat(coord[1])];
                        marker.geometry = new ol.geom.Point(coord);
                    } else if (kv[0] === 'srs') {
                        marker.srs = 'EPSG:' + kv[1];
                    } else if (kv[0] === 'color') {
                        style = {
                            fillColor: '#' + kv[1],
                            strokeColor: '#' + kv[1],
                            graphicColor: '#' + kv[1]
                        };
                    }
                    else {
                        marker[kv[0]] = kv[1];
                    }
                });
                if(marker.geometry === undefined) {
                    return;
                }
                marker.geometry.transform(
                    marker.srs || self.defaultSrs,
                    MapService.view.getProjection()
                );
                marker.style = angular.merge({}, self.style, style);
                if(!self.usePopup && marker.label !== undefined) {
                    marker.style.text = marker.label;
                }
                self.features.push(new ol.Feature(marker));

            });
        };

        UrlMarkers.prototype.createLayer = function(features) {
            var layer = new anol.layer.Feature({
                name: 'markersLayer',
                olLayer: {
                    source: {
                        features: features
                  }
                }
            });

            var olLayerOptions = layer.olLayerOptions;
            olLayerOptions.source = new layer.OL_SOURCE_CLASS(layer.olSourceOptions);
            layer.setOlLayer(new layer.OL_LAYER_CLASS(olLayerOptions));

            return layer;
        };

        UrlMarkers.prototype.createPopups = function(features)  {
            var self = this;
            angular.forEach(features, function(feature) {
                var label = feature.get('label');
                if(label === undefined) {
                    return;
                }
                var coordinate = feature.getGeometry().getCoordinates();
                if(coordinate === undefined) {
                    return;
                }
                var template = '
{{ label }}
';
                var compiled = $compile(angular.element(template));
                var popupScope = $rootScope.$new();
                popupScope.coordinate = coordinate;
                popupScope.label = label;
                popupScope.layers = [self.layer];
                popupScope.offset = self.popupOffset;
                $document.find('body').append(compiled(popupScope));
            });

        };

        return new UrlMarkers(_defaultSrs, _propertiesDelimiter, _keyValueDelimiter, _style, _usePopup, _popupOffset);
    }];
}]);
<|endoftext|>


<commit_before>function TapWrap(a){var o=Object.create(TapWrap.prototype);o._wrapped=a;return o};TapWrap.prototype={val:function(){return this._wrapped},set:function(prop,val){if(arguments.length>2)while(arguments.length)this.set([].shift.call(arguments),[].shift.call(arguments));if(prop instanceof Object)for(var i in prop)prop.hasOwnProperty(i)&&(this._wrapped[i]=prop[i]); else this._wrapped[prop]=val;return this},tap:function(func,args,val){var g;if(typeof func=="function")g=func.apply(this._wrapped,args);else g=this._wrapped[func].apply(this._wrapped,args);return val?g:this;}};Object.defineProperty(Object.prototype,"tapWrap",{value:function(){return TapWrap(this);}})

<commit_msg>TapWrap.js uploaded<commit_after>function TapWrap(i){var o=Object.create(TapWrap.prototype);o._wrapped=i;return o};TapWrap.prototype={val:function(){return this._wrapped},set:function(prop,val){if(arguments.length>2)while(arguments.length)this.set([].shift.call(arguments),[].shift.call(arguments));if(prop instanceof Object)for(var i in prop)prop.hasOwnProperty(i)&&(this._wrapped[i]=prop[i]); else this._wrapped[prop]=val;return this},tap:function(func,args,val){var g;if(typeof func=="function")g=func.apply(this._wrapped,args);else g=this._wrapped[func].apply(this._wrapped,args);return val?g:this;}};Object.defineProperty(Object.prototype,"tapWrap",{value:function(){return TapWrap(this);}})

<|endoftext|>


<commit_before>/*
 * This program is part of the OpenLMIS logistics management information system platform software.
 * Copyright © 2017 VillageReach
 *
 * This program is free software: you can redistribute it and/or modify it under the terms
 * of the GNU Affero General Public License as published by the Free Software Foundation, either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details. You should have received a copy of
 * the GNU Affero General Public License along with this program. If not, see
 * http://www.gnu.org/licenses.  For additional information contact info@OpenLMIS.org.
 */

(function() {

    'use strict';

    /**
     * @ngdoc directive
     * @restrict E
     * @name openlmis-table.directive:tbodyTitle
     *
     * @description
     * Takes the title attribute from a tbody element and changes it into a stylable banner.
     *
     * @example
     * To add a title heading to any tbody element, just add a title element with a translated string (this element will not translate strings for you)
     * ```
     * <table>
     *   <tbody tbody-title="Category Title">
     *     <tr><td>123</td><td>456</td></tr>
     *     <tr><td>Foo</td><td>Bar</td></tr>
     *   </tbody>
     * </table>
     * ```
     * Which will produce the following markup
     * ```
     * <table>
     *   <tbody>
     *     <tr class="title"><td colspan="2"><div>Category Title</div></td></tr>
     *     <tr><td>123</td><td>456</td></tr>
     *     <tr><td>Foo</td><td>Bar</td></tr>
     *   </tbody>
     * </table>
     * ```
     */
    angular
        .module('openlmis-table')
        .directive('tbody', tbodyTitle);

    tbodyTitle.$inject = ['$compile', '$window', 'jQuery'];
    function tbodyTitle($compile, $window, jQuery) {
        var template = '

{{title}}

';

        return {
            restrict: 'E',
            replace: false,
            link: link
        };

        function link(scope, element, attrs) {
            if(attrs.tbodyTitle && attrs.tbodyTitle != ""){
                var titleScope = scope.$new(true);

                titleScope.title = attrs.tbodyTitle;

                scope.$watch(function(){
                    return element.children('tr:not(.title):first').children('td, th').length;
                }, function(num){
                    titleScope.colspan = num
                });

                var titleElement = $compile(template)(titleScope);
                element.prepend(titleElement);

                if(element.parents('.openlmis-table-container').length > 0){
                    var table = element.parents('table:first');

                    // openlmis-table-container will rewrite table's parent
                    // after this link is run... so we are watching
                    var parent = table.parent();
                    scope.$watch(function(){
                        return table.parent()[0];
                    }, function(newParent){
                        parent.off('scroll', blit);
                        parent = table.parent();
                        parent.on('scroll', blit);
                    });
                    element.on('$destroy', function(){
                        parent.off('scroll', blit);
                    });

                    scope.$watch(function(){
                        return jQuery('td, th', table).length;
                    }, blit);

                    angular.element($window).bind('resize', blit);
                    element.on('$destroy', function() {
                        angular.element($window).unbind('resize', blit);
                    });
                }
            }

            function blit(){
                var expandableElement = jQuery('td',titleElement).children();
                expandableElement.outerWidth(parent.outerWidth());

                var offset = table.position().left * -1;
                if(offset + expandableElement.outerWidth() <= table.width()){
                    expandableElement.css('left', offset + 'px');
                }
            }
        }
    }

})();
<commit_msg>OLMIS-2355: added small workaround for tbody title directive<commit_after>/*
 * This program is part of the OpenLMIS logistics management information system platform software.
 * Copyright © 2017 VillageReach
 *
 * This program is free software: you can redistribute it and/or modify it under the terms
 * of the GNU Affero General Public License as published by the Free Software Foundation, either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details. You should have received a copy of
 * the GNU Affero General Public License along with this program. If not, see
 * http://www.gnu.org/licenses.  For additional information contact info@OpenLMIS.org.
 */

(function() {

    'use strict';

    /**
     * @ngdoc directive
     * @restrict E
     * @name openlmis-table.directive:tbodyTitle
     *
     * @description
     * Takes the title attribute from a tbody element and changes it into a stylable banner.
     *
     * @example
     * To add a title heading to any tbody element, just add a title element with a translated string (this element will not translate strings for you)
     * ```
     * <table>
     *   <tbody tbody-title="Category Title">
     *     <tr><td>123</td><td>456</td></tr>
     *     <tr><td>Foo</td><td>Bar</td></tr>
     *   </tbody>
     * </table>
     * ```
     * Which will produce the following markup
     * ```
     * <table>
     *   <tbody>
     *     <tr class="title"><td colspan="2"><div>Category Title</div></td></tr>
     *     <tr><td>123</td><td>456</td></tr>
     *     <tr><td>Foo</td><td>Bar</td></tr>
     *   </tbody>
     * </table>
     * ```
     */
    angular
        .module('openlmis-table')
        .directive('tbody', tbodyTitle);

    tbodyTitle.$inject = ['$compile', '$window', 'jQuery'];
    function tbodyTitle($compile, $window, jQuery) {
        var template = '

{{title}}

';

        return {
            restrict: 'E',
            replace: false,
            link: link
        };

        function link(scope, element, attrs) {
            if(attrs.tbodyTitle && attrs.tbodyTitle != ""){
                var titleScope = scope.$new(true);

                titleScope.title = attrs.tbodyTitle;

                scope.$watch(function(){
                    return element.children('tr:not(.title):first').children('td, th').length;
                }, function(num){
                    titleScope.colspan = num
                });

                var titleElement = $compile(template)(titleScope);
                element.prepend(titleElement);

                if(element.parents('.openlmis-table-container').length > 0){
                    var table = element.parents('table:first');

                    // openlmis-table-container will rewrite table's parent
                    // after this link is run... so we are watching
                    var parent = table.parent();
                    scope.$watch(function(){
                        return table.parent()[0];
                    }, function(newParent){
                        parent.off('scroll', blit);
                        parent = table.parent();
                        parent.on('scroll', blit);
                    });
                    element.on('$destroy', function(){
                        parent.off('scroll', blit);
                    });

                    scope.$watch(function(){
                        return jQuery('td, th', table).length;
                    }, blit);

                    angular.element($window).bind('resize', blit);
                    element.on('$destroy', function() {
                        angular.element($window).unbind('resize', blit);
                    });
                }
            }

            function blit(){
                var expandableElement = jQuery('td',titleElement).children();
                expandableElement.outerWidth(parent.outerWidth());

                var offset = table.position().left * -1;
                if(offset + expandableElement.outerWidth() <= table.width() + 1){
                    expandableElement.css('left', offset + 'px');
                }
            }
        }
    }

})();
<|endoftext|>


<commit_before>(function ($) {
  $.fn.buildNav = function (options) {
    defaults = {
      content: '',
      margin: 70
    };
    var options = $.extend(defaults, options);
    return this.each(function () {
      var $this = $(this);
      var $new_ul = $('
')
      var $anchors = (options.content).find('a[toc]');
      if ($anchors.length > 0) {
        $anchors.each(function () {
          this_a = $(this);
          title = this_a.attr('title');
          target = this_a.attr('toc');
          itemClass = this_a.attr('id');
          new_li = $('
' + title + '
').addClass(itemClass).appendTo($new_ul);
        });
        $new_ul.find('li').eq(0).addClass('active');

        $new_ul.prependTo($this);
        $this.on("click", "a.scroll", function (event) {
          var link = $(this);

          //window.history.pushState is not on all browsers
          if (window.history.pushState) {
            window.history.pushState({}, document.title, event.target.href);
          }

          event.preventDefault();
          $('html,body').animate({scrollTop: $('[name="' + this.hash.substring(1) + '"]').offset().top - options.margin}, 500, function () {
            // see spec
            // window.location.hash = link.attr('href');
          });
        });
      }

    });
  };
})(jQuery);
<commit_msg>DPRO-435: Refactor JavaScript<commit_after>(function ($) {
  $.fn.buildNav = function (options) {
    var defaults = {
      content: '',
      margin: 70
    };
    var options = $.extend(defaults, options);
    return this.each(function () {
      var $this = $(this);
      var $new_ul = $('
')
      var $anchors = (options.content).find('a[toc]');
      if ($anchors.length > 0) {
        $anchors.each(function () {
          var this_a = $(this),
            title = this_a.attr('title'),
            target = this_a.attr('toc'),
            itemClass = this_a.attr('id');
          $('
' + title + '
').addClass(itemClass).appendTo($new_ul);
        });
        $new_ul.find('li').eq(0).addClass('active');

        $new_ul.prependTo($this);
        $this.on("click", "a.scroll", function (event) {
          var link = $(this);

          //window.history.pushState is not on all browsers
          if (window.history.pushState) {
            window.history.pushState({}, document.title, event.target.href);
          }

          event.preventDefault();
          $('html,body').animate({scrollTop: $('[name="' + this.hash.substring(1) + '"]').offset().top - options.margin}, 500, function () {
            // see spec
            // window.location.hash = link.attr('href');
          });
        });
      }

    });
  };
})(jQuery);
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2012-2014 B3Partners B.V.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

Ext.define("viewer.components.sf.Config", {
    configObject: null,
    id: null,
    form: null,
    constructor: function (config) {
        this.configObject = config.configObject;
        this.id = this.configObject.id ? this.configObject.id : Ext.id();
        var items = this.getFormItems();
        this.form = Ext.create("Ext.form.Panel", {
            title: this.getTitle(),
            width: 325,
            bodyPadding: 5,
            layout: 'anchor',
            defaults: {
                anchor: '100%',
                flex:1
            },
            defaultType: 'textfield',
            items: items
        });

        Ext.getCmp(config.renderTo).items.add(this.form);
    },
    getFormItems: function () {
        var items = [{
            fieldLabel: 'Label',
            name: 'label',
            value: this.configObject.label ? this.configObject.label : ""
        }, {
            fieldLabel: "Beginwaarde(s)",
            name: "start",
            value: this.configObject.start ? this.configObject.start : this.getDefaultStartValue(),
            qtip: "Vul een vaste waarde in of 'min' of 'max'. Bij een slider voor een bereik geef twee waardes op gescheiden door een komma",
            listeners: {
                render: function (c) {
                    Ext.QuickTips.register({
                        target: c.getEl(),
                        text: c.qtip
                    });
                }
            }
        }];

        return items;
    },
    getConfig: function() {
        var config = this.form.getValues();
        config.id = this.id;
        return config;
    },
    getDefaultStartValue : function(){
        console.log("Error: getDefaultStartValue() not yet implemented");
    },
    getTitle : function(){
        console.log("Error: getTitle() not yet implemented");
    }
});

Ext.define("viewer.components.sf.CheckboxConfig", {
    extend: "viewer.components.sf.Config",
    constructor: function(config) {
        viewer.components.sf.CheckboxConfig.superclass.constructor.call(this, config);
        for (var i = 0 ; i < config.configObject.options.length ; i++){
            var option = config.configObject.options[i];
            this.addOption(option);
        }

    },
    getFormItems : function(){
        var items = this.callParent();
        items = items.concat([
        {
            name: "addOption",
            xtype: "button",
            id: "addOption",
            text: "Voeg optie toe",
            listeners: {
                click: {
                    fn: function (c) {
                        var id = Ext.id();
                        this.addOption({id:id});
                    },
                    scope: this
                }
            }
        },
        {
            xtype: "panel",
            border: 0,
            id: "optionsPanel",
            items : []
        }
        ]);
        return items;
    },
    addOption: function(entry){
        var panel = Ext.getCmp("optionsPanel");
        var items = [{
            name: "label" + entry.id,
            flex:1,
            id: "label" + entry.id,
            value: entry.label
        },
        {
            name: "value" + entry.id,
            id: "value"+ entry.id,
            flex:1,
            value: entry.value
        },
        {
            xtype: "button",
            id: "remove" + entry.id,
            name: "remove" + entry.id,
            text: "X",
            width: 25,
            flex:0,
            handler: function(){
                alert (12);
            }
        }];
        if (panel.items.length=== 0) {
            var header = Ext.create("Ext.container.Container", {
                layout: {
                    type: 'hbox'
                },
                border: 0,
                defaults: {
                    flex: 1
                },
                defaultType: "textfield",
                items:  [
                    {
                        xtype: 'label',
                        forId: 'label' + entry.id,
                        text: 'Label'
                    },
                    {
                        xtype: 'label',
                        forId: 'value' + entry.id,
                        text: 'Waarde'
                    },
                    {
                        xtype: 'label',
                        forId: 'remove' + entry.id,
                        text: 'Verwijder'
                    }
                ]
            });
            panel.add(header);
        }
        var item = Ext.create("Ext.container.Container", {
            layout: {
                type: 'hbox'
            },
            border: 0,
            defaults: {
                flex: 1
            },
            defaultType: "textfield",
            items: items
        });
        panel.add(item);
    },
    getTitle : function (){
        return "Vinkvak";
    },
    getDefaultStartValue : function (){
        return "";
    },
    getConfig : function(){
        var parentConfig = this.callParent();
        var config = {
            id: parentConfig.id,
            label : parentConfig.label,
            start: parentConfig.start
        };
        var options = [];
        var panel = Ext.getCmp("optionsPanel");
        for(var i = 1 ; i < panel.items.items.length ; i++){
            var item = panel.items.items[i];
            var data =item.items.items;
            var id = data[0].getId().substring(5);
            var option = {
                label: data[0].getValue(),
                value: data[1].getValue(),
                id: id
            };
            options.push(option);
        }
        config.options = options;
        return config;
    }
});

Ext.define("viewer.components.sf.ComboConfig", {
    extend: "viewer.components.sf.Config",
    constructor: function(config) {
        viewer.components.sf.ComboConfig.superclass.constructor.call(this, config);
    },
    getFormItems : function(){
        var items = this.callParent();
        items = items.concat([ {
            xtype: 'combo',
            fieldLabel: "Waardes selectielijst",
            name: "comboType",
            store: Ext.create("Ext.data.Store", {
                fields: ["type", "label"],
                data: [
                    {type: "unique", label: "Unieke waardes uit bron"},
                    {type: "own", label: "Eigen waardes toevoegen"},
                    {type: "range", label: "Numerieke waardes tussen bereik genereren."}
                ]
            }),
            queryModes: "local",
            displayField: "label",
            editable: false,
            valueField: "type",
            value: this.configObject.comboType ? this.configObject.comboType : "unique",
            listeners: {
                change: {
                    scope: this,
                    fn: function(obj, newValue){
                        var min = Ext.getCmp("min");
                        var max = Ext.getCmp("max");
                        var ownValues = Ext.getCmp("ownValues");
                        if(newValue === "unique" ){
                            min.hide();
                            max.hide();
                            ownValues.hide();
                        }else if (newValue === "range"){
                            min.show();
                            max.show();
                            ownValues.hide();
                        }else if (newValue === "own"){
                            min.hide();
                            max.hide();
                            ownValues.show();
                        }
                    }
                }
            }
        },
        {
            fieldLabel: "Minimale waarde",
            name: "min",
            hidden: (this.configObject.comboType && this.configObject.comboType !== "range") || !this.configObject.comboType,
            id: "min",
            qtip: "De minimale waarde voor de waardes in het bereik",
            value: this.configObject.min ? this.configObject.min : "",
            listeners: {
                render: function (c) {
                    Ext.QuickTips.register({
                        target: c.getEl(),
                        text: c.qtip
                    });
                }
            }
        }, {
            fieldLabel: "Maximale waarde",
            name: "max",
            hidden: ( this.configObject.comboType && this.configObject.comboType !== "range" ) || !this.configObject.comboType,
            qtip: "De maximale waarde voor de waardes in het bereik",
            id: "max",
            value: this.configObject.max ? this.configObject.max : "",
            listeners: {
                render: function (c) {
                    Ext.QuickTips.register({
                        target: c.getEl(),
                        text: c.qtip
                    });
                }
            }
        }, {
            fieldLabel: "Eigen waardes",
            name: "ownValues",
            hidden: (this.configObject.comboType && this.configObject.comboType !== "own") || !this.configObject.comboType,
            id: "ownValues",
            qtip: "Vul hier een lijst met eigen waardes in. De waardes moeten komma gescheiden zijn, bijvoorbeeld: 1,2,3",
            value: this.configObject.ownValues ? this.configObject.ownValues : "",
            listeners: {
                render: function (c) {
                    Ext.QuickTips.register({
                        target: c.getEl(),
                        text: c.qtip
                    });
                }
            }
        }
        ]);
        return items;
    },
    getDefaultStartValue : function (){
        return "max";
    },
    getTitle : function (){
        return "Selectielijst";
    }
});

Ext.define("viewer.components.sf.SliderConfig", {
    extend: "viewer.components.sf.Config",
    constructor: function(config) {
        viewer.components.sf.SliderConfig.superclass.constructor.call(this, config);
    },
    getFormItems : function(){
        var items = this.callParent();
        items = items.concat([{
            fieldLabel: "Minimale waarde",
            name: "min",
            qtip: "Indien geen waarde ingevuld wordt kleinste attribuutwaarde uit de attribuutlijst gebruikt",
            value: this.configObject.min ? this.configObject.min : "",
            listeners: {
                render: function (c) {
                    Ext.QuickTips.register({
                        target: c.getEl(),
                        text: c.qtip
                    });
                }
            }
        }, {
            fieldLabel: "Maximale waarde",
            name: "max",
            value: this.configObject.max ? this.configObject.max : "",
            qtip: "Indien geen waarde ingevuld wordt grootste attribuutwaarde uit de attribuutlijst gebruikt",
            listeners: {
                render: function (c) {
                    Ext.QuickTips.register({
                        target: c.getEl(),
                        text: c.qtip
                    });
                }
            }
        }, {
            fieldLabel: "Stap",
            name: "step",
            value: this.configObject.step ? this.configObject.step : "1"
        }, {
            xtype: 'combo',
            fieldLabel: "Soort slider",
            name: "sliderType",
            store: Ext.create("Ext.data.Store", {
                fields: ["type", "label"],
                data: [
                    {type: "eq", label: "Attribuut gelijk aan waarde slider"},
                    {type: "gt", label: "Attribuut groter dan waarde slider"},
                    {type: "lt", label: "Attribuut kleiner dan waarde slider"},
                    {type: "range", label: "Attribuut binnen bereik (twee schuifjes)"}
                ]
            }),
            queryModes: "local",
            displayField: "label",
            editable: false,
            valueField: "type",
            value: this.configObject.sliderType ? this.configObject.sliderType : "eq"
        }, {
            fieldLabel: "Waarde format string",
            name: "valueFormatString",
            value: this.configObject.valueFormatString ? this.configObject.valueFormatString : "",
            qtip: "Laat leeg om geen waarde van de schuifjes te tonen. Voorbeelden format strings: '0' (alleen hele getallen), '0 m²' (met eenheid), '0.00' (twee decimalen), '0,000' (met duizendtalscheidingsteken), '€ 0,000.00' (bedrag)",
            listeners: {
                render: function (c) {
                    Ext.QuickTips.register({
                        target: c.getEl(),
                        text: c.qtip
                    });
                }
            }
        }]);
        return items;
    },
    getDefaultStartValue : function (){
        return "min,max";
    },
    getTitle : function(){
        return "Slider";
    }

});<commit_msg>Removing of options implemented<commit_after>/*
 * Copyright (C) 2012-2014 B3Partners B.V.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

Ext.define("viewer.components.sf.Config", {
    configObject: null,
    id: null,
    form: null,
    constructor: function (config) {
        this.configObject = config.configObject;
        this.id = this.configObject.id ? this.configObject.id : Ext.id();
        var items = this.getFormItems();
        this.form = Ext.create("Ext.form.Panel", {
            title: this.getTitle(),
            width: 325,
            bodyPadding: 5,
            layout: 'anchor',
            defaults: {
                anchor: '100%',
                flex:1
            },
            defaultType: 'textfield',
            items: items
        });

        Ext.getCmp(config.renderTo).items.add(this.form);
    },
    getFormItems: function () {
        var items = [{
            fieldLabel: 'Label',
            name: 'label',
            value: this.configObject.label ? this.configObject.label : ""
        }, {
            fieldLabel: "Beginwaarde(s)",
            name: "start",
            value: this.configObject.start ? this.configObject.start : this.getDefaultStartValue(),
            qtip: "Vul een vaste waarde in of 'min' of 'max'. Bij een slider voor een bereik geef twee waardes op gescheiden door een komma",
            listeners: {
                render: function (c) {
                    Ext.QuickTips.register({
                        target: c.getEl(),
                        text: c.qtip
                    });
                }
            }
        }];

        return items;
    },
    getConfig: function() {
        var config = this.form.getValues();
        config.id = this.id;
        return config;
    },
    getDefaultStartValue : function(){
        console.log("Error: getDefaultStartValue() not yet implemented");
    },
    getTitle : function(){
        console.log("Error: getTitle() not yet implemented");
    }
});

Ext.define("viewer.components.sf.CheckboxConfig", {
    extend: "viewer.components.sf.Config",
    constructor: function(config) {
        viewer.components.sf.CheckboxConfig.superclass.constructor.call(this, config);
        for (var i = 0 ; i < config.configObject.options.length ; i++){
            var option = config.configObject.options[i];
            this.addOption(option);
        }

    },
    getFormItems : function(){
        var items = this.callParent();
        items = items.concat([
        {
            name: "addOption",
            xtype: "button",
            id: "addOption",
            text: "Voeg optie toe",
            listeners: {
                click: {
                    fn: function (c) {
                        var id = Ext.id();
                        this.addOption({id:id});
                    },
                    scope: this
                }
            }
        },
        {
            xtype: "panel",
            border: 0,
            id: "optionsPanel",
            items : []
        }
        ]);
        return items;
    },
    addOption: function(entry){
        var panel = Ext.getCmp("optionsPanel");
        var items = [{
            name: "label" + entry.id,
            flex:1,
            id: "label" + entry.id,
            value: entry.label
        },
        {
            name: "value" + entry.id,
            id: "value"+ entry.id,
            flex:1,
            value: entry.value
        },
        {
            xtype: "button",
            id: "remove" + entry.id,
            name: "remove" + entry.id,
            text: "X",
            width: 25,
            flex:0,
            listeners:{
                click:{
                    scope:this,
                    fn:function (button) {
                        var id = button.getId().substring("remove".length);
                        this.removeOption(id);
                    }
                }
            }
        }];
        if (panel.items.length=== 0) {
            var header = Ext.create("Ext.container.Container", {
                layout: {
                    type: 'hbox'
                },
                border: 0,
                defaults: {
                    flex: 1
                },
                defaultType: "textfield",
                items:  [
                    {
                        xtype: 'label',
                        forId: 'label' + entry.id,
                        text: 'Label'
                    },
                    {
                        xtype: 'label',
                        forId: 'value' + entry.id,
                        text: 'Waarde'
                    },
                    {
                        xtype: 'label',
                        forId: 'remove' + entry.id,
                        text: 'Verwijder'
                    }
                ]
            });
            panel.add(header);
        }
        var item = Ext.create("Ext.container.Container", {
            id: "optionContainer" + entry.id,
            layout: {
                type: 'hbox'
            },
            border: 0,
            defaults: {
                flex: 1
            },
            defaultType: "textfield",
            items: items
        });
        panel.add(item);
    },
    removeOption : function(id){
        var panel = Ext.getCmp("optionsPanel");
        var container = Ext.getCmp("optionContainer" + id);
        panel.remove(container);
    },
    getTitle : function (){
        return "Vinkvak";
    },
    getDefaultStartValue : function (){
        return "";
    },
    getConfig : function(){
        var parentConfig = this.callParent();
        var config = {
            id: parentConfig.id,
            label : parentConfig.label,
            start: parentConfig.start
        };
        var options = [];
        var panel = Ext.getCmp("optionsPanel");
        for(var i = 1 ; i < panel.items.items.length ; i++){
            var item = panel.items.items[i];
            var data =item.items.items;
            var id = data[0].getId().substring(5);
            var option = {
                label: data[0].getValue(),
                value: data[1].getValue(),
                id: id
            };
            options.push(option);
        }
        config.options = options;
        return config;
    }
});

Ext.define("viewer.components.sf.ComboConfig", {
    extend: "viewer.components.sf.Config",
    constructor: function(config) {
        viewer.components.sf.ComboConfig.superclass.constructor.call(this, config);
    },
    getFormItems : function(){
        var items = this.callParent();
        items = items.concat([ {
            xtype: 'combo',
            fieldLabel: "Waardes selectielijst",
            name: "comboType",
            store: Ext.create("Ext.data.Store", {
                fields: ["type", "label"],
                data: [
                    {type: "unique", label: "Unieke waardes uit bron"},
                    {type: "own", label: "Eigen waardes toevoegen"},
                    {type: "range", label: "Numerieke waardes tussen bereik genereren."}
                ]
            }),
            queryModes: "local",
            displayField: "label",
            editable: false,
            valueField: "type",
            value: this.configObject.comboType ? this.configObject.comboType : "unique",
            listeners: {
                change: {
                    scope: this,
                    fn: function(obj, newValue){
                        var min = Ext.getCmp("min");
                        var max = Ext.getCmp("max");
                        var ownValues = Ext.getCmp("ownValues");
                        if(newValue === "unique" ){
                            min.hide();
                            max.hide();
                            ownValues.hide();
                        }else if (newValue === "range"){
                            min.show();
                            max.show();
                            ownValues.hide();
                        }else if (newValue === "own"){
                            min.hide();
                            max.hide();
                            ownValues.show();
                        }
                    }
                }
            }
        },
        {
            fieldLabel: "Minimale waarde",
            name: "min",
            hidden: (this.configObject.comboType && this.configObject.comboType !== "range") || !this.configObject.comboType,
            id: "min",
            qtip: "De minimale waarde voor de waardes in het bereik",
            value: this.configObject.min ? this.configObject.min : "",
            listeners: {
                render: function (c) {
                    Ext.QuickTips.register({
                        target: c.getEl(),
                        text: c.qtip
                    });
                }
            }
        }, {
            fieldLabel: "Maximale waarde",
            name: "max",
            hidden: ( this.configObject.comboType && this.configObject.comboType !== "range" ) || !this.configObject.comboType,
            qtip: "De maximale waarde voor de waardes in het bereik",
            id: "max",
            value: this.configObject.max ? this.configObject.max : "",
            listeners: {
                render: function (c) {
                    Ext.QuickTips.register({
                        target: c.getEl(),
                        text: c.qtip
                    });
                }
            }
        }, {
            fieldLabel: "Eigen waardes",
            name: "ownValues",
            hidden: (this.configObject.comboType && this.configObject.comboType !== "own") || !this.configObject.comboType,
            id: "ownValues",
            qtip: "Vul hier een lijst met eigen waardes in. De waardes moeten komma gescheiden zijn, bijvoorbeeld: 1,2,3",
            value: this.configObject.ownValues ? this.configObject.ownValues : "",
            listeners: {
                render: function (c) {
                    Ext.QuickTips.register({
                        target: c.getEl(),
                        text: c.qtip
                    });
                }
            }
        }
        ]);
        return items;
    },
    getDefaultStartValue : function (){
        return "max";
    },
    getTitle : function (){
        return "Selectielijst";
    }
});

Ext.define("viewer.components.sf.SliderConfig", {
    extend: "viewer.components.sf.Config",
    constructor: function(config) {
        viewer.components.sf.SliderConfig.superclass.constructor.call(this, config);
    },
    getFormItems : function(){
        var items = this.callParent();
        items = items.concat([{
            fieldLabel: "Minimale waarde",
            name: "min",
            qtip: "Indien geen waarde ingevuld wordt kleinste attribuutwaarde uit de attribuutlijst gebruikt",
            value: this.configObject.min ? this.configObject.min : "",
            listeners: {
                render: function (c) {
                    Ext.QuickTips.register({
                        target: c.getEl(),
                        text: c.qtip
                    });
                }
            }
        }, {
            fieldLabel: "Maximale waarde",
            name: "max",
            value: this.configObject.max ? this.configObject.max : "",
            qtip: "Indien geen waarde ingevuld wordt grootste attribuutwaarde uit de attribuutlijst gebruikt",
            listeners: {
                render: function (c) {
                    Ext.QuickTips.register({
                        target: c.getEl(),
                        text: c.qtip
                    });
                }
            }
        }, {
            fieldLabel: "Stap",
            name: "step",
            value: this.configObject.step ? this.configObject.step : "1"
        }, {
            xtype: 'combo',
            fieldLabel: "Soort slider",
            name: "sliderType",
            store: Ext.create("Ext.data.Store", {
                fields: ["type", "label"],
                data: [
                    {type: "eq", label: "Attribuut gelijk aan waarde slider"},
                    {type: "gt", label: "Attribuut groter dan waarde slider"},
                    {type: "lt", label: "Attribuut kleiner dan waarde slider"},
                    {type: "range", label: "Attribuut binnen bereik (twee schuifjes)"}
                ]
            }),
            queryModes: "local",
            displayField: "label",
            editable: false,
            valueField: "type",
            value: this.configObject.sliderType ? this.configObject.sliderType : "eq"
        }, {
            fieldLabel: "Waarde format string",
            name: "valueFormatString",
            value: this.configObject.valueFormatString ? this.configObject.valueFormatString : "",
            qtip: "Laat leeg om geen waarde van de schuifjes te tonen. Voorbeelden format strings: '0' (alleen hele getallen), '0 m²' (met eenheid), '0.00' (twee decimalen), '0,000' (met duizendtalscheidingsteken), '€ 0,000.00' (bedrag)",
            listeners: {
                render: function (c) {
                    Ext.QuickTips.register({
                        target: c.getEl(),
                        text: c.qtip
                    });
                }
            }
        }]);
        return items;
    },
    getDefaultStartValue : function (){
        return "min,max";
    },
    getTitle : function(){
        return "Slider";
    }

});<|endoftext|>


<commit_before>export { ShuffleNetV2_ByMobileNetV1_padValid };

import * as ValueDesc from "../../../Unpacker/ValueDesc.js";
import { Params } from "../Block_Param.js";
import { ShuffleNetV2_ByMobileNetV1 } from "./ShuffleNetV2_ByMobileNetV1.js";

/**
 * This class is almost the same as ShuffleNetV2_ByMobileNetV1 except the depthwise convolution's padding is "valid" (instead of "same").
 *
 *
 * 1. Reason
 *
 * Q: Why is this configuration necessary?
 * A: The right-most pixel of depthwise convolution seems wrong when ( strides = 1, pad = "same" ) in backend WebGL of some
 *    platforms (e.g. mobile phone Moto e40). But the issue does not exist when ( strides = 2, pad = "same" ) or ( pad = "valid" )
 *    in those platforms.
 *
 * For achieving ShuffleNetV2 with depthwise padding "valid", ShuffleNetV2_ByMobileNetV1 is necessary because other ShuffleNetV2_ByXxx
 * (with depthwise padding "same") could not concatenate two channel groups whic have different image size (due to padding "valid").
 *
 *
 * 2. Drawback
 *
 * The disadvantage is that the right-most and bottom-most pixels will be dropped when pass-through the higher half of depthwise
 * convolution due to padding "valid".
 *
 *
 * 2.1 Drawback and 1D data
 *
 * Although 1D data (e.g. voice) has only one line (i.e. the only bottom-most data) which should not be dropped (otherwise,
 * all data are dropped), this disadvantage will not be a diaster for 1D data.
 *
 * The reason is that depthwise filter size (in some direction) can not be larger than input data size (in that diecrtion).
 * For 1D data, this means that only depthwise convolution with ( depthwiseFilterHeight == 1 ) could be used.
 *
 * When filter size is 1 (in some direction), the output size (in that direction) will always be the same as input even
 * if ( pad = "valid" ). So, the only one bottom-most data will not be dropped diasterly.
 *
 */
class ShuffleNetV2_ByMobileNetV1_padValid extends ShuffleNetV2_ByMobileNetV1 {

  /** @override */
  configTo_beforeStep0() {
    super.configTo_beforeStep0(); // Step0 is almost the same as ShuffleNetV2_ByMobileNetV1.

    // Except padding is "valid" (not "same").
    this.depthwiseStridesPad = ValueDesc.StridesPad.Singleton.Ids.STRIDES_2_PAD_VALID;
  }

  /** @override */
  configTo_afterStep0() {
    super.configTo_afterStep0(); // Step1, 2, 3, ... are almost the same as ShuffleNetV2_ByMobileNetV1.

    // Except padding is "valid" (not "same").
    this.depthwiseStridesPad = ValueDesc.StridesPad.Singleton.Ids.STRIDES_1_PAD_VALID;
  }
}

<commit_msg>Update ShuffleNetV2_ByMobileNetV1_padValid.js<commit_after>export { ShuffleNetV2_ByMobileNetV1_padValid };

import * as ValueDesc from "../../../Unpacker/ValueDesc.js";
import { Params } from "../Block_Param.js";
import { ShuffleNetV2_ByMobileNetV1 } from "./ShuffleNetV2_ByMobileNetV1.js";

/**
 * This class is almost the same as ShuffleNetV2_ByMobileNetV1 except the depthwise convolution's padding is "valid" (instead of "same").
 *
 *
 * 1. Reason
 *
 * Q: Why is this configuration necessary?
 * A: The right-most pixel of depthwise convolution seems wrong when ( strides = 1, pad = "same" ) in backend WebGL of some
 *    platforms (e.g. mobile phone Moto e40). But the issue does not exist when ( strides = 2, pad = "same" ) or ( pad = "valid" )
 *    in those platforms.
 *
 * For achieving ShuffleNetV2 with depthwise padding "valid", ShuffleNetV2_ByMobileNetV1 is necessary because other ShuffleNetV2_ByXxx
 * (with depthwise padding "same") could not concatenate two channel groups whic have different image size (due to padding "valid").
 *
 *
 * 2. Drawback
 *
 * The disadvantage is that the right-most and bottom-most pixels will be dropped when pass-through the higher half of depthwise
 * convolution due to padding "valid".
 *
 *
 * 2.1 Drawback and 1D data
 *
 * Although 1D data (e.g. voice) has only one line (i.e. the only bottom-most data) which should not be dropped (otherwise,
 * all data are dropped), this disadvantage will not be a diaster for 1D data.
 *
 * The reason is that depthwise filter size (in some direction) can not be larger than input data size (in that diecrtion).
 * For 1D data, this means that only depthwise convolution with ( depthwiseFilterHeight == 1 ) could be used.
 *
 * When filter size is 1 (in some direction), the output size (in that direction) will always be the same as input even
 * if ( pad = "valid" ). So, the only one bottom-most data will not be dropped diasterly.
 *
 */
class ShuffleNetV2_ByMobileNetV1_padValid extends ShuffleNetV2_ByMobileNetV1 {

  /** @override */
  configTo_beforeStep0() {
    super.configTo_beforeStep0(); // Step0 is almost the same as ShuffleNetV2_ByMobileNetV1.

    // Except padding is "valid" (not "same").
    this.depthwiseStridesPad = ValueDesc.StridesPad.Singleton.Ids.STRIDES_2_PAD_VALID;
  }

  /** @override */
  configTo_afterStep0() {
    super.configTo_afterStep0(); // Step1, 2, 3, ... are almost the same as ShuffleNetV2_ByMobileNetV1.

    // Except padding is "valid" (not "same").
    this.depthwiseStridesPad = ValueDesc.StridesPad.Singleton.Ids.STRIDES_1_PAD_VALID;
  }

  /** @override */
  configTo_beforeStepLast() {
    super.configTo_beforeStepLast(); // StepLast is the same as ShuffleNetV2_ByMobileNetV1.
  }
}

<|endoftext|>