').data('kink', name).addClass('kinkRow');
+ for(var i = 0; i < fields.length; i++) {
+ var $choices = inputKinks.createChoice();
+ $choices.data('field', fields[i]);
+ $choices.addClass('choice-' + strToClass(fields[i]));
+ $('| ').append($choices).appendTo($row);
+ }
+ $(' | ').text(name).appendTo($row);
+ $row.addClass('kink-' + strToClass(name));
+ return $row;
+ },
+ createColumns: function(){
+ var colClasses = ['100', '50', '33', '25'];
+
+ var numCols = Math.floor((document.body.scrollWidth - 20) / 400);
+ if(!numCols) numCols = 1;
+ if(numCols > 4) numCols = 4;
+ var colClass = 'col' + colClasses[numCols - 1];
+
+ inputKinks.$columns = [];
+ for(var i = 0; i < numCols; i++){
+ inputKinks.$columns.push($('').addClass('col ' + colClass).appendTo($('#InputList')));
+ }
+ },
+ placeCategories: function($categories){
+ var $body = $('body');
+ var totalHeight = 0;
+ for(var i = 0; i < $categories.length; i++) {
+ var $clone = $categories[i].clone().appendTo($body);
+ var height = $clone.height();;
+ totalHeight += height;
+ $clone.remove();
+ }
+
+ var colHeight = totalHeight / (inputKinks.$columns.length);
+ var colIndex = 0;
+ for(var i = 0; i < $categories.length; i++) {
+ var curHeight = inputKinks.$columns[colIndex].height();
+ var catHeight = $categories[i].height();
+ if(curHeight + (catHeight / 2) > colHeight) colIndex++;
+ while(colIndex >= inputKinks.$columns.length) {
+ colIndex--;
+ }
+ inputKinks.$columns[colIndex].append($categories[i]);
+ }
+ },
+ fillInputList: function(){
+ $('#InputList').empty();
+ inputKinks.createColumns();
+
+ var $categories = [];
+ var kinkCats = Object.keys(kinks);
+ for(var i = 0; i < kinkCats.length; i++) {
+ var catName = kinkCats[i];
+ var category = kinks[catName];
+ var fields = category.fields;
+ var kinkArr = category.kinks;
+
+ var $category = inputKinks.createCategory(catName, fields);
+ var $tbody = $category.find('tbody');
+ for(var k = 0; k < kinkArr.length; k++) {
+ $tbody.append(inputKinks.createKink(fields, kinkArr[k]));
+ }
+
+ $categories.push($category);
+ }
+ inputKinks.placeCategories($categories);
+
+ // Make things update hash
+ $('#InputList').find('button.choice').on('click', function(){
+ location.hash = inputKinks.updateHash();
+ });
+ },
+ init: function(){
+ // Set up DOM
+ inputKinks.fillInputList();
+
+ // Read hash
+ inputKinks.parseHash();
+
+ // Make export button work
+ $('#Export').on('click', inputKinks.export);
+ $('#URL').on('click', function(){ this.select(); });
+
+ // On resize, redo columns
+ (function(){
+
+ var lastResize = 0;
+ $(window).on('resize', function(){
+ var curTime = (new Date()).getTime();
+ lastResize = curTime;
+ setTimeout(function(){
+ if(lastResize === curTime) {
+ inputKinks.fillInputList();
+ inputKinks.parseHash();
+ }
+ }, 500);
+ });
+
+ })();
+ },
+ hashChars: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.=+*^!@",
+ maxPow: function(base, maxVal) {
+ var maxPow = 1;
+ for(var pow = 1; Math.pow(base, pow) <= maxVal; pow++){
+ maxPow = pow;
+ }
+ return maxPow;
+ },
+ prefix: function(input, len, char){
+ while(input.length < len) {
+ input = char + input;
+ }
+ return input;
+ },
+ drawLegend: function(context){
+ context.font = "bold 13px Arial";
+ context.fillStyle = '#000000';
+
+ var levels = Object.keys(colors);
+ var x = context.canvas.width - 15 - (120 * levels.length);
+ for(var i = 0; i < levels.length; i++) {
+ context.beginPath();
+ context.arc(x + (120 * i), 17, 8, 0, 2 * Math.PI, false);
+ context.fillStyle = colors[levels[i]];
+ context.fill();
+ context.strokeStyle = 'rgba(0, 0, 0, 0.5)'
+ context.lineWidth = 1;
+ context.stroke();
+
+ context.fillStyle = '#000000';
+ context.fillText(levels[i], x + 15 + (i * 120), 22);
+ }
+ },
+ setupCanvas: function(width, height, username){
+ $('canvas').remove();
+ var canvas = document.createElement('canvas');
+ canvas.width = width;
+ canvas.height = height;
+
+ var $canvas = $(canvas);
+ $canvas.css({
+ width: width,
+ height: height
+ });
+ // $canvas.insertBefore($('#InputList'));
+
+ var context = canvas.getContext('2d');
+ context.fillStyle = '#FFFFFF';
+ context.fillRect(0, 0, canvas.width, canvas.height);
+
+ context.font = "bold 24px Arial";
+ context.fillStyle = '#000000';
+ context.fillText('Kinklist ' + username, 5, 25);
+
+ inputKinks.drawLegend(context);
+ return { context: context, canvas: canvas };
+ },
+ drawCallHandlers: {
+ simpleTitle: function(context, drawCall){
+ context.fillStyle = '#000000';
+ context.font = "bold 18px Arial";
+ context.fillText(drawCall.data, drawCall.x, drawCall.y + 5);
+ },
+ titleSubtitle: function(context, drawCall){
+ context.fillStyle = '#000000';
+ context.font = "bold 18px Arial";
+ context.fillText(drawCall.data.category, drawCall.x, drawCall.y + 5);
+
+ var fieldsStr = drawCall.data.fields.join(', ');
+ context.font = "italic 12px Arial";
+ context.fillText(fieldsStr, drawCall.x, drawCall.y + 20);
+ },
+ kinkRow: function(context, drawCall){
+ context.fillStyle = '#000000';
+ context.font = "12px Arial";
+
+ var x = drawCall.x + 5 + (drawCall.data.choices.length * 20);
+ var y = drawCall.y - 6;
+ context.fillText(drawCall.data.text, x, y);
+
+ // Circles
+ for(var i = 0; i < drawCall.data.choices.length; i++){
+ var choice = drawCall.data.choices[i];
+ var color = colors[choice];
+
+ var x = 10 + drawCall.x + (i * 20);
+ var y = drawCall.y - 10;
+
+ context.beginPath();
+ context.arc(x, y, 8, 0, 2 * Math.PI, false);
+ context.fillStyle = color;
+ context.fill();
+ context.strokeStyle = 'rgba(0, 0, 0, 0.5)'
+ context.lineWidth = 1;
+ context.stroke();
+ }
+
+ }
+ },
+ export: function(){
+ var username = prompt("Please enter your name");
+ if(typeof username !== 'string') return;
+ else if (username.length ) username = '(' + username + ')';
+
+ $('#Loading').fadeIn();
+ $('#URL').fadeOut();
+
+ // Constants
+ var numCols = 6;
+ var columnWidth = 250;
+ var simpleTitleHeight = 35;
+ var titleSubtitleHeight = 50;
+ var rowHeight = 25;
+ var offsets = {
+ left: 10,
+ right: 10,
+ top: 50,
+ bottom: 10
+ };
+
+ // Find out how many we have of everything
+ var numCats = $('.kinkCategory').length;
+ var dualCats = $('.kinkCategory th + th + th').length;
+ var simpleCats = numCats - dualCats;
+ var numKinks = $('.kinkRow').length;
+
+ // Determine the height required for all categories and kinks
+ var totalHeight = (
+ (numKinks * rowHeight) +
+ (dualCats * titleSubtitleHeight) +
+ (simpleCats * simpleTitleHeight)
+ );
+
+ // Initialize columns and drawStacks
+ var columns = [];
+ for(var i = 0; i < numCols; i++){
+ columns.push({ height: 0, drawStack: []});
+ }
+
+ // Create drawcalls and place them in the drawStack
+ // for the appropriate column
+ var avgColHeight = totalHeight / numCols;
+ var columnIndex = 0;
+ $('.kinkCategory').each(function(){
+ var $cat = $(this);
+ var catName = $cat.data('category');
+ var category = kinks[catName];
+ var fields = category.fields;
+ var catKinks = category.kinks;
+
+ var catHeight = 0;
+ catHeight += (fields.length === 1) ? simpleTitleHeight : titleSubtitleHeight;
+ catHeight += (catKinks.length * rowHeight);
+
+ // Determine which column to place this category in
+ if((columns[columnIndex].height + (catHeight / 2)) > avgColHeight) columnIndex++;
+ while(columnIndex >= numCols) columnIndex--;
+ var column = columns[columnIndex];
+
+ // Drawcall for title
+ var drawCall = { y: column.height };
+ column.drawStack.push(drawCall);
+ if(fields.length < 2) {
+ column.height += simpleTitleHeight;
+ drawCall.type = 'simpleTitle';
+ drawCall.data = catName;
+ }
+ else {
+ column.height += titleSubtitleHeight;
+ drawCall.type = 'titleSubtitle';
+ drawCall.data = {
+ category: catName,
+ fields: fields
+ };
+ }
+
+ // Drawcalls for kinks
+ $cat.find('.kinkRow').each(function(){
+ var $kinkRow = $(this);
+ var drawCall = { y: column.height, type: 'kinkRow', data: {
+ choices: [],
+ text: $kinkRow.data('kink')
+ }};
+ column.drawStack.push(drawCall);
+ column.height += rowHeight;
+
+ // Add choices
+ $kinkRow.find('.choices').each(function(){
+ var $selection = $(this).find('.choice.selected');
+ var selection = ($selection.length > 0)
+ ? $selection.data('level')
+ : Object.keys(level)[0];
+
+ drawCall.data.choices.push(selection);
+ });
+ });
+ });
+
+ var tallestColumnHeight = 0;
+ for(var i = 0; i < columns.length; i++){
+ if(tallestColumnHeight < columns[i].height) {
+ tallestColumnHeight = columns[i].height;
+ }
+ }
+
+ var canvasWidth = offsets.left + offsets.right + (columnWidth * numCols);
+ var canvasHeight = offsets.top + offsets.bottom + tallestColumnHeight;
+ var setup = inputKinks.setupCanvas(canvasWidth, canvasHeight, username);
+ var context = setup.context;
+ var canvas = setup.canvas;
+
+ for(var i = 0; i < columns.length; i++) {
+ var column = columns[i];
+ var drawStack = column.drawStack;
+
+ var drawX = offsets.left + (columnWidth * i);
+ for(var j = 0; j < drawStack.length; j++){
+ var drawCall = drawStack[j];
+ drawCall.x = drawX;
+ drawCall.y += offsets.top;
+ inputKinks.drawCallHandlers[drawCall.type](context, drawCall);
+ }
+ }
+
+ //return $(canvas).insertBefore($('#InputList'));
+
+ // Send canvas to imgur
+ $.ajax({
+ url: 'https://api.imgur.com/3/image',
+ type: 'POST',
+ headers: {
+ // Your application gets an imgurClientId from Imgur
+ Authorization: 'Client-ID ' + imgurClientId,
+ Accept: 'application/json'
+ },
+ data: {
+ // convert the image data to base64
+ image: canvas.toDataURL().split(',')[1],
+ type: 'base64'
+ },
+ success: function(result) {
+ $('#Loading').hide();
+ var url = 'https://i.imgur.com/' + result.data.id + '.png';
+ $('#URL').val(url).fadeIn();
+ },
+ fail: function(){
+ $('#Loading').hide();
+ alert('Failed to upload to imgur, could not connect');
+ }
+ });
+ },
+ encode: function(base, input){
+ var hashBase = inputKinks.hashChars.length;
+ var outputPow = inputKinks.maxPow(hashBase, Number.MAX_SAFE_INTEGER);
+ var inputPow = inputKinks.maxPow(base, Math.pow(hashBase, outputPow));
+
+ var output = "";
+ var numChunks = Math.ceil(input.length / inputPow);
+ var inputIndex = 0;
+ for(var chunkId = 0; chunkId < numChunks; chunkId++) {
+ var inputIntValue = 0;
+ for(var pow = 0; pow < inputPow; pow++) {
+ var inputVal = input[inputIndex++];
+ if(typeof inputVal === "undefined") break;
+ var val = inputVal * Math.pow(base, pow);
+ inputIntValue += val;
+ }
+
+ var outputCharValue = "";
+ while(inputIntValue > 0) {
+ var maxPow = Math.floor(log(inputIntValue, hashBase));
+ var powVal = Math.pow(hashBase, maxPow);
+ var charInt = Math.floor(inputIntValue / powVal);
+ var subtract = charInt * powVal;
+ var char = inputKinks.hashChars[charInt];
+ outputCharValue += char;
+ inputIntValue -= subtract;
+ }
+ var chunk = inputKinks.prefix(outputCharValue, outputPow, inputKinks.hashChars[0]);
+ output += chunk;
+ }
+ return output;
+ },
+ decode: function(base, output){
+ var hashBase = inputKinks.hashChars.length;
+ var outputPow = inputKinks.maxPow(hashBase, Number.MAX_SAFE_INTEGER);
+
+ var values = [];
+ var numChunks = Math.max(output.length / outputPow)
+ for(var i = 0; i < numChunks; i++){
+ var chunk = output.substring(i * outputPow, (i + 1) * outputPow);
+ var chunkValues = inputKinks.decodeChunk(base, chunk);
+ for(var j = 0; j < chunkValues.length; j++) {
+ values.push(chunkValues[j]);
+ }
+ }
+ return values;
+ },
+ decodeChunk: function(base, chunk){
+ var hashBase = inputKinks.hashChars.length;
+ var outputPow = inputKinks.maxPow(hashBase, Number.MAX_SAFE_INTEGER);
+ var inputPow = inputKinks.maxPow(base, Math.pow(hashBase, outputPow));
+
+ var chunkInt = 0;
+ for(var i = 0; i < chunk.length; i++) {
+ var char = chunk[i];
+ var charInt = inputKinks.hashChars.indexOf(char);
+ var pow = chunk.length - 1 - i;
+ var intVal = Math.pow(hashBase, pow) * charInt;
+ chunkInt += intVal;
+ }
+ var chunkIntCopy = chunkInt;
+
+ var output = [];
+ for(var pow = inputPow - 1; pow >= 0; pow--) {
+ var posBase = Math.floor(Math.pow(base, pow));
+ var posVal = Math.floor(chunkInt / posBase);
+ var subtract = posBase * posVal;
+ output.push(posVal);
+ chunkInt -= subtract;
+ }
+ output.reverse();
+ return output;
+ },
+ updateHash: function(){
+ var hashValues = [];
+ $('#InputList .choices').each(function(){
+ var $this = $(this);
+ var lvlInt = $this.find('.selected').data('levelInt');
+ if(!lvlInt) lvlInt = 0;
+ hashValues.push(lvlInt);
+ });
+ return inputKinks.encode(Object.keys(colors).length, hashValues);
+ },
+ parseHash: function(){
+ var hash = location.hash.substring(1);
+ if(hash.length < 10) return;
+
+ var values = inputKinks.decode(Object.keys(colors).length, hash);
+ var valueIndex = 0;
+ $('#InputList .choices').each(function(){
+ var $this = $(this);
+ var value = values[valueIndex++];
+ $this.children().eq(value).addClass('selected');
+ });
+ },
+ saveSelection: function(){
+ var selection = [];
+ $('.choice.selected').each(function(){
+ // .choice selector
+ var selector = '.' + this.className.replace(/ /g, '.');
+ // .choices selector
+ selector = '.' + $(this).closest('.choices')[0].className.replace(/ /g, '.') + ' ' + selector;
+ // .kinkRow selector
+ selector = '.' + $(this).closest('tr.kinkRow')[0].className.replace(/ /g, '.') + ' ' + selector;
+ // .kinkCategory selector
+ selector = '.' + $(this).closest('.kinkCategory')[0].className.replace(/ /g, '.') + ' ' + selector;
+ selector = selector.replace('.selected', '');
+ selection.push(selector);
+ });
+ return selection;
+ },
+ inputListToText: function(){
+ var KinksText = "";
+ var kinkCats = Object.keys(kinks);
+ for(var i = 0; i < kinkCats.length; i++){
+ var catName = kinkCats[i];
+ var catFields = kinks[catName].fields;
+ var catKinks = kinks[catName].kinks;
+ KinksText += '#' + catName + "\r\n";
+ KinksText += '(' + catFields.join(', ') + ")\r\n";
+ for(var j = 0; j < catKinks.length; j++){
+ KinksText += '* ' + catKinks[j] + "\r\n";
+ }
+ KinksText += "\r\n";
+ }
+ return KinksText;
+ },
+ restoreSavedSelection: function(selection){
+ setTimeout(function(){
+ for(var i = 0; i < selection.length; i++){
+ var selector = selection[i];
+ $(selector).addClass('selected');
+ }
+ location.hash = inputKinks.updateHash();
+ }, 300);
+ },
+ parseKinksText: function(kinksText){
+ var newKinks = {};
+ var lines = kinksText.replace(/\r/g, '').split("\n");
+
+ var cat = null;
+ var catName = null;
+ for(var i = 0; i < lines.length; i++){
+ var line = lines[i];
+ if(!line.length) continue;
+
+ if(line[0] === '#') {
+ if(catName){
+ if(!(cat.fields instanceof Array) || cat.fields.length < 1){
+ alert(catName + ' does not have any fields defined!');
+ return;
+ }
+ if(!(cat.kinks instanceof Array) || cat.kinks.length < 1){
+ alert(catName + ' does not have any kinks listed!');
+ return;
+ }
+ newKinks[catName] = cat;
+ }
+ catName = line.substring(1).trim();
+ cat = { kinks: [] };
+ }
+ if(!catName) continue;
+ if(line[0] === '(') {
+ cat.fields = line.substring(1, line.length - 1).trim().split(',');
+ for(var j = 0; j < cat.fields.length; j++){
+ cat.fields[j] = cat.fields[j].trim();
+ }
+ }
+ if(line[0] === '*'){
+ var kink = line.substring(1).trim();
+ cat.kinks.push(kink);
+ }
+ }
+ if(catName && !newKinks[catName]){
+ if(!(cat.fields instanceof Array) || cat.fields.length < 1){
+ alert(catName + ' does not have any fields defined!');
+ return;
+ }
+ if(!(cat.kinks instanceof Array) || cat.kinks.length < 1){
+ alert(catName + ' does not have any kinks listed!');
+ return;
+ }
+ newKinks[catName] = cat;
+ }
+ return newKinks;
+ }
+ };
+
+ $('#Edit').on('click', function(){
+ var KinksText = inputKinks.inputListToText();
+ $('#Kinks').val(KinksText.trim());
+ $('#EditOverlay').fadeIn();
+ });
+ $('#EditOverlay').on('click', function(){
+ $(this).fadeOut();
+ });
+ $('#KinksOK').on('click', function(){
+ var selection = inputKinks.saveSelection();
+ try {
+ var kinksText = $('#Kinks').val();
+ kinks = inputKinks.parseKinksText(kinksText);
+ inputKinks.fillInputList();
+ }
+ catch(e){
+ alert('An error occured trying to parse the text entered, please correct it and try again');
+ return;
+ }
+ inputKinks.restoreSavedSelection(selection);
+ $('#EditOverlay').fadeOut();
+ });
+ $('.overlay > *').on('click', function(e){
+ e.stopPropagation();
+ });
+
+ var stylesheet = document.styleSheets[0];
+ $('.legend .choice').each(function(){
+ var $choice = $(this);
+ var $parent = $choice.parent();
+ var text = $parent.text().trim();
+ var color = $choice.data('color');
+ var cssClass = this.className.replace('choice ', '').trim();
+
+ addCssRule('.choice.' + cssClass, 'background-color: ' + color + ';');
+ colors[text] = color;
+ level[text] = cssClass;
+ });
+
+ kinks = inputKinks.parseKinksText($('#Kinks').text().trim());
+ inputKinks.init();
+
+ (function(){
+ var $popup = $('#InputOverlay');
+ var $previous = $('#InputPrevious');
+ var $next = $('#InputNext');
+
+ // current
+ var $category = $('#InputCategory');
+ var $field = $('#InputField');
+ var $options = $('#InputValues');
+
+ function getChoiceValue($choices){
+ var $selected = $choices.find('.choice.selected');
+ return $selected.data('level');
+ }
+
+ function getChoicesElement(category, kink, field){
+ var selector = '.cat-' + strToClass(category);
+ selector += ' .kink-' + strToClass(kink);
+ selector += ' .choice-' + strToClass(field);
+
+ var $choices = $(selector);
+ return $choices;
+ }
+
+ inputKinks.getAllKinks = function(){
+ var list = [];
+
+ var categories = Object.keys(kinks);
+ for(var i = 0; i < categories.length; i++){
+ var category = categories[i];
+ var fields = kinks[category].fields;
+ var kinkArr = kinks[category].kinks;
+
+ for(var j = 0; j < fields.length; j++) {
+ var field = fields[j];
+ for(var k = 0; k < kinkArr.length; k++){
+ var kink = kinkArr[k];
+ var $choices = getChoicesElement(category, kink, field);
+ var value = getChoiceValue($choices);
+ var obj = { category: category, kink: kink, field: field, value: value, $choices: $choices, showField: (fields.length >= 2)};
+ list.push(obj);
+ }
+ }
+
+ }
+ return list;
+ };
+
+ inputKinks.inputPopup = {
+ numPrev: 3,
+ numNext: 3,
+ allKinks: [],
+ kinkByIndex: function(i){
+ var numKinks = inputKinks.inputPopup.allKinks.length;
+ i = (numKinks + i) % numKinks;
+ return inputKinks.inputPopup.allKinks[i];
+ },
+ generatePrimary: function(kink){
+ var $container = $(' ');
+ var btnIndex = 0;
+ $('.legend > div').each(function(){
+ var $btn = $(this).clone();
+ $btn.addClass('big-choice');
+ $btn.appendTo($container);
+
+ $(' ')
+ .addClass('btn-num-text')
+ .text(btnIndex++)
+ .appendTo($btn)
+
+ var text = $btn.text().trim().replace(/[0-9]/g, '');
+ if(kink.value === text) {
+ $btn.addClass('selected');
+ }
+
+ $btn.on('click', function(){
+ $container.find('.big-choice').removeClass('selected');
+ $btn.addClass('selected');
+ kink.value = text;
+ $options.fadeOut(200, function(){
+ $options.show();
+ inputKinks.inputPopup.showNext();
+ });
+ var choiceClass = strToClass(text);
+ kink.$choices.find('.' + choiceClass).click();
+ });
+ });
+ return $container;
+ },
+ generateSecondary: function(kink){
+ var $container = $('');
+ $('').addClass(level[kink.value]).appendTo($container);
+ $('').text(kink.category).appendTo($container);
+ if(kink.showField){
+ $('').text(kink.field).appendTo($container);
+ }
+ $('').text(kink.kink).appendTo($container);
+ return $container;
+ },
+ showIndex: function(index){
+ $previous.html('');
+ $next.html('');
+ $options.html('');
+ $popup.data('index', index);
+
+ // Current
+ var currentKink = inputKinks.inputPopup.kinkByIndex(index);
+ var $currentKink = inputKinks.inputPopup.generatePrimary(currentKink);
+ $options.append($currentKink);
+ $category.text(currentKink.category);
+ $field.text((currentKink.showField ? '(' + currentKink.field + ') ' : '') + currentKink.kink);
+ $options.append($currentKink);
+
+ // Prev
+ for(var i = inputKinks.inputPopup.numPrev; i > 0; i--){
+ var prevKink = inputKinks.inputPopup.kinkByIndex(index - i);
+ var $prevKink = inputKinks.inputPopup.generateSecondary(prevKink);
+ $previous.append($prevKink);
+ (function(skip){
+ $prevKink.on('click', function(){
+ inputKinks.inputPopup.showPrev(skip);
+ });
+ })(i);
+ }
+ // Next
+ for(var i = 1; i <= inputKinks.inputPopup.numNext; i++){
+ var nextKink = inputKinks.inputPopup.kinkByIndex(index + i);
+ var $nextKink = inputKinks.inputPopup.generateSecondary(nextKink);
+ $next.append($nextKink);
+ (function(skip){
+ $nextKink.on('click', function(){
+ inputKinks.inputPopup.showNext(skip);
+ });
+ })(i);
+ }
+ },
+ showPrev: function(skip){
+ if(typeof skip !== "number") skip = 1;
+ var index = $popup.data('index') - skip;
+ var numKinks = inputKinks.inputPopup.allKinks.length;
+ index = (numKinks + index) % numKinks;
+ inputKinks.inputPopup.showIndex(index);
+ },
+ showNext: function(skip){
+ if(typeof skip !== "number") skip = 1;
+ var index = $popup.data('index') + skip;
+ var numKinks = inputKinks.inputPopup.allKinks.length;
+ index = (numKinks + index) % numKinks;
+ inputKinks.inputPopup.showIndex(index);
+ },
+ show: function(){
+ inputKinks.inputPopup.allKinks = inputKinks.getAllKinks();
+ inputKinks.inputPopup.showIndex(0);
+ $popup.fadeIn();
+ }
+ };
+
+ $(window).on('keydown', function(e){
+ if(e.altKey || e.shiftKey || e.ctrlKey) return;
+ if(!$popup.is(':visible')) return;
+
+ if(e.keyCode === 38) {
+ inputKinks.inputPopup.showPrev();
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ if(e.keyCode === 40) {
+ inputKinks.inputPopup.showNext();
+ e.preventDefault();
+ e.stopPropagation();
+ }
+
+ var btn = -1;
+ if(e.keyCode >= 96 && e.keyCode <= 101) {
+ btn = e.keyCode - 96;
+ }
+ else if(e.keyCode >= 48 && e.keyCode <= 53) {
+ btn = e.keyCode - 48;
+ }
+ else {
+ return;
+ }
+
+ var $btn = $options.find('.big-choice').eq(btn);
+ $btn.click();
+ });
+ $('#StartBtn').on('click', inputKinks.inputPopup.show);
+ $('#InputCurrent .closePopup, #InputOverlay').on('click', function(){
+ $popup.fadeOut();
+ });
+ })();
+});
\ No newline at end of file
diff --git a/src/scss/app.scss b/src/scss/app.scss
new file mode 100644
index 0000000..e4f21bb
--- /dev/null
+++ b/src/scss/app.scss
@@ -0,0 +1,502 @@
+body {
+ font-family: 'Verdana', 'Arial';
+ font-size: 12px;
+}
+h2 {
+ padding: 0;
+ margin: 0;
+ margin-top: 10px;
+ margin-bottom: 5px;
+ font-size: 18px;
+}
+table {
+ border-collapse: collapse;
+ margin-bottom: 10px;
+ width: 100%;
+}
+th {
+ border: solid #999 1px;
+ border-right: none;
+ margin: 0px;
+ padding: 4px;
+ background-color: #666;
+ color: #FFF;
+}
+th.choicesCol {
+ box-sizing: border-box;
+ width: 125px;
+}
+th + th {
+ border-left: none;
+}
+th:last-child {
+ border-right: solid #999 1px;
+}
+td {
+ border-left: solid #999 1px;
+ border-bottom: solid #999 1px;
+ border-right: solid #999 1px;
+ margin: 0px;
+ padding: 4px;
+ padding-right: 2px;
+}
+@-moz-document url-prefix() {
+ td {
+ padding: 3.3px;
+ }
+}
+td + td {
+ border-left-style: none;
+}
+.choice {
+ box-sizing: border-box;
+ width: 15px;
+ height: 15px;
+ opacity: 0.35;
+ overflow: hidden;
+ text-indent: 100px;
+ border: solid #000 1px;
+ border-radius: 50%;
+ outline-style: none!important;
+ vertical-align: middle;
+ display: inline-block;
+ cursor: pointer;
+ font-size: 0;
+ padding: 0;
+}
+.choices .choice {
+ transition: all 0.3s ease-in-out;
+}
+.choice + .choice {
+ margin-left: 5px;
+}
+.choices .choice:hover {
+ opacity: 0.75;
+}
+.choice.selected, .selected > .choice {
+ opacity: 1;
+ border-width: 2px;
+}
+
+.legend {
+ vertical-align: middle;
+ font-size: 14px;
+ div {
+ display: inline-block;
+ }
+ .choice {
+ opacity: 1;
+ cursor: default;
+ }
+}
+
+.legend-text {
+ vertical-align: middle;
+}
+
+#ExportWrapper {
+ width: 460px;
+ height: 36px;
+}
+#URL {
+ display: none;
+ position: absolute;
+ top: 3px;
+ box-sizing: border-box;
+ width: 300px;
+ height: 30px;
+ border-radius: 4px;
+ border: solid #CCC 1px;
+ font-size: 16px;
+ padding: 10px;
+ text-align: center;
+ color: #666;
+ font-weight: bold;
+}
+#Export {
+ position: absolute;
+ left: 310px;
+ box-sizing: border-box;
+ color: #FFF;
+ text-transform: uppercase;
+ background-color: #4980ae;
+ font-size: 18px;
+ width: 150px;
+ height: 36px;
+ border-style: none;
+ border-radius: 4px;
+ cursor: pointer;
+ transition: all 0.3s ease-in-out;
+
+ &:hover {
+ opacity: 0.85;
+ }
+}
+#Loading {
+ display: none;
+ overflow: visible;
+ line-height: 26px;
+ font-size: 16px;
+ color: #999;
+ font-weight: bold;
+ position: absolute;
+ top: 4px;
+ left: 220px;
+}
+#Loading:before {
+ content: '';
+ position: absolute;
+ box-sizing: border-box;
+ width: 26px;
+ height: 26px;
+ border-radius: 50%;
+ border: solid #999 2px;
+ border-top-color: transparent;
+ border-left-color: #CCC;
+ border-right-color: #666;
+ animation: spin .5s infinite linear;
+ margin-left: -40px;
+}
+@media (min-width: 1700px) {
+ .legend {
+ position: absolute;
+ top: 7px;
+ left: 160px;
+ }
+ .legend div {
+ width: 130px;
+ }
+ #ExportWrapper {
+ position: absolute;
+ top: -3px;
+ right: 46px;
+ }
+ h1 {
+ margin-bottom: 0;
+ }
+}
+@media (max-width: 1700px) and (min-width: 800px) {
+ .legend div {
+ width: 130px;
+ padding-bottom: 10px;
+ }
+ #ExportWrapper {
+ position: absolute;
+ top: -3px;
+ right: 46px;
+ }
+}
+@media (max-width: 800px) and (min-width: 598px) {
+ .legend div {
+ width: 180px;
+ padding-bottom: 10px;
+ padding-left: 10px;
+ }
+ #ExportWrapper {
+ position: relative;
+ margin-top: 10px;
+ margin-left: 5px;
+ }
+ #URL {
+ left: 155px;
+ width: 190px;
+ font-size: 10px;
+ }
+ #Export {
+ left: 0px;
+ }
+ #Loading {
+ left: 230px;
+ }
+}
+@media (max-width: 597px) {
+ body {
+ font-size: 10px;
+ }
+ table {
+ min-width: 345px;
+ }
+ .legend div {
+ width: 150px;
+ padding-bottom: 10px;
+ padding-left: 10px;
+ }
+ #ExportWrapper {
+ position: relative;
+ margin-top: 10px;
+ margin-left: 0px;
+ width: 345px;
+ }
+ #URL {
+ left: 155px;
+ width: 190px;
+ font-size: 10px;
+ }
+ #Export {
+ left: 0px;
+ }
+ #Loading {
+ left: 230px;
+ }
+}
+@keyframes spin {
+ 0% {transform: rotate(0deg);}
+ 100% {transform: rotate(-360deg);}
+}
+
+#ExportWrapper :last-child:after {
+ content: '';
+ display: block;
+ clear: both;
+}
+.kinkCategory {
+
+}
+.col {
+ float: left;
+ box-sizing: border-box;
+ margin: 0;
+ padding: 5px;
+}
+.col.col25 { width: 25%; }
+.col.col33 { width: 33.33333%; }
+.col.col50 { width: 50%; }
+.col.col100 { width: 100%; padding: 0px; }
+.widthWrapper {
+ max-width: 1700px;
+ margin-left: auto;
+ margin-right: auto;
+ position: relative;
+}
+#Edit {
+ width: 18px;
+ height: 18px;
+ background-color: transparent;
+ background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAAWdEVYdENyZWF0aW9uIFRpbWUAMTAvMTIvMTUsb8MLAAABaElEQVQ4jZWUvY3jMBCF390mzpQ6I1wBS5A6oDuQOxi4Ap4rUAlqwR1M7IhQBYRCR1To7G1giJBkes/7gElGg4/zK7AgVaWI0FpLAIwxlsJWwtbRdR0BrKzruvw9pUTnHEMIP4NCCC8gay2991TVnGVVVSvYCyil9AJ6Z0sY5nJCCEwp5Rc/NefcE6Sqb4OMMRQRigiNMcWSU0pPkIgUIW3b5gmqKkmybdtVzOwnSZRKMcaQJOu6zr66rklylZn3PoO+7vf7P2x0Op2w2+1wuVyybxxHNE0DALjdbgCAaZrweDyw3+/xN8aIvu9hrd3y/qthGHA+n3E4HJDH773/dWnLpmfQdnqfNHs2EeEfkpymCU3TYBiGVerGGByPRwDA9XrFOI7FElX1WZpz7ldLOO9PCCHfIeb7qqrqY9C8hEvlHi1h1lqqKr33xZPZXv4KNMOcc6sX+77/8bdSBJUUY8xZisjqLJb6Bpjss/W5PAkOAAAAAElFTkSuQmCC');
+ background-repeat: no-repeat;
+ float: left;
+ border-style: none;
+ outline-style: none!important;
+ margin-top: 6px;
+ margin-right: 4px;
+ opacity: 0.5;
+ cursor: pointer;
+}
+#Edit:hover {
+ opacity: 1;
+}
+
+.overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: rgba(0, 0, 0, 0.8);
+ display: none;
+}
+#EditOverlay #Kinks {
+ box-sizing: border-box;
+ position: absolute;
+ top: 10px;
+ bottom: 50px;
+ width: 330px;
+ left: 50%;
+ margin-left: -165px;
+ resize: none;
+ padding: 10px;
+ border-radius: 5px;
+ font-family: monospace, 'Courier new', Courier;
+}
+#EditOverlay #KinksOK {
+ box-sizing: border-box;
+ position: absolute;
+ bottom: 10px;
+ width: 330px;
+ height: 30px;
+ left: 50%;
+ margin-left: -165px;
+ color: #FFF;
+ text-transform: uppercase;
+ background-color: #4980ae;
+ font-size: 18px;
+ border-style: none;
+ border-radius: 5px;
+ cursor: pointer;
+}
+
+#InputOverlay {
+ text-align: center;
+ white-space: nowrap;
+}
+#InputOverlay:before {
+ content: '';
+ display: inline-block;
+ height: 100%;
+ vertical-align: middle;
+ margin-right: -0.25em;
+}
+#InputOverlay .widthWrapper {
+ display: inline-block;
+ vertical-align: middle;
+ width: 400px;
+ text-align: left;
+ max-width: 100%;
+}
+#InputOverlay .widthWrapper #InputCurrent, #InputOverlay .widthWrapper .kink-simple {
+ display: block;
+ box-sizing: border-box;
+ padding: 10px;
+ background-color: #EEE;
+}
+#InputOverlay .widthWrapper .kink-simple {
+ position: relative;
+ height: 40px;
+ line-height: 20px;
+ cursor: pointer;
+}
+#InputOverlay .widthWrapper .kink-simple .choice {
+ margin-right: 5px;
+}
+#InputOverlay .widthWrapper .kink-simple .txt-category {
+ position: absolute;
+ right: 5px;
+ top: 5px;
+ text-transform: uppercase;
+ font-size: 90%;
+ font-weight: bold;
+ opacity: 0.6;
+ line-height: 1em;
+}
+#InputOverlay .widthWrapper .kink-simple .txt-field, #InputOverlay .widthWrapper .kink-simple .txt-kink {
+ vertical-align: middle;
+}
+#InputOverlay .widthWrapper .kink-simple .txt-field:empty {
+ display: none;
+}
+#InputOverlay .widthWrapper .kink-simple .txt-field:before {
+ content: '(';
+}
+#InputOverlay .widthWrapper .kink-simple .txt-field:after {
+ content: ') ';
+}
+
+#InputOverlay .widthWrapper #InputPrevious .kink-simple:first-child,
+#InputOverlay .widthWrapper #InputNext .kink-simple:nth-child(3) {
+ background-color: #BBB;
+ font-size: 10px;
+ margin-left: 12px;
+ margin-right: 12px;
+ height: 33px;
+}
+#InputOverlay .widthWrapper #InputPrevious .kink-simple:nth-child(2),
+#InputOverlay .widthWrapper #InputNext .kink-simple:nth-child(2) {
+ background-color: #CCC;
+ font-size: 11px;
+ margin-left: 6px;
+ margin-right: 6px;
+ height: 37px;
+}
+#InputOverlay .widthWrapper #InputPrevious .kink-simple:nth-child(3),
+#InputOverlay .widthWrapper #InputNext .kink-simple:first-child {
+ background-color: #DDD;
+ margin-left: 3px;
+ margin-right: 3px;
+}
+#InputOverlay .widthWrapper #InputPrevious .kink-simple:first-child {
+ padding-bottom: 4px;
+ padding-top: 7px;
+}
+#InputOverlay .widthWrapper #InputNext .kink-simple:nth-child(3) {
+ padding-top: 4px;
+}
+#InputOverlay .widthWrapper #InputPrevious .kink-simple:nth-child(2) {
+ padding-bottom: 7px;
+ padding-top: 9px;
+}
+#InputOverlay .widthWrapper #InputNext .kink-simple:nth-child(2) {
+ padding-top: 7px;
+}
+
+#InputPrevious .kink-simple {
+ border-top-left-radius: 2px;
+ border-top-right-radius: 2px;
+}
+#InputNext .kink-simple {
+ border-bottom-left-radius: 2px;
+ border-bottom-right-radius: 2px;
+}
+
+#InputOverlay .widthWrapper #InputCurrent {
+ position: relative;
+}
+#InputOverlay .widthWrapper #InputCurrent .closePopup {
+ position: absolute;
+ top: 0;
+ right: 5px;
+ border-style: none;
+ background-color: transparent;
+ font-size: 30px;
+ cursor: pointer;
+ outline-style: none!important;
+ opacity: 0.65;
+}
+#InputOverlay .widthWrapper #InputCurrent .closePopup:hover {
+ opacity: 1;
+}
+#InputOverlay .widthWrapper #InputCurrent h2 {
+ text-transform: uppercase;
+ opacity: 0.6;
+ margin: 0;
+}
+#InputOverlay .widthWrapper #InputCurrent h3 {
+ margin-top: 3px;
+ margin-bottom: 0;
+ font-size: 14px;
+}
+#InputOverlay .widthWrapper #InputCurrent #InputValues .big-choice {
+ padding: 10px;
+ background-color: rgba(255,255,255,0.75);
+ border-radius: 4px;
+ margin-top: 5px;
+ cursor: pointer;
+}
+#InputOverlay .widthWrapper #InputCurrent #InputValues .big-choice.selected {
+ font-weight: bold;
+}
+#InputOverlay .widthWrapper #InputCurrent #InputValues .big-choice.selected .choice {
+ opacity: 1;
+}
+#InputOverlay .widthWrapper #InputCurrent #InputValues .big-choice:hover {
+ padding: 8px;
+ border: solid #999 2px;
+ background-color: rgba(255,255,255,1);
+}
+#InputOverlay .widthWrapper #InputCurrent #InputValues .big-choice .btn-num-text {
+ float: right;
+ display: inline-block;
+ border: solid #CCC 1px;
+ text-align: center;
+ width: 16px;
+ border-radius: 3px;
+}
+#StartBtn {
+ position: absolute;
+ top: -3px;
+ right: 5px;
+ box-sizing: border-box;
+ width: 36px;
+ height: 36px;
+ background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAAWdEVYdENyZWF0aW9uIFRpbWUAMTAvMTUvMTWxuPuyAAACcElEQVRYhe3X30tTYRzH8fdz3FYTd1xamAuTLDbM3EwqNMnoQgxydVH0A6Ks/oG6Mvp1n1flVUJE3pjUTVPCCJxmEKTWRAuCApujkmhJoZu57ZwuwsCaOx7nbBf73D2H7/PldfjCc54j6CxXSaNI/xvwdzIgrWRAWsmAtJJ2IIOe4iLzejoqmym1lDAZ+UFEicatC8Vm6A++5Jb/Pm+nxlIHatl2keo8FwJBriGHREe8U7bjyrWz7/m51IHq1lWjqire4AAvJkf5qczGrduUvYHTRQdxyQ5dGN0gg8hCBc4MXyUQnliwbqO5kOO2/ZzyXQagONvGcO0DLrxp5m7As3ygxUZB4aTvEt1fnuGSHQgEnoleKnIdEEi8NymQ6h7555nocvJt9jsPJ3o4XFhHq/MaAkFF/xE+hD5p9kwKJLqccZ+HYjMcs9XTXnkdSUi0BToXhYEUnUM7rFvnYRqHryx6b1Ig1T2C6h4h0uDjqK0eSUi4ZAc9VbeRhMS76XFdGFjmkblkB3277yAbc3g/PY7D69bdc9lGNoexGi10fOzG7nWTb7KuLCh8YJAyy2YEgqE997AaLbQFOjnxqom1JiueXTd190xqZOZHOwFoLDrEVCxMm9/D+dfNSELiSVUrpZaSlQXNpTc4wJrHNX/W+SYr5bKdqBr/45soSxqZQWTNW/tDn+etV0umpbT93VtP8awSwZhl4EZZE/7wwgddsdmGJAQxRUktyPt1gIaCvTQU1Ca8eghAVVX6goO6QULPn2vBqnyatpylJm87RrHwu0TVKE+DQ7SMtSe8FSQNWomk3Z06A9JKBqSVDEgraQf6BTg8uT5wSV/pAAAAAElFTkSuQmCC');
+ border-style: none;
+ border-radius: 4px;
+ cursor: pointer;
+}
+#StartBtn:hover {
+ opacity: 0.8;
+}
+@media (max-height: 500px) {
+ #InputPrevious, #InputNext {
+ display: none;
+ }
+}
\ No newline at end of file
|