2022年6月23日 星期四

設定焦點直到成功

考慮有些元件是後來才會動態出現,或一開始被設為禁用之後才動態改為啟用,透過 retry 直到成功設定為止
通常是搭配 vue.js 這類透過資料綁定控制顯示隱藏或禁用的方式需要以這種方式設定焦點

function autofocus(elem, id) {
    setTimeout(function () {
        if (id) elem = document.getElementById(id);
        let isFocused = (document.activeElement === elem)
        if (!isFocused) {
            $(elem).focus();
            autofocus(elem);
        }
    }, 100);
}

2022年6月20日 星期一

html5 內建表單驗證用法

html
====
<form id="form1"> 
 <input required .../> // 檢查是否有輸入資料
 <input type="email" ... /> // 檢查是否符合email 格式
 <input type="number" min="1" max="10" .../> // 檢查數值是否落在指定範圍
 <input pattern="..." .../> // 用正規表示式檢查輸入資料  
</form>

javascript
====
需要驗證表單則呼叫 checkValidity()
ex. $('#form1')[0].checkValidity()
需要顯示錯誤訊息則呼叫 reportValidity() (自動呼叫checkValidity())
ex. $('#form1')[0].reportValidity()

2022年6月17日 星期五

列舉 轉為 IEnumerable

public enum colors { red,blue,green }

var list=Enum.GetValues(typeof(colors)).Cast<colors>().Select(a => new { value = (int)a, text = a.ToString() });

2022年6月16日 星期四

淺層複製物件 by 走訪屬性

 public static T1 Clone<T1>(this object a, T1 target = default)
        {
            var obj = target == null ? (T1)Activator.CreateInstance(typeof(T1)) : target;
            foreach (var pbase in a.GetType().GetProperties())
            {
                var p = obj.GetType().GetProperties().Where(b => b.CanWrite && pbase.Name == b.Name && (pbase.PropertyType == b.PropertyType || pbase.PropertyType.IsAssignableFrom(b.PropertyType) || b.PropertyType.IsAssignableFrom(pbase.PropertyType))).SingleOrDefault(); // 考慮同型態但nullable 不同也進行複製(如 datetime? 和 datetime)
                if (p != null) p.SetValue(obj, pbase.GetValue(a, null), null);
            }
            return obj;
        }

用法:
a.Clone(b)
var b = a.Clone<xxx>()

讓網站色彩轉為深色模式 (和 windows 色彩設定連動)


<script src="https://cdn.jsdelivr.net/npm/darkmode-js"></script>
<script>
    function addDarkmodeWidget() {
        new Darkmode();
    }
    if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
        var head = document.getElementsByTagName('head')[0];
        var link = document.createElement('link');
        link.rel = 'stylesheet';
        link.type = 'text/css';
        link.href = '@Url.Content("~/Content/深色主題.css?"+DateTime.Now.ToShortTimeString())';
        link.media = 'all';
        head.appendChild(link);
        window.addEventListener('load', addDarkmodeWidget);
    }
</script> 

深色主題.css // 手動優化部分顏色配置
option {
    color: rgb(200,200,200);
    background-color: #333;
}

2022年6月13日 星期一

判斷IP是否為內部IP

 public static class IPAddressExtensions
    {
        /// <summary>
        /// Returns true if the IP address is in a private range.<br/>
        /// IPv4: Loopback, link local ("169.254.x.x"), class A ("10.x.x.x"), class B ("172.16.x.x" to "172.31.x.x") and class C ("192.168.x.x").<br/>
        /// IPv6: Loopback, link local, site local, unique local and private IPv4 mapped to IPv6.<br/>
        /// </summary>
        /// <param name="ip">The IP address.</param>
        /// <returns>True if the IP address was in a private range.</returns>
        /// <example><code>bool isPrivate = IPAddress.Parse("127.0.0.1").IsPrivate();</code></example>
        public static bool IsPrivate(this System.Net.IPAddress ip)
        {
            // Map back to IPv4 if mapped to IPv6, for example "::ffff:1.2.3.4" to "1.2.3.4".
            if (ip.IsIPv4MappedToIPv6)
                ip = ip.MapToIPv4();

            // Checks loopback ranges for both IPv4 and IPv6.
            if (System.Net.IPAddress.IsLoopback(ip)) return true;

            // IPv4
            if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                return IsPrivateIPv4(ip.GetAddressBytes());

            // IPv6
            if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
            {
                return ip.IsIPv6LinkLocal ||
#if NET6_0
                       ip.IsIPv6UniqueLocal ||
#endif
                       ip.IsIPv6SiteLocal;
            }

            throw new NotSupportedException(
                    $"IP address family {ip.AddressFamily} is not supported, expected only IPv4 (InterNetwork) or IPv6 (InterNetworkV6).");
        }

        private static bool IsPrivateIPv4(byte[] ipv4Bytes)
        {
            // Link local (no IP assigned by DHCP): 169.254.0.0 to 169.254.255.255 (169.254.0.0/16)
            bool IsLinkLocal() => ipv4Bytes[0] == 169 && ipv4Bytes[1] == 254;

            // Class A private range: 10.0.0.0 – 10.255.255.255 (10.0.0.0/8)
            bool IsClassA() => ipv4Bytes[0] == 10;

            // Class B private range: 172.16.0.0 – 172.31.255.255 (172.16.0.0/12)
            bool IsClassB() => ipv4Bytes[0] == 172 && ipv4Bytes[1] >= 16 && ipv4Bytes[1] <= 31;

            // Class C private range: 192.168.0.0 – 192.168.255.255 (192.168.0.0/16)
            bool IsClassC() => ipv4Bytes[0] == 192 && ipv4Bytes[1] == 168;

            return IsLinkLocal() || IsClassA() || IsClassC() || IsClassB();
        }
    }

舉例用法 : 檢查函數呼叫者是否來自內部IP
public static string xxx() {
var clientIP = System.Net.IPAddress.Parse(HttpContext.Current.Request.UserHostAddress);
if (!clientIP.IsPrivate()) throw new Exception("非法呼叫!!");
}

input 連結 datalist 用程式控制彈出選項

範例: nextTick(() => document.querySelector('input').showPicker());  ※僅支援現代瀏覽器