MapleStory Bug Reporter v3

Now with AngularJS!

by MegaScience

HTML

<script src="https://cdn.rawgit.com/nfrasser/linkify-shim/v2.0.3/linkify.js"></script>
<script src="https://cdn.rawgit.com/nfrasser/linkify-shim/v2.0.3/linkify-string.js"></script>
<form name="bugReport" ng-controller="mainController" ng-class="{cleared: cleared}" ng-submit="processReport() && false">
  <table>
    <thead>
      <tr>
        <th colspan="2">Formatting-Aid for MapleStory Bug Reporting</th>
      </tr>
    </thead>
    <tbody>
      <tr ng-repeat="(mIndex, tier) in entries" ng-switch on="tier.entryType">
        <th ng-if="tier.entryType !== 'br'">{{tier.title || ""}}</th>
        <td ng-switch-when="input">
          <input attrs="tier.attributes" ng-model="tier.value" ng-model-options="{ debounce: 1000 }" ng-change="storeData()" />
        </td>
        <td ng-switch-when="textarea">
          <textarea attrs="tier.attributes" ng-model="tier.value" ng-model-options="{ debounce: 1000 }" ng-change="storeData()"></textarea>
        </td>
        <!--<td ng-switch-when="ol">-->
        <td ng-if="tier.entryType === 'ol' || tier.entryType === 'ul'">
          <ol ng-class="{ul: tier.entryType === 'ul'}">
            <li ng-repeat="entry in tier.items track by $index">
              <button type="button" tabindex="-1" ng-click="listButton(mIndex, $index)">{{$index === 0 ? "+" : "-"}}</button><span><input type="text" ng-model="entry.value" ng-model-options="{ debounce: 1000 }" ng-change="storeData()"/></span></li>
          </ol>
        </td>
        <td ng-switch-when="select">
          <select attrs="tier.attributes" ng-model="tier.value" ng-model-options="{ debounce: 1000 }" ng-change="storeData()">
            <option ng-repeat="option in tier.options">{{option}}</option>
          </select>
        </td>
        <td ng-switch-when="br" colspan="2">
          <!--Line Break (This is included since, table-wise, a slight gap is formed.)-->
        </td>
      </tr>
      <tr>
        <td class="controls" colspan="2">
          <input type="submit"...

CSS

html,
body {
  background-color: #ccccc4;
  //background-image: url("http://nxcache.nexon.net/maplestory/assets-new/img/bg_section_ghosted_grey_variation_8.jpg");
  //background-image: url("http://nxcache.nexon.net/maplestory/assets-new/img/bg_section_ghosted_grey.jpg");
  //background-position: 50% 0;
  //background-repeat: no-repeat;
  min-height: 100%;
  margin: 0;
  font-family: arial, sans-serif;
  font-size: 14px;
}

th[colspan="2"] {
  padding: 5px 0;
  font-size: 24px;
}

th:not([colspan="2"]) {
  text-align: left;
  vertical-align: top;
  width: 14em;
  padding-left: 3px;
}

form {
  max-width: 960px;
  margin: 5px auto;
  min-height: calc(100% - 35px);
  background-color: #FFF;
  border-radius: 25px;
  padding-bottom: 25px;
  //background-color: rgba(255, 255, 255, 0.35);
}

table {
  width: 100%;
  border-collapse: collapse;
}

input,
button,
select,
textarea {
  -moz-box-sizing: border-box;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
}

ol,
ul {
  margin: 0;
  padding-left: 0;
  list-style-position: outside;
}

ol.ul {
  list-style-type: disc;
}

input,
select,
textarea {
  width: 100%;
}

li span {
  display: block;
  overflow: hidden;
}

li button {
  float: right;
  padding: 0;
  width: 1.65em;
  height: 1.65em;
}

textarea[name="output"] {
  min-height: 14em;
}

textarea {
  resize: vertical;
}

form.cleared input:invalid,
form.cleared textarea:invalid,
form.cleared select:invalid {
  box-shadow: none;
}

.controls input,
.controls button {
  display: inline-block;
}

.controls input {
  width: 70%;
}

.controls button {
  width: 15%;
}

JavaScript

var theModule = angular.module('generateTableApp', []);
theModule.config(function($logProvider) {
  $logProvider.debugEnabled(false);
});
theModule.controller('mainController', ['$scope', '$log', mainController]);

// For adding attributes codewise, instead of hard-coded into the above HTML.
theModule.directive('attrs', function() {
  return {
    link: function(scope, element, attributes) {
      //var attrs2 = angular.copy();
      element.attr(scope.$eval(attributes.attrs));
    }
  };
});

function mainController($scope, $log) {
  $scope.MSBRLog = function(message, debug) {
    var str = "MapleStory Bug Report" + (debug ? " [Debug]" : "") + ": " + message;
    if (debug) $log.debug(str);
    else $log.log(str);
  };
  $scope.processValue = function(str) {
  	try {
      return linkifyStr(str, {
        tagName: "url"
      }).replace(/<url href=\"([^\"]+)\"[^>]+>([^<]+)<\/url>/gmi, function(match, p1, p2) {
        if (/\.(jpe?g|png|gif)(\?.*)?$/i.test(p1))
          return "<img src=\"" + p1 + "\"/>";
        else
          return match;
      }).replace(/^([\t ]*?<img src=".*?"\/>[\t ]*?)+$/gmi, "<div style=\"display: block; margin: 0 auto;\">$&</div>");
    }
    catch(e) {
    	$log.log(e);
    	return str;
    }
  };
  $scope.listEntry = function (value) {
  	this.value = !!value ? value : "";
    this.prefix = "<li>";
    this.suffix = "</li>";
  };
  $scope.listButton = function(pIndex, sIndex) {
    var list = $scope.entries[pIndex].items;
    //console.log(list[sIndex]);
    if (sIndex === 0) list.push(new $scope.listEntry());
    else list.splice(sIndex, 1);
  };
  $scope.processReport = function() {
  	try {
      var output = [],
        temp = [],
        token = false;
      angular.forEach($scope.entries, function(entry, entryIndex) {
        switch (entry.entryType) {
          case "input":
          case "textarea":
          case "select":
            if (!!entry.value) output.push(entry.prefix + $scope.processValue(entry.value));
         ...