Initial commit
jdarwood007

jdarwood007 commited on 2021-02-22 06:20:19
Showing 4 changed files, with 484 additions and 0 deletions.

... ...
@@ -0,0 +1,14 @@
1
+BSD 3-Clause License
2
+
3
+Copyright (c) 2021, Jeremy (SleePy) All rights reserved.
4
+
5
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6
+
7
+Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
8
+
9
+Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
10
+
11
+Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
12
+
13
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
+
... ...
@@ -0,0 +1,181 @@
1
+# JQuery Number Control
2
+
3
+Implants a plugin for JQuery to add number spinner that is mobile friendly and a virtual keyboard.  
4
+
5
+# Requirements
6
+ - JQuery v3 or higher.
7
+ - Bootstrap v4 or higher.
8
+
9
+# Install
10
+## Add to your javascript sources
11
+ - jquery-numbercontrol.js (or .min.js)
12
+## Attach to any input
13
+    $(document).ready(function() {
14
+		$('#numbercontrol').numbercontrol();
15
+	});
16
+
17
+# Full Sample Code
18
+    <input type="text" id="numbercontrol" value="1" min="-500" max="500" />
19
+	<script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
20
+	<script type="text/javascript" src="./jquery-numbercontrol.js"></script>
21
+	<script type="text/javascript">
22
+	$(document).ready(function() {
23
+		console.log('loading');
24
+		$('#numbercontrol').numbercontrol();
25
+	});
26
+	</script>
27
+
28
+# HTML 5 Input Type="number"
29
+This plugin supports working with input type="number", decimal and text.  It will detect usage of min, max and step attributes on the input tag.  These can be optionally specified in the loading of the numbercontrol plugin.  The priority of the options are
30
+
31
+ 1. Options specified
32
+	 {min: 0, max: 1000, step: 10}
33
+ 2. Tag attributes
34
+	 <input type="number" min="0" max="1000" step="10" value="1" / >
35
+ 3. Default sane attributes
36
+	 Step: 1
37
+	 Min: Number.MIN_VALUE
38
+	 Max: Number.MAX_VALUE 
39
+
40
+# Options
41
+## type
42
+Optionally override an input type.  By default it sets to "number"
43
+#### Type: string
44
+### Values
45
+ - text
46
+ - number
47
+ - decimal
48
+
49
+## disableVirtualKeyboard
50
+Disable the virtual keyboard popup upon clicking the input.
51
+### Type: Bool
52
+
53
+## separator
54
+decimal separator
55
+### type: string
56
+### Values
57
+Any valid character such as period (.) or comma (,).
58
+
59
+## inputWrap
60
+Wraps the input object in a container.
61
+### type: Html
62
+### Values:
63
+Any valid HTML.  This should be kept basic.  If multiple nested html containers are used, the default logic is to find the nearest container to the input object as the "parent" container.
64
+### Default Value: `<div class="input-group numberControl"></div>`
65
+
66
+## parentSelector
67
+Optionally specify the parent selector.  If left blank, we locate the nearest parent to the input object.
68
+### type: JQuery Selector
69
+
70
+## inputCss
71
+Specify css to add to the input object
72
+### type: css class styles
73
+### Default Value: `numberControlInput form-control px-1`
74
+
75
+## prependHtml
76
+Specify different HTML to prepend to the input object
77
+### type: Html
78
+### Default Value: `<div class="input-group-prepend"><button class="btn btn-decrease btn-outline-secondary px-1"><span class="oi oi-minus" /></button></div>`
79
+
80
+## appendHtml
81
+Specify different HTML to append to the input object
82
+### type: HTML
83
+### Default Value: `<div class="input-group-append"><button class="btn btn-increase btn-outline-secondary px-1"><span class="oi oi-plus" /></button></div>`
84
+
85
+## DisableNumberSpinStyleFix
86
+Optionally Disables the default HTML 5 spin (Increase/Decrease buttons) fix when input type is number/decimal.  By default this plugin will append a style fix to the body element to hide this.
87
+### type: bool
88
+## bindButtonEvents
89
+Optionally specify events used to trigger buttons/inputs.
90
+### type: user actions
91
+### Default Value: `click tap touch touchstart`
92
+
93
+## virtualKeyboardAttachSelector
94
+Optionally specify where to attach the virtual keyboard.  If left blank, it is appended the nearest to the input object.
95
+### type: JQuery Selector
96
+
97
+## keyboardLayout
98
+Specify a custom keyboard layout.   This has placeholders for all functions/input controls.  These are surrounded by curly braces {}.  The current buttons are:
99
+ - Numbers 0-9
100
+ - INPUTBOX
101
+ - DELETE
102
+ - SEP
103
+ - UP
104
+ - DOWN
105
+ - CLEAR
106
+ - INVERSE
107
+ - DONE
108
+
109
+### type: HTML
110
+## keyboardControl[]
111
+Optionally specify custom HTML for any button.  This will be replaced with the layout placeholders on initialization.  The INPUTBOX control placeholder optionally can hold {VAL} which will be replaced with the current value.  All others can optionally contain a {[CONTROL]_LANG} which will replace the button with the appropriate language for the button.  The button object should contain a "data-function" which indicates which control function it should trigger.
112
+### Custom function
113
+If a custom function is needed the function should be specified in "data-custom-function"
114
+#### Parameters
115
+ - this: (the current object)
116
+ - event: (the user event such as mouse click, or touch)
117
+ - thisFunction: the string from "data-function"
118
+
119
+## keyboardLanguage[]
120
+Optionally specify a custom language string for any control button.  
121
+
122
+## onBeforeInitialized
123
+Add a custom event handler before any logic has been applied to the input object.
124
+### Paramaters:
125
+ - this: (the current object)
126
+
127
+## onAfterInitialized
128
+Add a custom event handler after all logic has been applied to the input object.
129
+### Paramaters:
130
+ - this: (the current object)
131
+
132
+## onBeforeClickDecrease
133
+Add a custom event handler before clicking the decrease button built in event triggers
134
+### Paramaters:
135
+ - this: (the current object)
136
+ - event: (the user event such as mouse click, or touch)
137
+
138
+## onAfterClickDecrease
139
+Add a custom event handler after clicking the decrease button built in event triggers
140
+### Paramaters:
141
+ - this: (the current object)
142
+ - event: (the user event such as mouse click, or touch)
143
+
144
+## onBeforeClickIncrease
145
+Add a custom event handler before clicking the increase button built in event triggers
146
+### Paramaters:
147
+ - this: (the current object)
148
+ - event: (the user event such as mouse click, or touch)
149
+
150
+## onAfterClickIncrease
151
+Add a custom event handler after clicking the increase button built in event triggers
152
+### Paramaters:
153
+ - this: (the current object)
154
+ - event: (the user event such as mouse click, or touch)
155
+
156
+## onBeforeVirtualKeyboardInitalized
157
+Add a custom event handler before the initialization of the virtual keyboard.
158
+### Paramaters:
159
+ - this: (the current object)
160
+
161
+## onAfterVirtualKeyboardInitalized
162
+Add a custom event handler after the initialization of the virtual keyboard.
163
+### Paramaters:
164
+ - this: (the current object)
165
+
166
+## onBeforeVirtualKeyboardOpen
167
+Add a custom event handler before the opening of the virtual keyboard.
168
+### Paramaters:
169
+ - this: (the current object)
170
+
171
+## onAfterVirtualKeyboardOpen
172
+Add a custom event handler after the opening of the virtual keyboard.
173
+### Paramaters:
174
+ - this: (the current object)
175
+
176
+## onBeforeVirtualKeyboardButton
177
+Add a custom event handler before the trigger of a keyboard button.
178
+### Paramaters:
179
+ - this: (the current object)
180
+ - event: (the user event such as mouse click, or touch)
181
+ - thisFunction: The button action
0 182
\ No newline at end of file
... ...
@@ -0,0 +1,262 @@
1
+;(function ($) {
2
+    "use strict"
3
+    $.fn.numbercontrol = function (methodOrProps) {
4
+        if (methodOrProps === "destroy") {
5
+            this.each(function () {
6
+                this.destroyInputSpinner()
7
+            })
8
+            return this
9
+        }
10
+
11
+		// Allow customizing the options.
12
+        var options = {
13
+        	debug: false,
14
+        	separator: '.',
15
+        	type: "number",
16
+        	prependHtml: '<div class="input-group-prepend"><button class="btn btn-decrease btn-outline-secondary px-1"><span class="oi oi-minus" /></button></div>',
17
+        	appendHtml: '<div class="input-group-append"><button class="btn btn-increase btn-outline-secondary px-1"><span class="oi oi-plus" /></button></div>',
18
+        	inputWrap: '<div class="input-group numberControl"></div>',
19
+        	inputCss: 'numberControlInput form-control px-1',
20
+        	bindButtonEvents: 'click tap touch touchstart',
21
+        	keyboardLanguage: {
22
+        		'UP' : '<span class="oi oi-chevron-top" />',
23
+        		'DOWN' : '<span class="oi oi-chevron-bottom" />',
24
+        		'INVERSE' : '<span class="oi oi-transfer" />',
25
+        		'SEP' : '<span class="oi oi-media-record" />',
26
+        	},
27
+        	keyboardControl: {
28
+        	},
29
+			buttons: [...Array(10).keys(), 'DELETE', 'CLEAR', 'DONE', 'CANCEL', 'UP', 'DOWN', 'SEP', 'INVERSE']
30
+        }
31
+        for (var option in methodOrProps) {
32
+            options[option] = methodOrProps[option]
33
+        }
34
+
35
+		function setNewValue(container, value)
36
+		{
37
+			if (options.type === 'number')
38
+				$(container).val(parseInt(value));
39
+			else
40
+				$(container).val(parseFloat(value));
41
+		}
42
+
43
+		function findMinMaxValue()
44
+		{
45
+			var testValue;
46
+			for (var i=0; i < arguments.length; i++) {
47
+				testValue = arguments[i];
48
+				if (typeof testValue !== 'undefined' && !isNaN(testValue))
49
+				{
50
+					if (options.type === 'number' && parseInt(testValue) !== null)
51
+						return parseInt(testValue);
52
+					else if (parseFloat(testValue) !== null)
53
+						return parseFloat(testValue);
54
+					continue;
55
+				}
56
+			}
57
+			return 0;
58
+		}
59
+
60
+		// Bind to each input selector
61
+        this.each(function () {
62
+			if (options.onBeforeInitialized !== undefined)
63
+				options.onBeforeInitialized(this);
64
+
65
+            var $base = $(this);
66
+
67
+			// Some settings we either can pull in from a options, from standard attributes or defaults.
68
+			var $step = findMinMaxValue(parseFloat(options.step), parseFloat($base.attr('step')), 1);
69
+			var $minValue = findMinMaxValue(options.min, $base.attr('min'), Number.MIN_VALUE);
70
+			var $maxValue = findMinMaxValue(options.max, $base.attr('max'), Number.MAX_VALUE);
71
+
72
+			// Build the parent up. 
73
+			$base.wrap(options.inputWrap);
74
+			var $parent = $base.parent(options.parentSelector);
75
+
76
+			// Set the base.
77
+			$base.attr('type', options.type);
78
+			$base.addClass(options.inputCss);
79
+
80
+			// Wrap the buttons around.			
81
+			$base.before(options.prependHtml);
82
+			$base.after(options.appendHtml);
83
+			
84
+			// Add the style to the body to cleanup input controls for number.
85
+			if (options.type == 'number' && !options.DisableNumberSpinStyleFix)
86
+				$('body').append('<style>' +
87
+							'.numberControlInput::-webkit-outer-spin-button,.numberControlInput::-webkit-inner-spin-button {' + 
88
+								'-webkit-appearance: none;' +
89
+							'}</style>'
90
+				);
91
+
92
+			// The decrease event.
93
+			var $decreaseButton = $parent.find('.btn-decrease');
94
+			$decreaseButton.on(options.bindButtonEvents, function (event) {
95
+				if (options.onBeforeClickDecrease !== undefined)
96
+					options.onBeforeClickDecrease(this, event);
97
+				if ($base.val() > $minValue)
98
+					setNewValue($base, parseFloat($base.val()) - parseFloat($step));
99
+				if (options.onAfterClickDecrease !== undefined)
100
+					options.onAfterClickDecrease(this, event);
101
+				if (options.debug)
102
+					console.log('numbercontrl: decreaseButton: Click', event, $base.val(), $minValue);
103
+			});
104
+
105
+			// The increase event.
106
+			var $decreaseButton = $parent.find('.btn-increase');
107
+			$decreaseButton.on(options.bindButtonEvents, function (event) {
108
+				if (options.onBeforeClickIncrease !== undefined)
109
+					options.onBeforeClickIncrease(this, event);
110
+				if ($base.val() < $maxValue)
111
+					setNewValue($base, parseFloat($base.val()) + parseFloat($step));
112
+				if (options.onAfterClickIncrease !== undefined)
113
+					options.onAfterClickIncrease(this, event);
114
+				if (options.debug)
115
+					console.log('numbercontrl: increaseButton: Click', event, $base.val(), $minValue);
116
+			});
117
+
118
+			// The Popup Numberpad
119
+			if (!options.disableVirtualKeyboard)
120
+			{
121
+				if (options.onBeforeVirtualKeyboardInitalized !== undefined)
122
+					options.onBeforeVirtualKeyboardInitalized(this);
123
+
124
+				$base.on(options.bindButtonEvents, function (event) {
125
+					event.stopPropagation();
126
+
127
+					if (options.onBeforeVirtualKeyboardOpen !== undefined)
128
+						options.onBeforeVirtualKeyboardOpen(this);
129
+
130
+					var $location = options.virtualKeyboardAttachSelector ? $(options.virtualKeyboardAttachSelector) : $base;
131
+
132
+					if (options.keyboardLayout)
133
+						var $KeyboardLayout = options.keyboardLayout;
134
+					else
135
+						var $KeyboardLayout = 
136
+							'<div class="modal-dialog modal-dialog-centered" style="width: 250px;">' +
137
+								'<div class="modal-content">' +
138
+									'<table>' +
139
+										'<tr>' +
140
+											'<td colspan="4">{INPUTBOX}</td>' +
141
+										'</tr><tr>' +
142
+											'<td>{7}</td>' +
143
+											'<td>{8}</td>' +
144
+											'<td>{9}</td>' +
145
+											'<td>{DELETE}</td>' +
146
+										'</tr><tr>' +
147
+											'<td>{4}</td>' +
148
+											'<td>{5}</td>' +
149
+											'<td>{6}</td>' +
150
+											'<td>{CLEAR}</td>' +
151
+										'</tr><tr>' +
152
+											'<td>{1}</td>' +
153
+											'<td>{2}</td>' +
154
+											'<td>{3}</td>' +
155
+											'<td>{DONE}</td>' +
156
+										'</tr><tr>' +
157
+											'<td>{UP}</td>' +
158
+											'<td>{0}</td>' +
159
+											'<td>{DOWN}</td>' +
160
+											'<td>{CANCEL}</td>' +
161
+										'</tr>' +
162
+									'</table>' +
163
+								'</div>' +
164
+							'</div>'
165
+						;
166
+
167
+					// Fill out the input.
168
+					if (typeof options.keyboardControl["INPUTBOX"] === 'undefined')
169
+						options.keyboardControl["INPUTBOX"] = '<input class="numberControlVirtualNumPad numberControlVirtualNumPadINPUT form-control" type="text" readonly value="{VAL}"/>';
170
+					$KeyboardLayout = $KeyboardLayout.replace('{INPUTBOX}', options.keyboardControl["INPUTBOX"].replace('{VAL}', $base.val()).toString());
171
+
172
+					// Fill out all buttons.
173
+					$.each(options.buttons, function(i, v){
174
+						var LanguageBox = options.keyboardLanguage[v] ? options.keyboardLanguage[v] : v;
175
+
176
+						if (typeof options.keyboardControl[v] === 'undefined')
177
+							options.keyboardControl[v] = '<button class="numberControlVirtualNumPad numberControlVirtualNumPad' + v + ' btn btn-outline-secondary w-100" data-function="' + v + '">{' + v + '_LANG}</button>';
178
+						$KeyboardLayout = $KeyboardLayout.replace('{' + v + '}', options.keyboardControl[v].replace('{' + v + '_LANG}', LanguageBox));
179
+					});
180
+
181
+					// Attach the keyboard to the container.
182
+					$location.after('<div class="numberControlVirtualNumPad modal d-block">' + $KeyboardLayout + '</div>');
183
+					var $VirtualKeyboard = $parent.find('.numberControlVirtualNumPad');
184
+					var $VirtualKeyboardInput = $VirtualKeyboard.find('.numberControlVirtualNumPadINPUT');
185
+
186
+					// Bind the virtual Keyboard action.
187
+					$VirtualKeyboard.find('.numberControlVirtualNumPad').on(options.bindButtonEvents, function(event){						
188
+						if (options.debug) console.log('numbercontrl: numberControlVirtualNumPad: Click', event, $base.val(), $VirtualKeyboardInput.val().toString(), $(this).attr('data-function'));
189
+
190
+						var thisFunction = $(this).attr('data-function');
191
+
192
+						if (options.onBeforeVirtualKeyboardButton !== undefined)
193
+							options.onBeforeVirtualKeyboardButton(this, event, thisFunction);
194
+
195
+						switch (thisFunction)
196
+						{
197
+							case 'DELETE':
198
+								$VirtualKeyboardInput.val($VirtualKeyboardInput.val().toString().slice(0, -1));
199
+							break;
200
+							
201
+							case 'CLEAR':
202
+								$VirtualKeyboardInput.val("");
203
+							break;
204
+							
205
+							// Done break.
206
+							case 'DONE':
207
+								if ($VirtualKeyboardInput.val() > $maxValue)
208
+									setNewValue($base, $maxValue);
209
+								else if ($VirtualKeyboardInput.val() < $minValue)
210
+									setNewValue($base, $minValue);
211
+								else
212
+									setNewValue($base, $VirtualKeyboardInput.val());
213
+							case 'CANCEL':
214
+								$VirtualKeyboard.remove();
215
+							break;
216
+							
217
+							case 'UP':
218
+								if ($VirtualKeyboardInput.val() < $maxValue)
219
+									setNewValue($VirtualKeyboardInput, parseFloat($VirtualKeyboardInput.val()) + parseFloat($step));
220
+							break;
221
+							
222
+							case 'DOWN':
223
+								if ($VirtualKeyboardInput.val() > $minValue)
224
+									setNewValue($VirtualKeyboardInput, parseFloat($VirtualKeyboardInput.val()) - parseFloat($step));
225
+							break;
226
+
227
+							case 'SEP':
228
+								if ($VirtualKeyboardInput.val().toString().indexOf(options.separator) === -1)
229
+									$VirtualKeyboardInput.val($VirtualKeyboardInput.val().toString() + options.separator);
230
+							break;
231
+
232
+							case 'INVERSE':
233
+								setNewValue($VirtualKeyboardInput, parseFloat($VirtualKeyboardInput.val()) * -1);
234
+							break;
235
+														
236
+							// Default to assume its numbers.
237
+							default:
238
+								if ($(this).attr('data-custom-function'))
239
+									$(this).attr('data-custom-function')(this, event, thisFunction);
240
+								else
241
+									setNewValue($VirtualKeyboardInput, $VirtualKeyboardInput.val().toString() + $(this).attr('data-function'));
242
+						}
243
+
244
+						if (options.onAfterVirtualKeyboardButton !== undefined)
245
+							options.onAfterVirtualKeyboardButton(this, event, thisFunction);
246
+					});
247
+
248
+					if (options.onAfterVirtualKeyboardOpen !== undefined)
249
+						options.onAfterVirtualKeyboardOpen(this);
250
+				});
251
+
252
+				if (options.onAfterVirtualKeyboardInitalized !== undefined)
253
+					options.onAfterVirtualKeyboardInitalized(this);
254
+			}
255
+
256
+			if (options.onAfterInitialized !== undefined)
257
+				options.onAfterInitialized(this);
258
+			if (options.debug) console.log($base.parent());
259
+		});
260
+}
261
+
262
+}(jQuery));
0 263
\ No newline at end of file
... ...
@@ -0,0 +1,27 @@
1
+<!DOCTYPE html>
2
+<html>
3
+<head>
4
+	<meta http-equiv="content-type" content="text/html; charset=UTF-8">
5
+	<title>JQuery Number Control with Virtual Keyboard</title>
6
+	<meta name="robots" content="noindex, nofollow">
7
+	<meta name="googlebot" content="noindex, nofollow">
8
+	<meta name="viewport" content="width=device-width, initial-scale=1">
9
+	<link rel="stylesheet" type="text/css" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
10
+	<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/open-iconic/1.1.1/font/css/open-iconic-bootstrap.min.css">
11
+	<link rel="stylesheet" type="text/css" href="./jquery-numbercontrol.css">
12
+</head>
13
+<body>
14
+<br><br><br><br><br><br><br><br><br><br>
15
+	<div class="col-sm-2">	
16
+	<input type="text" id="numbercontrol" value="1" min="-500" max="500" />
17
+	<script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
18
+	<script type="text/javascript" src="./jquery-numbercontrol.js"></script>
19
+	<script type="text/javascript">
20
+	$(document).ready(function() {
21
+		console.log('loading');
22
+		$('#numbercontrol').numbercontrol();
23
+	});
24
+	</script>
25
+	</div>
26
+</body>
27
+</html>
0 28
\ No newline at end of file
1 29