├── dist ├── CNAME ├── assets │ ├── favicon.ico │ └── img │ │ ├── fav.png │ │ ├── ads300.gif │ │ ├── ads300.png │ │ ├── loading.gif │ │ └── loading (1).gif ├── components │ └── common │ │ ├── footer │ │ └── footer.tpl.html │ │ ├── header │ │ └── header.tpl.html │ │ └── keyboard │ │ └── keyboard.tpl.html ├── views │ ├── home │ │ └── home.tpl.html │ ├── editor │ │ └── editor.tpl.html │ └── practice │ │ ├── practice.tpl.html │ │ └── practise.tpl.html ├── auth │ ├── login │ │ └── login.tpl.html │ └── user-register │ │ └── user-register.tpl.html ├── 404.html ├── index.html ├── app.css └── app.min.js ├── client ├── CNAME ├── components │ ├── common │ │ ├── header │ │ │ ├── header.css │ │ │ ├── header.js │ │ │ └── header.tpl.html │ │ ├── footer │ │ │ ├── footer.css │ │ │ ├── footer.ctrl.js │ │ │ └── footer.tpl.html │ │ └── keyboard │ │ │ ├── keyboard.component.js │ │ │ ├── keyboard.tpl.html │ │ │ └── keyboard.css │ └── common.module.js ├── assets │ ├── favicon.ico │ └── img │ │ ├── fav.png │ │ ├── ads300.gif │ │ ├── ads300.png │ │ ├── loading.gif │ │ └── loading (1).gif ├── app.css ├── services │ ├── capitalisefirst.service.js │ ├── limitobj.filter.js │ ├── datafetch.service.js │ ├── socket.service.js │ ├── filter.service.js │ ├── authentication.service.js │ └── keyboardlayout.service.js ├── views │ ├── home │ │ ├── home.tpl.html │ │ └── home.ctrl.js │ ├── practice │ │ ├── practise.css │ │ ├── practice.tpl.html │ │ └── practise.ctrl.js │ └── editor │ │ ├── editor.ctrl.js │ │ ├── editor.tpl.html │ │ └── editor.css ├── auth │ ├── user-register │ │ ├── user-register.ctrl.js │ │ └── user-register.tpl.html │ └── login │ │ ├── login.tpl.html │ │ └── login.controller.js ├── app.js └── index.html ├── .bowerrc ├── server ├── config.json ├── app │ ├── routes.js │ ├── api.controller.js │ └── app.controller.js └── server.js ├── .gitignore ├── gulpfiles ├── build.js ├── prodtpl.js ├── uglifycss.js ├── github.js ├── uglify.js ├── app.js ├── watch.js ├── inject.js ├── server.js └── prod.js ├── e2e-tests ├── protractor.conf.js └── scenarios.js ├── .travis.yml ├── .jshintrc ├── gulpfile.js ├── karma.conf.js ├── bower.json ├── package.json ├── README.md └── data └── type-content └── strings.json /dist/CNAME: -------------------------------------------------------------------------------- 1 | typali.mjt.com.np -------------------------------------------------------------------------------- /client/CNAME: -------------------------------------------------------------------------------- 1 | typali.mjt.com.np -------------------------------------------------------------------------------- /client/components/common/header/header.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "./bower_components" 3 | } -------------------------------------------------------------------------------- /client/components/common.module.js: -------------------------------------------------------------------------------- 1 | angular 2 | .module('typali.common',[]); -------------------------------------------------------------------------------- /client/components/common/footer/footer.css: -------------------------------------------------------------------------------- 1 | .footer li a { 2 | margin: 10px; 3 | } -------------------------------------------------------------------------------- /dist/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emp3ror/typali/HEAD/dist/assets/favicon.ico -------------------------------------------------------------------------------- /dist/assets/img/fav.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emp3ror/typali/HEAD/dist/assets/img/fav.png -------------------------------------------------------------------------------- /client/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emp3ror/typali/HEAD/client/assets/favicon.ico -------------------------------------------------------------------------------- /client/assets/img/fav.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emp3ror/typali/HEAD/client/assets/img/fav.png -------------------------------------------------------------------------------- /dist/assets/img/ads300.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emp3ror/typali/HEAD/dist/assets/img/ads300.gif -------------------------------------------------------------------------------- /dist/assets/img/ads300.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emp3ror/typali/HEAD/dist/assets/img/ads300.png -------------------------------------------------------------------------------- /client/assets/img/ads300.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emp3ror/typali/HEAD/client/assets/img/ads300.gif -------------------------------------------------------------------------------- /client/assets/img/ads300.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emp3ror/typali/HEAD/client/assets/img/ads300.png -------------------------------------------------------------------------------- /client/assets/img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emp3ror/typali/HEAD/client/assets/img/loading.gif -------------------------------------------------------------------------------- /dist/assets/img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emp3ror/typali/HEAD/dist/assets/img/loading.gif -------------------------------------------------------------------------------- /dist/assets/img/loading (1).gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emp3ror/typali/HEAD/dist/assets/img/loading (1).gif -------------------------------------------------------------------------------- /client/assets/img/loading (1).gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emp3ror/typali/HEAD/client/assets/img/loading (1).gif -------------------------------------------------------------------------------- /server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "localApiUri": "http://localhost:8080/api", 3 | "serverApiUri" : "" 4 | } 5 | 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | logs/* 2 | !.gitkeep 3 | node_modules/ 4 | bower_components/ 5 | public/ 6 | tmp 7 | .DS_Store 8 | .idea 9 | .tags 10 | .tags_sorted_by_file 11 | client/configFile.js 12 | *~ 13 | \#*\# -------------------------------------------------------------------------------- /client/components/common/footer/footer.ctrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('typali') 3 | .controller('FooterCtrl', FooterCtrl); 4 | FooterCtrl.$inject = ['$scope']; 5 | 6 | function FooterCtrl ($scope) { 7 | var vm = this; 8 | } -------------------------------------------------------------------------------- /gulpfiles/build.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'), 2 | watch = require('gulp-watch'); 3 | 4 | var source = './client'; 5 | gulp.task('build',function () { 6 | return gulp.src(source+'/**/*.*', { base: source+'/' }) 7 | .pipe(gulp.dest('public')); 8 | }); -------------------------------------------------------------------------------- /gulpfiles/prodtpl.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | 3 | var print = require('gulp-print'); 4 | 5 | 6 | 7 | gulp.task('prodtpl', function () { 8 | var target = gulp.src('./client/**/*.html'); 9 | 10 | return target 11 | .pipe(gulp.dest('./dist')); 12 | }); 13 | -------------------------------------------------------------------------------- /client/components/common/header/header.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('typali') 3 | .controller('HeaderCtrl', HeaderCtrl) 4 | 5 | HeaderCtrl.$inject = ['$scope','$rootScope']; 6 | 7 | function HeaderCtrl ($scope,$rootScope) { 8 | var vm = this; 9 | 10 | 11 | 12 | 13 | 14 | } -------------------------------------------------------------------------------- /client/app.css: -------------------------------------------------------------------------------- 1 | html,body { 2 | background: #fff; 3 | font-family: ProximaNova,-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif; 4 | font-size: 16px; 5 | color: #231f20; 6 | } 7 | /* app css stylesheet */ 8 | 9 | .mainView { 10 | min-height: 300px; 11 | margin-bottom: 20px; 12 | } -------------------------------------------------------------------------------- /client/services/capitalisefirst.service.js: -------------------------------------------------------------------------------- 1 | angular.module('typali'). 2 | filter('capitalize', function() { 3 | return function(input, all) { 4 | var reg = (all) ? /([^\W_]+[^\s-]*) */g : /([^\W_]+[^\s-]*)/; 5 | return (!!input) ? input.replace(reg, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();}) : ''; 6 | } 7 | }); -------------------------------------------------------------------------------- /gulpfiles/uglifycss.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var uglifycss = require('gulp-uglifycss'); 3 | var concat = require('gulp-concat'); 4 | 5 | gulp.task('uglifycss', function () { 6 | gulp.src('./client/**/*.css') 7 | .pipe(uglifycss({ 8 | "maxLineLen": 0, 9 | "uglyComments": true 10 | })) 11 | .pipe(concat('app.css')) 12 | .pipe(gulp.dest('./dist/')); 13 | }); 14 | -------------------------------------------------------------------------------- /e2e-tests/protractor.conf.js: -------------------------------------------------------------------------------- 1 | //jshint strict: false 2 | exports.config = { 3 | 4 | allScriptsTimeout: 11000, 5 | 6 | specs: [ 7 | '*.js' 8 | ], 9 | 10 | capabilities: { 11 | 'browserName': 'chrome' 12 | }, 13 | 14 | baseUrl: 'http://localhost:8000/', 15 | 16 | framework: 'jasmine', 17 | 18 | jasmineNodeOpts: { 19 | defaultTimeoutInterval: 30000 20 | } 21 | 22 | }; 23 | -------------------------------------------------------------------------------- /dist/components/common/footer/footer.tpl.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/components/common/footer/footer.tpl.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/views/home/home.tpl.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 7 |
8 |
9 | 10 | Home is making, keep checking Practice 11 |
12 |
-------------------------------------------------------------------------------- /dist/views/home/home.tpl.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 7 |
8 |
9 | 10 | Home is making, keep checking Practice 11 |
12 |
-------------------------------------------------------------------------------- /gulpfiles/github.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var rename = require("gulp-rename"); 3 | 4 | gulp.task('github-cname', function () { 5 | var target = gulp.src('./client/CNAME'); 6 | 7 | return target 8 | .pipe(gulp.dest('./dist')); 9 | }); 10 | 11 | 12 | gulp.task('github',['prod','github-cname'],function () { 13 | var target = gulp.src('./dist/index.html'); 14 | return target 15 | .pipe(rename("404.html")) 16 | .pipe(gulp.dest('./dist')) 17 | }) -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '4.4' 4 | 5 | before_script: 6 | - export DISPLAY=:99.0 7 | - sh -e /etc/init.d/xvfb start 8 | - npm start > /dev/null & 9 | - npm run update-webdriver 10 | - sleep 1 # give server time to start 11 | 12 | script: 13 | - node_modules/.bin/karma start karma.conf.js --no-auto-watch --single-run --reporters=dots --browsers=Firefox 14 | - node_modules/.bin/protractor e2e-tests/protractor.conf.js --browser=firefox 15 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "strict": "global", 3 | "globals": { 4 | // Angular 5 | "angular": false, 6 | 7 | // Angular mocks 8 | "module": false, 9 | "inject": false, 10 | 11 | // Jasmine 12 | "jasmine": false, 13 | "describe": false, 14 | "beforeEach": false, 15 | "afterEach": false, 16 | "it": false, 17 | "expect": false, 18 | 19 | // Protractor 20 | "browser": false, 21 | "element": false, 22 | "by": false 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /server/app/routes.js: -------------------------------------------------------------------------------- 1 | // load the todo model 2 | // var Todo = require('./models/todo'); 3 | // var socketio = require('./socketio.js'); 4 | var request = require('request'); 5 | 6 | // expose the routes to our app with module.exports 7 | module.exports = function(app) { 8 | 9 | app.use('/api',require('./api.controller')); 10 | 11 | app.use("/",require("./app.controller")); 12 | 13 | // api --------------------------------------------------------------------- 14 | 15 | }; 16 | -------------------------------------------------------------------------------- /gulpfiles/uglify.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var uglify = require('gulp-uglify'); 3 | var bytediff = require('gulp-bytediff'); 4 | var rename = require('gulp-rename'); 5 | var plumber = require('gulp-plumber') 6 | 7 | gulp.task('uglify', ['app'], function() { 8 | return gulp.src('dist/app.js') 9 | .pipe(plumber()) 10 | .pipe(bytediff.start()) 11 | .pipe(uglify({mangle: true})) 12 | .pipe(bytediff.stop()) 13 | .pipe(rename('app.min.js')) 14 | .pipe(plumber.stop()) 15 | .pipe(gulp.dest('dist/')); 16 | }); 17 | -------------------------------------------------------------------------------- /gulpfiles/app.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var concat = require('gulp-concat'); 3 | var ngAnnotate = require('gulp-ng-annotate'); 4 | var plumber = require('gulp-plumber'); 5 | var angularFilesort = require('gulp-angular-filesort'); 6 | var print = require('gulp-print'); 7 | 8 | gulp.task('app', function() { 9 | return gulp.src(['./client/**/*.js', '!./client/**/*test.js'], { 10 | relative: true}) 11 | .pipe(angularFilesort()) 12 | .pipe(print()) 13 | .pipe(plumber()) 14 | .pipe(concat('app.js', {newLine: ';'})) 15 | .pipe(ngAnnotate({add: true})) 16 | .pipe(plumber.stop()) 17 | .pipe(gulp.dest('dist/')); 18 | }); 19 | -------------------------------------------------------------------------------- /server/app/api.controller.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var request = require('request'); 4 | 5 | var config = require('../config.json'); 6 | 7 | var textCollection = require("../../data/type-content/strings.json"); 8 | 9 | var length = textCollection.length; 10 | 11 | router.get('/getstring/:id', function (req,res) { 12 | 13 | 14 | var id = parseInt(req.params.id); 15 | 16 | console.log(req.params.id,id,length); 17 | 18 | if (id >=length) { 19 | id = 0; 20 | } 21 | 22 | 23 | var data = textCollection[id]; 24 | 25 | res.json({data : data}); 26 | }); 27 | 28 | module.exports = router; -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | /* jshint node: true */ 2 | 3 | 'use strict'; 4 | 5 | var gulp = require('gulp'); 6 | var wrench = require('wrench'); 7 | 8 | /* 9 | concatenate all *.js / *.coffee files in the 'gulp' folder 10 | */ 11 | wrench.readdirSyncRecursive('./gulpfiles').filter(function(file) { 12 | return (/\.(js|coffee)$/i).test(file); 13 | }).map(function(file) { 14 | require('./gulpfiles/' + file); 15 | }); 16 | 17 | /* 18 | executed as default task, when no task is specified 19 | */ 20 | // gulp.task('default', ['html', 'lib', 'css', 'fonts', 'images', 'index', 'ts', 'tsTest', 'tsE2E']); 21 | /*gulp.task('default', ['clean'], function () { 22 | gulp.start('build'); 23 | });*/ -------------------------------------------------------------------------------- /client/services/limitobj.filter.js: -------------------------------------------------------------------------------- 1 | var app=angular.module('typali'); 2 | app.filter('limitobj', [function(){ 3 | return function(obj, limit){ 4 | if (typeof obj != 'object') { 5 | return []; 6 | } 7 | var keys = Object.keys(obj); 8 | if(keys.length < 1 || typeof keys == 'undefined'){ 9 | return []; 10 | } 11 | 12 | var ret = new Object, 13 | count = 0; 14 | angular.forEach(keys, function(key, arrayIndex){ 15 | if(count >= limit){ 16 | return false; 17 | } 18 | ret[key] = obj[key]; 19 | count++; 20 | }); 21 | return ret; 22 | }; 23 | }]); -------------------------------------------------------------------------------- /client/services/datafetch.service.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | (function () { 3 | 4 | angular 5 | .module('typali') 6 | .service('datafetchService', DatafetchService); 7 | 8 | DatafetchService.$inject = ['$http']; 9 | 10 | function DatafetchService ($http) { 11 | var service = this; 12 | 13 | var url = "https://typali.herokuapp.com/api/"; 14 | // var url = "http://localhost:8080/api/"; 15 | 16 | /*get string*/ 17 | service.getString = function (params) { 18 | var response = $http({ 19 | cache: true, 20 | method: 'GET', 21 | url: url+"getstring/"+params 22 | }); 23 | 24 | console.log("url : ",url+"getstring/"+params); 25 | 26 | return response; 27 | }; 28 | 29 | 30 | 31 | } 32 | 33 | })(); 34 | -------------------------------------------------------------------------------- /client/auth/user-register/user-register.ctrl.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | angular 4 | .module('typali') 5 | .config(['$stateProvider', function($stateProvider) { 6 | $stateProvider 7 | .state('app.register', { 8 | url:'/register', 9 | views: { 10 | 'container@' : { 11 | templateUrl: 'auth/user-register/user-register.tpl.html', 12 | controller: 'UserRegisterCtrl', 13 | controllerAs : 'vm' 14 | } 15 | } 16 | 17 | }); 18 | }]) 19 | .controller('UserRegisterCtrl', userRegisterCtrl); 20 | 21 | userRegisterCtrl.$inject = ['$location', 'authentication']; 22 | function userRegisterCtrl($location, authentication) { 23 | var vm = this; 24 | 25 | } 26 | 27 | })(); -------------------------------------------------------------------------------- /gulpfiles/watch.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'), 2 | watch = require('gulp-watch'); 3 | 4 | var modRewrite = require('connect-modrewrite'); 5 | 6 | 7 | var browserSync = require("browser-sync").create(); 8 | 9 | 10 | gulp.task('watch-folder', function() { 11 | browserSync.init({ 12 | server: { 13 | baseDir: ["./public","./client"], 14 | routes: { 15 | "/bower_components": "bower_components" 16 | }, 17 | middleware: [ 18 | modRewrite([ 19 | '!\\.\\w+$ /index.html [L]' 20 | ]) 21 | ] 22 | } 23 | }); 24 | gulp.watch('./client/**/*', ['inject']).on('change', browserSync.reload);; 25 | }); 26 | 27 | -------------------------------------------------------------------------------- /client/auth/login/login.tpl.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 | 7 |
8 |
9 | 10 | 11 |
12 | 13 | register 14 |
15 |
16 |
-------------------------------------------------------------------------------- /dist/auth/login/login.tpl.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 | 7 |
8 |
9 | 10 | 11 |
12 | 13 | register 14 |
15 |
16 |
-------------------------------------------------------------------------------- /client/views/home/home.ctrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('typali') 4 | 5 | .config(['$stateProvider', function($stateProvider) { 6 | $stateProvider 7 | .state('app.home', { 8 | url:'/', 9 | views : { 10 | 'container@': { 11 | templateUrl: 'views/home/home.tpl.html', 12 | controller: 'HomeCtrl', 13 | controllerAs : 'vm' 14 | } 15 | } 16 | }) 17 | 18 | }]) 19 | 20 | .controller('HomeCtrl', HomeCtrl); 21 | HomeCtrl.$inject = ['$scope','$rootScope']; 22 | function HomeCtrl ($scope,$rootScope) { 23 | var vm = this; 24 | 25 | $rootScope.lang = "unicode"; 26 | vm.lang = $rootScope.lang; 27 | 28 | vm.update = function() { 29 | console.log("lang",vm.lang); 30 | $rootScope.lang=vm.lang; 31 | $rootScope.$broadcast("lang",vm.lang); 32 | } 33 | }; -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | //jshint strict: false 2 | module.exports = function(config) { 3 | config.set({ 4 | 5 | basePath: './app', 6 | 7 | files: [ 8 | 'bower_components/angular/angular.js', 9 | 'bower_components/angular-route/angular-route.js', 10 | 'bower_components/angular-mocks/angular-mocks.js', 11 | 'components/**/*.js', 12 | 'view*/**/*.js' 13 | ], 14 | 15 | autoWatch: true, 16 | 17 | frameworks: ['jasmine'], 18 | 19 | browsers: ['Chrome'], 20 | 21 | plugins: [ 22 | 'karma-chrome-launcher', 23 | 'karma-firefox-launcher', 24 | 'karma-jasmine', 25 | 'karma-junit-reporter' 26 | ], 27 | 28 | junitReporter: { 29 | outputFile: 'test_out/unit.xml', 30 | suite: 'unit' 31 | } 32 | 33 | }); 34 | }; 35 | -------------------------------------------------------------------------------- /server/app/app.controller.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var router = express.Router(); 3 | 4 | 5 | router.use('/', function (req, res, next) { 6 | 7 | /*if (req.path !== '/login' && !req.session.token) { 8 | return res.redirect('/login'); 9 | } 10 | */ 11 | 12 | 13 | next(); 14 | }); 15 | 16 | /*static defined*/ 17 | // res.sendfile('./public/index.html'); 18 | 19 | // router.use("/", express.static('./public/')); //public folder run by gulp 20 | 21 | // router.use("/", express.static('./client/')); //client folder also taken as static 22 | 23 | // router.use("/img/", express.static('./client/assets/img/')); 24 | 25 | // router.use('*', express.static('./public/index.html')) 26 | /*router.get('*', function(req, res) { 27 | res.sendfile('./public/index.html'); 28 | }); 29 | */ 30 | module.exports = router; -------------------------------------------------------------------------------- /client/services/socket.service.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('typali') 3 | 4 | //Here LoopBackAuth service must be provided as argument for authenticating the user 5 | .factory('socket', function ($rootScope) { 6 | var socket = io.connect(); 7 | return { 8 | on: function (eventName, callback) { 9 | socket.on(eventName, function () { 10 | var args = arguments; 11 | $rootScope.$apply(function () { 12 | callback.apply(socket, args); 13 | }); 14 | }); 15 | }, 16 | emit: function (eventName, data, callback) { 17 | socket.emit(eventName, data, function () { 18 | var args = arguments; 19 | $rootScope.$apply(function () { 20 | if (callback) { 21 | callback.apply(socket, args); 22 | } 23 | }); 24 | }) 25 | } 26 | }; 27 | }); 28 | -------------------------------------------------------------------------------- /dist/components/common/header/header.tpl.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | Fork me on GitHub 18 | 19 | 20 | -------------------------------------------------------------------------------- /client/components/common/header/header.tpl.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | Fork me on GitHub 18 | 19 | 20 | -------------------------------------------------------------------------------- /client/services/filter.service.js: -------------------------------------------------------------------------------- 1 | var app=angular.module('typali'); 2 | app.filter('filterByProperty',['$filter', function ($filter) { 3 | /* array is first argument, each addiitonal argument is prefixed by a ":" in filter markup*/ 4 | return function (dataArray, searchTerm, propertyName) { 5 | console.log("reached here", searchTerm, propertyName); 6 | if (!dataArray) return; 7 | /* when term is cleared, return full array*/ 8 | if (!searchTerm) { 9 | return dataArray 10 | } else if (propertyName === "$") { 11 | return $filter('filter')(dataArray, searchTerm) 12 | } 13 | else { 14 | /* otherwise filter the array */ 15 | console.log(searchTerm); 16 | var term = searchTerm.toString().toLowerCase(); 17 | return dataArray.filter(function (item) { 18 | return item[propertyName].toString().toLowerCase().indexOf(term) > -1; 19 | }); 20 | } 21 | } 22 | }]); -------------------------------------------------------------------------------- /client/auth/login/login.controller.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | angular 4 | .module('typali') 5 | .config(['$stateProvider', function($stateProvider) { 6 | $stateProvider 7 | .state('app.login', { 8 | url:'/login', 9 | views: { 10 | 'container@' : { 11 | templateUrl: 'auth/login/login.tpl.html', 12 | controller: 'LoginCtrl', 13 | controllerAs : 'vm' 14 | } 15 | } 16 | 17 | }); 18 | }]) 19 | .controller('LoginCtrl', loginCtrl); 20 | 21 | loginCtrl.$inject = ['$location', 'authentication']; 22 | function loginCtrl($location, authentication) { 23 | var vm = this; 24 | 25 | vm.credentials = { 26 | email : "yo@hotmail.com", 27 | password : "" 28 | }; 29 | 30 | vm.onSubmit = function () { 31 | authentication 32 | .login(vm.credentials) 33 | .error(function(err){ 34 | console.log(err); 35 | }) 36 | .then(function(){ 37 | $location.path('profile'); 38 | }); 39 | }; 40 | 41 | } 42 | 43 | })(); -------------------------------------------------------------------------------- /e2e-tests/scenarios.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* https://github.com/angular/protractor/blob/master/docs/toc.md */ 4 | 5 | describe('my app', function() { 6 | 7 | 8 | it('should automatically redirect to /view1 when location hash/fragment is empty', function() { 9 | browser.get('index.html'); 10 | expect(browser.getLocationAbsUrl()).toMatch("/view1"); 11 | }); 12 | 13 | 14 | describe('view1', function() { 15 | 16 | beforeEach(function() { 17 | browser.get('index.html#!/view1'); 18 | }); 19 | 20 | 21 | it('should render view1 when user navigates to /view1', function() { 22 | expect(element.all(by.css('[ng-view] p')).first().getText()). 23 | toMatch(/partial for view 1/); 24 | }); 25 | 26 | }); 27 | 28 | 29 | describe('view2', function() { 30 | 31 | beforeEach(function() { 32 | browser.get('index.html#!/view2'); 33 | }); 34 | 35 | 36 | it('should render view2 when user navigates to /view2', function() { 37 | expect(element.all(by.css('[ng-view] p')).first().getText()). 38 | toMatch(/partial for view 2/); 39 | }); 40 | 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /gulpfiles/inject.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'), 2 | wiredep = require('wiredep').stream, 3 | inject = require('gulp-inject'), 4 | angularFilesort = require('gulp-angular-filesort'), 5 | watch = require('gulp-watch'); 6 | var print = require('gulp-print'); 7 | 8 | 9 | 10 | gulp.task('inject', function () { 11 | var target = gulp.src('./client/index.html'); 12 | 13 | var sources = gulp.src(['./client/**/*.js', '!./client/**/*test.js' ],{ 14 | 15 | relative: false}) 16 | .pipe(angularFilesort()) 17 | .pipe(print()); 18 | 19 | var injectStyles = gulp.src(['./client/**/*.css'], 20 | { read: false, 21 | relative: false }) 22 | .pipe(print()); 23 | 24 | var options = { 25 | directory: './bower_components/', 26 | ignorePath: '../', 27 | devDependencies: true, 28 | relative: false 29 | }; 30 | 31 | return target 32 | .pipe(wiredep(options)) 33 | .pipe(inject(sources, 34 | {ignorePath:"client", 35 | addRootSlash : false,} 36 | )) 37 | .pipe(inject(injectStyles, 38 | {ignorePath:"client", 39 | addRootSlash : false,} 40 | )) 41 | .pipe(gulp.dest('./public')); 42 | }); 43 | -------------------------------------------------------------------------------- /gulpfiles/server.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'), 2 | spawn = require('child_process').spawn, 3 | node; 4 | 5 | 6 | /** 7 | * $ gulp server 8 | * description: launch the server. If there's a server already running, kill it. 9 | */ 10 | gulp.task('server', function() { 11 | if (node) node.kill() 12 | node = spawn('node', ['./server/server.js'], {stdio: 'inherit'}) 13 | node.on('close', function (code) { 14 | if (code === 8) { 15 | gulp.log('Error detected, waiting for changes...'); 16 | } 17 | }); 18 | }) 19 | 20 | /** 21 | * $ gulp 22 | * description: start the development environment 23 | */ 24 | gulp.task('launch-server',['inject','server','watch-folder'], function() { 25 | /*gulp.run('server'); 26 | gulp.run('inject'); 27 | */ 28 | // gulp.watch(['./server/server.js', './server/app/**/*.js'], function() { 29 | // gulp.run('server') 30 | // }); 31 | gulp.watch(['./server/server.js', './server/app/**/*.js','./server/jsons/**/*.json'],['server']); 32 | 33 | }) 34 | 35 | // clean up if an error goes unhandled. 36 | process.on('exit', function() { 37 | if (node) node.kill() 38 | }) 39 | 40 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typali", 3 | "description": "typali nepali typing tutor", 4 | "version": "0.0.", 5 | "homepage": "typali.com", 6 | "private": true, 7 | "dependencies": { 8 | "angular": "~1.5.0", 9 | "angular-loader": "~1.5.0", 10 | "bootstrap": "^3.3.4", 11 | "jquery": "^3.1.0", 12 | "font-awesome": "^4.6.3", 13 | "angular-sanitize": "~1.5.0", 14 | "angular-ui-router": "^0.3.2", 15 | "angular-loading-bar": "^0.9.0", 16 | "angular-aria": "~1.5.0", 17 | "angular-animate": "~1.5.0", 18 | "angular-messages": "~1.5.0" 19 | }, 20 | "overrides": { 21 | "jquery": { 22 | "main": [] 23 | }, 24 | "angular": { 25 | "main": [] 26 | }, 27 | "angular-loader": { 28 | "main": [] 29 | }, 30 | "angular-sanitize": { 31 | "main": [] 32 | }, 33 | "angular-ui-router": { 34 | "main": [] 35 | }, 36 | "angular-aria": { 37 | "main": [] 38 | }, 39 | "angular-animate": { 40 | "main": [] 41 | }, 42 | "angular-messages": { 43 | "main": [] 44 | }, 45 | "bootstrap": { 46 | "main": [] 47 | }, 48 | "angular-bootstrap": { 49 | "main": [] 50 | }, 51 | "angular-loading-bar": { 52 | "main": [] 53 | }, 54 | "font-awesome": { 55 | "main": [] 56 | }, 57 | "highcharts": { 58 | "main": [] 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typali", 3 | "private": true, 4 | "version": "0.0.1", 5 | "description": "Nepali typing all", 6 | "dependencies": { 7 | "body-parser": "^1.15.2", 8 | "ejs": "^2.5.5", 9 | "express": "^4.10.2", 10 | "express-session": "^1.14.2", 11 | "gulp-rename": "^1.2.2", 12 | "morgan": "^1.7.0", 13 | "nodemon": "^1.11.0", 14 | "request": "^2.74.0", 15 | "wagner-core": "^0.2.0" 16 | }, 17 | "devDependencies": { 18 | "bower": "^1.7.7", 19 | "browser-sync": "^2.18.5", 20 | "connect-modrewrite": "^0.10.1", 21 | "gulp": "^3.9.1", 22 | "gulp-angular-filesort": "^1.1.1", 23 | "gulp-bytediff": "^1.0.0", 24 | "gulp-concat": "^2.6.1", 25 | "gulp-inject": "^4.1.0", 26 | "gulp-ng-annotate": "^2.0.0", 27 | "gulp-ng-config": "^1.4.0", 28 | "gulp-plumber": "^1.1.0", 29 | "gulp-print": "^2.0.1", 30 | "gulp-remove-files": "^0.0.3", 31 | "gulp-rename": "^1.2.2", 32 | "gulp-uglify": "^2.1.2", 33 | "gulp-uglifycss": "^1.0.8", 34 | "gulp-watch": "^4.3.9", 35 | "http-server": "^0.9.0", 36 | "jasmine-core": "^2.4.1", 37 | "karma": "^0.13.22", 38 | "karma-chrome-launcher": "^0.2.3", 39 | "karma-firefox-launcher": "^0.1.7", 40 | "karma-jasmine": "^0.3.8", 41 | "karma-junit-reporter": "^0.4.1", 42 | "protractor": "^3.2.2", 43 | "wiredep": "^4.0.0", 44 | "wrench": "^1.5.9" 45 | }, 46 | "scripts": { 47 | "prestart": "npm install", 48 | "start": "node server/server.js" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /client/views/practice/practise.css: -------------------------------------------------------------------------------- 1 | 2 | .showArea { 3 | min-height: 50px; 4 | color: #727070; 5 | font-size: 0.8em; 6 | } 7 | 8 | .writeArea { 9 | border: 1px solid #c9c9c9; 10 | padding: 5px 10px; 11 | background: #fff; 12 | margin: 20px 0; 13 | } 14 | 15 | .active { 16 | border: 1px solid #66ceff; 17 | box-shadow: 0px 0px 2px #66ceff; 18 | } 19 | 20 | .writeArea .word { 21 | display: inline-block; 22 | font-size: 18px; 23 | } 24 | 25 | .writeArea input { 26 | border: none; 27 | font-size: 18px; 28 | outline: none; 29 | color: #fff; 30 | } 31 | 32 | .writeArea input:focus { 33 | outline: none; 34 | } 35 | 36 | @keyframes blink { 37 | 50% { 38 | opacity: 0.0; 39 | } 40 | } 41 | @-webkit-keyframes blink { 42 | 50% { 43 | opacity: 0.0; 44 | } 45 | } 46 | .blink { 47 | display: inline-block; 48 | font-size: 14px; 49 | color : 878383; 50 | animation: blink 1s step-start 0s infinite; 51 | -webkit-animation: blink 1s step-start 0s infinite; 52 | } 53 | 54 | .writeArea.alert-danger { 55 | background: #F2DEDE; 56 | } 57 | 58 | .writeArea.alert-danger input { 59 | background: #F2DEDE; 60 | color: #F2DEDE; 61 | } 62 | 63 | .highlightWord span { 64 | /*background: #000;*/ 65 | font-weight: bold; 66 | border-bottom: 1px solid #000; 67 | } 68 | 69 | .practice .msgHolder { 70 | position: absolute; 71 | width: 100%; 72 | height: 100%; 73 | top: 0; 74 | left: 0; 75 | background: rgba(0,0,0,0.7); 76 | } 77 | 78 | .practice .messegebox { 79 | position: absolute; 80 | background: #fff; 81 | top: 100px; 82 | left: 30%; 83 | width: 400px; 84 | transform: translateX(-150px); 85 | padding: 10px; 86 | border: 1px solid #c9c9c9; 87 | box-shadow: 0 0 5px #f8f8f8; 88 | border-radius: 5px; 89 | } -------------------------------------------------------------------------------- /client/views/editor/editor.ctrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('typali') 4 | 5 | .config(['$stateProvider', function($stateProvider) { 6 | $stateProvider 7 | .state('app.editor', { 8 | url:'/editor', 9 | views : { 10 | 'container@': { 11 | templateUrl: 'views/editor/editor.tpl.html', 12 | controller: 'editorCtrl', 13 | controllerAs : 'vm' 14 | } 15 | } 16 | }) 17 | 18 | }]) 19 | 20 | .controller('editorCtrl', EditorCtrl); 21 | EditorCtrl.$inject = ['$scope']; 22 | function EditorCtrl ($scope) { 23 | var vm = this; 24 | 25 | var colorPalette = ['000000', 'FF9966', '6699FF', '99FF66', 'CC0000', '00CC00', '0000CC', '333333', '0066FF', 'FFFFFF']; 26 | var forePalette = $('.fore-palette'); 27 | var backPalette = $('.back-palette'); 28 | 29 | for (var i = 0; i < colorPalette.length; i++) { 30 | forePalette.append(''); 31 | backPalette.append(''); 32 | } 33 | 34 | $('.toolbar a').click(function(e) { 35 | var command = $(this).data('command'); 36 | if (command == 'h1' || command == 'h2' || command == 'p') { 37 | document.execCommand('formatBlock', false, command); 38 | } 39 | if (command == 'forecolor' || command == 'backcolor') { 40 | document.execCommand($(this).data('command'), false, $(this).data('value')); 41 | } 42 | if (command == 'createlink' || command == 'insertimage') { 43 | url = prompt('Enter the link here: ', 'http:\/\/'); 44 | document.execCommand($(this).data('command'), false, url); 45 | } else document.execCommand($(this).data('command'), false, null); 46 | }); 47 | 48 | }; -------------------------------------------------------------------------------- /client/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Declare app level module which depends on views, and components 4 | 5 | function run($rootScope, $location, authentication,$window) { 6 | $rootScope.$on('$routeChangeStart', function(event, nextRoute, currentRoute) { 7 | /*if (!authentication.isLoggedIn()) { 8 | $location.path('/login'); 9 | }*/ 10 | }); 11 | 12 | 13 | $rootScope.facebookAppId = '[]'; // set your facebook app id here 14 | // initialise google analytics 15 | /* $window.ga('create', '', 'auto'); 16 | 17 | // track pageview on state change 18 | $rootScope.$on('$stateChangeSuccess', function (event) { 19 | $window.ga('send', 'pageview', $location.path()); 20 | });*/ 21 | 22 | } 23 | 24 | 25 | var app = angular.module('typali', [ 26 | 'ui.router', 27 | 'ngSanitize', 28 | 'angular-loading-bar' 29 | ]) 30 | 31 | .config(['$locationProvider', '$stateProvider', '$urlRouterProvider', function($locationProvider, $stateProvider, $urlRouterProvider) { 32 | $locationProvider.hashPrefix('!'); 33 | 34 | $urlRouterProvider.otherwise('/404'); 35 | 36 | $stateProvider 37 | .state('app',{ 38 | url : '', 39 | views : { 40 | 'header@' : { 41 | controller : 'HeaderCtrl', 42 | templateUrl : 'components/common/header/header.tpl.html', 43 | controllerAs : "vm" 44 | }, 45 | 'footer@' : { 46 | controller : 'FooterCtrl', 47 | templateUrl : 'components/common/footer/footer.tpl.html', 48 | controllerAs : "vm" 49 | } 50 | } 51 | }) 52 | 53 | .state('app.404',{ 54 | url : '/404', 55 | views : { 56 | 'header@' : { 57 | templateUrl : 'components/common/header/header.tpl.html' 58 | } 59 | } 60 | }); 61 | 62 | $locationProvider.html5Mode(true); 63 | 64 | 65 | 66 | }]) 67 | .run(['$rootScope', '$location', 'authentication', '$window', run]); -------------------------------------------------------------------------------- /client/services/authentication.service.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | angular 4 | .module('typali') 5 | .service('authentication', authentication); 6 | 7 | authentication.$inject = ['$http', '$window']; 8 | function authentication ($http, $window) { 9 | 10 | var saveToken = function (token) { 11 | $window.localStorage['typali-token'] = token; 12 | }; 13 | 14 | var getToken = function () { 15 | return $window.localStorage['typali-token']; 16 | }; 17 | 18 | var isLoggedIn = function() { 19 | var token = getToken(); 20 | var payload; 21 | 22 | if(token){ 23 | payload = token.split('.')[1]; 24 | payload = $window.atob(payload); 25 | payload = JSON.parse(payload); 26 | 27 | return payload.exp > Date.now() / 1000; 28 | } else { 29 | return false; 30 | } 31 | }; 32 | 33 | var currentUser = function() { 34 | if(isLoggedIn()){ 35 | var token = getToken(); 36 | var payload = token.split('.')[1]; 37 | payload = $window.atob(payload); 38 | payload = JSON.parse(payload); 39 | return { 40 | email : payload.email, 41 | name : payload.name 42 | }; 43 | } 44 | }; 45 | 46 | var register = function(user) { 47 | return $http.post('/api/register', user).success(function(data){ 48 | saveToken(data.token); 49 | }); 50 | }; 51 | 52 | var login = function(user) { 53 | return $http.post('/api/login', user) 54 | .success(function(data) { 55 | console.log(data.token); 56 | saveToken(data.token); 57 | }); 58 | }; 59 | 60 | var logout = function() { 61 | $window.localStorage.removeItem('typali-token'); 62 | }; 63 | 64 | return { 65 | currentUser : currentUser, 66 | saveToken : saveToken, 67 | getToken : getToken, 68 | isLoggedIn : isLoggedIn, 69 | register : register, 70 | login : login, 71 | logout : logout 72 | }; 73 | } 74 | 75 | 76 | })(); 77 | -------------------------------------------------------------------------------- /server/server.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | app = express(); 3 | var http = require('http').Server(app); 4 | var morgan = require('morgan'); 5 | var bodyParser = require('body-parser'); 6 | // var session = require('express-session'); 7 | 8 | // var io = require('socket.io')(http); 9 | var request = require('request'); 10 | 11 | var config = require('./config.json'); 12 | 13 | var port = process.env.PORT || 8080; 14 | 15 | console.log("from serverjs"); 16 | app.use(morgan('dev')); 17 | 18 | 19 | 20 | 21 | // app.set('view engine', 'ejs'); 22 | // app.set('views', __dirname + '/views'); 23 | 24 | // app.use('/bower_components', express.static('./bower_components')); 25 | 26 | app.use(bodyParser.urlencoded({ extended: true, parameterLimit: 5000 })); // parse application/x-www-form-urlencoded 27 | app.use(bodyParser.json()); // parse application/json 28 | app.use(bodyParser.json({ type: 'application/vnd.api+json' })); // parse application/vnd.api+json as json 29 | 30 | // app.use(session({ secret: "mjt", resave: false, saveUninitialized: true })); 31 | 32 | app.use(function(req, res, next) { 33 | // req.io = io; 34 | res.header("Access-Control-Allow-Origin", "*"); 35 | res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); 36 | next(); 37 | }); 38 | 39 | 40 | require('./app/routes.js')(app); 41 | 42 | 43 | 44 | // app.listen(port); 45 | // console.log("App listening on port " + port); 46 | 47 | 48 | http.listen(port,function(){ 49 | console.log('listening on *:'+port); 50 | }); 51 | /* 52 | io.on('connection', function (socket) { 53 | console.log('client connect'); 54 | // socket.on('echo', function (data) { 55 | var url = config.localApiUri+"/marketlive" 56 | request.get({url : url},function (error, response, html) { 57 | if (!error) { 58 | var resArray = JSON.parse(html); 59 | console.log("from io first connection"); 60 | console.log(resArray); 61 | io.emit('update', resArray.data); 62 | } 63 | } 64 | ) 65 | 66 | // }) 67 | 68 | });*/ 69 | 70 | // io.emit('update', {msg : 'i reached everywhere'}); 71 | // }); -------------------------------------------------------------------------------- /client/auth/user-register/user-register.tpl.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 | Register 7 |
8 |
9 | 10 | 11 |
12 | 13 |

Username can contain any letters or numbers, without spaces

14 |
15 |
16 | 17 |
18 | 19 | 20 |
21 | 22 |

Please provide your E-mail

23 |
24 |
25 | 26 |
27 | 28 | 29 |
30 | 31 |

Password should be at least 4 characters

32 |
33 |
34 | 35 |
36 | 37 | 38 |
39 | 40 |

Please confirm password

41 |
42 |
43 | 44 |
45 | 46 |
47 | 48 |
49 |
50 |
51 |
52 |
53 |
-------------------------------------------------------------------------------- /dist/auth/user-register/user-register.tpl.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 | Register 7 |
8 |
9 | 10 | 11 |
12 | 13 |

Username can contain any letters or numbers, without spaces

14 |
15 |
16 | 17 |
18 | 19 | 20 |
21 | 22 |

Please provide your E-mail

23 |
24 |
25 | 26 |
27 | 28 | 29 |
30 | 31 |

Password should be at least 4 characters

32 |
33 |
34 | 35 |
36 | 37 | 38 |
39 | 40 |

Please confirm password

41 |
42 |
43 | 44 |
45 | 46 |
47 | 48 |
49 |
50 |
51 |
52 |
53 |
-------------------------------------------------------------------------------- /dist/views/editor/editor.tpl.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 | 7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | H1 28 | H2 29 | 30 | 31 | 32 | P 33 | 34 | 35 |
36 |
37 |

A WYSIWYG Editor.

38 |

Try making some changes here. Add your own text or maybe an image.

39 |
40 |
41 |
42 |
-------------------------------------------------------------------------------- /client/views/editor/editor.tpl.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | 6 | 7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | H1 28 | H2 29 | 30 | 31 | 32 | P 33 | 34 | 35 |
36 |
37 |

A WYSIWYG Editor.

38 |

Try making some changes here. Add your own text or maybe an image.

39 |
40 |
41 |
42 |
-------------------------------------------------------------------------------- /client/components/common/keyboard/keyboard.component.js: -------------------------------------------------------------------------------- 1 | angular.module('typali') 2 | .component('keyboard2', { 3 | templateUrl: 'components/common/keyboard/keyboard.tpl.html', 4 | controller: keyboardCtrl, 5 | bindings: { 6 | keyboard: '<', 7 | word: '<', 8 | letter: '<', 9 | shift: '<' 10 | } 11 | }); 12 | 13 | 14 | keyboardCtrl.$inject = ['$document', '$scope'] 15 | function keyboardCtrl($document, $scope) { 16 | var ctrl = this; 17 | 18 | var keyboard = ctrl.keyboard; 19 | 20 | var cls; 21 | 22 | console.log("letter = ", ctrl.letter); 23 | 24 | // highlightLetter(ctrl.letter) 25 | 26 | var allKeys = [], 27 | engData_all, 28 | codeData_all, 29 | npData_all, 30 | npShiftData_all; 31 | 32 | // function makeKeyboard() { 33 | for (var key in keyboard) { 34 | for (var i = 0; i < keyboard[key].length; i++) { 35 | allKeys.push(keyboard[key][i]) 36 | }; 37 | } 38 | 39 | 40 | 41 | 42 | engData_all = allKeys.map(function (item) { return item.en; }); 43 | codeData_all = allKeys.map(function (item) { return item.code; }); 44 | npData_all = allKeys.map(function (item) { return item.np; }); 45 | npShiftData_all = allKeys.map(function (item) { return item.npShift; }); 46 | // } 47 | 48 | this.$onInit = function () { 49 | console.log("changing"); 50 | // makeKeyboard(); 51 | highlightLetter(ctrl.letter); 52 | } 53 | 54 | console.log("in components", ctrl.word, ctrl.letter); 55 | this.$onChanges = function (changes) { 56 | // console.log("changed in components",changes.word,changes.letter.currentValue); 57 | console.log("changes", changes); 58 | if (typeof changes.letter != 'undefined') { 59 | highlightLetter(changes.letter.currentValue); 60 | } /* else { 61 | console.log("here"); 62 | // makeKeyboard(); 63 | highlightLetter(changes.letter); 64 | } */ 65 | } 66 | 67 | 68 | function highlightLetter(letter) { 69 | console.log("letter again = ", ctrl.letter); 70 | $(".highlightLetter").removeClass("highlightLetter"); 71 | if (letter == " ") { 72 | cls = "spacebar"; 73 | // return; 74 | } else { 75 | 76 | if (npData_all.indexOf(letter) > -1) { 77 | cls = "c" + codeData_all[npData_all.indexOf(letter)]; 78 | console.log(npData_all,npData_all.indexOf(letter)); 79 | 80 | } else { 81 | cls = "c" + codeData_all[npShiftData_all.indexOf(letter)]; 82 | $(".shiftKey").addClass("highlightLetter"); 83 | } 84 | } 85 | 86 | console.log("letter again = ", ctrl.letter, cls); 87 | $document.find("." + cls).addClass("highlightLetter"); 88 | } 89 | 90 | // highlightLetter(ctrl.letter) 91 | } -------------------------------------------------------------------------------- /client/views/practice/practice.tpl.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 |
8 | 9 | {{value}}  10 | 11 | 12 |
13 | 14 |
15 | {{vm.sentence}} 16 |
17 | 18 | 19 |
20 |
21 | {{vm.word}} 22 |
23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
32 | 33 |
34 | 35 | 36 |
37 | 38 | 39 | 40 |
41 |
42 |
43 |
44 | Time : {{vm.time}} 45 |
46 |
47 | Speed : {{vm.speed}} WPM 48 |
49 |
50 | {{vm.timeTaken}} millisecond 51 |
52 | 53 |
54 |
55 |
56 |
57 |
Congratulation! You completed
58 |
59 | This text is brought from {{vm.art.title}} by {{vm.art.author}} 60 |
61 |
62 | full content is Here 63 |
64 |
65 |
66 | Home 67 | New 68 |
69 |
70 |
71 |
72 | -------------------------------------------------------------------------------- /dist/views/practice/practice.tpl.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 |
8 | 9 | {{value}}  10 | 11 | 12 |
13 | 14 |
15 | {{vm.sentence}} 16 |
17 | 18 | 19 |
20 |
21 | {{vm.word}} 22 |
23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
32 | 33 |
34 | 35 | 36 |
37 | 38 | 39 | 40 |
41 |
42 |
43 |
44 | Time : {{vm.time}} 45 |
46 |
47 | Speed : {{vm.speed}} WPM 48 |
49 |
50 | {{vm.timeTaken}} millisecond 51 |
52 | 53 |
54 |
55 |
56 |
57 |
Congratulation! You completed
58 |
59 | This text is brought from {{vm.art.title}} by {{vm.art.author}} 60 |
61 |
62 | full content is Here 63 |
64 |
65 |
66 | Home 67 | New 68 |
69 |
70 |
71 |
72 | -------------------------------------------------------------------------------- /dist/views/practice/practise.tpl.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 |
8 | 9 | {{value}}  10 | 11 | 12 |
13 | 14 |
15 | {{vm.sentence}} 16 |
17 | 18 | 19 |
20 |
21 | {{vm.word}} 22 |
23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
32 | 33 |
34 | 35 | 36 |
37 | 38 | 39 | 40 |
41 |
42 |
43 |
44 | Time : {{vm.time}} 45 |
46 |
47 | Speed : {{vm.speed}} WPM 48 |
49 |
50 | {{vm.timeTaken}} millisecond 51 |
52 | 53 |
54 |
55 |
56 |
57 |
Congratulation! You completed
58 |
59 | This text is brought from {{vm.art.title}} by {{vm.art.author}} 60 |
61 |
62 | full content is Here 63 |
64 |
65 |
66 | Home 67 | New 68 |
69 |
70 |
71 |
72 | -------------------------------------------------------------------------------- /client/views/editor/editor.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | .editor a { 4 | cursor: pointer; 5 | } 6 | 7 | .editor #editor { 8 | box-shadow: 0 0 2px #CCC; 9 | min-height: 150px; 10 | overflow: auto; 11 | padding: 1em; 12 | margin-top: 20px; 13 | resize: vertical; 14 | outline: none; 15 | } 16 | 17 | .editor .toolbar { 18 | text-align: center; 19 | } 20 | 21 | .editor .toolbar a, 22 | .editor .fore-wrapper, 23 | .editor .back-wrapper { 24 | border: 1px solid #AAA; 25 | background: #FFF; 26 | font-family: 'Candal'; 27 | border-radius: 1px; 28 | color: black; 29 | padding: 5px; 30 | width: 1.5em; 31 | margin: -2px; 32 | margin-top: 10px; 33 | display: inline-block; 34 | text-decoration: none; 35 | box-shadow: 0px 1px 0px #CCC; 36 | } 37 | 38 | .editor .toolbar a:hover, 39 | .editor .fore-wrapper:hover, 40 | .editor .back-wrapper:hover { 41 | background: #f2f2f2; 42 | border-color: #8c8c8c; 43 | } 44 | 45 | .editor a[data-command='redo'], 46 | .editor a[data-command='strikeThrough'], 47 | .editor a[data-command='justifyFull'], 48 | .editor a[data-command='insertOrderedList'], 49 | .editor a[data-command='outdent'], 50 | .editor a[data-command='p'], 51 | .editor a[data-command='superscript'] { 52 | margin-right: 5px; 53 | border-radius: 0 3px 3px 0; 54 | } 55 | 56 | .editor a[data-command='undo'], 57 | .editor .fore-wrapper, 58 | .editor a[data-command='justifyLeft'], 59 | .editor a[data-command='insertUnorderedList'], 60 | .editor a[data-command='indent'], 61 | .editor a[data-command='h1'], 62 | .editor a[data-command='subscript'] { 63 | border-radius: 3px 0 0 3px; 64 | } 65 | 66 | .editor a.palette-item { 67 | height: 1em; 68 | border-radius: 3px; 69 | margin: 2px; 70 | width: 1em; 71 | border: 1px solid #CCC; 72 | } 73 | 74 | .editor a.palette-item:hover { 75 | border: 1px solid #CCC; 76 | box-shadow: 0 0 3px #333; 77 | } 78 | 79 | .editor .fore-palette, 80 | .editor .back-palette { 81 | display: none; 82 | } 83 | 84 | .editor .fore-wrapper, 85 | .editor .back-wrapper { 86 | display: inline-block; 87 | cursor: pointer; 88 | } 89 | 90 | .editor .fore-wrapper:hover .fore-palette, 91 | .editor .back-wrapper:hover .back-palette { 92 | display: block; 93 | float: left; 94 | position: absolute; 95 | padding: 3px; 96 | width: 160px; 97 | background: #FFF; 98 | border: 1px solid #DDD; 99 | box-shadow: 0 0 5px #CCC; 100 | height: 70px; 101 | } 102 | 103 | .editor .fore-palette a, 104 | .editor .back-palette a { 105 | background: #FFF; 106 | margin-bottom: 2px; 107 | } 108 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Typali: Nepali typing tutor 2 | Type+Nepali = typali :D 3 | 4 | # why typali (not typesala) 5 | typesala.com typeshala.com domains where too high ;) 6 | 7 | 8 | # Demo 9 | [Demo](https://emp3ror.github.io/typali/). 10 | 11 | ## sample text 12 | * this string is used from 13 | * कथा : दोषी चश्मा 14 | 15 | # Gross speed 16 | WPM (word per minute) 17 |
18 | Taking a [sample text](https://emp3ror.github.io/typesala/speed/sample-text1.md) seems average letters per word on a paragraph (including space) is 6 19 |
20 | So, our formula for gross speed is : 21 |
22 | Gross WPM = (All typed Entries/6)/Time 23 | 24 | 25 | # TODO 26 | * calculate speed 27 | * Ending Message 28 | * Nepali paragraphs Array 29 | * Landing page : (choose easy to hard paragraphs) 30 | 31 | 32 | ## How to use in local 33 | 34 | ### if NVM 35 | ```bash 36 | $ source /usr/share/nvm/init-nvm.sh 37 | $ nvm use v10.18.0 38 | ``` 39 | 40 | 41 | ### Setup 42 | 43 | Install node, npm according to you OS 44 | on ARCH 45 | ```bash 46 | $ sudo pacman -S nodejs 47 | ``` 48 | 49 | ### Install bower,gulp: 50 | 51 | ```bash 52 | $ npm install -g gulp 53 | $ npm install -g bower 54 | $ npm install 55 | $ bower install 56 | ``` 57 | 58 | and run gulp script like this: 59 | 60 | ```bash 61 | $ gulp launch-server 62 | ``` 63 | 64 | for production 65 | 66 | ```bash 67 | $ gulp prod 68 | ``` 69 | 70 | # /dist 71 | dist folder is created when 72 | ```bash 73 | $ gulp prod 74 | ``` 75 | 76 | ### for gh-pages 77 | rename index.html to 404.html (hack for github redirect) 78 | ``` 79 | $ git subtree push --prefix dist origin gh-pages 80 | or force push 81 | $ git push origin `git subtree split --prefix dist master`:gh-pages --force 82 | ``` 83 | 84 | 85 | ## License 86 | 87 | * [Apache Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html) 88 | 89 | ## Acknowledgements 90 | 91 | My sincere respect to all the open source community, all those people who manages their time to help on finding solution to needy, blog their experiences and write tutorials. 92 | 93 | ## Contributing 94 | 95 | Please fork this repository and contribute back using 96 | [pull requests](https://github.com/emp3ror/typesala/pulls). 97 | 98 | Any contributions, large or small, major features, bug fixes, additional 99 | language translations, unit/integration tests are welcomed and appreciated 100 | but will be thoroughly reviewed and discussed. 101 | 102 | 103 | ## Reference for speed calculation 104 | https://www.speedtypingonline.com/typing-equations 105 | -------------------------------------------------------------------------------- /gulpfiles/prod.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'), 2 | wiredep = require('wiredep').stream, 3 | inject = require('gulp-inject'), 4 | angularFilesort = require('gulp-angular-filesort'), 5 | watch = require('gulp-watch'); 6 | var print = require('gulp-print'); 7 | var removeFiles = require('gulp-remove-files'); 8 | 9 | 10 | gulp.task('prod', ['uglify', 'uglifycss','move-assets','prodtpl'], function () { 11 | 12 | // remove app.js 13 | gulp.src('./dist/app.js') 14 | .pipe(removeFiles()); 15 | 16 | // inject app.min.js and app.css 17 | var target = gulp.src('./client/index.html'); 18 | 19 | var sources = gulp.src(['./dist/app.min.js'],{ 20 | relative: true}) 21 | .pipe(angularFilesort()) 22 | .pipe(print()); 23 | 24 | var injectStyles = gulp.src(['./dist/app.css'], 25 | { read: false, 26 | relative: true }) 27 | .pipe(print()); 28 | 29 | var options = { 30 | directory: './bower_components/', 31 | ignorePath: '../', 32 | devDependencies: true, 33 | relative: false 34 | }; 35 | 36 | return target 37 | .pipe(wiredep(options)) 38 | .pipe(inject(sources, 39 | {ignorePath:"dist", 40 | addRootSlash : false,} 41 | )) 42 | .pipe(inject(injectStyles, 43 | {ignorePath:"dist", 44 | addRootSlash : false,} 45 | )) 46 | .pipe(gulp.dest('./dist')); 47 | }); 48 | 49 | gulp.task('move-assets',function () { 50 | //temporary solutions to mkdir for existing directory problem 51 | gulp.src('./dist/*') 52 | .pipe(removeFiles()); 53 | 54 | gulp.src(['./client/assets/**/*']) 55 | .pipe(gulp.dest('./dist/assets/')); 56 | }) 57 | 58 | 59 | gulp.task('test-minify', ['uglify', 'uglifycss'], function () { 60 | 61 | 62 | // inject app.min.js and app.css 63 | var target = gulp.src('./client/index.html'); 64 | 65 | var sources = gulp.src(['./dist/app.js'],{ 66 | relative: true}) 67 | .pipe(angularFilesort()) 68 | .pipe(print()); 69 | 70 | var injectStyles = gulp.src(['./dist/app.css'], 71 | { read: false, 72 | relative: true }) 73 | .pipe(print()); 74 | 75 | var options = { 76 | directory: './bower_components/', 77 | ignorePath: '../', 78 | devDependencies: true, 79 | relative: false 80 | }; 81 | 82 | return target 83 | .pipe(wiredep(options)) 84 | .pipe(inject(sources, 85 | {ignorePath:"dist", 86 | addRootSlash : false,} 87 | )) 88 | .pipe(inject(injectStyles, 89 | {ignorePath:"dist", 90 | addRootSlash : false,} 91 | )) 92 | .pipe(gulp.dest('./dist')); 93 | }); 94 | 95 | -------------------------------------------------------------------------------- /data/type-content/strings.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "text" : "सानो छ खेत सानो छ बारी सानै छ जहान, नगरी काम पुग्दैन खान साझ र बिहान, बिहानपख झुल्किनछ घाम देउराली पाखामा, आसरे गीत घन्किनछ अनि सुरिलो भाकामा", 4 | "title" : "किसानको रहर", 5 | "author" : "लक्ष्मी प्रसाद देवकोटा ", 6 | "desc" : "", 7 | "url_readmore" : "", 8 | "img_url" : "" 9 | }, 10 | { 11 | "text" : "मेरो गाउँ ज्यामिरे, जमुनीको छोरो म, काले भन्छन् मलाई, तर मान्छे गोरो म। सबै पढ्न गएछन्, जान्ने सुन्ने भएछन्, म त अझै गोठमा, छैन हाँसो ओठमा। किन किन मन यो, दुखे दुखे जस्तो छ,", 12 | "title" : "जमुनीको छोरो", 13 | "author" : "रामबाबु सुवेदी,स्वर्णिम स्कूलका विद्यार्थीहरू,रामेश श्रेष्ठ", 14 | "desc" : "", 15 | "url_readmore" : "", 16 | "img_url" : "" 17 | }, 18 | { 19 | "text" : "हुँदैन बिहान मिर्मिरेमा तारा झरेर नगए, बन्दैन मुलुक दुई-चार सपूत मरेर नगए", 20 | "title" : "शहीदहरुको सम्झनामा", 21 | "author" : "भुपी शेरचन", 22 | "desc" : "", 23 | "url_readmore" : "", 24 | "img_url" : "" 25 | }, 26 | { 27 | "text" : "भर जन्म घासँ तिर मन दिई धन कमायो, नाम् केही रहोस् पछी भनि कुवा खनायो, घाँशी दरिद्र घरको तर बुद्दी कस्तो, म भानुभक्त धनी भैकन आज एस्तो", 28 | "title" : "घासी", 29 | "author" : "आदिकवि भानुभक्त", 30 | "desc" : "", 31 | "url_readmore" : "", 32 | "img_url" : "" 33 | }, 34 | { 35 | "text" : "लेकका हामी केटाकेटी, कुहिरो भित्र इस्कुल छ, चौरीलाई चराउँदै दिन बित्छ, पढ्नु र लेख्नु मुस्किल छ, हिउँमा कोरेको अक्षर त, एकछिनमा बिलाई जाइजान्छ, दिनभरि हेर्नु छ गाईबस्तु, नहेरे भालुले खाइजान्छ", 36 | "title" : "लेकका हामी केटाकटी", 37 | "author" : "", 38 | "desc" : "", 39 | "url_readmore" : "", 40 | "img_url" : "" 41 | }, 42 | { 43 | "text" : "केशवराजको चश्मा दोषी थियो। अलिक टाढाको मानिस तिनी चिन्न सक्तैनथे। किताब पढ्दा तिनको आँखालाई निकै बल पर्थ्यो। चश्माको पावर तिनका आँखाका लागि कम भएछ। धेरै दिनदेखि अर्को चश्मा लिनें विचारमा थिए, तर अझै अनुकूल परेको थिएन।", 44 | "title" : "दोषी चस्मा", 45 | "author" : "विश्वेश्वर प्रसाद कोइरा", 46 | "desc" : "", 47 | "url_readmore" : "", 48 | "img_url" : "" 49 | }, 50 | { 51 | "text" : "भोलिवादको श्रीगणेश कुन बेला, कसको पालादेखि कसले सुरु गर्‍यो, त्यो किट्न सकिन्न, तर हेरिल्याउँदा नेपाली समाजमा भानुभक्तभन्दा अघिदेखि नै यसले खुट्टो घुमाएको बुझिन्छ।", 52 | "title" : "जय भोलि !", 53 | "author" : "भैरव अर्याल", 54 | "desc" : "", 55 | "url_readmore" : "", 56 | "img_url" : "" 57 | }, 58 | { 59 | "text" : "हिजोसम्म रोईरोई बाँचिरहेका थिए। आज तिनै हाँसीहाँसी मर्न तयार छन्। हिजोसम्म जसको बोलीमा केही थिएन; मनको प्रतिध्वनिसम्म थिएन, मानिसले बोलेजस्तै थिएन; केवल शब्द थियो, अर्थ थिएन; आज तिनैको बोलीमा प्राण छ, व्यथा, उन्माद, आह्वान छ, आकर्षण छ, आज तिनैको मौनता पनि बोल्छ।", 60 | "title" : "Pariwartan", 61 | "author" : "Gopal Prasad Rimal", 62 | "desc" : "", 63 | "url_readmore" : "", 64 | "img_url" : "" 65 | }, 66 | { 67 | "text" : "नटिप्नु हेर कोपिला, नचुँड्नु पाप लाग्दछ, नच्यात्नु फुल नानी हो, दया र धर्म भाग्दछ", 68 | "title" : "पाप लाग्छ", 69 | "author" : "लक्ष्मीप्रसाद देवकोटा", 70 | "desc" : "", 71 | "url_readmore" : "", 72 | "img_url" : "" 73 | } 74 | 75 | ] 76 | -------------------------------------------------------------------------------- /client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | नेपाली typing 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 68 | 69 | 70 | 71 | 72 | 73 | 76 | 77 |
78 |
79 | 80 |
81 |
82 |
83 | 84 | 85 |
86 |
87 |
88 | 89 |
90 | 93 |
94 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /dist/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | नेपाली typing 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 68 | 69 | 70 | 71 | 72 | 73 | 76 | 77 |
78 |
79 | 80 |
81 |
82 |
83 | 84 | 85 |
86 |
87 |
88 | 89 |
90 | 93 |
94 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | नेपाली typing 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 68 | 69 | 70 | 71 | 72 | 73 | 76 | 77 |
78 |
79 | 80 |
81 |
82 |
83 | 84 | 85 |
86 |
87 |
88 | 89 |
90 | 93 |
94 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /client/components/common/keyboard/keyboard.tpl.html: -------------------------------------------------------------------------------- 1 |
2 | 18 | 27 | 38 | 58 | 80 | 97 |
98 | -------------------------------------------------------------------------------- /dist/components/common/keyboard/keyboard.tpl.html: -------------------------------------------------------------------------------- 1 |
2 | 18 | 27 | 38 | 58 | 80 | 97 |
98 | -------------------------------------------------------------------------------- /dist/app.css: -------------------------------------------------------------------------------- 1 | html,body{background:#fff;font-family:ProximaNova,-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-size:16px;color:#231f20}.mainView{min-height:300px;margin-bottom:20px} 2 | .editor a{cursor:pointer}.editor #editor{box-shadow:0 0 2px #CCC;min-height:150px;overflow:auto;padding:1em;margin-top:20px;resize:vertical;outline:0}.editor .toolbar{text-align:center}.editor .toolbar a,.editor .fore-wrapper,.editor .back-wrapper{border:1px solid #AAA;background:#FFF;font-family:'Candal';border-radius:1px;color:black;padding:5px;width:1.5em;margin:-2px;margin-top:10px;display:inline-block;text-decoration:none;box-shadow:0 1px 0 #CCC}.editor .toolbar a:hover,.editor .fore-wrapper:hover,.editor .back-wrapper:hover{background:#f2f2f2;border-color:#8c8c8c}.editor a[data-command='redo'],.editor a[data-command='strikeThrough'],.editor a[data-command='justifyFull'],.editor a[data-command='insertOrderedList'],.editor a[data-command='outdent'],.editor a[data-command='p'],.editor a[data-command='superscript']{margin-right:5px;border-radius:0 3px 3px 0}.editor a[data-command='undo'],.editor .fore-wrapper,.editor a[data-command='justifyLeft'],.editor a[data-command='insertUnorderedList'],.editor a[data-command='indent'],.editor a[data-command='h1'],.editor a[data-command='subscript']{border-radius:3px 0 0 3px}.editor a.palette-item{height:1em;border-radius:3px;margin:2px;width:1em;border:1px solid #CCC}.editor a.palette-item:hover{border:1px solid #CCC;box-shadow:0 0 3px #333}.editor .fore-palette,.editor .back-palette{display:none}.editor .fore-wrapper,.editor .back-wrapper{display:inline-block;cursor:pointer}.editor .fore-wrapper:hover .fore-palette,.editor .back-wrapper:hover .back-palette{display:block;float:left;position:absolute;padding:3px;width:160px;background:#FFF;border:1px solid #DDD;box-shadow:0 0 5px #CCC;height:70px}.editor .fore-palette a,.editor .back-palette a{background:#FFF;margin-bottom:2px} 3 | .showArea{min-height:50px;color:#727070;font-size:.8em}.writeArea{border:1px solid #c9c9c9;padding:5px 10px;background:#fff;margin:20px 0}.active{border:1px solid #66ceff;box-shadow:0 0 2px #66ceff}.writeArea .word{display:inline-block;font-size:18px}.writeArea input{border:0;font-size:18px;outline:0;color:#fff}.writeArea input:focus{outline:0}@keyframes blink{50%{opacity:.0}}@-webkit-keyframes blink{50%{opacity:.0}}.blink{display:inline-block;font-size:14px;color:878383;animation:blink 1s step-start 0s infinite;-webkit-animation:blink 1s step-start 0s infinite}.writeArea.alert-danger{background:#f2dede}.writeArea.alert-danger input{background:#f2dede;color:#f2dede}.highlightWord span{font-weight:bold;border-bottom:1px solid #000}.practice .msgHolder{position:absolute;width:100%;height:100%;top:0;left:0;background:rgba(0,0,0,0.7)}.practice .messegebox{position:absolute;background:#fff;top:100px;left:30%;width:400px;transform:translateX(-150px);padding:10px;border:1px solid #c9c9c9;box-shadow:0 0 5px #f8f8f8;border-radius:5px} 4 | .footer li a{margin:10px} 5 | 6 | .highlight.key{background:#daf1fe !important}.highlightLetter.key{background:#6cedc4 !important}#keyboard{margin-left:-15px;left:0;width:784px;background:#f3f3f3}ul{list-style-type:none;width:784px;margin:0 auto}li{float:left}.key{display:block;color:#aaa;font:bold 9pt arial;text-decoration:none;text-align:center;width:44px;height:41px;margin:5px;background:#eff0f2;-moz-border-radius:4px;border-radius:4px;border-top:1px solid #f5f5f5;-webkit-box-shadow:inset 0 0 25px #e8e8e8,0 1px 0 #c3c3c3,0 2px 0 #c9c9c9,0 2px 3px #333;-moz-box-shadow:inset 0 0 25px #e8e8e8,0 1px 0 #c3c3c3,0 2px 0 #c9c9c9,0 2px 3px #333;box-shadow:inset 0 0 25px #e8e8e8,0 1px 0 #c3c3c3,0 2px 0 #c9c9c9,0 2px 3px #333;text-shadow:0 1px 0 #f5f5f5}.key:active,.keydown{color:#888;background:#ebeced;margin:7px 5px 3px;-webkit-box-shadow:inset 0 0 25px #ddd,0 0 3px #333;-moz-box-shadow:inset 0 0 25px #ddd,0 0 3px #333;box-shadow:inset 0 0 25px #ddd,0 0 3px #333;border-top:1px solid #eee}.fn span{display:block;margin:14px 5px 0 0;text-align:right;font:bold 6pt arial;text-transform:uppercase}#esc{margin:6px 15px 0 0;font-size:7.5pt;text-transform:lowercase}#numbers li a span{display:block}#numbers li a b{margin:3px 0 3px;display:block}#numbers li .alt b{display:block;margin:0 0 3px}#numbers li #backspace span{text-align:right;margin:23px 10px 0 0;font-size:7.5pt;text-transform:lowercase}#qwerty li a,#asdfg li a,#zxcvb li a{display:block;position:relative;color:#4b4949}#qwerty li a span,#asdfg li a span,#zxcvb li a span{display:block;text-transform:uppercase}#qwerty li a span.en,#asdfg li a span.en,#zxcvb li a span.en{position:absolute;display:inline-block;color:#b86c0d;top:25px;left:5px}#qwerty li a span.en-shift,#asdfg li a span.en-shift,#zxcvb li a span.en-shift{position:absolute;display:inline-block;color:#b86c0d;top:5px;left:5px}#qwerty li a span.np,#asdfg li a span.np,#zxcvb li a span.np{position:absolute;display:inline-block;color:#000;top:20px;left:25px}#qwerty li #tab span{text-align:left;margin:23px 0 0 10px;font-size:7.5pt;text-transform:lowercase}#qwerty li .alt b{display:block;margin:3px 0 0}#qwerty li .alt span{margin:2px 0 0}#asdfg li .alt span{margin:0;text-transform:lowercase}#asdfg li .alt b{display:block;margin:3px 0 0}#asdfg li #caps b{display:block;background:#999;width:4px;height:4px;border-radius:10px;margin:9px 0 0 10px;-webkit-box-shadow:inset 0 1px 0 #666;-moz-box-shadow:inset 0 1px 0 #666;box-shadow:inset 0 1px 0 #666}#asdfg li #caps span{text-align:left;margin:10px 0 0 10px;font-size:7.5pt}#asdfg li #enter span{text-align:right;margin:23px 10px 0 0;font-size:7.5pt}#zxcvb li .shiftleft span{text-align:left;margin:23px 0 0 10px;font-size:7.5pt;text-transform:lowercase}#zxcvb li .shiftright span{text-align:right;margin:23px 10px 0 0;font-size:7.5pt;text-transform:lowercase}#zxcvb li .alt b{display:block;margin:4px 0 0}#zxcvb li .alt span{margin:0}#bottomrow li #fn span,#bottomrow li #Ctrl span,#bottomrow li #mjtleft span,#bottomrow li #AltKeyleft span{display:block;text-align:left;margin:31px 0 0 8px;font-size:7.5pt;text-transform:lowercase}#bottomrow li #CtrlKeyright span,#bottomrow li #AltKeyright span{display:block;text-align:right;margin:31px 8px 0 0;font-size:7.5pt;text-transform:lowercase}#bottomrow ol li #left span,#bottomrow ol li #right span,#bottomrow ol li #up span,#bottomrow ol li #down span{display:block;margin:9px 0 0}.fn{height:26px;width:46px}#backspace{width:72px}#tab{width:72px}#caps{width:85px}#enter{width:85px}.shiftleft,.shiftright{width:112px}#fn,#Ctrl,.mjt,#CtrlKeyright,.AltKey,#spacebar{height:49px}.ctrl{width:75px}.mjt{width:46px}.AltKey{width:67px}#spacebar{width:226px}#left img,#up img,#down img,#right img{border:0}ul ol{list-style-type:none}#down{height:23px}#up,#left,#right{height:24px}#left,#right{margin:30px 5px 5px}#left:active,#right:active{margin:32px 5px 3px}#up{margin:5px 5px 1px;border-bottom-right-radius:0;border-bottom-left-radius:0}#up:active{margin:8px 5px -2px}#down{margin:0 5px 5px;border-top-left-radius:0;border-top-right-radius:0}#down:active{margin:3px 5px 4px}#main{width:700px;padding:20px 50px;margin:0 auto 50px;background:#fff;border-radius:5px;-webkit-box-shadow:0 1px 2px #aaa}h1{color:#888;text-align:center;font:bold 25pt/25pt arial;margin:30px 0 60px}h2{color:#666;font:13pt/0 arial}p{color:#999;font:9pt/17pt arial;margin:0 0 50px}small{font:italic 8pt/12pt arial;color:#aaa;padding:0 130px 0 0;display:block}cite{display:block;padding:0 0 30px;margin:0 auto;text-align:center;color:#999;font:italic bold 8pt arial}ul,ol{padding:0;margin:0}.cf:before,.cf:after{content:"";display:table}.cf:after{clear:both}.cf{zoom:1} -------------------------------------------------------------------------------- /client/components/common/keyboard/keyboard.css: -------------------------------------------------------------------------------- 1 | .highlight { 2 | 3 | } 4 | 5 | .highlight.key { 6 | background: #daf1fe !important; 7 | } 8 | 9 | .highlightLetter.key { 10 | background: #6cedc4 !important; 11 | } 12 | 13 | /* 14 | First Keyboad layout design forked from 15 | http://cssdeck.com/labs/apple-keyboard-via-css3 16 | redefined by mjt 17 | */ 18 | #keyboard { 19 | /*margin: 15px auto 0;*/ 20 | margin-left: -15px; 21 | left: 0; 22 | width: 784px; 23 | /*padding: 10px 0 0 10px;*/ 24 | background: #f3f3f3; 25 | /*left: 50%;*/ 26 | /*transform:translateX(250px);*/ 27 | /*display: none;*/ 28 | } 29 | 30 | ul {list-style-type: none; width: 784px; margin: 0 auto;} 31 | li {float: left;} 32 | 33 | 34 | .key{ 35 | display: block; 36 | color: #aaa; 37 | font: bold 9pt arial; 38 | text-decoration: none; 39 | text-align: center; 40 | width: 44px; 41 | height: 41px; 42 | margin: 5px; 43 | background: #eff0f2; 44 | -moz-border-radius: 4px; 45 | border-radius: 4px; 46 | border-top: 1px solid #f5f5f5; 47 | -webkit-box-shadow: 48 | inset 0 0 25px #e8e8e8, 49 | 0 1px 0 #c3c3c3, 50 | 0 2px 0 #c9c9c9, 51 | 0 2px 3px #333; 52 | -moz-box-shadow: 53 | inset 0 0 25px #e8e8e8, 54 | 0 1px 0 #c3c3c3, 55 | 0 2px 0 #c9c9c9, 56 | 0 2px 3px #333; 57 | box-shadow: 58 | inset 0 0 25px #e8e8e8, 59 | 0 1px 0 #c3c3c3, 60 | 0 2px 0 #c9c9c9, 61 | 0 2px 3px #333; 62 | text-shadow: 0px 1px 0px #f5f5f5;} 63 | 64 | .key:active, .keydown { 65 | color: #888; 66 | background: #ebeced; 67 | margin: 7px 5px 3px; 68 | -webkit-box-shadow: 69 | inset 0 0 25px #ddd, 70 | 0 0 3px #333; 71 | -moz-box-shadow: 72 | inset 0 0 25px #ddd, 73 | 0 0 3px #333; 74 | box-shadow: 75 | inset 0 0 25px #ddd, 76 | 0 0 3px #333; 77 | border-top: 1px solid #eee;} 78 | 79 | .fn span { 80 | display: block; 81 | margin: 14px 5px 0 0; 82 | text-align: right; 83 | font: bold 6pt arial; 84 | text-transform: uppercase;} 85 | #esc { 86 | margin: 6px 15px 0 0; 87 | font-size: 7.5pt; 88 | text-transform: lowercase;} 89 | 90 | 91 | #numbers li a span { 92 | display: block;} 93 | 94 | #numbers li a b { 95 | margin: 3px 0 3px; 96 | display: block;} 97 | 98 | #numbers li .alt b {display: block;margin: 0 0 3px;} 99 | 100 | #numbers li #backspace span { 101 | text-align: right; 102 | margin: 23px 10px 0 0; 103 | font-size: 7.5pt; 104 | text-transform: lowercase;} 105 | 106 | #qwerty li a, 107 | #asdfg li a, 108 | #zxcvb li a { 109 | display: block; 110 | position: relative; 111 | color: #4b4949; 112 | } 113 | 114 | #qwerty li a span, 115 | #asdfg li a span, 116 | #zxcvb li a span { 117 | display: block; 118 | /*margin: 13px 0 0;*/ 119 | text-transform: uppercase;} 120 | 121 | #qwerty li a span.en, 122 | #asdfg li a span.en, 123 | #zxcvb li a span.en { 124 | position: absolute; 125 | display: inline-block; 126 | color: #b86c0d; 127 | top: 25px ; 128 | left: 5px; 129 | } 130 | 131 | #qwerty li a span.en-shift, 132 | #asdfg li a span.en-shift, 133 | #zxcvb li a span.en-shift { 134 | position: absolute; 135 | display: inline-block; 136 | color: #b86c0d; 137 | top: 5px ; 138 | left: 5px; 139 | } 140 | 141 | #qwerty li a span.np, 142 | #asdfg li a span.np, 143 | #zxcvb li a span.np { 144 | position: absolute; 145 | display: inline-block; 146 | color: #000; 147 | top: 20px ; 148 | left: 25px; 149 | /*font-weight: bold;*/ 150 | } 151 | 152 | #qwerty li #tab span { 153 | text-align: left; 154 | margin: 23px 0 0 10px; 155 | font-size: 7.5pt; 156 | text-transform: lowercase;} 157 | 158 | #qwerty li .alt b {display: block; margin: 3px 0 0;} 159 | #qwerty li .alt span {margin: 2px 0 0;} 160 | 161 | 162 | #asdfg li .alt span {margin: 0; text-transform: lowercase;} 163 | #asdfg li .alt b {display: block; margin: 3px 0 0;} 164 | #asdfg li #caps b { 165 | display: block; 166 | background: #999; 167 | width: 4px; 168 | height: 4px; 169 | border-radius: 10px; 170 | margin: 9px 0 0 10px; 171 | -webkit-box-shadow: inset 0 1px 0 #666; 172 | -moz-box-shadow:inset 0 1px 0 #666; 173 | box-shadow:inset 0 1px 0 #666;} 174 | #asdfg li #caps span { 175 | text-align: left; 176 | margin: 10px 0 0 10px; 177 | font-size: 7.5pt;} 178 | #asdfg li #enter span { 179 | text-align: right; 180 | margin: 23px 10px 0 0; 181 | font-size: 7.5pt;} 182 | 183 | 184 | #zxcvb li .shiftleft span { 185 | text-align: left; 186 | margin: 23px 0 0 10px; 187 | font-size: 7.5pt; 188 | text-transform: lowercase;} 189 | #zxcvb li .shiftright span { 190 | text-align: right; 191 | margin: 23px 10px 0 0; 192 | font-size: 7.5pt; 193 | text-transform: lowercase;} 194 | #zxcvb li .alt b {display: block;margin: 4px 0 0;} 195 | #zxcvb li .alt span {margin: 0;} 196 | 197 | 198 | #bottomrow li #fn span, 199 | #bottomrow li #Ctrl span, 200 | #bottomrow li #mjtleft span, 201 | #bottomrow li #AltKeyleft span { 202 | display: block; 203 | text-align: left; 204 | margin: 31px 0 0 8px; 205 | font-size: 7.5pt; 206 | text-transform: lowercase; 207 | } 208 | 209 | #bottomrow li #CtrlKeyright span, 210 | #bottomrow li #AltKeyright span { 211 | display: block; 212 | text-align: right; 213 | margin: 31px 8px 0 0; 214 | font-size: 7.5pt; 215 | text-transform: lowercase;} 216 | 217 | #bottomrow ol li #left span, 218 | #bottomrow ol li #right span, 219 | #bottomrow ol li #up span, 220 | #bottomrow ol li #down span { 221 | display: block; 222 | margin: 9px 0 0;} 223 | 224 | .fn {height: 26px; width: 46px;} 225 | #backspace {width: 72px;} 226 | #tab {width: 72px;} 227 | #caps {width: 85px;} 228 | #enter {width: 85px;} 229 | .shiftleft, .shiftright {width: 112px;} 230 | #fn, #Ctrl, .mjt, #CtrlKeyright, .AltKey, #spacebar {height: 49px;} 231 | 232 | .ctrl {width: 75px;} 233 | .mjt {width: 46px;} 234 | .AltKey {width: 67px;} 235 | #spacebar {width: 226px;} 236 | 237 | #left img, #up img, #down img, #right img {border: none;} 238 | ul ol {list-style-type: none;} 239 | #down {height: 23px;} 240 | #up, #left, #right {height: 24px;} 241 | #left, #right {margin: 30px 5px 5px;} 242 | #left:active, #right:active {margin: 32px 5px 3px;} 243 | #up {margin: 5px 5px 1px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px;} 244 | #up:active {margin: 8px 5px -2px;} 245 | #down {margin: 0 5px 5px; border-top-left-radius: 0px; border-top-right-radius: 0px;} 246 | #down:Active {margin: 3px 5px 4px;} 247 | #main { 248 | width: 700px; 249 | padding: 20px 50px; 250 | margin: 0 auto 50px; 251 | background: #fff; 252 | border-radius: 5px; 253 | -webkit-box-shadow: 0 1px 2px #aaa;} 254 | 255 | h1 { 256 | color: #888; 257 | text-align: center; 258 | font: bold 25pt/25pt arial; 259 | margin: 30px 0 60px;} 260 | 261 | h2 { 262 | color: #666; 263 | font: 13pt/0pt arial;} 264 | 265 | p { 266 | color: #999; 267 | font: 9pt/17pt arial; 268 | margin: 0 0 50px;} 269 | 270 | small { 271 | font: italic 8pt/12pt arial; 272 | color: #aaa; 273 | padding: 0 130px 0 0; 274 | display: block;} 275 | 276 | cite { 277 | display: block; 278 | padding: 0 0 30px; 279 | margin: 0 auto; 280 | text-align: center; 281 | color: #999; 282 | font: italic bold 8pt arial;} 283 | 284 | ul, ol {padding: 0px; margin: 0;} 285 | 286 | /* Micro Clearfix by Nicolas Gallagher - http://nicolasgallagher.com/micro-clearfix-hack */ 287 | /* For modern browsers */ 288 | .cf:before, .cf:after {content:""; display:table;} 289 | .cf:after {clear:both;} 290 | 291 | /* For IE 6/7 (trigger hasLayout) */ 292 | .cf {zoom:1;} -------------------------------------------------------------------------------- /client/views/practice/practise.ctrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('typali') 4 | 5 | .config(['$stateProvider', function ($stateProvider) { 6 | $stateProvider 7 | .state('app.practice', { 8 | url: '/practice', 9 | views: { 10 | 'container@': { 11 | templateUrl: 'views/practice/practice.tpl.html', 12 | controller: 'practiceCtrl', 13 | controllerAs: "vm" 14 | } 15 | } 16 | }) 17 | .state('app.practice.param', { 18 | url: '/:param', 19 | views: { 20 | 'container@': { 21 | templateUrl: 'views/practice/practice.tpl.html', 22 | controller: 'practiceCtrl', 23 | controllerAs: "vm" 24 | } 25 | } 26 | }); 27 | 28 | }]) 29 | 30 | .controller('practiceCtrl', PracticeCtrl); 31 | 32 | PracticeCtrl.$inject = ['$rootScope', '$scope', '$stateParams', '$document', "keyboardlayout", '$interval', 'datafetchService']; 33 | function PracticeCtrl($rootScope, $scope, $stateParams, $document, keyboardlayout, $interval, datafetchService) { 34 | var vm = this; 35 | 36 | var param = $stateParams.param; 37 | 38 | /*param*/ 39 | 40 | if (typeof param == 'undefined' || param == '') { 41 | param = Math.floor((Math.random() * 10)); 42 | } 43 | 44 | // console.log("param = ", param); 45 | 46 | vm.isloading = true; 47 | 48 | var isFirstLetter = true; 49 | 50 | var arrString, 51 | lenString, 52 | count = 0, 53 | countLetter = 0, 54 | grossCount = 0, 55 | isLetterCorrect = false; 56 | 57 | var initTime = 0; 58 | 59 | vm.time = 0; 60 | var timeRunner; 61 | 62 | var word = ''; 63 | var sentence = ''; 64 | 65 | 66 | var typedisable = false; 67 | 68 | vm.sentence = ""; 69 | 70 | vm.word = "Type here"; 71 | 72 | vm.alert = false; 73 | 74 | var str = "सानो छ खेत"; 75 | var textAll = {}; 76 | 77 | 78 | /*promise to get string*/ 79 | var promise = datafetchService.getString(param); 80 | promise.then(function (response) { 81 | 82 | var contents = response.data; 83 | // console.log(contents); 84 | textAll = contents.data; 85 | str = contents.data.text; 86 | // str = str; 87 | afterStringIsArrived(); 88 | messagebox(); 89 | }) 90 | .catch(function (error) { 91 | console.log(error); 92 | }) 93 | 94 | 95 | /* keyboard settlement*/ 96 | var allKeys, 97 | engData_all, 98 | codeData_all, 99 | npData_all, 100 | npShiftData_all; 101 | 102 | var keyboard = (typeof $rootScope.lang!=='undefined') ? keyboardlayout[$rootScope.lang] : keyboardlayout.unicode ; 103 | console.log(keyboard); 104 | 105 | function keyboard__() { 106 | vm.keyboard = keyboard; 107 | 108 | allKeys = [] 109 | for (var key in keyboard) { 110 | for (var i = 0; i < keyboard[key].length; i++) { 111 | allKeys.push(keyboard[key][i]) 112 | }; 113 | } 114 | 115 | engData_all = allKeys.map(function (item) { return item.en; }); 116 | codeData_all = allKeys.map(function (item) { return item.code; }); 117 | npData_all = allKeys.map(function (item) { return item.np; }); 118 | npShiftData_all = allKeys.map(function (item) { return item.npShift; }); 119 | } 120 | 121 | keyboard__(); 122 | 123 | $rootScope.$on("lang",function(event,data){ 124 | // console.log("yo"); 125 | keyboard = keyboardlayout[$rootScope.lang]; 126 | keyboard__(); 127 | // afterStringIsArrived(); 128 | }) 129 | 130 | /* key board settlement ends*/ 131 | 132 | function afterStringIsArrived() { 133 | 134 | 135 | arrString = str.split(" "); 136 | lenString = arrString.length; 137 | 138 | count = 0; 139 | 140 | countLetter = 0; 141 | 142 | grossCount = 0; 143 | 144 | isLetterCorrect = false; 145 | 146 | vm.highlight = arrString[count]; 147 | vm.highlightSingle = ""; 148 | 149 | vm.text = arrString; 150 | 151 | setTimeout(function () { 152 | highlightWord(); 153 | }, 1000); 154 | 155 | vm.isloading = false; 156 | 157 | } 158 | 159 | 160 | 161 | 162 | 163 | $('.writeArea').on('click', function () { 164 | $document.find(".writeArea input").focus(); 165 | }) 166 | 167 | $document.find(".writeArea input").on('keydown', function (event) { 168 | console.log("keypress"); 169 | if (typedisable) { 170 | return; 171 | } 172 | 173 | if (isFirstLetter) { 174 | isFirstLetter = false; 175 | initialiseTime(); 176 | } 177 | 178 | var code = event.which || event.charCode; 179 | // console.log(code,character,event.shiftKey); 180 | var newChar = ''; 181 | 182 | var shift = event.shiftKey; 183 | 184 | if (code == 8 || code == 46) { 185 | console.log("backspace"); 186 | if (isLetterCorrect && countLetter > 0) { 187 | countLetter = countLetter - 1; 188 | console.log("backspace", countLetter); 189 | // highlightSingleKey(); 190 | }; 191 | word = word.substring(0, word.length - 1); 192 | vm.word = word; 193 | $scope.$apply(); 194 | validateQuick(); 195 | 196 | } else if (code == 32) { 197 | console.log("space has been pressed 1"); 198 | validateWord(); 199 | } else { 200 | code += ""; 201 | var character = ''; 202 | console.log("code = ", code, codeData_all.indexOf(code)); 203 | if (codeData_all.indexOf(code) > -1) { 204 | if (shift) { 205 | character = allKeys[codeData_all.indexOf(code)].npShift; 206 | } else { 207 | character = allKeys[codeData_all.indexOf(code)].np; 208 | } 209 | 210 | console.log(character); 211 | 212 | word = word + character; 213 | 214 | vm.inputChar = '' 215 | vm.word = word; 216 | 217 | $scope.$apply(); 218 | // $scope.$digest() 219 | validateQuick(); 220 | } 221 | 222 | 223 | } 224 | 225 | 226 | }) 227 | 228 | 229 | function validateQuick() { 230 | var len = word.length; 231 | var compareStr = arrString[count].substring(0, len); 232 | 233 | console.log(word, compareStr); 234 | 235 | if (word != compareStr) { 236 | vm.alert = true; 237 | } else { 238 | vm.alert = false; 239 | if (isLetterCorrect) { 240 | countLetter++; 241 | } 242 | countLetter = len; 243 | isLetterCorrect = true; 244 | highlightSingleKey(); 245 | // 246 | } 247 | $scope.$apply(); 248 | } 249 | 250 | 251 | function validateWord() { 252 | console.log("space has been pressed"); 253 | if (word === arrString[count]) { 254 | countLetter = 0; 255 | sentence += word + " "; 256 | word = ''; 257 | vm.sentence = sentence; 258 | vm.word = word; 259 | count++; 260 | 261 | grossCount = grossCount + countLetter + 1; 262 | 263 | countLetter = 0; 264 | $scope.$apply(); 265 | if (count >= vm.text.length) { 266 | typedisable = true; 267 | timeRunner 268 | $interval.cancel(timeRunner); 269 | stop = undefined; 270 | vm.msgbox = true; 271 | console.log("string complete", vm.msgbox); 272 | $scope.$apply(); 273 | } else { 274 | highlightKeys(); 275 | 276 | highlightWord(); 277 | } 278 | 279 | calulateWPM(); 280 | }; 281 | } 282 | 283 | 284 | function highlightKeys() { 285 | vm.highlight = arrString[count]; 286 | highlightSingleKey(); 287 | } 288 | 289 | function highlightSingleKey() { 290 | 291 | var letterToHighlight = arrString[count].charAt(countLetter); 292 | 293 | if (letterToHighlight == '') { 294 | vm.highlightSingle = ' ' 295 | return; 296 | }; 297 | 298 | vm.highlightSingle = letterToHighlight; 299 | } 300 | 301 | vm.highlightSingleFn = function () { 302 | if (typedisable) return; 303 | highlightSingleKey(); 304 | } 305 | 306 | function highlightWord() { 307 | var countWordHere = count + 1; 308 | $document.find(".text span").removeClass("highlightWord"); 309 | $document.find(".text > span:nth-child(" + countWordHere + ")").addClass("highlightWord"); 310 | } 311 | 312 | 313 | 314 | 315 | 316 | function initialiseTime() { 317 | var d = new Date(); 318 | initTime = d.getTime(); 319 | 320 | 321 | 322 | timeRunner = $interval(function () { 323 | vm.time += 1; 324 | }, 1000); 325 | 326 | } 327 | 328 | function calulateWPM() { 329 | var d = new Date(); 330 | var hereTime = d.getTime(); 331 | 332 | var timeTaken = hereTime - initTime; 333 | vm.timeTaken = timeTaken; 334 | var wpm = 1000 * 60 * (grossCount / 6) / timeTaken; 335 | vm.speed = Math.round(wpm); 336 | } 337 | 338 | function messagebox() { 339 | vm.art = { 340 | title: textAll.title, 341 | author: textAll.author 342 | } 343 | 344 | console.log("textAll", textAll); 345 | 346 | } 347 | 348 | 349 | }; -------------------------------------------------------------------------------- /dist/app.min.js: -------------------------------------------------------------------------------- 1 | "use strict";function run(n,e,t,o){n.$on("$routeChangeStart",function(n,e,t){}),n.facebookAppId="[]"}function keyboardCtrl(n,e){function t(e){console.log("letter again = ",i.letter),$(".highlightLetter").removeClass("highlightLetter")," "==e?o="spacebar":a.indexOf(e)>-1?(o="c"+c[a.indexOf(e)],console.log(a,a.indexOf(e))):(o="c"+c[l.indexOf(e)],$(".shiftKey").addClass("highlightLetter")),console.log("letter again = ",i.letter,o),n.find("."+o).addClass("highlightLetter")}var o,i=this,r=i.keyboard;console.log("letter = ",i.letter);var c,a,l,p=[];for(var f in r)for(var d=0;d=S.text.length?(O=!0,r.cancel(A),stop=void 0,S.msgbox=!0,console.log("string complete",S.msgbox),e.$apply()):(d(),u()),g())}function d(){S.highlight=y[k],h()}function h(){var n=y[k].charAt(w);if(""==n)return void(S.highlightSingle=" ");S.highlightSingle=n}function u(){var n=k+1;o.find(".text span").removeClass("highlightWord"),o.find(".text > span:nth-child("+n+")").addClass("highlightWord")}function s(){var n=new Date;j=n.getTime(),A=r(function(){S.time+=1},1e3)}function g(){var n=new Date,e=n.getTime(),t=e-j;S.timeTaken=t;var o=x/6*6e4/t;S.speed=Math.round(o)}function m(){S.art={title:L.title,author:L.author},console.log("textAll",L)}var S=this,v=t.param;void 0!==v&&""!=v||(v=Math.floor(10*Math.random())),S.isloading=!0;var y,C,b=!0,k=0,w=0,x=0,F=!1,j=0;S.time=0;var A,P="",U="",O=!1;S.sentence="",S.word="Type here",S.alert=!1;var H="सानो छ खेत",L={};c.getString(v).then(function(n){var e=n.data;L=e.data,H=e.data.text,l(),m()}).catch(function(n){console.log(n)});var T,z,E,q,I,M=void 0!==n.lang?i[n.lang]:i.unicode;console.log(M),a(),n.$on("lang",function(e,t){M=i[n.lang],a()}),$(".writeArea").on("click",function(){o.find(".writeArea input").focus()}),o.find(".writeArea input").on("keydown",function(n){if(console.log("keypress"),!O){b&&(b=!1,s());var t=n.which||n.charCode,o=n.shiftKey;if(8==t||46==t)console.log("backspace"),F&&w>0&&(w-=1,console.log("backspace",w)),P=P.substring(0,P.length-1),S.word=P,e.$apply(),p();else if(32==t)console.log("space has been pressed 1"),f();else{t+="";var i="";console.log("code = ",t,E.indexOf(t)),E.indexOf(t)>-1&&(i=o?T[E.indexOf(t)].npShift:T[E.indexOf(t)].np,console.log(i),P+=i,S.inputChar="",S.word=P,e.$apply(),p())}}}),S.highlightSingleFn=function(){O||h()}}function EditorCtrl(n){for(var e=["000000","FF9966","6699FF","99FF66","CC0000","00CC00","0000CC","333333","0066FF","FFFFFF"],t=$(".fore-palette"),o=$(".back-palette"),i=0;i'),o.append('');$(".toolbar a").click(function(n){var e=$(this).data("command");"h1"!=e&&"h2"!=e&&"p"!=e||document.execCommand("formatBlock",!1,e),"forecolor"!=e&&"backcolor"!=e||document.execCommand($(this).data("command"),!1,$(this).data("value")),"createlink"==e||"insertimage"==e?(url=prompt("Enter the link here: ","http://"),document.execCommand($(this).data("command"),!1,url)):document.execCommand($(this).data("command"),!1,null)})}function HomeCtrl(n,e){var t=this;e.lang="unicode",t.lang=e.lang,t.update=function(){console.log("lang",t.lang),e.lang=t.lang,e.$broadcast("lang",t.lang)}}var app=angular.module("typali",["ui.router","ngSanitize","angular-loading-bar"]).config(["$locationProvider","$stateProvider","$urlRouterProvider",function(n,e,t){n.hashPrefix("!"),t.otherwise("/404"),e.state("app",{url:"",views:{"header@":{controller:"HeaderCtrl",templateUrl:"components/common/header/header.tpl.html",controllerAs:"vm"},"footer@":{controller:"FooterCtrl",templateUrl:"components/common/footer/footer.tpl.html",controllerAs:"vm"}}}).state("app.404",{url:"/404",views:{"header@":{templateUrl:"components/common/header/header.tpl.html"}}}),n.html5Mode(!0)}]).run(["$rootScope","$location","authentication","$window",run]);angular.module("typali").component("keyboard2",{templateUrl:"components/common/keyboard/keyboard.tpl.html",controller:keyboardCtrl,bindings:{keyboard:"<",word:"<",letter:"<",shift:"<"}}),keyboardCtrl.$inject=["$document","$scope"],angular.module("typali").controller("HeaderCtrl",HeaderCtrl),HeaderCtrl.$inject=["$scope","$rootScope"],angular.module("typali").controller("FooterCtrl",FooterCtrl),FooterCtrl.$inject=["$scope"],angular.module("typali").config(["$stateProvider",function(n){n.state("app.practice",{url:"/practice",views:{"container@":{templateUrl:"views/practice/practice.tpl.html",controller:"practiceCtrl",controllerAs:"vm"}}}).state("app.practice.param",{url:"/:param",views:{"container@":{templateUrl:"views/practice/practice.tpl.html",controller:"practiceCtrl",controllerAs:"vm"}}})}]).controller("practiceCtrl",PracticeCtrl),PracticeCtrl.$inject=["$rootScope","$scope","$stateParams","$document","keyboardlayout","$interval","datafetchService"],angular.module("typali").config(["$stateProvider",function(n){n.state("app.editor",{url:"/editor",views:{"container@":{templateUrl:"views/editor/editor.tpl.html",controller:"editorCtrl",controllerAs:"vm"}}})}]).controller("editorCtrl",EditorCtrl),EditorCtrl.$inject=["$scope"],angular.module("typali").config(["$stateProvider",function(n){n.state("app.home",{url:"/",views:{"container@":{templateUrl:"views/home/home.tpl.html",controller:"HomeCtrl",controllerAs:"vm"}}})}]).controller("HomeCtrl",HomeCtrl),HomeCtrl.$inject=["$scope","$rootScope"],function(){function n(n,e){}angular.module("typali").config(["$stateProvider",function(n){n.state("app.register",{url:"/register",views:{"container@":{templateUrl:"auth/user-register/user-register.tpl.html",controller:"UserRegisterCtrl",controllerAs:"vm"}}})}]).controller("UserRegisterCtrl",n),n.$inject=["$location","authentication"]}(),function(){function n(n,e){var t=this;t.credentials={email:"yo@hotmail.com",password:""},t.onSubmit=function(){e.login(t.credentials).error(function(n){console.log(n)}).then(function(){n.path("profile")})}}angular.module("typali").config(["$stateProvider",function(n){n.state("app.login",{url:"/login",views:{"container@":{templateUrl:"auth/login/login.tpl.html",controller:"LoginCtrl",controllerAs:"vm"}}})}]).controller("LoginCtrl",n),n.$inject=["$location","authentication"]}(),angular.module("typali").factory("socket",["$rootScope",function(n){var e=io.connect();return{on:function(t,o){e.on(t,function(){var t=arguments;n.$apply(function(){o.apply(e,t)})})},emit:function(t,o,i){e.emit(t,o,function(){var t=arguments;n.$apply(function(){i&&i.apply(e,t)})})}}}]);var app=angular.module("typali");app.filter("limitobj",[function(){return function(n,e){if("object"!=typeof n)return[];var t=Object.keys(n);if(t.length<1||void 0===t)return[];var o=new Object,i=0;return angular.forEach(t,function(t,r){if(i>=e)return!1;o[t]=n[t],i++}),o}}]),angular.module("typali").factory("keyboardlayout",["$rootScope",function(n){var e={};return e.unicode={qwerty:[{code:"81",en:"q",npShift:"ठ",np:"ट"},{code:"87",en:"w",npShift:"औ",np:"ौ"},{code:"69",en:"e",npShift:"ै",np:"े"},{code:"82",en:"r",npShift:"ृ",np:"र"},{code:"84",en:"t",npShift:"थ",np:"त"},{code:"89",en:"y",npShift:"ञ",np:"य"},{code:"85",en:"u",npShift:"ू",np:"ु"},{code:"73",en:"i",npShift:"ी",np:"ि"},{code:"79",en:"o",npShift:"ओ",np:"ो"},{code:"80",en:"p",npShift:"फ",np:"प"},{code:"219",en:"[",npShift:"ई",np:"इ"},{code:"221",en:"]",npShift:"ऐ",np:"ए"},{code:"220",en:"\\",npShift:"ः",np:"ॐ"}],asdfg:[{code:"65",en:"a",npShift:"आ",np:"ा"},{code:"83",en:"s",npShift:"श",np:"स"},{code:"68",en:"d",npShift:"ध",np:"द"},{code:"70",en:"f",npShift:"ऊ",np:"उ"},{code:"71",en:"g",npShift:"घ",np:"ग"},{code:"72",en:"h",npShift:"अ",np:"ह"},{code:"74",en:"j",npShift:"झ",np:"ज"},{code:"75",en:"k",npShift:"ख",np:"क"},{code:"76",en:"l",npShift:"॥",np:"ल"},{code:"186",en:"l",npShift:":",np:";"},{code:"222",en:"l",npShift:'"',np:"'"}],zxcvb:[{code:"90",en:"z",npShift:"ऋ",np:"ष"},{code:"88",en:"x",npShift:"ढ",np:"ड"},{code:"67",en:"c",npShift:"च",np:"छ"},{code:"86",en:"v",npShift:"ँ",np:"व"},{code:"66",en:"b",npShift:"भ",np:"ब"},{code:"78",en:"n",npShift:"ण",np:"न"},{code:"77",en:"m",npShift:"ं",np:"म"},{code:"188",en:",",npShift:"ङ",np:","},{code:"190",en:".",npShift:">",np:"।"},{code:"191",en:"/",npShift:"?",np:"्"}],1234:[{code:"192",en:"`",enShift:"~",npShift:"~",np:"`"},{code:"49",en:"1",npShift:"!",np:"१"},{code:"50",en:"2",npShift:"@",np:"२"},{code:"51",en:"3",npShift:"#",np:"३"},{code:"52",en:"4",npShift:"रु",np:"४"},{code:"53",en:"5",npShift:"%",np:"५"},{code:"54",en:"6",npShift:"^",np:"६"},{code:"55",en:"7",npShift:"&",np:"७"},{code:"56",en:"8",npShift:"*",np:"८"},{code:"59",en:"9",npShift:"(",np:"९"},{code:"48",en:"0",npShift:")",np:"०"},{code:"189",en:"-",npShift:"_",np:"-"},{code:"187",en:"=",npShift:"+‍‌‍‍‍‍",np:"="}]},e.unicodeTraditional={qwerty:[{code:"81",en:"q",npShift:"त्त",np:"त्र"},{code:"87",en:"w",npShift:"ड्ढ",np:"ध"},{code:"69",en:"e",npShift:"ऐ",np:"भ"},{code:"82",en:"r",npShift:"द्ब",np:"च"},{code:"84",en:"t",npShift:"ट्ट",np:"त"},{code:"89",en:"y",npShift:"ठ्ठ",np:"थ"},{code:"85",en:"u",npShift:"ऊ",np:"ग"},{code:"73",en:"i",npShift:"क्ष",np:"ष"},{code:"79",en:"o",npShift:"इ",np:"य"},{code:"80",en:"p",npShift:"ए",np:"उ"},{code:"219",en:"[",npShift:"ृ",np:"र्"},{code:"221",en:"]",npShift:"ै",np:"े"},{code:"220",en:"\\",npShift:"ं",np:"्"}],asdfg:[{code:"65",en:"a",npShift:"आ",np:"ब"},{code:"83",en:"s",npShift:"ङ्क",np:"क"},{code:"68",en:"d",npShift:"ङ्ग",np:"म"},{code:"70",en:"f",npShift:"ँ",np:"ा"},{code:"71",en:"g",npShift:"द्द",np:"न"},{code:"72",en:"h",npShift:"झ",np:"ज"},{code:"74",en:"j",npShift:"ो",np:"व"},{code:"75",en:"k",npShift:"फ",np:"प"},{code:"76",en:"l",npShift:"ी",np:"ि"},{code:"186",en:";",npShift:"ट्ठ",np:"स"},{code:"222",en:"'",npShift:"ू",np:"ु"}],zxcvb:[{code:"90",en:"z",npShift:"क्क",np:"श"},{code:"88",en:"x",npShift:"ह्य",np:"ह"},{code:"67",en:"c",npShift:"ऋ",np:"अ"},{code:"86",en:"v",npShift:"ॐ",np:"ख"},{code:"66",en:"b",npShift:"ौ",np:"द"},{code:"78",en:"n",npShift:"द्य",np:"ल"},{code:"77",en:"m",npShift:"ड्ड",np:"ः"},{code:"188",en:",",npShift:"ङ",np:"ऽ"},{code:"190",en:".",npShift:"श्र",np:"।"},{code:"191",en:"/",npShift:"रु",np:"र"}],1234:[{code:"192",en:"`",enShift:"~",npShift:"॥",np:"ञ`"},{code:"49",en:"1",enShift:"!",npShift:"ज्ञ",np:"१"},{code:"50",en:"2",enShift:"@",npShift:"ई",np:"२"},{code:"51",en:"3",enShift:"#",npShift:"घ",np:"३"},{code:"52",en:"4",enShift:"$",npShift:"द्ध",np:"४"},{code:"53",en:"5",enShift:"%",npShift:"छ",np:"५"},{code:"54",en:"6",enShift:"^",npShift:"ट",np:"६"},{code:"55",en:"7",enShift:"&",npShift:"ठ",np:"७"},{code:"56",en:"8",enShift:"*",npShift:"ड",np:"८"},{code:"59",en:"9",enShift:"(",npShift:"ढ",np:"९"},{code:"48",en:"0",enShift:")",npShift:"ण",np:"०"},{code:"189",en:"-",enShift:"_",npShift:"ओ",np:"औ"},{code:"187",en:"=",enShift:"+‍‌‍‍‍‍",npShift:"‌‌‌‌‍‍‍",np:"‌‍‍‍‍‍‍"}]},e}]);var app=angular.module("typali");app.filter("filterByProperty",["$filter",function(n){return function(e,t,o){if(console.log("reached here",t,o),e){if(t){if("$"===o)return n("filter")(e,t);console.log(t);var i=t.toString().toLowerCase();return e.filter(function(n){return n[o].toString().toLowerCase().indexOf(i)>-1})}return e}}}]),function(){function n(n){var e=this,t="https://typali.herokuapp.com/api/";e.getString=function(e){var o=n({cache:!0,method:"GET",url:t+"getstring/"+e});return console.log("url : ",t+"getstring/"+e),o}}angular.module("typali").service("datafetchService",n),n.$inject=["$http"]}(),angular.module("typali").filter("capitalize",function(){return function(n,e){var t=e?/([^\W_]+[^\s-]*) */g:/([^\W_]+[^\s-]*)/;return n?n.replace(t,function(n){return n.charAt(0).toUpperCase()+n.substr(1).toLowerCase()}):""}}),function(){function n(n,e){var t=function(n){e.localStorage["typali-token"]=n},o=function(){return e.localStorage["typali-token"]},i=function(){var n,t=o();return!!t&&(n=t.split(".")[1],n=e.atob(n),n=JSON.parse(n),n.exp>Date.now()/1e3)};return{currentUser:function(){if(i()){var n=o(),t=n.split(".")[1];return t=e.atob(t),t=JSON.parse(t),{email:t.email,name:t.name}}},saveToken:t,getToken:o,isLoggedIn:i,register:function(e){return n.post("/api/register",e).success(function(n){t(n.token)})},login:function(e){return n.post("/api/login",e).success(function(n){console.log(n.token),t(n.token)})},logout:function(){e.localStorage.removeItem("typali-token")}}}angular.module("typali").service("authentication",n),n.$inject=["$http","$window"]}(),angular.module("typali.common",[]); -------------------------------------------------------------------------------- /client/services/keyboardlayout.service.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('typali') 3 | .factory('keyboardlayout', function ($rootScope) { 4 | 5 | /*can add different keybord*/ 6 | 7 | /*unicode default keyboard*/ 8 | var keyboard = {}; 9 | keyboard.unicode = { 10 | "qwerty": [ 11 | { 12 | "code": "81", 13 | "en": "q", 14 | "npShift": "ठ", 15 | "np": "ट" 16 | }, 17 | { 18 | "code": "87", 19 | "en": "w", 20 | "npShift": "औ", 21 | "np": "ौ" 22 | }, 23 | { 24 | "code": "69", 25 | "en": "e", 26 | "npShift": "ै", 27 | "np": "े" 28 | }, 29 | { 30 | "code": "82", 31 | "en": "r", 32 | "npShift": "ृ", 33 | "np": "र" 34 | }, 35 | { 36 | "code": "84", 37 | "en": "t", 38 | "npShift": "थ", 39 | "np": "त" 40 | }, 41 | { 42 | "code": "89", 43 | "en": "y", 44 | "npShift": "ञ", 45 | "np": "य" 46 | }, 47 | { 48 | "code": "85", 49 | "en": "u", 50 | "npShift": "ू", 51 | "np": "ु" 52 | }, 53 | { 54 | "code": "73", 55 | "en": "i", 56 | "npShift": "ी", 57 | "np": "ि" 58 | }, 59 | { 60 | "code": "79", 61 | "en": "o", 62 | "npShift": "ओ", 63 | "np": "ो" 64 | }, 65 | { 66 | "code": "80", 67 | "en": "p", 68 | "npShift": "फ", 69 | "np": "प" 70 | }, 71 | { 72 | "code": "219", 73 | "en": "[", 74 | "npShift": "ई", 75 | "np": "इ" 76 | }, 77 | { 78 | "code": "221", 79 | "en": "]", 80 | "npShift": "ऐ", 81 | "np": "ए" 82 | }, 83 | { 84 | "code": "220", 85 | "en": "\\", 86 | "npShift": "ः", 87 | "np": "ॐ" 88 | } 89 | ], 90 | "asdfg": [ 91 | { 92 | "code": "65", 93 | "en": "a", 94 | "npShift": "आ", 95 | "np": "ा" 96 | }, 97 | { 98 | "code": "83", 99 | "en": "s", 100 | "npShift": "श", 101 | "np": "स" 102 | }, 103 | { 104 | "code": "68", 105 | "en": "d", 106 | "npShift": "ध", 107 | "np": "द" 108 | }, 109 | { 110 | "code": "70", 111 | "en": "f", 112 | "npShift": "ऊ", 113 | "np": "उ" 114 | }, 115 | { 116 | "code": "71", 117 | "en": "g", 118 | "npShift": "घ", 119 | "np": "ग" 120 | }, 121 | { 122 | "code": "72", 123 | "en": "h", 124 | "npShift": "अ", 125 | "np": "ह" 126 | }, 127 | { 128 | "code": "74", 129 | "en": "j", 130 | "npShift": "झ", 131 | "np": "ज" 132 | }, 133 | { 134 | "code": "75", 135 | "en": "k", 136 | "npShift": "ख", 137 | "np": "क" 138 | }, 139 | { 140 | "code": "76", 141 | "en": "l", 142 | "npShift": "॥", 143 | "np": "ल" 144 | }, 145 | { 146 | "code": "186", 147 | "en": "l", 148 | "npShift": "\:", 149 | "np": "\;" 150 | }, 151 | { 152 | "code": "222", 153 | "en": "l", 154 | "npShift": "\"", 155 | "np": "\'" 156 | } 157 | ], 158 | "zxcvb": [ 159 | 160 | { 161 | "code": "90", 162 | "en": "z", 163 | "npShift": "ऋ", 164 | "np": "ष" 165 | }, 166 | { 167 | "code": "88", 168 | "en": "x", 169 | "npShift": "ढ", 170 | "np": "ड" 171 | }, 172 | { 173 | "code": "67", 174 | "en": "c", 175 | "npShift": "च", 176 | "np": "छ" 177 | }, 178 | { 179 | "code": "86", 180 | "en": "v", 181 | "npShift": "ँ", 182 | "np": "व" 183 | }, 184 | { 185 | "code": "66", 186 | "en": "b", 187 | "npShift": "भ", 188 | "np": "ब" 189 | }, 190 | { 191 | "code": "78", 192 | "en": "n", 193 | "npShift": "ण", 194 | "np": "न" 195 | }, 196 | { 197 | "code": "77", 198 | "en": "m", 199 | "npShift": "ं", 200 | "np": "म" 201 | }, 202 | { 203 | "code": "188", 204 | "en": ",", 205 | "npShift": "ङ", 206 | "np": "," 207 | }, 208 | { 209 | "code": "190", 210 | "en": ".", 211 | "npShift": ">", 212 | "np": "।" 213 | }, 214 | { 215 | "code": "191", 216 | "en": "/", 217 | "npShift": "?", 218 | "np": "्" 219 | } 220 | ], 221 | "1234": [ 222 | { 223 | "code": "192", 224 | "en": "\`", 225 | "enShift": "\~", 226 | "npShift": "\~", 227 | "np": "\`" 228 | }, { 229 | "code": "49", 230 | "en": "1", 231 | "npShift": "!", 232 | "np": "१" 233 | }, { 234 | "code": "50", 235 | "en": "2", 236 | "npShift": "@", 237 | "np": "२" 238 | }, { 239 | "code": "51", 240 | "en": "3", 241 | "npShift": "#", 242 | "np": "३" 243 | }, { 244 | "code": "52", 245 | "en": "4", 246 | "npShift": "रु", 247 | "np": "४" 248 | }, { 249 | "code": "53", 250 | "en": "5", 251 | "npShift": "%", 252 | "np": "५" 253 | }, { 254 | "code": "54", 255 | "en": "6", 256 | "npShift": "^", 257 | "np": "६" 258 | }, { 259 | "code": "55", 260 | "en": "7", 261 | "npShift": "&", 262 | "np": "७" 263 | }, { 264 | "code": "56", 265 | "en": "8", 266 | "npShift": "*", 267 | "np": "८" 268 | }, { 269 | "code": "59", 270 | "en": "9", 271 | "npShift": "(", 272 | "np": "९" 273 | }, { 274 | "code": "48", 275 | "en": "0", 276 | "npShift": ")", 277 | "np": "०" 278 | }, { 279 | "code": "189", 280 | "en": "-", 281 | "npShift": "_", 282 | "np": "-" 283 | }, { 284 | "code": "187", 285 | "en": "=", 286 | "npShift": "+‍‌‍‍‍‍", 287 | "np": "=" 288 | } 289 | ] 290 | 291 | 292 | } 293 | 294 | keyboard.unicodeTraditional = { 295 | "qwerty": [ 296 | { 297 | "code": "81", 298 | "en": "q", 299 | "npShift": "त्त", 300 | "np": "त्र" 301 | }, 302 | { 303 | "code": "87", 304 | "en": "w", 305 | "npShift": "ड्ढ", 306 | "np": "ध" 307 | }, 308 | { 309 | "code": "69", 310 | "en": "e", 311 | "npShift": "ऐ", 312 | "np": "भ" 313 | }, 314 | { 315 | "code": "82", 316 | "en": "r", 317 | "npShift": "द्ब", 318 | "np": "च" 319 | }, 320 | { 321 | "code": "84", 322 | "en": "t", 323 | "npShift": "ट्ट", 324 | "np": "त" 325 | }, 326 | { 327 | "code": "89", 328 | "en": "y", 329 | "npShift": "ठ्ठ", 330 | "np": "थ" 331 | }, 332 | { 333 | "code": "85", 334 | "en": "u", 335 | "npShift": "ऊ", 336 | "np": "ग" 337 | }, 338 | { 339 | "code": "73", 340 | "en": "i", 341 | "npShift": "क्ष", 342 | "np": "ष" 343 | }, 344 | { 345 | "code": "79", 346 | "en": "o", 347 | "npShift": "इ", 348 | "np": "य" 349 | }, 350 | { 351 | "code": "80", 352 | "en": "p", 353 | "npShift": "ए", 354 | "np": "उ" 355 | }, 356 | { 357 | "code": "219", 358 | "en": "[", 359 | "npShift": "ृ", 360 | "np": "र्" 361 | }, 362 | { 363 | "code": "221", 364 | "en": "]", 365 | "npShift": "ै", 366 | "np": "े" 367 | }, 368 | { 369 | "code": "220", 370 | "en": "\\", 371 | "npShift": "ं", 372 | "np": "्" 373 | } 374 | ], 375 | "asdfg": [ 376 | { 377 | "code": "65", 378 | "en": "a", 379 | "npShift": "आ", 380 | "np": "ब" 381 | }, 382 | { 383 | "code": "83", 384 | "en": "s", 385 | "npShift": "ङ्क", 386 | "np": "क" 387 | }, 388 | { 389 | "code": "68", 390 | "en": "d", 391 | "npShift": "ङ्ग", 392 | "np": "म" 393 | }, 394 | { 395 | "code": "70", 396 | "en": "f", 397 | "npShift": "ँ", 398 | "np": "ा" 399 | }, 400 | { 401 | "code": "71", 402 | "en": "g", 403 | "npShift": "द्द", 404 | "np": "न" 405 | }, 406 | { 407 | "code": "72", 408 | "en": "h", 409 | "npShift": "झ", 410 | "np": "ज" 411 | }, 412 | { 413 | "code": "74", 414 | "en": "j", 415 | "npShift": "ो", 416 | "np": "व" 417 | }, 418 | { 419 | "code": "75", 420 | "en": "k", 421 | "npShift": "फ", 422 | "np": "प" 423 | }, 424 | { 425 | "code": "76", 426 | "en": "l", 427 | "npShift": "ी", 428 | "np": "ि" 429 | }, 430 | { 431 | "code": "186", 432 | "en": ";", 433 | "npShift": "ट्ठ", 434 | "np": "स" 435 | }, 436 | { 437 | "code": "222", 438 | "en": "'", 439 | "npShift": "ू", 440 | "np": "ु" 441 | } 442 | ], 443 | "zxcvb": [ 444 | 445 | { 446 | "code": "90", 447 | "en": "z", 448 | "npShift": "क्क", 449 | "np": "श" 450 | }, 451 | { 452 | "code": "88", 453 | "en": "x", 454 | "npShift": "ह्य", 455 | "np": "ह" 456 | }, 457 | { 458 | "code": "67", 459 | "en": "c", 460 | "npShift": "ऋ", 461 | "np": "अ" 462 | }, 463 | { 464 | "code": "86", 465 | "en": "v", 466 | "npShift": "ॐ", 467 | "np": "ख" 468 | }, 469 | { 470 | "code": "66", 471 | "en": "b", 472 | "npShift": "ौ", 473 | "np": "द" 474 | }, 475 | { 476 | "code": "78", 477 | "en": "n", 478 | "npShift": "द्य", 479 | "np": "ल" 480 | }, 481 | { 482 | "code": "77", 483 | "en": "m", 484 | "npShift": "ड्ड", 485 | "np": "ः" 486 | }, 487 | { 488 | "code": "188", 489 | "en": ",", 490 | "npShift": "ङ", 491 | "np": "ऽ" 492 | }, 493 | { 494 | "code": "190", 495 | "en": ".", 496 | "npShift": "श्र", 497 | "np": "।" 498 | }, 499 | { 500 | "code": "191", 501 | "en": "/", 502 | "npShift": "रु", 503 | "np": "र" 504 | } 505 | ], 506 | "1234": [ 507 | { 508 | "code": "192", 509 | "en": "\`", 510 | "enShift": "\~", 511 | "npShift": "\॥", 512 | "np": "ञ`" 513 | }, { 514 | "code": "49", 515 | "en": "1", 516 | "enShift": "!", 517 | "npShift": "ज्ञ", 518 | "np": "१" 519 | }, { 520 | "code": "50", 521 | "en": "2", 522 | "enShift": "@", 523 | "npShift": "ई", 524 | "np": "२" 525 | }, { 526 | "code": "51", 527 | "en": "3", 528 | "enShift": "#", 529 | "npShift": "घ", 530 | "np": "३" 531 | }, { 532 | "code": "52", 533 | "en": "4", 534 | "enShift": "$", 535 | "npShift": "द्ध", 536 | "np": "४" 537 | }, { 538 | "code": "53", 539 | "en": "5", 540 | "enShift": "%", 541 | "npShift": "छ", 542 | "np": "५" 543 | }, { 544 | "code": "54", 545 | "en": "6", 546 | "enShift": "^", 547 | "npShift": "ट", 548 | "np": "६" 549 | }, { 550 | "code": "55", 551 | "en": "7", 552 | "enShift": "&", 553 | "npShift": "ठ", 554 | "np": "७" 555 | }, { 556 | "code": "56", 557 | "en": "8", 558 | "enShift": "*", 559 | "npShift": "ड", 560 | "np": "८" 561 | }, { 562 | "code": "59", 563 | "en": "9", 564 | "enShift": "(", 565 | "npShift": "ढ", 566 | "np": "९" 567 | }, { 568 | "code": "48", 569 | "en": "0", 570 | "enShift": ")", 571 | "npShift": "ण", 572 | "np": "०" 573 | }, { 574 | "code": "189", 575 | "en": "-", 576 | "enShift": "_", 577 | "npShift": "ओ", 578 | "np": "औ" 579 | }, { 580 | "code": "187", 581 | "en": "=", 582 | "enShift": "+‍‌‍‍‍‍", 583 | "npShift": "‌‌‌‌‍‍‍", 584 | "np": "‌‍‍‍‍‍‍" 585 | } 586 | ] 587 | 588 | 589 | } 590 | return keyboard; 591 | }); 592 | --------------------------------------------------------------------------------