Skip to content

Commit

Permalink
Merge pull request #11 from suvash/add-traditional-layout-and-refactor
Browse files Browse the repository at this point in the history
Add 'traditional' layout with tests and refactor the library to support multiple layouts
  • Loading branch information
suvash authored Mar 2, 2021
2 parents 044933c + b99cad4 commit 177f183
Show file tree
Hide file tree
Showing 17 changed files with 777 additions and 271 deletions.
20 changes: 20 additions & 0 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Setup the project and run tests

on: [push, pull_request]

jobs:
build:

runs-on: ubuntu-latest

steps:
- name: Check out code
id: check-out-code
uses: actions/checkout@v2

- name: Install packages and run tests
uses: actions/setup-node@v2
with:
node-version: '14'
- run: npm install
- run: npm run test
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. This change
## [Unreleased]
- Setup local testing
- Added tests for layouts and romanized module
- Added 'traditional' layout with tests
- Refactor modules for better testability
- Expose availableLayouts function to top level export

## [0.4.2] - 2021-02-15
- Update all npm dependencies except webpack
Expand Down
46 changes: 40 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Nepalify

A JavaScript library that adds support for typing (Romanized) Nepali(नेपाली) input on HTML `<input>` and `<textarea>`.
A JavaScript library that adds support for typing Unicode Nepali(नेपाली) input on HTML `<input>` and `<textarea>` (using both traditional and romanized layouts).

## Supported Browsers

Expand Down Expand Up @@ -70,15 +70,37 @@ import nepalify from "nepalify";
The default exports from the library consists of a handful of functions, as explained below.
### availableLayouts()
This method returns all available layouts, currently `romanized` and `traditional`. These layout names can be provided as options to other functions.
```javascript
console.log(nepalify.availableLayouts());
// ["romanized", "traditional"]
```
### interceptElementByID("unique-id")
This method allows the library code to intercept the keypress events on `<input>` and `<textarea>` html elements, given an `id` selector. This can only be used in a browser.
The argument to this function is the same as you'd provide to the standard `getElementById`
```javascript
var inputEl = nepalify.interceptElementById("unique-input");
var textareaEl = nepalify.interceptElementById("unique-textarea");
var inputEl = nepalify.interceptElementById("unique-input-1");
var textareaEl = nepalify.interceptElementById("unique-textarea-1");
// Further options can be provided as a second argument
const options = {
layout: "traditional",
enable: false,
};
nepalify.interceptElementById("unique-input-2", options);
// When the options are not provided, the following defaults are used
const defaultOptions = {
layout: "romanized",
enable: true,
};
```
At this point, the library should already be intercepting the keypresses. Go ahead and give it a try.
Expand All @@ -89,11 +111,10 @@ The object returned by the function above has more methods that can be used to c
Returns a boolean value indicating whether the interception is turned on or not.
#### enabled()
#### enable()
Enable the interception on the element. Already done by default.
#### disable()
Disable the interception on the element. Useful for clean up or building toggle behaviour.
Expand All @@ -106,7 +127,20 @@ This method allows you to format the text to Unicode nepali. Also usable in Node
```javascript
var text = "kiMkr/tv/ybimuX/";
console.log(nepalify.format(text));
//किंकर्तव्यबिमुढ्
// किंकर्तव्यबिमुढ्
// Further options can be provided as a second argument
var text = "asdfghjkl";
const options = {
layout: "traditional",
};
console.log(nepalify.format(text, options));
// बकमानजवपि
// When the options are not provided, the following defaults are used
const defaultOptions = {
layout: "romanized",
};
```
## Development
Expand Down
60 changes: 43 additions & 17 deletions example/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,61 @@
<div>
<h1>Nepalify Test page</h1>
<div id="app">
<input id="some-element" />
<textarea id="some-other-element"></textarea>
<textarea id="disabled-start-element"></textarea>
<div id="romanized">
<input id="rom-input-1" />
<textarea id="rom-text-1"></textarea>
<textarea id="rom-text-2"></textarea>
</div>
<div id="traditional">
<input id="trad-input-1" />
<textarea id="trad-text-1"></textarea>
<textarea id="trad-text-2"></textarea>
</div>
</div>
</div>
<% for (var f in htmlWebpackPlugin.files.js) { %>
<script src="<%= htmlWebpackPlugin.files.js[f] %>"></script>
<% } %>
<script>
var romanized = nepalify.layouts.romanized;
console.log(nepalify.availableLayouts());

var text = "kiMkr/tv/ybimuX/ haha";
var ftext = nepalify.format(text);
var fftext = nepalify.format(text, { layout: romanized });
var rom_text = "kiMkr/tv/ybimuX/ haha";
var rom_ftext = nepalify.format(rom_text, { layout: "romanized" });
console.log(rom_text);
console.log(rom_ftext);

console.log(text);
console.log(ftext);
console.log(fftext);
var default_ftext = nepalify.format(rom_text);
console.log(default_ftext);

var nep1 = nepalify.interceptElementById("some-element");
var nep2 = nepalify.interceptElementById("some-other-element", {
layout: romanized,
var trad_text = "asdfghjkl";
var trad_ftext = nepalify.format(trad_text, { layout: "traditional" });
console.log(trad_text);
console.log(trad_ftext);

var rom_nep1 = nepalify.interceptElementById("rom-input-1");
var rom_nep2 = nepalify.interceptElementById("rom-text-1", {
layout: "romanized",
});
var rom_nep3 = nepalify.interceptElementById("rom-text-2", {
enable: false,
});
console.log("rom_nep1 enabled :" + rom_nep1.isEnabled());
console.log("rom_nep2 enabled :" + rom_nep2.isEnabled());
console.log("rom_nep3 enabled :" + rom_nep3.isEnabled());

var trad_nep1 = nepalify.interceptElementById("trad-input-1", {
layout: "traditional",
});
var trad_nep2 = nepalify.interceptElementById("trad-text-1", {
layout: "traditional",
});
var nep3 = nepalify.interceptElementById("disabled-start-element", {
var trad_nep3 = nepalify.interceptElementById("trad-text-2", {
layout: "traditional",
enable: false,
});
console.log("nep1 enabled :" + nep1.isEnabled());
console.log("nep2 enabled :" + nep2.isEnabled());
console.log("nep3 enabled :" + nep3.isEnabled());
console.log("trad_nep1 enabled :" + trad_nep1.isEnabled());
console.log("trad_nep2 enabled :" + trad_nep2.isEnabled());
console.log("trad_nep3 enabled :" + trad_nep3.isEnabled());
</script>
</body>
</html>
70 changes: 70 additions & 0 deletions src/dom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { fetchLayout, defaultLayout } from "./layouts";

function wrapHandlerwithLayout(layout) {
function isValidTarget(target) {
return target.type === "text" || target.type === "textarea";
}

const handler = function handleKeypress(event) {
if (isValidTarget(event.target)) {
const formattedKey = layout.formatKey(event.key);
if (formattedKey) {
event.preventDefault();
event.stopPropagation();

const selectionStart = event.target.selectionStart;
const selectionEnd = event.target.selectionEnd;

const beforeSelection = event.target.value.substring(0, selectionStart);
const afterSelection = event.target.value.substring(selectionEnd);

event.target.value = beforeSelection + formattedKey + afterSelection;
const newSelectionPos = selectionStart + formattedKey.length;

event.target.setSelectionRange(newSelectionPos, newSelectionPos);
}
}
};

return handler;
}

export function interceptElementById(dirtyIdSelector, dirtyOptions) {
const defaultOptions = {
layout: defaultLayout,
enable: true,
};

const options = { ...defaultOptions, ...dirtyOptions };
const selector = String(dirtyIdSelector);
const el = document.getElementById(selector);

const layout = fetchLayout(options.layout);
const handler = wrapHandlerwithLayout(layout);
var enabled = false;

if (options.enable) {
enable();
}

function enable() {
el.addEventListener("keypress", handler);
enabled = true;
}

function disable() {
el.removeEventListener("keypress", handler);
enabled = false;
}

function isEnabled() {
return enabled;
}

return {
el: el,
enable: enable,
disable: disable,
isEnabled: isEnabled,
};
}
13 changes: 13 additions & 0 deletions src/format.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { fetchLayout, defaultLayout } from "./layouts";

export function format(dirtyStr, dirtyOptions) {
const defaultOptions = {
layout: defaultLayout,
};
const text = String(dirtyStr);
const options = { ...defaultOptions, ...dirtyOptions };

const layout = fetchLayout(options.layout);

return Array.from(text, (c) => layout.formatKey(c) || c).join("");
}
86 changes: 4 additions & 82 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,88 +1,10 @@
import layouts from "./layouts";

const defaultLayout = layouts.romanized;

function format(dirtyStr, dirtyOptions) {
const str = String(dirtyStr);
const options = dirtyOptions || {};

const layout = options.layout || defaultLayout;

return layout.format(str);
}

function wrapHandlerwithLayout(layout) {
function validTarget(target) {
return target.type === "text" || target.type === "textarea";
}

const handler = function handleKeypress(event) {
if (validTarget(event.target)) {
const formattedKey = layout.formatKey(event.key);
if (formattedKey) {
event.preventDefault();
event.stopPropagation();

const selectionStart = event.target.selectionStart;
const selectionEnd = event.target.selectionEnd;

const beforeSelection = event.target.value.substring(0, selectionStart);
const afterSelection = event.target.value.substring(selectionEnd);

event.target.value = beforeSelection + formattedKey + afterSelection;
const newSelectionPos = selectionStart + formattedKey.length;

event.target.setSelectionRange(newSelectionPos, newSelectionPos);
}
}
};

return handler;
}

function interceptElementById(dirtyIdSelector, dirtyOptions) {
const defaultOptions = {
layout: defaultLayout,
enable: true,
};

const options = { ...defaultOptions, ...dirtyOptions };
const selector = String(dirtyIdSelector);
const el = document.getElementById(selector);

var layout = options.layout;
var handler = wrapHandlerwithLayout(layout);
var enabled = false;

if (options.enable) {
enable();
}

function enable() {
el.addEventListener("keypress", handler);
enabled = true;
}

function disable() {
el.removeEventListener("keypress", handler);
enabled = false;
}

function isEnabled() {
return enabled;
}

return {
el: el,
enable: enable,
disable: disable,
isEnabled: isEnabled,
};
}
import { format } from "./format";
import { availableLayouts } from "./layouts";
import { interceptElementById } from "./dom";

const nepalify = {
layouts: layouts,
format: format,
availableLayouts: availableLayouts,
interceptElementById: interceptElementById,
};

Expand Down
Loading

0 comments on commit 177f183

Please sign in to comment.