2022/07/12

multiple checkbox filter for datatables

最近在練習 datatables 這個好用的工具,他可以搭配 jQueryBootstrap 讓你可以很快的建立有 RWD 的表格,他有非常豐富的 API 可以客製內容,今天示範一下怎麼使用 checkbox 去 filter 出符合的內容。

使用正規式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet"
          href="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.21/css/jquery.dataTables.min.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.21/js/jquery.dataTables.min.js"></script>
    <script>
        $(function() {
            let data = [
                [
                    "Chan",
                    "basketball"
                ],
                [
                    "Phoebe",
                    "volleyball"
                ],
                [
                    "Lucas",
                    "tennis"
                ],
                [
                    "LBJ",
                    "basketball"
                ],
            ];
            let table = $('#data_table').DataTable({
                data: data
            });

            $(':checkbox').on('click', function() {
                let options = $(':checkbox:checked').map(function() {
                    return $(this).val()
                }).get();

                if (options.length === 0) {
                    table.columns(1).search('').draw();
                } else {
                    let regex = options.join('|');

                    table.columns(1).search(regex, true, false).draw();
                }
            });
        });
    </script>
</head>
<body>
<div>
    <label> basketball
        <input type="checkbox" value="basketball">
    </label>
    <label> volleyball
        <input type="checkbox" value="volleyball">
    </label>
    <label> tennis
        <input type="checkbox" value="tennis">
    </label>
</div>
<table id="data_table">
    <thead>
    <tr>
        <th>name</th>
        <th>hobby</th>
    </tr>
    </thead>
    <tbody></tbody>
</table>
</body>
</html>

使用 extension

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet"
          href="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.21/css/jquery.dataTables.min.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.21/js/jquery.dataTables.min.js"></script>
    <script>
        $(function() {
            let data = [
                [
                    "Chan",
                    "basketball"
                ],
                [
                    "Phoebe",
                    "volleyball"
                ],
                [
                    "Lucas",
                    "tennis"
                ],
                [
                    "LBJ",
                    "basketball"
                ],
            ];
            let table = $('#data_table').DataTable({
                data: data
            });

            $.fn.dataTable.ext.search.push(function(settings, data) {
                let options = $(':checkbox:checked').map(function() {
                    return $(this).val()
                }).get();

                if (options.length === 0) {
                    return true;
                }

                return options.indexOf(data[1]) !== -1;
            });

            $(':checkbox').on('click', function() {
                table.draw();
            });
        });
    </script>
</head>
<body>
<div>
    <label> basketball
        <input type="checkbox" value="basketball">
    </label>
    <label> volleyball
        <input type="checkbox" value="volleyball">
    </label>
    <label> tennis
        <input type="checkbox" value="tennis">
    </label>
</div>
<table id="data_table">
    <thead>
    <tr>
        <th>name</th>
        <th>hobby</th>
    </tr>
    </thead>
    <tbody></tbody>
</table>
</body>
</html>

上面使用交集的方法篩選,稍微改寫一下就可以變聯集了。

2022/07/06

learning latteart opening

自學拉花也好幾年了,買過很多跟拉花相關的器材,但穩定性一直不是很好。

https://www.instagram.com/p/Ce-TmSGh8np/

這次終於痛下決心去找老師上課,survery 了坊間很久,沒想到自己的愛店 Shawn Coffee 就有開課,透過 IG 跟老師聯繫之後,約定好了上課日期(不太好排,太紅了),今天是我的第一天上課,我還蠻緊張的,都四十幾歲了還能夠重回學生時代的學習初心跟重溫未知的忐忑感我覺得很棒,Wish myself luck。

Compile Apache and OpenSSL

OS: CentOS 8
Target:

  • PHP 7.4
  • PHP-FPM
  • Apache 2.4.46
  • OpenSSL 1.1.1g

Start compile

sudo dnf install install -y gcc gcc-c++ make prec-devel libtool perl-core zlib-devel

# Compile apr
sudo ./configure --prefix=/usr/local/apr
sudo make
sudo make install

# Compile apr-util
sudo ./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr
sudo make
sudo make install

# Compile openssl
sudo ./config --prefix=/usr/local/openssl --openssldir=/usr/local/openssl shared zlib
sudo make
sudo make install

# Compile apache
sudo ./configure --prefix=/usr/local/apache2446 --enable-so --enable-ssl --enable-cgi --enable-rewrite --enable-modules=most --enable-mpms-shared=all --with-mpm=prefork --with-zlib --with-apr=/usr/local/apr --with-apr-util=/usr/local/apr-util --with-ssl=/usr/local/openssl
sudo make
sudo make install

# Apache system configuration
# Add Apache executables to PATH ( You can use nano instead of vi)
# create and open the following file
sudo vim /etc/profile.d/httpd.sh
  
# paste the following content, save and exit
pathmunge /usr/local/apache2446/bin

# Add Systemd entry

# create and open the following file
sudo vim /etc/systemd/system/httpd.service

paste the following content, save and exit.

[Unit]
Description=The Apache HTTP Server
After=network.target

[Service]
Type=forking
ExecStart=/usr/local/apache2446/bin/apachectl -k start
ExecReload=/usr/local/apache2446/bin/apachectl -k graceful
ExecStop=/usr/local/apache2446/bin/apachectl -k graceful-stop
PIDFile=/usr/local/apache2446/logs/httpd.pid
PrivateTmp=true

[Install]
WantedBy=multi-user.target
# reload the systemctl daemon
sudo systemctl daemon-reload

# start Apache httpd server (ignore the warnings at this stage)
sudo systemctl start httpd
sudo systemctl enable httpd

# Install PHP
sudo dnf install -y http://rpms.remirepo.net/enterprise/remi-release-8.rpm
dnf module reset php
dnf module install -y php:remi-7.4

sudo service php-fpm start
sudo systemctl enable php-fpm

Reference

2022/07/04

JsRender Sample

現在前端 framework 百家爭鳴,不過和後端 framework
遇到一樣的問題,版本更動超快寫法不相容,今日的當紅炸子機相隔一年後消失的無影無蹤時有所聞,後端比較沒有迅速隕落的問題,畢竟他的開發門檻還是稍高一些,也因此除了有玩一下 vuejs 以外對
front-end framework 真的沒有太高的興趣,即便我超愛寫 JavaScript,不過專案裡面還滿常用到 js render template 這件事情,所以我還是有使用一些 plugin
來實現這件事情,今天就來介紹 JsRender 這個 plugin

基礎功能

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JsRender</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jsrender/0.9.88/jsrender.min.js"></script>
    <script>
        $(function() {
            var data = {name: 'chan'};
            var html = $.templates('<strong>{{:name}}</strong>').render(data);
            $('#app').append(html);
        });
    </script>
</head>
<body>
<div id="app"></div>
</body>
</html>

JsRender 傳進去的資料為 JSON,上面的內容會得到:

<div id="app"><strong>chan</strong></div>

如果是複數的內容,JsRender 會自動幫你做 repeat。

script
$(function() {
    let data = [
        {name: 'chan'},
        {name: 'phoebe'}
    ];
    let html = $.templates('<strong>{{:name}}</strong>').render(data);
    $('#app').append(html);
});
output

<div id="app"><strong>chan</strong><strong>phoebe</strong></div>

樣板

如果將樣板寫在 script 裡面,往往會變得很難維護,字串也超長,所以 JsRender 有一個把樣板隔離出來的套用方式。

script
$(function() {
    let data = [
        {name: 'chan'},
        {name: 'phoebe'}
    ];
    let html = $.templates('#info').render(data);

    $('#app').append(html);
});
html
<script id="info" type="text/html">
    <strong>{{:name}}</strong>
</script>
output
<div id="app">
    <strong>chan</strong>
    <strong>phoebe</strong>
</div>

內建函式

{{> …}} (HTML-encode)

將輸出的部份加上 > 的話會將程式碼 encode。

script
$(function() {
    let data = {link: '<a href="http://www.google.com">google</a>'};
    let html = $.templates('#info').render(data);

    $('#app').append(html);
});
html
<script id="info" type="text/html">
    {{>link}}
</script>
output
&lt;a href&#61;&#34;http://www.google.com&#34;&gt;google&lt;/a&gt;

{{if …}}

判斷式。

script
$(function() {
    let data = [
        {name: 'chan', age: 37},
        {name: 'phoebe', age: 38},
        {name: 'lucas', age: 2}
    ];
    let html = $.templates('#info').render(data);

    $('#app').append(html);
});
html
<script id="info" type="text/html">
    {{:name}} is {{if age > 10}}adult{{else}}children{{/if}}<br>
</script>
output
<div id="app">
    chan is adult<br>
    phoebe is adult<br>
    lucas is children<br>
</div>

{{for …}}

迴圈。

script
$(function() {
    let data = [{
        name: 'chan',
        likes: [{
            name: 'music'
        }, {
            name: 'movie'
        }]
    }, {
        name: 'phoebe'
    }, {
        name: 'lucas',
        likes: [{
            name: 'cartoon'
        }]
    }];
    let html = $.templates('#info').render(data);

    $('#app').append(html);
});
html
<script id="info" type="text/html">
    <div>
        {{:#index}}: {{:name}}
        {{if likes}}
        <ul>
            {{for likes}}
            <li>{{:#index + 1}}: {{:name}}</li>
            {{/for}}
        </ul>
        {{else}}
        <div>no likes</div>
        {{/if}}
    </div>
</script>
output
<div id="app">
    <div>
        0: chan
        <ul>
            <li>1: music</li>
            <li>2: movie</li>
        </ul>
    </div>
    <div>
        1: phoebe
        <div>no likes</div>
    </div>
    <div>
        2: lucas
        <ul>
            <li>1: cartoon</li>
        </ul>
    </div>
</div>

{{include …}}

引入其他的樣板。

script
$(function() {
    let data = {
        name: 'test',
        data: [
            {
                name: 'chan',
                age: 42
            },
            {
                name: 'phoebe',
                age: 42
            }
        ]
    };

    console.log($('#main').render(data));
});

html
<script id="main" type="text/html">
    <h3>{{:name}}</h3>
    {{include tmpl="#sub"/}}
</script>
<script id="sub" type="text/html">
    <ol>
        {{for data}}
        <li>{{:name}}: {{:age}}</li>
        {{/for}}
    </ol>
</script>

output
<h3>test</h3>
<ol>
    <li>chan: 42</li>
    <li>phoebe: 42</li>
</ol>

{{props …}}

key value 式的迴圈。

script
$(function() {
    var data = [
        {
            name: 'Chan',
            likes: {
                name: 'a1',
                age: 33
            }
        },
        {
            name: 'Phoebe',
            likes: {
                food: 'steak',
                drink: 'juice'
            }
        }
    ]
    var html = $.templates('#info').render(data);

    $('#app').html(html);
});
html
<script id="info" type="text/html">
    <div>
        {{:name}}
        <ul>
            {{props likes}}
            <li>{{:key}}: {{:prop}}</li>
            {{/props}}
        </ul>
    </div>
</script>
output
<div id="app">
    <div>
        Chan
        <ul>
            <li>name: a1</li>
            <li>age: 33</li>
        </ul>
    </div>
    <div>
        Phoebe
        <ul>
            <li>food: steak</li>
            <li>drink: juice</li>
        </ul>
    </div>
</div>

helper

helper 也是一種 JSON 格式,可以是文字或者是 function。

script
$(function() {
    var helpers = {
        prefix: function(val) {
            return val + ' is cool';
        },
        version: '1.1'
    };
    var data = {
        name: 'chan'
    };
    var html = $.templates('#info').render(data, helpers);

    $('#app').append(html);
});
html

<script id="info" type="text/html">
    version: {{:~version}} name: {{:~prefix(name)}}
</script>
output
<div id="app">
    version: 1.1 name: chan is cool
</div>

helper 還有另一種 global 的傳入方式。

script
$(function() {
    let helpers = {
        prefix: function(val) {
            return val + ' is cool';
        },
        version: '1.1'
    };
    $.views.helpers(helpers);
    let data = {
        name: 'chan'
    };
    let html = $.templates('#info').render(data);

    $('#app').append(html);
});

以上是最基本的範例,不過應該可以應付大部分的情況了,若要使用其他更詳盡的功能可以前往他的官網 https://www.jsviews.com/

2022/06/10

Shell Script With Optional Arguments

我們在操作 Linux 上的 script 時,常常會使用一些 optional arguments,例如:

ls -l
grep -iR --include *.php

我們自己製作腳本時可以使用 getopts 以及 shift 達到這樣的效果,以一個安裝系統的腳本舉例。

install.sh

#/bin/bash

install_nginx=0
install_mysql=0
nginx_port=80
mysql_port=3306

while getopts "nmP:p:" OPTION; do
  case "$OPTION" in
  n)
    install_nginx=1
    ;;
  m)
    install_mysql=1
    ;;
  p)
    nginx_port="$OPTARG"
    ;;
  P)
    mysql_port="$OPTARG"
    ;;
  esac
done

echo "Install basic"

if [ "$install_nginx" == 1 ]; then
  echo "Install nginx with port $nginx_port"
fi

if [ "$install_mysql" == 1 ]; then
  echo "Install mysql with port $mysql_port"
fi
bash install.sh

# Install basic

bash install.sh -n

# Install basic
# Install nginx with port 80

bash install.sh -n -p 8888 -m
# Install basic
# Install nginx with port 8888
# Install mysql with port 3306

上面的方法只能帶入單一字符,所以像是 port 這種常見共用的文字只能用大小寫或者不同字符取代,彈性比較少,使用 shift 可以解決這個問題。

#/bin/bash

install_nginx=0
install_mysql=0
nginx_port=80
mysql_port=3306

while [ "$1" != "" ]; do
  case "$1" in
  --nginx)
    install_nginx=1
    ;;
  --nginx-port)
    shift
    nginx_port="$1"
    ;;
  --mysql)
    install_mysql=1
    ;;
  --mysql-port)
    shift
    mysql_port="$1"
    ;;
  esac
  shift
done

echo "Install basic"

if [ "$install_nginx" == 1 ]; then
  echo "Install nginx with port $nginx_port"
fi

if [ "$install_mysql" == 1 ]; then
  echo "Install mysql with port $mysql_port"
fi
bash install.sh --nginx
# Install basic
# Install nginx with port 80

bash install.sh --nginx --nginx-port 8888
# Install basic
# Install nginx with port 8888

bash install.sh --nginx --mysql --mysql-port 3307
# Install basic
# Install nginx with port 80
# Install mysql with port 3307

reference

2022/04/07

Makefile

如果我們的專案有指令是會重複執行的,透過 Makefile 可以集成內容,最方便的是多組合依序執行。

建立一個檔案名稱為 Makefile

基本應用

init:
        echo first command
        echo second command
$ make init
echo first command
first command
echo second command
second command

安靜輸出

如果你不希望 terminal 印出你下的命令內容,有幾種寫法可以避免。

.SILENT: init

init:
        echo first command
        echo second command
.SILENT: #影響全部

init:
        echo first command
        echo second command
init:
        @echo first command
        @echo second command

多重步驟

first_check:
        echo first check

second_check:
        echo second check

init: first_check second_check
        echo init
$ make init
echo first check
first check
echo second check
second check
echo init
init

變數

file=default

init:
        @echo file is $(file)
$ make
file is default

$ make file=new
file is new

變數可以經由帶入方式覆蓋。

2022/03/02

Linux Fun Command

網路上有一些方便的指令,會在這邊持續的更新做為筆記

設定 history 顯示時間
# 使用 history 可以查看之前下了什麼指令,但預設是沒有顯示時間的,可以透過設定來決定時間格式

$ HISTTIMEFORMAT="%Y-%m-%d %T "
$ HISTTIMEFORMAT="%F %T: " # 跟上面結果相同

# 想要永久存在的話就是去 .bashrc 或 .profile 設定

export HISTTIMEFORMAT="%Y-%m-%d %T "
檢查 port 是否存在
# 一般人會用這個指令,但我覺得他不是「專門」來做檢查這件事的
$ telnet cha15.info 21

# 使用nc 的話,會得到正確的資訊
$ nc -zv chan15.info 80
$ Connection to chan15.info 80 port [tcp/http] succeeded!

# 他同時也支援同時檢查多個 port
$ nc -zv chan15.info 80 21 33
$ Connection to chan15.info 80 port [tcp/http] succeeded!
$ Connection to chan15.info 21 port [tcp/ftp] succeeded!
$ nc: connect to chan15.info port 33 (tcp) failed: Connection refused
一次寫入多行資料
$ cat <<eot > test.txt
> 1
> 2
> 3
> eot
搜尋語取代檔案文字
grep -rl 'windows' | xargs sed -i 's/windows/linux/g'
刪除超過三十天的檔案
find PATH -ctime +30 | xargs -f
nmap

之前會用 nc 檢查 service,用 nmap 來做更方便

$ nmap localhost

Starting Nmap 7.01 ( https://nmap.org ) at 2019-05-03 15:05 CST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.0000080s latency).
Not shown: 995 closed ports
PORT    STATE SERVICE
21/tcp  open  ftp
22/tcp  open  ssh
25/tcp  open  smtp
80/tcp  open  http
443/tcp open  https
du 特殊用法

一般使用 du 的話他會列出你當前目錄每一個層級的所有的檔案內容跟大小,不過其實這樣不太實用,我們通常只要在第一層知道檔案大小即可

$ du -h -d 1
12K     ./apm
24K     ./wireshark
16K     ./cron.d
20K     ./apport
8.0K    ./cron.hourly
40K     ./sysctl.d

如果希望可以照檔案大小排序的話

$ du -h -d 1 | sort -h
4.0K    ./binfmt.d
4.0K    ./landscape
4.0K    ./libpaper.d
4.0K    ./modules-load.d
4.0K    ./opt
4.0K    ./pki

$ du -h -d 1 | sort -h -r
8.7M    .
880K    ./apache2
756K    ./ssl
668K    ./apparmor.d
440K    ./php
400K    ./init
368K    ./init.d