MapleStory Bug Reporter v3
Now with AngularJS!
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: inline-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));
...