Intro
For example, when I use table elements, I only can select horizontally.
Index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="../css/home_page.css" >
</head>
<body>
<div>First element</div>
<table id="table_area">
<tr class="table_row">
<td class="table_cell">1.Hello</td>
<td class="table_cell">1.World</td>
<td class="table_cell"></td>
<td class="table_cell"></td>
<td class="table_cell"></td>
<td class="table_cell">1.!!!</td>
</tr>
<tr class="table_row">
<td class="table_cell">2.Hello</td>
<td class="table_cell">2.World</td>
<td class="table_cell"></td>
<td class="table_cell"></td>
<td class="table_cell"></td>
<td class="table_cell">2.!!!</td>
</tr>
</table>
</body>
</html>
home_page.css
#table_area{
margin: 1%;
width: 10vw;
height: 5vh;
border: 1px solid black;
border-collapse: collapse;
}
.table_cell{
border: 1px solid black;
border-collapse: collapse;
min-width: 2vw;
}
But in this time, I want to select each column.
Environments
- Node.js ver.15.0.0
package.json
{
"browserslist": [
"last 2 version"
],
"scripts": {
"css": "npx postcss postcss -c postcss.config.js -d wwwroot/css -w"
},
"dependencies": {
"autoprefixer": "^10.0.1",
"postcss": "^8.1.2",
"postcss-cli": "^8.1.0",
"postcss-import": "^13.0.0",
"precss": "^4.0.0",
"ts-loader": "^8.0.6",
"tsc": "^1.20150623.0",
"typescript": "^4.0.3",
"webpack": "^5.2.0",
"webpack-cli": "^4.1.0"
}
}
[PostCSS] Input Error: You must pass a valid list of files to parse
On my Surface 6, when I tried executing compiling PostCSS command "npx postcss postcss/*.css -c postcss.config.js -d wwwroot/css", I got an error.
Input Error: You must pass a valid list of files to parse
But on my another PC didn't occurr.
Though I haven't know why, I could avoid this error by changing the command to "npx postcss postcss -c postcss.config.js -d wwwroot/css"
("postcss" was a directory name).
Arrange elements vertically
Because I want to make elements select vertically, I have to arrange them vertically.
This time, I use Flexbox.
Index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="../css/home_page.css" >
</head>
<body>
...
<div id="item_area">
<div class="item_column">
<div class="item_cell">1. hello</div>
<div class="item_cell">1. world</div>
<div class="item_cell"></div>
<div class="item_cell"></div>
<div class="item_cell"></div>
<div class="item_cell">1. !!!</div>
</div>
<div class="item_column">
<div class="item_cell">2. hello</div>
<div class="item_cell"></div>
<div class="item_cell"></div>
<div class="item_cell"></div>
<div class="item_cell">2. world</div>
<div class="item_cell">2. !!!</div>
</div>
</div>
</body>
</html>
home_page.css
...
#item_area{
display: flex;
flex-direction: row;
}
.item_column{
display: flex;
flex-direction: column;
}
.item_cell{
border: 1px solid black;
display: flex;
align-items: center;
justify-content: center;
width: 10vw;
height: 5vh;
}
To compile PostCSS, I execute "npm run css" or "npx postcss postcss -c postcss.config.js -d wwwroot/css".
Now I can select vertically.
Copy & paste
One problem is occurred when I try copying the elements and pasting another place(For example on an Excel sheet).
The copied values are like below.
The empty values and columns are ignored.
Now I try to edit copied values by TypeScript.
tsconfig.json
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"lib": ["DOM", "ES2015"],
"outDir": "./wwwroot/js",
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"alwaysStrict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}
webpack.config.js
var path = require('path');
module.exports = {
mode: 'development',
entry: {
'homePage': './ts/home.page.ts',
},
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
},
resolve: {
extensions: [ '.tsx', '.ts', '.js' ]
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, './wwwroot/js'),
library: 'Page',
libraryTarget: 'umd'
}
};
Index.html
...
<script src="../js/homePage.bundle.js"></script>
<script>
(function() {
Page.init();
})();
</script>
</body>
</html>
home.page.ts
import { CopyCellValues } from "./copy-cell-values";
var ctrlActive: boolean = false;
export function init()
{
// track Ctrl + C
document.body.addEventListener('keydown', e => handleKeyDownEvents(e));
document.body.addEventListener('keyup', e => handleKeyUpEvents(e));
}
function handleKeyDownEvents(e: KeyboardEvent)
{
switch(e.key)
{
case 'Control':
ctrlActive = true;
break;
}
}
function handleKeyUpEvents(e: KeyboardEvent)
{
switch(e.key)
{
case 'c':
copyToClipboard();
break;
case 'Control':
ctrlActive = false;
break;
}
}
function copyToClipboard()
{
if (ctrlActive === false)
{
return;
}
const copyCellValues = new CopyCellValues();
copyCellValues.copyToClipboard();
}
copy-cell-values.ts
export class CopyCellValues {
public copyToClipboard() {
const selection = window.getSelection();
if(selection == null ||
selection.rangeCount <= 0) {
console.warn("no selection");
return;
}
const targetTexts = this.getSelectedTexts(selection.getRangeAt(0).cloneContents());
this.copy(targetTexts);
}
private getSelectedTexts(selectedDom: DocumentFragment): Array<Array<string>> {
let parent: HTMLElement|null = null;
for(let i = 0; i < selectedDom.childNodes.length; i++) {
const targetElement = selectedDom.childNodes[i] as HTMLElement;
if (targetElement?.id === 'item_area') {
parent = targetElement;
break;
}
}
if(parent == null) {
// when select inside "item_area"
return this.getTexts(selectedDom.childNodes);
}
// when select outside "item_area"
return this.getTexts(parent.childNodes);
}
private getTexts(parentNodes: NodeListOf<ChildNode>): Array<Array<string>> {
let results = new Array<Array<string>>();
for(let i = 0; i < parentNodes.length; i++) {
const targetElement = parentNodes[i] as HTMLElement;
if (targetElement.className !== 'item_column') {
continue;
}
let gotTexts: Array<string>| null = null;
for(let j = 0; j < targetElement.childNodes.length; j++) {
let child = targetElement.childNodes[j] as HTMLElement;
if (child.className !== 'item_cell' ||
child.textContent == null) {
continue;
}
if (gotTexts == null) {
gotTexts = new Array<string>();
}
gotTexts.push(child.textContent);
}
if(gotTexts == null) {
continue;
}
results.push(gotTexts);
}
return this.addEmptyRows(results, this.getMaxRowCount(results));
}
private getMaxRowCount(texts: Array<Array<string>>): number {
let result = 0;
for(const columnItems of texts) {
const rowCount = columnItems.length;
if (result < rowCount) {
result = rowCount;
}
}
return result;
}
private addEmptyRows(texts: Array<Array<string>>, rowCount: number): Array<Array<string>> {
if(texts.length <= 0) {
return texts;
}
if (texts[0].length < rowCount) {
const addedFirstTexts = new Array<string>();
const addEmptyCount = rowCount - texts[0].length;
for(let i = 0; i < addEmptyCount; i++) {
addedFirstTexts.push('');
}
for(const t of texts[0]) {
addedFirstTexts.push(t);
}
texts[0] = addedFirstTexts;
}
if(texts.length > 1) {
const targetIndex = texts.length - 1;
if (texts[targetIndex].length < rowCount) {
const addedLastTexts = new Array<string>();
const addEmptyCount = rowCount - texts[targetIndex].length;
for(const t of texts[0]) {
addedLastTexts.push(t);
}
for(let i = 0; i < addEmptyCount; i++) {
addedLastTexts.push('');
}
texts[targetIndex] = addedLastTexts;
}
}
return texts;
}
private copy(texts: Array<Array<string>>) {
let result = '';
const rowCount = texts[0].length;
for(let i = 0; i < rowCount; i++) {
let rowText = '';
for(const columnItem of texts) {
if (rowText !== '') {
rowText += '\t';
}
rowText += columnItem[i];
}
result += rowText;
result += '\n';
}
navigator.clipboard.writeText(result);
}
}
I can get selected elements by "getSelection".
And I can rewrite the clipboard values by "navigator.clipboard.writeText".
Editable elements
Now I try making the elements editable.
I can use "contentEditable" to do this.
But when I make the elements editable, I get another problem.
When I focus the editable element, I can't select other elements.
So I have to distinguish edit and select operations.
I decide when I double click an element, the editing mode is started.
After that, if I click other elements, the editing mode is stopped, and the selecting mode is started.
Maybe I can write more simpler codes with jQuery plugin or RxJs or other libraries.
But in this time, I try using only TypeScript.
home.page.ts
import { ClickEventHandler } from "./click-event-handler";
import { CopyCellValues } from "./copy-cell-values";
var ctrlActive: boolean = false;
export function init()
{
...
const clickEvent = new ClickEventHandler();
clickEvent.init();
}
...
click-event-handler.ts
export class ClickEventHandler {
private clickedElement: HTMLElement|null = null;
private lastClickeTime: number = 0;
private editing: boolean = false;
public init() {
document.onclick = e => this.handleClickEvent(e);
}
private handleClickEvent(e: MouseEvent){
const target = e.target as HTMLElement;
if(target.className !== 'item_cell') {
if (this.clickedElement != null) {
this.clickedElement.contentEditable = 'false';
}
this.clickedElement = null;
this.editing = false;
this.lastClickeTime = 0;
return;
}
const clickedTime = (new Date()).getTime();
if (this.editing === false &&
this.clickedElement != null) {
if ((clickedTime - this.lastClickeTime) > 1000) {
this.clickedElement.contentEditable = 'false';
this.clickedElement = null;
}
}
this.lastClickeTime = clickedTime;
if (target === this.clickedElement) {
target.contentEditable = 'true';
target.focus();
this.editing = true;
return;
} else {
if (this.clickedElement != null) {
this.clickedElement.contentEditable = 'false';
}
target.contentEditable = 'false';
this.editing = false;
}
this.clickedElement = e.target as HTMLElement;
}
}
Top comments (0)