Commit f367ed65607e716a5d876429afedfe762a212d00
Exists in
master
and in
1 other branch
Merge branch 'master' into 'master'
Master (pmarco) See merge request modulos-npm/foca-teclado!2
Showing
4 changed files
Show diff stats
gulpfile.js
| 1 | const clean = require('gulp-clean'); | 1 | const clean = require('gulp-clean'); |
| 2 | const concat = require('gulp-concat'); | 2 | const concat = require('gulp-concat'); |
| 3 | const connect = require('gulp-connect'); | 3 | const connect = require('gulp-connect'); |
| 4 | const gulp = require('gulp'); | 4 | const gulp = require('gulp'); |
| 5 | const htmlmin = require('gulp-htmlmin'); | 5 | const htmlmin = require('gulp-htmlmin'); |
| 6 | const jshint = require('gulp-jshint'); | 6 | const jshint = require('gulp-jshint'); |
| 7 | const pump = require('pump'); | 7 | const pump = require('pump'); |
| 8 | const rename = require('gulp-rename'); | 8 | const rename = require('gulp-rename'); |
| 9 | const replace = require('gulp-replace'); | 9 | const replace = require('gulp-replace'); |
| 10 | const templateCache = require('gulp-angular-templatecache'); | 10 | const templateCache = require('gulp-angular-templatecache'); |
| 11 | const uglify = require('gulp-uglify-es').default; | 11 | const uglify = require('gulp-uglify-es').default; |
| 12 | const sass = require('gulp-sass'); | 12 | const sass = require('gulp-sass'); |
| 13 | 13 | ||
| 14 | var paths = { | 14 | var paths = { |
| 15 | dist: 'dist/', | 15 | dist: 'dist/', |
| 16 | srcJS: 'src/js/*.js', | 16 | srcJS: 'src/js/*.js', |
| 17 | srcViews: 'src/views/*.html', | 17 | srcViews: 'src/views/*.html', |
| 18 | tmp: 'tmp' | 18 | tmp: 'tmp' |
| 19 | }; | 19 | }; |
| 20 | 20 | ||
| 21 | gulp.task('templates', function() { | 21 | gulp.task('templates', function() { |
| 22 | return pump( | 22 | return pump( |
| 23 | [ | 23 | [ |
| 24 | gulp.src(paths.srcViews), | 24 | gulp.src(paths.srcViews), |
| 25 | htmlmin(), | 25 | htmlmin(), |
| 26 | templateCache('views.js', { | 26 | templateCache('views.js', { |
| 27 | module: 'focaTeclado', | 27 | module: 'focaTeclado', |
| 28 | root: '' | 28 | root: '' |
| 29 | }), | 29 | }), |
| 30 | gulp.dest(paths.tmp) | 30 | gulp.dest(paths.tmp) |
| 31 | ] | 31 | ] |
| 32 | ); | 32 | ); |
| 33 | }); | 33 | }); |
| 34 | 34 | ||
| 35 | gulp.task('sass', function() { | 35 | gulp.task('sass', function() { |
| 36 | return gulp.src('src/sass/*.scss') | 36 | return gulp.src('src/sass/*.scss') |
| 37 | .pipe(sass({outputStyle: 'compressed'}).on('error', sass.logError)) | 37 | .pipe(sass({outputStyle: 'compressed'}).on('error', sass.logError)) |
| 38 | .pipe(gulp.dest('css')); | 38 | .pipe(gulp.dest('css')); |
| 39 | }); | 39 | }); |
| 40 | 40 | ||
| 41 | gulp.task('uglify', ['templates'], function() { | 41 | gulp.task('uglify', ['templates'], function() { |
| 42 | return pump( | 42 | return pump( |
| 43 | [ | 43 | [ |
| 44 | gulp.src([ | 44 | gulp.src([ |
| 45 | paths.srcJS, | 45 | paths.srcJS, |
| 46 | 'tmp/views.js' | 46 | 'tmp/views.js' |
| 47 | ]), | 47 | ]), |
| 48 | concat('foca-teclado.js'), | 48 | concat('foca-teclado.js'), |
| 49 | replace('src/views/', ''), | 49 | replace('src/views/', ''), |
| 50 | replace("'ngSanitize', 'onScreenKeyboard'", ''), | 50 | replace("'ngSanitize', 'onScreenKeyboard'", ''), |
| 51 | gulp.dest(paths.tmp), | 51 | gulp.dest(paths.tmp), |
| 52 | rename('foca-teclado.min.js'), | 52 | rename('foca-teclado.min.js'), |
| 53 | uglify(), | 53 | uglify(), |
| 54 | gulp.dest(paths.dist) | 54 | gulp.dest(paths.dist) |
| 55 | ] | 55 | ] |
| 56 | ); | 56 | ); |
| 57 | }); | 57 | }); |
| 58 | 58 | ||
| 59 | gulp.task('clean', function() { | 59 | gulp.task('clean', function() { |
| 60 | return gulp.src(['tmp', 'dist'], {read: false}) | 60 | return gulp.src(['tmp', 'dist'], {read: false}) |
| 61 | .pipe(clean()); | 61 | .pipe(clean()); |
| 62 | }); | 62 | }); |
| 63 | 63 | ||
| 64 | gulp.task('pre-commit', function() { | 64 | gulp.task('pre-commit', function() { |
| 65 | pump( | 65 | pump( |
| 66 | [ | 66 | [ |
| 67 | gulp.src(paths.srcJS), | 67 | gulp.src(paths.srcJS), |
| 68 | jshint('.jshintrc'), | 68 | jshint('.jshintrc'), |
| 69 | jshint.reporter('default'), | 69 | jshint.reporter('default'), |
| 70 | jshint.reporter('fail') | 70 | jshint.reporter('fail') |
| 71 | ] | 71 | ] |
| 72 | ); | 72 | ); |
| 73 | }); | 73 | }); |
| 74 | 74 | ||
| 75 | gulp.task('webserver', function() { | 75 | gulp.task('webserver', function() { |
| 76 | pump [ | 76 | pump [ |
| 77 | connect.server( | 77 | connect.server( |
| 78 | { | 78 | { |
| 79 | port: 3000 | 79 | port: 3000 |
| 80 | } | 80 | } |
| 81 | ) | 81 | ) |
| 82 | ] | 82 | ] |
| 83 | }); | 83 | }); |
| 84 | 84 | ||
| 85 | gulp.task('clean-post-install', function() { | 85 | gulp.task('clean-post-install', function() { |
| 86 | return gulp.src(['src', 'tmp', '.jshintrc','readme.md', '.gitignore', 'gulpfile.js', | 86 | return gulp.src(['src', 'tmp', '.jshintrc','readme.md', '.gitignore', 'gulpfile.js', |
| 87 | 'index.html'], {read: false}) | 87 | 'index.html'], {read: false}) |
| 88 | .pipe(clean()); | 88 | .pipe(clean()); |
| 89 | }); | 89 | }); |
| 90 | 90 | ||
| 91 | gulp.task('default', ['webserver']); | 91 | gulp.task('default', ['webserver']); |
| 92 | |||
| 93 | gulp.task('watch', function() { | ||
| 94 | gulp.watch([paths.srcJS, paths.srcViews], ['uglify']); | ||
| 95 | }); | ||
| 92 | 96 |
src/js/angular-on-screen-keyboard-directive.js
| File was created | 1 | angular.module('onScreenKeyboard', ['ngSanitize']) | |
| 2 | .directive('onScreenKeyboard', ['$timeout', '$document', function($timeout, $document) { | ||
| 3 | return { | ||
| 4 | restrict: 'E', | ||
| 5 | bindToController: true, | ||
| 6 | controllerAs: 'ctrl', | ||
| 7 | scope: { | ||
| 8 | rows : '=?', | ||
| 9 | uppercaseAllWords : '@', | ||
| 10 | alfanumeric : '=?', | ||
| 11 | numeric : '=?' | ||
| 12 | }, | ||
| 13 | controller: ['$sce', '$scope', function($sce, $scope) { | ||
| 14 | var ctrl = this; | ||
| 15 | |||
| 16 | if (!ctrl.rows) { | ||
| 17 | ctrl.rows = [ | ||
| 18 | ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', { | ||
| 19 | type: 'erase', colspan: 2, text: '⇐' | ||
| 20 | }], | ||
| 21 | ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '@'], | ||
| 22 | ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', '-', '_', {type: 'margin'}], | ||
| 23 | [ | ||
| 24 | {type: 'shift', upperCase: '⇓', lowerCase: '⇑'}, | ||
| 25 | 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', | ||
| 26 | {type: 'shift', upperCase: '⇓', lowerCase: '⇑'} | ||
| 27 | ], | ||
| 28 | [{type: 'margin'}, {type: 'space', colspan: 9, text: ' '}] | ||
| 29 | ]; | ||
| 30 | } | ||
| 31 | |||
| 32 | ctrl.getText = function(key) { | ||
| 33 | if (key.type === 'margin') { | ||
| 34 | return ''; | ||
| 35 | } | ||
| 36 | |||
| 37 | var val = ''; | ||
| 38 | |||
| 39 | if (key.text) { | ||
| 40 | val = key.text; | ||
| 41 | } | ||
| 42 | else if (key.lowerCase && !ctrl.isUpperCase) { | ||
| 43 | val = key.lowerCase; | ||
| 44 | } | ||
| 45 | else if (key.upperCase && ctrl.isUpperCase) { | ||
| 46 | val = key.upperCase; | ||
| 47 | } | ||
| 48 | else { | ||
| 49 | val = ctrl.isUpperCase ? key.toUpperCase() : key.toLowerCase(); | ||
| 50 | } | ||
| 51 | |||
| 52 | if (val && val.indexOf('&') > -1) { | ||
| 53 | return $sce.trustAsHtml(val); | ||
| 54 | } | ||
| 55 | |||
| 56 | return val; | ||
| 57 | }; | ||
| 58 | $scope.fondo = function() { | ||
| 59 | $timeout(function() { | ||
| 60 | ctrl.lastInputCtrl.focus(); | ||
| 61 | $scope.$emit('focus'); | ||
| 62 | }); | ||
| 63 | }; | ||
| 64 | }], | ||
| 65 | link: function(scope, element, attr) { | ||
| 66 | var ctrl = scope.ctrl; | ||
| 67 | ctrl.isUpperCase = false; | ||
| 68 | ctrl.lastInputCtrl = null; | ||
| 69 | ctrl.startPos = null; | ||
| 70 | ctrl.endPos = null; | ||
| 71 | |||
| 72 | ctrl.printKeyStroke = function(key, event) { | ||
| 73 | |||
| 74 | if (!ctrl.lastInputCtrl) { | ||
| 75 | return; | ||
| 76 | } | ||
| 77 | |||
| 78 | ctrl.startPos = ctrl.lastInputCtrl.selectionStart; | ||
| 79 | ctrl.endPos = ctrl.lastInputCtrl.selectionEnd; | ||
| 80 | |||
| 81 | if (key.type === 'erase') { | ||
| 82 | ctrl.eraseKeyStroke(); | ||
| 83 | return; | ||
| 84 | } else if (key.type === 'shift') { | ||
| 85 | ctrl.isUpperCase = !ctrl.isUpperCase; | ||
| 86 | return; | ||
| 87 | } | ||
| 88 | |||
| 89 | var htmlKeyVal = angular.element(event.target || event.srcElement).text(); | ||
| 90 | var lastInputCtrl = angular.element(ctrl.lastInputCtrl); | ||
| 91 | var val = lastInputCtrl.val(); | ||
| 92 | var pre = val.substring(0, ctrl.startPos); | ||
| 93 | var post = val.substring(ctrl.endPos, val.length); | ||
| 94 | lastInputCtrl.val(pre + htmlKeyVal + post); | ||
| 95 | lastInputCtrl.triggerHandler('change'); | ||
| 96 | |||
| 97 | ctrl.startPos += htmlKeyVal.length; | ||
| 98 | ctrl.endPos += htmlKeyVal.length; | ||
| 99 | ctrl.lastInputCtrl.selectionStart = ctrl.startPos; | ||
| 100 | ctrl.lastInputCtrl.selectionEnd = ctrl.startPos; | ||
| 101 | ctrl.setKeyboardLayout(); | ||
| 102 | ctrl.refocus(); | ||
| 103 | }; | ||
| 104 | |||
| 105 | ctrl.refocus = function() { | ||
| 106 | ctrl.lastInputCtrl.focus(); | ||
| 107 | }; | ||
| 108 | |||
| 109 | ctrl.eraseKeyStroke = function() { | ||
| 110 | if (!ctrl.lastInputCtrl) { | ||
| 111 | return; | ||
| 112 | } | ||
| 113 | |||
| 114 | var hasSel = ctrl.startPos !== ctrl.endPos; | ||
| 115 | |||
| 116 | var lastInputCtrl = angular.element(ctrl.lastInputCtrl); | ||
| 117 | var val = lastInputCtrl.val(); | ||
| 118 | var pre = val.substring(0, hasSel ? ctrl.startPos : ctrl.startPos - 1); | ||
| 119 | var post = val.substring(ctrl.endPos, val.length); | ||
| 120 | |||
| 121 | lastInputCtrl.val(pre + post); | ||
| 122 | lastInputCtrl.triggerHandler('change'); | ||
| 123 | |||
| 124 | if (hasSel) { | ||
| 125 | ctrl.endPos = ctrl.startPos; | ||
| 126 | } | ||
| 127 | else { | ||
| 128 | ctrl.startPos--; | ||
| 129 | ctrl.endPos--; | ||
| 130 | } | ||
| 131 | ctrl.lastInputCtrl.selectionStart = ctrl.startPos; | ||
| 132 | ctrl.lastInputCtrl.selectionEnd = ctrl.startPos; | ||
| 133 | ctrl.setKeyboardLayout(); | ||
| 134 | ctrl.refocus(); | ||
| 135 | }; | ||
| 136 | |||
| 137 | ctrl.setKeyboardLayout = function() { | ||
| 138 | if (!ctrl.lastInputCtrl) { | ||
| 139 | ctrl.isUpperCase = true; | ||
| 140 | return; | ||
| 141 | } | ||
| 142 | else if (ctrl.lastInputCtrl.className && ctrl.isUpperCase) { | ||
| 143 | ctrl.isUpperCase = true; | ||
| 144 | } | ||
| 145 | else if (angular.element(ctrl.lastInputCtrl).val().length === 0) { | ||
| 146 | ctrl.isUpperCase = true; | ||
| 147 | } | ||
| 148 | else if ( | ||
| 149 | angular.element(ctrl.lastInputCtrl).val().slice(-1) === ' ' && | ||
| 150 | !ctrl.isUpperCase && attr.uppercaseAllWords !== undefined | ||
| 151 | ) { | ||
| 152 | ctrl.isUpperCase = true; | ||
| 153 | } | ||
| 154 | else{ | ||
| 155 | ctrl.isUpperCase = true; | ||
| 156 | } | ||
| 157 | }; | ||
| 158 | |||
| 159 | var focusin = function(event) { | ||
| 160 | var e = event.target || event.srcElement; | ||
| 161 | |||
| 162 | if (e.tagName === 'INPUT' || e.tagName === 'TEXTAREA') { | ||
| 163 | ctrl.lastInputCtrl = e; | ||
| 164 | ctrl.setKeyboardLayout(); | ||
| 165 | } | ||
| 166 | }; | ||
| 167 | |||
| 168 | var keyup = function() { | ||
| 169 | if (!ctrl.lastInputCtrl) { | ||
| 170 | return; | ||
| 171 | } | ||
| 172 | |||
| 173 | ctrl.startPos = ctrl.lastInputCtrl.selectionStart; | ||
| 174 | ctrl.endPos = ctrl.lastInputCtrl.selectionEnd; | ||
| 175 | |||
| 176 | ctrl.setKeyboardLayout(); | ||
| 177 | scope.$digest(); | ||
| 178 | }; | ||
| 179 | |||
| 180 | $document.bind('focusin', focusin); | ||
| 181 | $document.bind('keyup', keyup); | ||
| 182 | |||
| 183 | scope.$on("$destroy", function() { | ||
| 184 | $document.unbind('focusin', focusin); | ||
| 185 | $document.unbind('keyup', keyup); | ||
| 186 | }); | ||
| 187 | |||
| 188 | element.bind('contextmenu', function(event) { | ||
| 189 | event.preventDefault(); | ||
| 190 | return false; | ||
| 191 | }); | ||
| 192 | |||
| 193 | $timeout(function() { | ||
| 194 | ctrl.isUpperCase = true; | ||
| 195 | }, 0); | ||
| 196 | }, | ||
| 197 | templateUrl: 'src/views/angular-on-screen-keyboard.html' | ||
| 198 | }; | ||
| 199 | }]); | ||
| 200 |
src/views/angular-on-screen-keyboard.html
| File was created | 1 | <div class="keyboard" ng-mousedown="fondo()"> | |
| 2 | <div class="row"> | ||
| 3 | <table | ||
| 4 | class="form-group col-12 col-sm-6 col-md-9" | ||
| 5 | ng-show="ctrl.alfanumeric" | ||
| 6 | > | ||
| 7 | <tr ng-repeat="row in ctrl.rows.alfa"> | ||
| 8 | <td ng-repeat="key in row" | ||
| 9 | ng-click="ctrl.printKeyStroke(key, $event)" | ||
| 10 | colspan="{{key.colspan || 1}}" | ||
| 11 | ng-class="{ | ||
| 12 | 'number': key.type === 'number', 'letter': key.type !== 'margin' && | ||
| 13 | key.type !== 'number' | ||
| 14 | }" | ||
| 15 | ng-bind-html="ctrl.getText(key)" | ||
| 16 | > | ||
| 17 | </td> | ||
| 18 | </tr> | ||
| 19 | </table> | ||
| 20 | <table | ||
| 21 | class="form-group col-12 col-sm-6 col-md-3" | ||
| 22 | ng-show="ctrl.numeric" | ||
| 23 | > | ||
| 24 | <tr ng-repeat="row in ctrl.rows.numeric"> | ||
| 25 | <td ng-repeat="key in row" | ||
| 26 | ng-click="ctrl.printKeyStroke(key, $event)" | ||
| 27 | colspan="{{key.colspan || 1}}" | ||
| 28 | ng-class="{ | ||
| 29 | 'number': key.type === 'number', 'letter': key.type !== 'margin' && | ||
| 30 | key.type !== 'number' | ||
| 31 | }" | ||
| 32 | ng-bind-html="ctrl.getText(key)" | ||
| 33 | > | ||
| 34 | </td> | ||
| 35 | </tr> | ||
| 36 | </table> | ||
| 37 | </div> | ||
| 38 | </div> | ||
| 39 |
src/views/teclado.html
| 1 | <on-screen-keyboard | 1 | <on-screen-keyboard |
| 2 | rows="rows" | 2 | rows="rows" |
| 3 | alfanumeric="$ctrl.alfanumeric" | 3 | alfanumeric="$ctrl.alfanumeric" |
| 4 | numeric="$ctrl.numeric" | 4 | numeric="$ctrl.numeric" |
| 5 | ></on-screen-keyboard> | 5 | ></on-screen-keyboard> |
| 6 | 6 |