const currency = new Intl.NumberFormat('zh-TW', {
style: 'currency',
currency: 'TWD',
// 最少小數位數
minimumFractionDigits: 2,
// 最多小數位數
maximumFractionDigits: 2,
});
const percent = new Intl.NumberFormat('zh-TW', {
style: 'percent',
// 最少小數位數
minimumFractionDigits: 0,
// 最多小數位數
maximumFractionDigits: 0,
// 小數點三位一撇 (因語系不同變化)
useGrouping: false,
});
/// ex
currency.format(1000);
// => $1,000.00
percent.format(1000);
// => 100000%
google fonts
2020年9月24日 星期四
NumberFormat
2019年3月18日 星期一
GitLab一直擋我SSH Key到底該設定哪裡?
這邊專指windows environment。
C:\Users\{{使用者帳號}}\.ssh\config
首先得新增一個.ssh的folder在你的使用者帳號底下,然後再新增一個沒有副檔名的config檔,內容如下:
Host YOUR_HOST_OR_IP
Preferredauthentications publickey
HostName YOUR_HOST_OR_IP
IdentityFile ~/.ssh/id_rsa_file
User YOUR_NAME
Host YOUR_HOST_OR_IP_2
Preferredauthentications publickey
HostName YOUR_HOST_OR_IP_2
IdentityFile ~/.ssh/id_rsa_file_2
User YOUR_NAME
※注意,其實IdentityFile放置的位置跟你現在config的位置相同。
目前這樣我就能解sourceTree吃不到SSH Key的問題,如果有其他狀況可留言給我= =
2018年4月18日 星期三
Tern for Sublime的自動完成支援
早上在設定ternjs這個擴充功能,我主要拿他來autocomplete sublime對javascript dom api的這段功能。簡而言之,我希望他像chrome的developer tool一樣,當我下
document.
的時候會出現下拉選單,讓我選完整的function name,因為javascript的fn很多都超級長,我害怕拼錯字= =

好,首先怎麼做呢?
按照官方文件的做法可以用git clone到packages的folder

或者可以用package control
ctrl+shift+p
Package Control: Install Package
tern_for_sublime
然後你會獲得一個一般js支援的ternjs,並不包含dom這塊。
接下來你看官方文件,會發覺他跟你說:
Tern uses code .tern-project files to configure loading libraries and plugins for a project. See the Tern docs for details
發覺,噢好棒棒,所以我只要加了"broswer"支援就可以了RRR!
所以,這個.tern-project該死的放在哪裡= =
大家會跟你說,把它放到.sublime-project同一層。
原來是這樣!
好吧,事實上他有幾個可以放的位置,第一個是如果你的js不屬於任何專案,但你又想看到這個功能,那你要把它放在Users/{你的帳號}的根目錄
C:/Users/{你的帳號}/.tern-project
第二個是你把你的專案include在某個.sublime-project裡面,如下圖:

那你就把.tern-project放在.sublime-project旁邊,如下圖:

最後一個就是只對該層js執行,如果你有打開過Preferences > Browse Packages... .\tern_for_sublime\test\demo\simple這個位置的話,你會發現他根本就已經附了sample。
所以把.tern-project放在js檔的旁邊也可以。

2017年9月1日 星期五
使用NodeJS做一個簡單的Send Mail Service
前端有時候就要做一些很阿雜的事,像是測試EDM之類的。最近碰到的CASE就是我使用的免費Web Test Mail被公司的Mail Server檔掉,然後設備工程師那邊沒時間理我……我就想應該有人寫了Send Mail的plugin了吧,基於我覺得蠻好用的,這邊筆記一下。
packages
NodeJS的安裝這邊就不特別寫了,如果想參考windows的各種安裝方案可以參考Node.js學習筆記:重複安裝後rollback安裝失敗這篇。
先到專案資料夾shift + 右鍵,可以選擇「在此處開啟命令視窗」。產生一個package.json
於命令視窗輸入npm init
npm init
這篇sample引用兩個package,一個是nodemailer(寄信),另一個是fs(讀檔)。
npm install nodemailer fs --save
開一隻testEmail.js,接著引用nodemailer及fs。 var nodemailer = require('nodemailer');
var fs = require('fs');
var smptCfg = require('./package').config.smtp;
我的習慣會把connecting string寫在config之類的地方,所以我就拉到package.json裡面,開一個config,加上上面init出來的package大略長這樣。
{
"name": "sendmails",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"fs": "0.0.1-security",
"nodemailer": "^4.1.0"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"config" : {
"smtp" : {
"host": "smtp.gmail.com",
"port": 465,
"secure": true,
"auth": {
"user": "Your Google account...",
"pass": "Google pwd..."
}
}
}
}
smtp的服務可以看自己方便選用,我套過公司的信箱跟gmail,這邊以方便取得的gmail為範本。Gmail的SMTP設定可以參考官方說明。
這邊簡單寫一下官方寫的設定標準:
- host: smtp.gmail.com
- Requires SSL: Yes
- Requires TLS: Yes (if available)
- Requires Authentication: Yes
- Port for SSL: 465
- Port for TLS/STARTTLS: 587
build
testEmail.js的範本可以參考Nodemailer官方文件,我這邊是稍微調整了比較容易異動的變數到文件上方,並且改為讀檔的方式來讀取本文內容(html)。
var nodemailer = require('nodemailer');
var fs = require('fs');
// package.json 設定的一些config資料
var smptCfg = require('./package').config.smtp;
var mailBodyPath = './system_email.html',
mailOptions = {
from: '"no-reply 測試信" <your@gmail.com>',
to: '',
bcc: 'testto@gmail.com',
subject: '[測試信] 某個主題'
// text: 'That was easy!',
// html: mailBody // 下方讀檔後覆蓋
};
// 設定於package.json
var transporter = nodemailer.createTransport({
host: smptCfg.host,
port: smptCfg.port,
secure: smptCfg.secure, // true for 465, false for other ports
auth: {
user: smptCfg.auth.user,
pass: smptCfg.auth.pass
}
});
// 讀檔
fs.readFile(mailBodyPath, 'utf8', function (err, mailBody) {
if (err) {
return console.log(err);
}
// 代入mail本文
mailOptions.html = mailBody;
// 寄信
transporter.sendMail(mailOptions, function(error, info){
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
});
接著在cmd build testEmail:
node testEmail
成功的話就會看到Email sent: + info.response。
筆者在家裡的電腦產生了TLSSocket的Error Msg。
C:\project\nodeSendMail>node testEmail
{ Error: self signed certificate in certificate chain
at Error (native)
at TLSSocket.<anonymous> (_tls_wrap.js:1092:38)
at emitNone (events.js:86:13)
at TLSSocket.emit (events.js:185:7)
at TLSSocket._finishInit (_tls_wrap.js:610:8)
at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:440:38) code: 'ECONNECTION', co
mmand: 'CONN' }
這邊採用修改參數的做法讓信件送出去。在CMD下:
set NODE_TLS_REJECT_UNAUTHORIZED=0
然後我的防毒軟體很雞婆的幫我塞病毒檢測沒有問題XD...
使用Google App Passwards
如果按照上面範例把帳號密碼打進去,其實就可以build了,但build的時候就會發現google跟你說,這樣很不安全,請使用應用程式密碼之類的,然後就會建置失敗XD。
這時候有兩個選擇,一個是啟用安全性較低的應用程式存取權,另一個是設定應用程式密碼。
第一個方式比較快,google帳戶說明也寫了路徑。缺點是google告訴你容易被盜用XD。
稍微設定一下就會發現,如果把帳號密碼打在package.json當然很危險阿XD...畢竟是明碼顯示,如果哪天交接忘記改也很麻煩。
因此這邊建議申請App Passwords。
步驟也蠻簡單的,先到Google Account啟用兩步驟驗證


然後就可以到應用程式密碼(上圖兩步驗證的下面)設定一組專門for特定應用程式的密碼,到時候如果要取消授權,可以直接從帳號這裡移除該組密碼。

一組不會再顯示的密碼,記得先複製下來:

2017年1月5日 星期四
純色小圖示的解決方案
如果有從設計手上拿過各種網頁小icon的話,應該都蠻困擾要怎麼處理這些小東西的吧?
雖然有用gulp或compass的人可能會選擇用sprite來把多個小icon組成一個images map,但還是有一些缺點的。像是如果icon要放大,可能就要存多個icon,畢竟不論放大縮小,png的邊緣都有可能模糊。
有玩過fontawesome的應該都知道純色圖片可以做成字型檔,由於字型檔本身是向量的結構,因此純色圖片可以壓成一張大的字型檔。
優點有這些:
- 縮放無鋸齒、模糊
- 改變顏色可以直接下color的CSS,不用做成另一張圖
- 改變大小用font-size做變化就好
- 基本上可以相容到ie8
- 文字可以用text-shadow這個CSS功能產生陰影
但也是有缺點的,就是只能做純色圖。因此icon有兩種以上的顏色可能要繼續沿用sprite了。
之前同事有跟我提這件事,她本來想有時間自己嘗試壓文字,但她離職就不了了之QQ
後來筆者找個時間研究,發現根本有線上支援的網站,不用花時間自己壓成多種格式(真要自己壓可以參考下面那篇網頁使用微軟正黑體的修復方案最後提到的製作補丁)。
目前我在使用的是fontastic,這套原本就包含好幾個免費icons,因此除非沒有適合的,不然也沒必要特別製作啦……
選用icons這邊就不示範,這裡提供上傳的方法。
2016年5月23日 星期一
文繞圖的失敗原因
話說為了迎合設計跟銷售端,我在網頁顯示那邊做了display: table跟列印樣式時覆蓋成文繞圖(float: left)。
文繞圖是一種很基本的排版樣式,至今我無法理解為何可以繞XD,但總而言之他的寫法就是不動文字的部分,然後將要被環繞的區域加上float就好。
若文繞圖失敗目前可歸類兩個原因,1. 本文內容消除溢出。2. 本文內容清除浮動。(浮動要在最外面container才能清,如下方展示。)
SASS學習筆記:Sourcemap
剛剛要整理NodeJS學習筆記的時候,為了不要亂貼CODE而不知其原因,因此上網翻「sourcemap」的功能。印象中,我最近提交專案上線後Chrome的Developer一直告訴我的map遺失。我是有想到我把css跟map放在不同folder(開發folder及發行folder),但由於我的網頁沒掛掉,因此我就先擱置在一邊。
今天剛好看到Getting started with CSS sourcemaps and in-browser Sass editing,覺得原來有這種功能很厲害!
原文那篇使用的是ROR,說要SASS 3.3以上才支援,但基本上我用NodeJS沒特別試過SASS的版本號啦@@
各種NodeJS方法中都會有Sourcemap的方法,筆者用gulp。所以在gulpfile.js這樣下:
// gulpfile.js
'use strict';
var gulp = require('gulp');
var sass = require('gulp-sass');
var sourcemaps = require('gulp-sourcemaps');
// autoprefixer
var autoprefixer = require('gulp-autoprefixer');
// sass
gulp.task('sass', function () {
gulp.src('./scss/**/*.{scss,sass}')
// Initializes sourcemaps
.pipe(sourcemaps.init())
// 轉譯SASS -> CSS
.pipe(sass({
//Log error
errLogToConsole: true,
}).on('error', sass.logError))
// add Prefix in CSS。
.pipe(autoprefixer({
browsers: ['last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4']
}))
// 寫入sourcemaps到當前資料夾(以下下列dest('../css')為基準點,sourceRoot:以匯出的資料夾為基準點找他原本的scss資料夾位置。
.pipe(sourcemaps.write('./', {includeContent: false, sourceRoot: '../src/scss'}))
// 輸出CSS
.pipe(gulp.dest('../css'));
});
// 有改變時即時 Watch
gulp.task('watch', function() {
// 任何scss folder下附檔名為scss、sass的檔案
var watcher = gulp.watch([
'./scss/**/*.{scss,sass}'
], ['sass']);
});
// 預設一開始會跑的任務
gulp.task('default', ['sass', 'watch']);
接著能在css folder內看到指定的*.css、*.css.map
然後接下來,在測試機的demo站使用Chrome開啟網頁按下F12(開發者工具)
如果路徑都沒錯的話,就能看到對應的scss位置:
![[開發者工具]>[Elements]](https://imgur.com/5xiicBT.jpg)
最有趣的來了!!!如果想要用開發者工具改scss也沒問題,到[Source]中左邊目錄可以看到對應的SASS資料夾,要確定路徑是對的。
![[開發者工具]>[Source]](https://imgur.com/WBtTNUL.jpg)
任意位置按右鍵[Add folder to workspace],搜尋專案資料夾。
![[Add folder to workspace]](https://imgur.com/GoDizJs.jpg)
[允許]後,若剛剛的專案資料夾消失,重新整理一下網頁,理論上專案資料夾就會出現。
![[允許]](https://imgur.com/ULaqc0s.jpg)
然後對著任一SCSS檔右鍵點選[Map to file system resource...]
![[Map to file system resource...]](https://imgur.com/F1lWQS1.jpg)
開發者工具即會列出剛剛資料夾內所有符合的檔案(及位置),選擇正確的路徑檔案,就會發現top內localhost下的資料夾消失了。

回去[Elements]隨便找一個可點選的scss link,可以發現他的確對到本機端的scss位置,不論是在[Elements]直接編輯或LINK到[Source]編輯,可以發現Ctrl+S是真的直接幫你存檔的!!!

但要注意的是[Elements]直接編輯的是*.css,到[Source]編輯才是改*.scss噢~
如果要編譯的話,一樣是得開CMD使用gulp、grunt、compass之類的compiler watch changed的~若Chrome沒有當掉,他偵測到更新後也會更新網頁。
最後,若是想跟我一樣同時產min跟非min(原始)的CSS的可以用下面的gulpfile。之所以用cssnano是由於之前試其他的CSS minify都失敗,餵關鍵字給辜狗後發現只有看到有人說cssnano支援sourcemap,但當code變大的時候,nano壓縮的速度真的有點慢QQ
// gulpfile.js
'use strict';
var gulp = require('gulp');
var sass = require('gulp-sass');
var sourcemaps = require('gulp-sourcemaps');
// Post CSS unit (目前壓縮使用cssnano才有辦法用sourcemap @__@)
var postcss = require('gulp-postcss');
var cssnano = require('cssnano');
// autoprefixer
var autoprefixer = require('gulp-autoprefixer');
var cssPath = ['../css/**/*.css', '!../css/**/*.min.css'];
// sass
gulp.task('sass', function () {
gulp.src('./scss/**/*.{scss,sass}')
// Initializes sourcemaps
.pipe(sourcemaps.init())
// 轉譯SASS -> CSS
.pipe(sass({
//Log error
errLogToConsole: true,
}).on('error', sass.logError))
// add Prefix in CSS。
.pipe(autoprefixer({
browsers: ['last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4']
}))
// 寫入sourcemaps到當前資料夾(以下下列dest('../css')為基準點,sourceRoot:以匯出的資料夾為基準點找他原本的scss資料夾位置。
.pipe(sourcemaps.write('./', {includeContent: false, sourceRoot: '../src/scss'}))
// 輸出CSS
.pipe(gulp.dest('../css'));
});
// css mini
gulp.task('mini', function () {
gulp.src(cssPath)
.pipe(sourcemaps.init())
// 再最小化,cssnano會幫你重新由小到大排序z-index,若不要要加入{ zindex: false }
.pipe(postcss([cssnano({ zindex: false })]))
// 將最小化的檔名末端加上.min
.pipe(rename({suffix: '.min'}))
// Writes sourcemaps into the CSS file
.pipe(sourcemaps.write('.', {includeContent: false, sourceRoot: ''}))
// 把最小化的寫入css folder
.pipe(gulp.dest('../css'));
});
// 有改變時即時 Watch
gulp.task('watch', function() {
// 任何scss folder下附檔名為scss、sass的檔案
var watcher = gulp.watch([
'./scss/**/*.{scss,sass}'
], ['sass']);
var watcher2 = gulp.watch(cssPath, ['mini']);
// 看有沒有修正到對的scss檔
watcher.on('change', function(event) {
console.log('SASS Task: File ' + event.path + ' was ' + event.type + ', running tasks...');
});
watcher2.on('change', function(event) {
console.log('Mini Task: CSS File ' + event.path + ' was ' + event.type + ', running tasks...');
});
});
// 預設一開始會跑的任務
gulp.task('default', ['sass', 'watch']);





