linux
network programming
http
CGI
Author: CrazyMonkey
E-mail: kccddb@gmail.com
Date: 20230222
Copyright: CC BY-NC-SA
現今 HTTP 除了 HTTP 1.0 與 HTTP 1.1 的差別外 還有一重要的改進: HTTP persistent connection (HTTP keep-alive)
HTTP persistent connection, is an instruction that allows a single TCP connection to remain open for multiple HTTP requests and responses.
您可以使用 Wireshark 幫助自己了解此現象!
詳見:
RFC 2616 Hypertext Transfer Protocol – HTTP/1.1
RFC 2616:
Persistent HTTP connections have a number of advantages:
- By opening and closing fewer TCP connections, CPU time is saved
in routers and hosts (clients, servers, proxies, gateways,
tunnels, or caches), and memory used for TCP protocol control
blocks can be saved in hosts.
- HTTP requests and responses can be pipelined on a connection.
Pipelining allows a client to make multiple requests without
waiting for each response, allowing a single TCP connection to
be used much more efficiently, with much lower elapsed time.
- Network congestion is reduced by reducing the number of packets
caused by TCP opens, and by allowing TCP sufficient time to
determine the congestion state of the network.
- Latency on subsequent requests is reduced since there is no time
spent in TCP's connection opening handshake.
- HTTP can evolve more gracefully, since errors can be reported
without the penalty of closing the TCP connection. Clients using
future versions of HTTP might optimistically try a new feature,
but if communicating with an older server, retry with old
semantics after an error is reported.
*
此例子 這主要用 fork() 完成也沒有處理 timeout! 經不起壓力測試的!! demo 學習用 !
練習 TRY IT, FIXME
int dup2(int oldfd, int newfd);
shttpcgi.c
gcc shttpcgi.c -o shttpcgi
shttpcgi 9000
TEST CGI:
shttpcgi 9000 1
Author:
WhoAmI 2019
以下連結請務必研讀(引用自 stackoverflow)
linux man dup2
linux man execvp
execve - execute program
linux man setenv
注意 backlog 的意義:
The backlog argument defines the maximum length to which the queue of pending connections for sockfd may grow.
TCP SYN flood, server 會出問題, Why?
int listen(int sockfd, int backlog);
很重要的理解 網路程式設計 的例子, 學以致用, 一定要實作
當 process 執行時 事先 open 了 stdin (0), stdout (1), stderr (2)
Please study Probability, Statistics, OS and Algorithms.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/stat.h>
#include <fcntl.h>
#define debug001(x)
#define debug000(x) x
//CHECK THIS
#define FORK 1
#define CYGWIN 1
#define READTIMEOUT 3
#define CANNOTREAD -110
//gcc httpcgi.c -o httpcgi
#define debug(x) x
#define HTTPHEADERLEN 1024
void PANIC(char* msg);
#define PANIC(msg) { perror(msg); exit(EXIT_FAILURE); }
static void sig_handler(int signo)
{
pid_t pid;
int stat;
switch(signo)
{
case SIGCHLD:
printf("SIGCHLD=%d\n",signo);
pid=waitpid(0,&stat,WNOHANG);
break;
case SIGINT:
printf("SIGINT=%d\n",signo);
break;
case SIGALRM:
printf("Got SIGALRM=%d, exit!\n",signo);
exit( EXIT_FAILURE);
break;
default:
printf("signal=%d\n",signo);
}
return;
}
static off_t getfilesize(char *fname)
{
struct stat sb;
/* off_t: total size, in bytes */
//%lld long long int
if (stat(fname, &sb) == -1)
{
perror("stat");
return -1;
}
debug(printf("File size:%lld bytes\n",(long long) sb.st_size));
return sb.st_size;
}
char *readfile(char *fname, int *size)
{
off_t ssize;
char *mem;
int fd;
int n;
mem=NULL;
ssize=getfilesize(fname);
if(ssize>0)
{
fd=open(fname, O_RDONLY);
if(fd>0)
{
mem=malloc(ssize);
if(mem)
{
n= read(fd,mem,ssize);
if(n>0)
{
*size=n;
}
else
{
*size=0;
}
close(fd);
return mem;
}
else
{
close(fd);
}
}
else
{
printf("Cannot open %s size=%lld",fname,ssize); //%lld long long int
}
}else{
printf("Cannot find %s\n",fname);
return CANNOTREAD;
}
return NULL;
}
static void pdebug(char *argv[])
{
int i;
for(i=0;argv[i]!=NULL;i++)
{
printf("%s \n",argv[i]);
}
}
static void http( struct sockaddr_in *client_addr )
{
char buffer[1512];
char port[10];
int pid;
#if CYGWIN
//char *argv[3]={"./findp.exe","./findp.exe",0};
char *argv[3]={"ls","-l",0};
#else
char *argv[3]={"./cgi","./cgi",0};
#endif
#if DEBUG
read(0,buffer,sizeof(buffer));
printf("%s\n",buffer);
#endif
setenv("REMOTE_ADDR", inet_ntoa(client_addr->sin_addr), 1);
sprintf(port,"%d",ntohs(client_addr->sin_port));
setenv("REMOTE_PORT", port, 1);
#if DEBUG
pdebug(argv);
#endif
pid=getpid();
printf("My pid is %d\n",pid);
if(pid>0)
{
printf("execvp...<BR>\n");
pdebug(argv);
execvp(argv[0], argv);
}
else
{
printf("This is the new child(pid=%d) <BR>\n",getpid());
exit(0);
}
}
static int httpResopnseBody(int fd)
{
char *body="<html><body><h1>It works!</h1></body></html>";
int n;
//FIXME: Locale
n=write(fd,body,strlen(body));
return n;
}
static int httpResponse(int fd)
{
int n;
char *header="HTTP/1.1 200 OK\nContent-Type: text/html; charset=UTF-8\r\n\r\n";
//FIXME: Locale
n=write(fd,header,strlen(header));//write header
n=httpResopnseBody(fd);
return n;
}
static ssize_t readln(int sockfd, char *buf,size_t len, int time_out)
{
int n;
fd_set readfds;
struct timeval tval;
ssize_t total;
int ret;
char *pc;
total=0;
FD_ZERO(&readfds);
do
{
FD_SET(sockfd, &readfds);
tval.tv_sec = time_out;
tval.tv_usec = 0;
if(time_out<=0)
{
if(( n = select(sockfd+1, &readfds, NULL, NULL, NULL))<0)return -1;
}
else
{
if ( (n = select(sockfd+1, &readfds, NULL, NULL, time_out ? &tval : NULL)) == 0)
{
errno = ETIMEDOUT;
printf("Read timeout!\n");
return(-1);
}
}
ret=read(sockfd,buf+total,1); //Notice that '\n'
pc= buf+total;
if(ret>0)
{
total+=ret;
if(*pc=='\n')break;
}
else if(ret==0)
{
//eof
break;
}
else
{
return -1;
}
}
while(total<len);
if(total<len)buf[total]=0;
else buf[len-1]=0;
return total;
}
static int dump_http(int fd)
{
//ssize_t read(int fd, void *buf, size_t count);
char buf[HTTPHEADERLEN];
ssize_t n;
size_t count;
char *mem;
int size;
int line=0;
char *fname,*p;
char *header_html="HTTP/1.1 200 OK\nContent-Type: text/html; charset=UTF-8\r\n\r\n";
char *header_jpg="HTTP/1.1 200 OK\nContent-Type: image/jpeg; charset=UTF-8\r\n\r\n";
char *header;
count=sizeof(buf)-1;
//FIXME: without timeout
do
{
n=readln(fd,buf, count,READTIMEOUT);
if(n>0)
{
buf[n]=0; //FIXME: CHECK THIS
debug001(printf("[%d][%s]",line,buf));
debug000(printf("%s",buf));
if(line==0)
{
//fname=&buf[1];
//case 0: files
p=strchr(buf,' ');
if(p)fname=p+2;
p=strchr(fname,' ');
if(p)*p=0;
debug001(printf("Read %s\n",fname));
header=header_html;
if(strstr(fname,".jpg"))header=header_jpg;
if(strstr(fname,".png"))header=header_jpg;
mem=readfile(fname,&size);
if(mem)
{
debug001(printf("Write %d bytes to %d...\n",size,fd));
write(fd,header,strlen(header));
write(fd,mem,size);
free(mem);
}else{
//cannot read file
return CANNOTREAD;
}
}
//case 1: open connection
//-----------------------------------------------------
//----------------------------------------------------------
line++;
}
else return n;
}
while(n>0);
return n;
}
static int process_http(int fd)
{
int httpret=0;
httpret=dump_http(fd);
httpret=httpResponse(fd);
return httpret;
}//process_http
int main(int argc, char *argv[])
{
int sd;
int port;
int new_fd;
int len;
int state;
int pid;
int httpret;
int size;
char *fname="play.txt";
char *mem;
int docgi=0;
struct sockaddr_in server_addr,client_addr;
if(argc>1)port=atoi(argv[1]);
else port=80;
if(argc==3)docgi=atoi(argv[2]);
signal (SIGCHLD, sig_handler);
//signal (SIGINT,sig_handler); //TRY IT!
// signal (SIGALRM,sig_handler);//TRY IT!
sd = socket(PF_INET, SOCK_STREAM, 0);
memset(&server_addr,0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = INADDR_ANY;
if ( bind(sd, (struct sockaddr*)&server_addr, sizeof(server_addr)) != 0 )
PANIC("Bind");
if ( listen(sd, 20) != 0 )
PANIC("Listen");
printf("Start server at port %d id=%d...",port,sd);
while (1)
{
len = sizeof(client_addr);
new_fd = accept(sd, (struct sockaddr*)&client_addr, &len);
printf("%d,Client from %s:%d\n", new_fd,inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
if ( new_fd < 0 )
perror("Accept");
else
{
pid=fork();
if ( pid==0 )
{
//child
close(sd);
httpret=process_http(new_fd);
if(httpret<=0 || docgi>0)
{
dup2(new_fd, 0);
dup2(new_fd, 1);
dup2(new_fd, 2);
close(new_fd);
http( &client_addr );
wait(&state);
}
exit(EXIT_SUCCESS );
}
close(new_fd);
}
}
exit(EXIT_SUCCESS );
}
cgi.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define QUERY_STRING getenv("QUERY_STRING")
#define CONTENT_TYPE getenv("CONTENT_TYPE")
#define CONTENT_LENGTH getenv("CONTENT_LENGTH")
#define REQUEST_METHOD getenv("REQUEST_METHOD")
#define REMOTE_HOST getenv("REMOTE_HOST")
#define REMOTE_ADDR getenv("REMOTE_ADDR")
#define REMOTE_PORT getenv("REMOTE_PORT")
print_environment()
{
printf("<B>REQUEST_METHOD:</B> %s<BR>\n",REQUEST_METHOD);
printf("<B>CONTENT_TYPE:</B> %s<BR>\n",CONTENT_TYPE);
printf("<B>CONTENT_LENGTH:</B> %s<BR>\n",CONTENT_LENGTH);
printf("<B>QUERY_STRING:</B> %s<BR>\n",QUERY_STRING);
printf("<B>REMOTE_HOST:</B> %s<BR>\n",REMOTE_HOST);
printf("<B>REMOTE_ADDR:</B> %s<BR>\n",REMOTE_ADDR);
}
static char *header="HTTP/1.1 200 OK\nContent-Type: text/html; charset=UTF-8\r\n\r\n";
int main(int argc, char* argv[])
{
time_t t;
t=time(NULL);
printf("%s",header);
printf("<html><body>");
printf("<BR>Hello CGI!<BR> %s <BR><p style='color:blue;'>[Your IP:PORT %s:%s]</p><BR>",ctime(&t ),REMOTE_ADDR, REMOTE_PORT);
print_environment();
printf("</body></html>\n\n");
}
Read Around:
Show the environment variables of a running process in Linux
How to Set Environment Variables in Linux
Environment Variables in Linux/Unix
e.g.,
kclai@ubuntu16:/proc/1867$ sudo cat environ
[sudo] password for kclai:
XDG_SESSION_ID=3SHELL=/bin/bashSSH_CLIENT=192.168.1.10 5376 22USER=kclaiMAIL=/var/mail/kclaiPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/binPWD=/home/kclaiLANG=en_US.UTF-8SHLVL=1HOME=/home/kclaiLOGNAME=kclaiSSH_CONNECTION=192.168.1.10 5376 192.168.1.31 22XDG_RUNTIME_DIR=/run/user/1000_=/usr/lib/openssh/sftp-serverkclai@ubuntu16:/proc/1867$
Homewok 實作與思考的問題
dup2(new_fd, 0);
dup2(new_fd, 1);
dup2(new_fd, 2);
close(new_fd);
Why? I/O redirection 運用 Linux system call 的實作方法 (redirect, pipe, …)
附註:
因圖中有 AJAX(Asynchronous JavaScript and XML)
盡可能 使用 AJAX POST 不要用傳統 FORM submit!
AJAX: Update a web page without reloading the page
盡可能 用 CSS
有些 夾雜 格式 於 HTML 中 方便學習, 但卻是不當的方法
不要期待 團隊裡成員 都懂 Javascript, PHP. 例如 美工可能不懂~
這是故意設計的例子把 callback, getElementsByName 加入
AJAX POST, callback and getElementsByName
<!DOCTYPE html>
<!--Author: WhoAmI -->
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<style>
body {
background-color: lightblue;
}
.redButton {
background-color:red;
}
</style>
</head>
<body>
<h2>盡可能 使用 AJAX POST 不要用傳統 FORM submit!</h2>
<h2>AJAX POST, callback and getElementsByName (call tdemo.php)</h2>
First Name: <input name="tName" type="text" value="Linux"><br>
First Name: <input name="tName" type="text" value="John"><br>
city: <input name="cName" type="text" value="taichung"><br>
city : <input name="cName" type="text" value="taipei">
<button onclick="searchdb()" class="redButton" >AJAX POST</button>
<!-- Display Server Response -->
<div id="result"></div>
<script>
//AJAX
//callback function
function myCallback(xmldoc){
document.getElementById("result").innerHTML=xmldoc.responseText;
}
function myPost(url, data, callback) {
var xmlDoc = new XMLHttpRequest();
xmlDoc.open('POST', url, true);
xmlDoc.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlDoc.onreadystatechange = function() {
if (xmlDoc.readyState === 4 && xmlDoc.status === 200) {
callback(xmlDoc);
}
}
xmlDoc.send(data);
}
//setup POST data
function searchdb() {
//getElementsByName():returns a collection of all elements ( NodeList )
list=document.getElementsByName("tName");
console.error(list);
var tvalue=[];
list.forEach(
function(currentValue, currentIndex, listObj) {
tvalue.push(currentValue.value);
console.error(tvalue+' ::'+currentValue + ', ' + currentIndex + ', ' + this);
},
'myThisArg'
);
list=document.getElementsByName("cName");
console.error(list);
var cvalue=[];
list.forEach(
function(currentValue, currentIndex, listObj) {
cvalue.push(currentValue.value);
console.error(cvalue+' ::'+currentValue + ', ' + currentIndex + ', ' + this);
},
'myThisArg'
);
query='tName='+tvalue+'&cName='+cvalue;
//write your jdemo.php
myPost('tdemo.php',query,myCallback);
}
</script>
</body>
</html>
tdemo.php
<?php
if(isset($_POST["tName"])){
$tName=$_POST["tName"];
echo "Input:<br>";
print_r($tName);
}
echo "<br>";
if(isset($_POST["cName"])){
$cName=$_POST["cName"];
echo "Select:<br>";
print_r($cName);
}
JavaScript
定義 class 方便使用 CSS
jelems-1.0.js
function crSelect(name,array,tarray=null,myclass="default-class"){
var selectList = document.createElement("select");
selectList.className = myclass;
selectList.name=name;
//Create and append the options
for (var i = 0; i < array.length; i++) {
var option = document.createElement("option");
option.value = array[i];
if(tarray===null)
option.text = array[i];
else option.text = tarray[i];
selectList.appendChild(option);
}
return selectList;
}
function crBtn(name,click=null,myclass="default-class")
{
var e=document.createElement("INPUT");
e.setAttribute("type","button");
e.className=myclass;
e.value=name;
if(click!==null)e.addEventListener("click",click);
return e;
}
function crImg(src,click=null,myclass="default-class")
{
var e=document.createElement("INPUT");
e.setAttribute("type","image");
e.src=src; //"img/enter.png";
if(click!==null)e.addEventListener("click",click);
e.className=myclass;
return e;
}
function createImage(src,click=null,myclass="default-class"){
var node = document.createElement('img');
node.src = src;
node.className=myclass;
if(click!==null)node.addEventListener("click",click);
return node;
}
function crList(click=null,myclass="default-class"){
var data="item 1 click it!";
var node = document.createElement('li');
node.appendChild(document.createTextNode(data));
if(click!==null)node.addEventListener("click",click);
node.className=myclass;
return node;
}
function crLists(items,click=null,myclass="default-class"){
var ul = document.createElement('ul');
ul.setAttribute("class", "lists");
items.forEach((data)=>{
let li=document.createElement('li');
li.className=myclass;
if( data.nodeType == Node.ELEMENT_NODE){
li.appendChild(data);
}else {
if(typeof data ==="string"){
let isimg= data.match(/\.(jpeg|jpg|png|gif|bmp)/i);
if(isimg){
//automatic convert to image
let img=createImage(data);
li.appendChild(img);
}else
li.appendChild(document.createTextNode(data));
}else li.appendChild(document.createTextNode(data));
}
//li.appendChild(document.createTextNode(data));
// console.warn(ul);
if(click!==null)li.addEventListener("click",click);
ul.appendChild(li);
});
ul.className=myclass;
return ul;
}
//creatre a TR via array
function crTR(fields,click=null,myclass="default-class"){
let td;
let tr = document.createElement('tr');
fields.forEach((field)=>{
td=document.createElement('td');
if( field.nodeType == Node.ELEMENT_NODE){
td.appendChild(field);
}else{
if(typeof field ==="string"){
let isimg= field.match(/\.(jpeg|jpg|png|gif|bmp)/i);
if(isimg){
//automatic convert to image
let img=createImage(field);
td.appendChild(img);
}else
td.appendChild(document.createTextNode(field));
}
}
tr.appendChild(td);
});
if(click===null){
}else tr.addEventListener("click",click);
tr.className=myclass;
return tr;
}
//creatre a TR via array
function crTable(cfields,click=null,myclass="default-class"){
let table=document.createElement('table');
cfields.forEach((fields)=>{
let tr= crTR(fields,click,myclass);
table.appendChild(tr);
}
);
table.className=myclass;
return table;
}
function insertRow(index=0,table,fields,myclass="default-class")
{
//index=0 Insert new row(s) at the first position of a table
row=table.insertRow(index);
let i=0;
fields.forEach((field)=>{
cell=row.insertCell(i);
//cell.appendChild(document.createTextNode(field));
if( field.nodeType == Node.ELEMENT_NODE){
cell.appendChild(field);
}else{
if(typeof field ==="string"){
let isimg= field.match(/\.(jpeg|jpg|png|gif|bmp)/i);
if(isimg){
//automatic convert to image
let img=createImage(field);
cell.appendChild(img);
}else
cell.appendChild(document.createTextNode(field));
}
}
i++;
});
}
//creatre a TH via array
function crTH(fields,click=null,myclass="default-class"){
let td;
let tr = document.createElement('th');
fields.forEach((field)=>{
td=document.createElement('td');
if( field.nodeType == Node.ELEMENT_NODE){
td.appendChild(field);
}else{
td.appendChild(document.createTextNode(field))
}
tr.appendChild(td);
});
if(click===null){
}else tr.addEventListener("click",click);
tr.className=myclass;
return tr;
}
function getCells(elem,callback=null)
{
var result=[];
for (let i = 0; i < elem.length; i++) {
if(callback===null){
}else callback(elem[i]);
result.push(elem[i].innerHTML);
}
console.log(result);
return result;
}
function genhref(href, linkname, click=null, myclass="default-class"){
var a = document.createElement('a');
// Create the text node for anchor element.
var link = document.createTextNode(linkname);
// Append the text node to anchor element.
a.appendChild(link);
// Set the title.
a.title = linkname;
a.href =href;
if(click!=null)a.addEventListener("click",click);
a.className=myclass;
console.warn(a);
//a.appendChild(link);
return a;
}
function crElems(fields,etype='div',click=null,myclass="default-class"){
var e=document.createElement(etype);
// let aa=[];
// aa=fields;
// console.warn("fields:"+fields);
// console.error(fields);
if( Array.isArray(fields)) {
fields.forEach((field)=>{
if( field.nodeType == Node.ELEMENT_NODE){
e.appendChild(field);
}
});
}else if( fields.nodeType == Node.ELEMENT_NODE){
//console.warn("element:"+fields);
e.appendChild(fields);
}else {
//other ?
console.warn("others:"+fields);
}
e.className=myclass;
return e;
}
function crDivs(cfields,click=null,myclass="default-class"){
let div=document.createElement('div');
cfields.forEach((fields)=>{
//console.warn("crDivs:"+fields);
let el= crElems(fields,'div',click,myclass);
div.appendChild(el);
}
);
div.className=myclass;
//console.warn("final:"+div);
return div;
}
function deleteID(id){
var e=null;
var child;
if( id.nodeType == Node.ELEMENT_NODE)child=id;
else
child=document.getElementById(id);
try{
e=child.parentNode.removeChild(child);
}catch(e){
console.warn(e);
}
return e;
}
function appendElement(id,e){
if( id.nodeType == Node.ELEMENT_NODE){
return id.appendChild(e);
}else return document.getElementById(id).appendChild(e);
}
function crInput(type,name,value='',myclass="default-class",elem='input'){
//crInput('TEXT','NAME',null,'CNAME');
var input = document.createElement(elem);
input.setAttribute("type", type);
if(type.toLowerCase()=='image'){
input.src=value;
}else{
input.value=value;
}
//if(click!=null)input.click=click;
input.className = myclass; // set the CSS class
input.name=name;
return input;
}
使用方法例如:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<script src="js/jelems-1.0.js"></script>
<style>
body {
background-color: lightblue;
}
.MYTABLE {
background-color :#99ccff;
text-align :center;
width:100%;
color:green;
border: 1px solid black;
text-align: left;
}
.MYTABLE2 {
background-color :#99ccff;
text-align :center;
width:100%;
color:green;
border: 1px solid black;
text-align: center;
}
</style>
</head>
<body>
<div id='showit'></div><div id='showit2'></div>
<script>
let tableitems=[['row0','img/apple.jpg'],['row1','cell1'],['row2','cell1']];
let table=crTable(tableitems,null,'MYTABLE');
document.getElementById('showit').appendChild(table);
let tableitems2=[['img/apple.jpg'],['caption- apple'],['img/banana.jpg'],['Fig 2. banana'],['row2','cell1']];
let table2=crTable(tableitems2,null,'MYTABLE2');
document.getElementById('showit2').appendChild(table2);
</script>
</body>
</html>
ctable 1.1.js
/*
Licence:GPL
Author: WhoAmI
Date: 2021/01/01
Version:1.1
e-mail:
Notice that setup cid( class ID) and table ID
See also HTMLTableElement.rows
*/
//cTable 20220701 via WhoAmI
function display(id,elem,callback=null){
var v;
if(callback!==null)v=callback(elem);
else v=elem;
if(typeof elem ==='string')document.getElementById(id).innerText=v;
if(typeof elem ==='object') return document.getElementById(id).appendChild(v);
return v;
}
class cTable {
parentid;
tobj;
border=''; //'1px solid black';
title;
rowclick=undefined; //callback
//Notice: class id!!!!
elementcid;
//element ID
elementid;
firstrow;
constructor(cid,tid='GEN_TABLEID'){
this.elementcid=cid;
this.elementid=tid;
//default parrent's id
this.parentid=document.body;
}
//return parent
show(id=this.parentid){
if(id==='undefined'){
var body= document.body;
}else {
var body=document.getElementById(id);
}
body.appendChild(this.tobj);
return body;
}
//create table element
create(objectArray, fieldTitles,trclass='TR_NAME') {
this.title=fieldTitles;
var _tobj = document.createElement('table');
_tobj.classList.add(this.elementcid);
let thead = document.createElement('thead');
let thr = document.createElement('tr');
this.firstrow=thr;
thr.className=trclass;
if(this.rowclick!==undefined)thr.onclick=this.rowclick;
fieldTitles.forEach((fieldTitle) => {
//console.error(fieldTitle);
let th = document.createElement('th');
th.className=trclass;
th.appendChild(document.createTextNode(fieldTitle));
thr.appendChild(th);
});
thead.appendChild(thr);
_tobj.appendChild(thead);
let tbdy = document.createElement('tbody');
let tr = document.createElement('tr');
objectArray.forEach((object) => {
// console.error(object);
let tr = document.createElement('tr');
tr.className=trclass;
if(this.rowclick!==undefined)tr.onclick=this.rowclick;
let i =0;
this.title.forEach((field) => {
var td = document.createElement('td');
if( object[i].nodeType === Node.ELEMENT_NODE){
td.appendChild((object[i]));
}else{
//find jpg image
// if(object[i].match(/.jpg/g)){
if(object[i].match(/[\/.](gif|jpg|jpeg|tiff|png)$/i)){
let img=this.createImage(object[i]);
td.appendChild(img);
}else{
td.appendChild(document.createTextNode(object[i]));
}
}
tr.appendChild(td);
i++;
});
tbdy.appendChild(tr);
});
_tobj.appendChild(tbdy);
this.tobj=_tobj;
return _tobj;
}
//delete one record
delete(index=0){
var tbdy=this.tobj;
tbdy.deleteRow(index);
return tbdy.rows.length;
}
//select element
createSelect(name,cname,array){
var selectList = document.createElement("select");
selectList.className = cname;
selectList.name=name;
//Create and append the options
for (var i = 0; i < array.length; i++) {
var option = document.createElement("option");
option.value = array[i];
option.text = array[i];
selectList.appendChild(option);
}
return selectList;
}
//img
createImage(src,cname='IMG_CLASS'){
var img = document.createElement('img');
img.src = src;
img.className=cname;
return img;
}
createInput(type,name,cname,elem='input',value=''){
//createInput('TEXT','NAME','CNAME');
var input = document.createElement(elem);
input.setAttribute("type", type);
if(type.toLowerCase()=='image'){
input.src=value;
}else{
input.value=value;
}
input.className = cname; // set the CSS class
input.name=name;
return input;
}
//insert one record
insert(objectArray,trclass='TR_NAME' ){
//let body = document.getElementsByTagName('body')[0];
var tbdy=this.tobj;
objectArray.forEach((object) => {
let tr = document.createElement('tr');
if(this.rowclick!=='undefined')tr.onclick=this.rowclick;
tr.className=trclass;
let i =0;
this.title.forEach((field) => {
//let i =0;
var td = document.createElement('td');
//console.error(field+object[i]);
//check nodType
//console.error(object[i].nodeType);
if( object[i].nodeType === undefined){ //FIXIT!!!!
// if( object[i]!== undefined){ //Node.ELEMENT_NODE
//console.log(object[i].innerHTML);
//td.appendChild((object[i]));
console.log("undefined:"+object[i]);
if(typeof object[i] === "string"){
if(object[i].match(/[\/.](gif|jpg|jpeg|tiff|png)$/i)){
let img=this.createImage(object[i]);
td.appendChild(img);
}else{
td.appendChild(document.createTextNode(object[i]));
}
}else if( object[i].nodeType === Node.ELEMENT_NODE){
td.appendChild((object[i]));
}
}else{
// JS RegExp
if(typeof object[i] === "string") {
console.log(object[i]);
if(object[i].match(/[\/.](gif|jpg|jpeg|tiff|png)$/i)){
let img=this.createImage(object[i]);
td.appendChild(img);
}else{
td.appendChild(document.createTextNode(object[i]));
}
}else if( object[i].nodeType === Node.ELEMENT_NODE){
td.appendChild((object[i]));
}
}
tr.appendChild(td);
i++;
});
/*
*You can try firstChild, lastChild
*
*/
tbdy.appendChild(tr);
});
return this.tobj.rows.length;
}
/*
*
*FIXME!!!
*/
insertBefore(index, objectArray,trclass='TR_NAME' ){
//let body = document.getElementsByTagName('body')[0];
var tbdy=this.tobj;
objectArray.forEach((object) => {
let tr = document.createElement('tr');
if(this.rowclick!=='undefined')tr.onclick=this.rowclick;
tr.className=trclass;
let i =0;
this.title.forEach((field) => {
//let i =0;
var td = document.createElement('td');
//console.error(field+object[i]);
//check nodType
//console.error(object[i].nodeType);
if( object[i].nodeType == undefined){ //FIXIT!!!!
// if( object[i]!== undefined){ //Node.ELEMENT_NODE
//console.log(object[i].innerHTML);
//td.appendChild((object[i]));
td.appendChild(document.createTextNode(object[i]));
}else{
// JS RegExp
if(object[i].match(/[\/.](gif|jpg|jpeg|tiff|png)$/i)){
let img=this.createImage(object[i]);
td.appendChild(img);
}else{
td.appendChild(document.createTextNode(object[i]));
}
}
tr.appendChild(td);
i++;
});
/*
*You can try firstChild, lastChild
*
*myrows = mytable.rows;
*firstRow = mytable.rows[0];
*lastRow = mytable.rows.item(mytable.rows.length-1);
*parentNode
*/
let firstRow=tbdy.rows[index];
firstRow.parentNode.insertBefore(tr,firstRow);
//tbdy.insertBefore(tr,firstRow);
//tbdy.appendChild(tr);
});
return this.tobj.rows.length;
}
} //end of class
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<script src="ctable-1.1.js"></script>
<style>
body {
background-color: lightblue;
}
.IMG_CLASS{
width: 50%;
}
.demodiv {
border-style: solid;
width:80%;
}
.TR_NAME {
background-color: green;
border-style: solid;
}
</style>
</head>
<body>
<h2>ctable.js TEST</h2>
<div id="elem"></div>
<div id="demodiv"></div>
<script>
//demo class cTable
tobj=new cTable('demodiv');
//tobj.border='1px solid black';
//Create INPUT TEborder-style: solid;XT
var input=tobj.createInput('TEXT','tName','CNAME');
//setup onclick on input if you need it
//input.onclick=add;
//Create select
var array=['car','fruit','dog']; //option array
var sel=tobj.createSelect('sName','CNAME',array);
document.getElementById('elem').appendChild(sel);
//Create hidden
var hidden=tobj.createInput('HIDDEN','sName','CNAME');
//setup onclick
//hidden.onclick=add;
//create button
var btn=tobj.createInput('button','bName','BNAME','input','Submit');
//document.body.appendChild(input);
//create checkbox
var chk=tobj.createInput('checkbox','cName','CNAME');
//create image input
var img=tobj.createInput('image','iName','CNAME','input','img/enter.png');
//create image
var image=tobj.createImage('img/banana.jpg');
var ftitle=['--zero--','--one--','--two--','--three--'];
var ffield=['ZERO',image,'TWO','THREE'];
var ffield2=[image,chk,'img/dancing.gif','THREE'];
//var iifield=[input,btn,image,sel];
tabobj=tobj.create([ffield2],ftitle);
tobj.show('demodiv');
var iifield=[input,btn,'img/apple.jpg',sel];
//insert two arrays
console.log(iifield);
let index=tobj.insert([iifield,ffield2]);
//insert textnode
index=tobj.insert([ffield]);
</script>
</body>
</html>
Authors: CrazyDog, CrazyMonkeyemail: kccddb@gmail.comDate: 20230222
Mar 14, 2025Author: \mathcal{CrazyDog}, Ph.D. in Electrical Engineering, NCTUemail: kccddb@gmail.comDate: 20230910
Nov 4, 2024Author: WhoAmI Date: 20230523 email:kccddb@gmail.com Copyright: CC BY-NC-SA 《荀子‧勸學》不積跬步,無以至千里;不積小流,無以成江海。 I. Mutex variables MUST be declared with type pthread_mutex_t, and must be initialized before they can be used. II. 了解 pthread_mutex_lock / pthread_mutex_unlock 與可能問題和代價 III. 程式執行效率與startvation 等問題
Jul 11, 2024Author: WhoAmIemail: kccddb@gmail.com
Dec 6, 2023or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up