tail -f pinzo.log
2016/08/02
Jekyll始めました


2016/07/28
serialのシーケンスがなが~い名前になる場合
serial
はシーケンスを生成するわけだけども、シーケンスの名前は table_name_column_name_seq
という形で生成される。users
テーブルの id
ならば users_id_seq
という感じで
しかし、シーケンス名は63文字までなので、なが~い名前のテーブルのなが~い名前の列を対象にした場合は63文字を超えてしまう場合も当然あって、そんな場合は切り詰められたものが名前になる。
例えば long_long_name_table_abcd_efgh_ijkl_mnop_qrst_uvwx_yz
テーブルの long_long_name_column_abcd_efgh_ijkl_mnop_qrst_uvwx_yz
を対象にした場合は sample.long_long_name_table_abcd_efg_long_long_name_column_abcd_ef_seq
となる。
このシーケンス名を取得するには pg_catalog.pg_get_serial_sequence
関数を使えばいいのだが、まあごくたまにはDBにアクセスせずにこのシーケンス名を指定したい場合があって、その場合は内部ルールをトレースする必要がある。
おそらく内部仕様はこんな感じ
- テーブル名と列名の長さが合わせて58文字以下ならそのまま作成
- テーブル名と列名ともに30文字以上ならばどちらも29文字に切り詰めて作成
- どちらかが29文字未満のばあい、短い方はそのまま使用し残りの分(58-短い方の文字数)を長い方から切り出して作成
var MAX_SEQ_NAME_LENGTH = 63; | |
var PARTS_LENGTH_THRESHOLD = 29; | |
function getSerialSequence(tableName, columnName) { | |
t = tableName; | |
c = columnName; | |
if (tableName.length + columnName.length + 5 > MAX_SEQ_NAME_LENGTH) { | |
if (tableName.length > PARTS_LENGTH_THRESHOLD) { | |
if (columnName.length > PARTS_LENGTH_THRESHOLD) { | |
t = tableName.substring(0, PARTS_LENGTH_THRESHOLD); | |
c = columnName.substring(0, PARTS_LENGTH_THRESHOLD); | |
} else { | |
t = tableName.substring(0, PARTS_LENGTH_THRESHOLD + (PARTS_LENGTH_THRESHOLD - columnName.length)); | |
} | |
} else { | |
c = columnName.substring(0, PARTS_LENGTH_THRESHOLD + (PARTS_LENGTH_THRESHOLD - tableName.length)); | |
} | |
} | |
return t + "_" + c + "_seq"; | |
} |
ちなみにこの結果、既存のシーケンスと名前が被るとき(例えば長い名前で末尾がほんの少しだけ違うテーブルのid列をserialで作成しようとした場合)は素直にエラーになってくれるので、名前を付け直すか integer で作って、シーケンスを別途作成しましょう。


2016/06/03
golangのテンプレート内でメソッドを呼び出す
text/template
のサンプルをいくつか見てみたところ、構造体を渡してフィールドを埋め込んで表示するサンプルばかりだった。じゃあメソッド呼べるの?と思ったので試してみた。
package main | |
import ( | |
"os" | |
"text/template" | |
) | |
type Person struct { | |
Name string | |
City string | |
} | |
func (p Person) GetAge() int { | |
return 36 | |
} | |
func main() { | |
tmpl, err := template.New("test").Parse("{{.Name}}({{.GetAge()}}) lives in {{.City}}.") | |
if err != nil { | |
panic(err) | |
} | |
p := Person{"pinzolo", "Kyoto"} | |
err = tmpl.Execute(os.Stdout, p) | |
if err != nil { | |
panic(err) | |
} | |
} |
panic: template: test:1: unexpected "(" in operand goroutine 1 [running]: panic(0x13f660, 0xc82000a440) /usr/local/Cellar/go/1.6.2/libexec/src/runtime/panic.go:481 +0x3e6 main.main() /Users/pinzolo/.cache/junkfile/2016/06/2016-06-03-101728.go:20 +0x24b exit status 2できなかった。
括弧が unexpected なら、括弧なしならどうなの??
package main | |
import ( | |
"os" | |
"text/template" | |
) | |
type Person struct { | |
Name string | |
City string | |
} | |
func (p Person) GetAge() int { | |
return 36 | |
} | |
func main() { | |
tmpl, err := template.New("test").Parse("{{.Name}}({{.GetAge}}) lives in {{.City}}.") | |
if err != nil { | |
panic(err) | |
} | |
p := Person{"pinzolo", "Kyoto"} | |
err = tmpl.Execute(os.Stdout, p) | |
if err != nil { | |
panic(err) | |
} | |
} |
pinzolo(36) lives in Kyoto.出来た。正直言って予想外だった。
じゃあ、引数はどうやって渡すの?len
とかのビルトイン関使うようにスペース開ければいいかな?
package main | |
import ( | |
"os" | |
"text/template" | |
) | |
type Person struct { | |
Name string | |
City string | |
} | |
func (p Person) GetAge() int { | |
return 36 | |
} | |
func (p Person) GetFutureAge(yearAfter int) int { | |
return p.GetAge() + yearAfter | |
} | |
func main() { | |
tmpl, err := template.New("test").Parse("{{.Name}}({{.GetAge}}) lives in {{.City}}. 2 years later he is {{.GetFutureAge 2}}.") | |
if err != nil { | |
panic(err) | |
} | |
p := Person{"pinzolo", "Kyoto"} | |
err = tmpl.Execute(os.Stdout, p) | |
if err != nil { | |
panic(err) | |
} | |
} |
pinzolo(36) lives in Kyoto. 2 years later he is 38.出来た。
じゃあ2つ以上の引数はスペース区切りかな?
package main | |
import ( | |
"os" | |
"text/template" | |
) | |
type Person struct { | |
Name string | |
City string | |
} | |
func (p Person) GetAge() int { | |
return 36 | |
} | |
func (p Person) GetFutureAge(yearAfter int, other int) int { | |
return p.GetAge() + yearAfter + other | |
} | |
func main() { | |
tmpl, err := template.New("test").Parse("{{.Name}}({{.GetAge}}) lives in {{.City}}. 5 years later he is {{.GetFutureAge 2 3}}.") | |
if err != nil { | |
panic(err) | |
} | |
p := Person{"pinzolo", "Kyoto"} | |
err = tmpl.Execute(os.Stdout, p) | |
if err != nil { | |
panic(err) | |
} | |
} |
pinzolo(36) lives in Kyoto. 5 years later he is 41.やっぱり。
趣向を変えて、構造体のポインタを渡してもうまく動くかな?
package main | |
import ( | |
"os" | |
"text/template" | |
) | |
type Person struct { | |
Name string | |
City string | |
} | |
func (p *Person) GetAge() int { | |
return 36 | |
} | |
func (p *Person) GetFutureAge(yearAfter int) int { | |
return p.GetAge() + yearAfter | |
} | |
func main() { | |
tmpl, err := template.New("test").Parse("{{.Name}}({{.GetAge}}) lives in {{.City}}. 2 years later he is {{.GetFutureAge 2}}.") | |
if err != nil { | |
panic(err) | |
} | |
p := &Person{"pinzolo", "Kyoto"} | |
err = tmpl.Execute(os.Stdout, p) | |
if err != nil { | |
panic(err) | |
} | |
} |
package main | |
import ( | |
"os" | |
"text/template" | |
) | |
type Person struct { | |
Name string | |
City string | |
} | |
func (p Person) GetAge() int { | |
return 36 | |
} | |
func (p Person) GetFutureAge(yearAfter int) int { | |
return p.GetAge() + yearAfter | |
} | |
func main() { | |
tmpl, err := template.New("test").Parse("{{.Name}}({{.GetAge}}) lives in {{.City}}. 2 years later he is {{.GetFutureAge 2}}.") | |
if err != nil { | |
panic(err) | |
} | |
p := &Person{"pinzolo", "Kyoto"} | |
err = tmpl.Execute(os.Stdout, p) | |
if err != nil { | |
panic(err) | |
} | |
} |
pinzolo(36) lives in Kyoto. 2 years later he is 38.問題ない。構造体に定義したメソッドもポインタに定義したメソッドも呼び出せてる。
結構色々出来るんだな text/template


2016/06/01
comment on exported function GetXxx should be of thee form "GetXxx ..."
Go は大文字で始まる public な型・関数に対してその直前に書かれたコメントをドキュメントとして扱ってくれる。
lintでドキュメント書くように勧めてくるのは意識高い感じでよい。
ただ、面倒なことにその型なり関数なりの名前で始まるのを推奨しているらしく、そうじゃない場合タイトルのような警告を出してくる。
こんな感じ
package main | |
// 設定情報を格納する ← メッセージ出しやがる | |
type Config struct {} | |
// ConfigError は設定情報に不備があった場合のエラー情報を格納する ← 推奨しているらしい | |
type ConfigError struct {} | |
// Fooを返す ← メッセージ出しやがる | |
func GetFoo() string { | |
return "Foo" | |
} | |
// GetBar は Bar を返す ← 推奨しているらしい | |
func GetBar() string { | |
return "Bar" | |
} |
英語で書く場合なら、GetFoo returns Foo みたいに書きやすいのだが、日本語でコメントを書く場合冗長なコメントになりがちな気がする。
関数名も型名も真下にあるじゃないか!
なんて言っても仕方ないし、エディタにマークつけ続けられるのも気持ち悪いのでせっせとおっしゃる通りにするのだ


2016/05/31
golang 入門した
ちょっととあるコマンドラインツール作ろうと思って、また gem で作ろうかと思ったんだけど Windows でも動かせるようにしたいし、使う人に Ruby 入れさせるのもアレなので、golang で作ってみようと思った。
土日ぐらいで A Tour of Go. を始めとしていろんな入門エントリ読んで、とりあえず手始めに github.com/pinzolo/casee とかいうライブラリ作ってみた。
とりあえずテストは通るし、動いている。


golang にて文字列のn番目の文字を取得する
package main | |
import ( | |
"fmt" | |
) | |
func main() { | |
s := "日本語" | |
fmt.Println(string(s[0])) // => æ | |
fmt.Println(string(getRuneAt(s, 0))) // => 日 | |
} | |
func getRuneAt(s string, i int) rune { | |
rs := []rune(s) | |
return rs[i] | |
} |


2016/04/07
Ubuntu 12.04 on さくらのVPS に GitBucket を入れたメモ
Tomcatのインストール
sudo aptitude install -y tomcat7 tomcat7-admin
Tomcatの設定
sudo vi /etc/tomcat7/server.xmlHTTPのConnector設定をコメントアウトし、AJPのConnector設定を有効にする。
GitBucketの配置
wget https://github.com/gitbucket/gitbucket/releases/download/3.13/gitbucket.war sudo mv gitbucket.war /var/lib/tomcat7/webapps ls -al /var/lib/tomcat7/webappsdrwxrwxr-x 4 tomcat7 tomcat7 4096 Apr 7 14:37 . drwxr-xr-x 6 root root 4096 Apr 7 14:24 .. drwxr-xr-x 7 tomcat7 tomcat7 4096 Apr 7 14:37 gitbucket -rw-r--r-- 1 root root 39783199 Apr 7 14:37 gitbucket.war drwxr-xr-x 3 root root 4096 Apr 7 14:25 ROOT
ApacheのGitBucket用設定ファイル
sudo vi /etc/apache2/sites-available/gitbucket.conf<VirtualHost *:443> ServerName gitbucket.my-domain:443 <Location /> ProxyPass ajp://localhost:8009/ </Location> SSLCertificateFile /etc/apache2/cert/ssl-cert.pem SSLCertificateKeyFile /etc/apache2/cert/ssl-cert.key </VirtualHost>sudo a2ensite gitbucket
再起動
sudo service tomcat7 restart sudo service apache2 restartしかし、アクセスしても 404 となる。
/var/log/tomcat7/localhost.2016-04-07.log
を見ると、こんなエラーが出ている。
SEVERE: Error configuring application listener of class gitbucket.core.ssh.SshServerListener java.lang.UnsupportedClassVersionError: gitbucket/core/ssh/SshServerListener : Unsupported major.minor version 52.0 (unable to load class gitbucket.core.ssh.SshServerListener) at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:2948) at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:1208) at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1688) at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1569) at org.apache.catalina.core.DefaultInstanceManager.loadClass(DefaultInstanceManager.java:529) at org.apache.catalina.core.DefaultInstanceManager.loadClassMaybePrivileged(DefaultInstanceManager.java:511) at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:139) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4888) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5467) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:632) at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1073) at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1857) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) at java.util.concurrent.FutureTask.run(FutureTask.java:262) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:745)https://github.com/gitbucket/gitbucket/issues/1082 によると、Java8を必要としているがJava8ではない場合に出るエラーのようだ。TomcatがJava8で動いていないっぽい。
JAVA_HOMEの設定
sudo vi /etc/default/tomcat7
JAVA_HOME=/usr/lib/jvm/java-8-oracle
を追加して再起動。しかしまだ表示されない。今度はこんなエラー。
SEVERE: Exception sending context initialized event to listener instance of class gitbucket.core.servlet.InitializeListener java.sql.SQLException: Connections could not be acquired from the underlying database! at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:118) at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:692) at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:140) at scala.slick.jdbc.JdbcBackend$DatabaseFactoryDef$$anon$3.createConnection(JdbcBackend.scala:47) at scala.slick.jdbc.JdbcBackend$BaseSession.conn$lzycompute(JdbcBackend.scala:397) at scala.slick.jdbc.JdbcBackend$BaseSession.conn(JdbcBackend.scala:397) at scala.slick.jdbc.JdbcBackend$BaseSession.withTransaction(JdbcBackend.scala:420) at scala.slick.backend.DatabaseComponent$DatabaseDef$$anonfun$withTransaction$1.apply(DatabaseComponent.scala:54) at scala.slick.backend.DatabaseComponent$DatabaseDef$$anonfun$withTransaction$1.apply(DatabaseComponent.scala:54) at scala.slick.backend.DatabaseComponent$DatabaseDef$class.withSession(DatabaseComponent.scala:34) at scala.slick.jdbc.JdbcBackend$DatabaseFactoryDef$$anon$3.withSession(JdbcBackend.scala:46) at scala.slick.backend.DatabaseComponent$DatabaseDef$class.withTransaction(DatabaseComponent.scala:54) at scala.slick.jdbc.JdbcBackend$DatabaseFactoryDef$$anon$3.withTransaction(JdbcBackend.scala:46) at gitbucket.core.servlet.InitializeListener.contextInitialized(InitializeListener.scala:30) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4973) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5467) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:632) at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1073) at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1857) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) Caused by: com.mchange.v2.resourcepool.CannotAcquireResourceException: A ResourcePool could not acquire a resource from its primary factory or source. at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1469) at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:644) at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:554) at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutAndMarkConnectionInUse(C3P0PooledConnectionPool.java:758) at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:685) ... 25 more Caused by: org.h2.jdbc.JdbcSQLException: Error while creating file "/usr/share/tomcat7/.gitbucket" [90062-190] at org.h2.message.DbException.getJdbcSQLException(DbException.java:345) at org.h2.message.DbException.get(DbException.java:179) at org.h2.message.DbException.get(DbException.java:155) at org.h2.store.fs.FilePathDisk.createDirectory(FilePathDisk.java:274) at org.h2.store.fs.FileUtils.createDirectory(FileUtils.java:42) at org.h2.store.fs.FileUtils.createDirectories(FileUtils.java:309) at org.h2.mvstore.db.MVTableEngine.init(MVTableEngine.java:73) at org.h2.engine.Database.getPageStore(Database.java:2450) at org.h2.engine.Database.open(Database.java:672) at org.h2.engine.Database.openDatabase(Database.java:269) at org.h2.engine.Database.(Database.java:263) at org.h2.engine.Engine.openSession(Engine.java:65) at org.h2.engine.Engine.openSession(Engine.java:175) at org.h2.engine.Engine.createSessionAndValidate(Engine.java:153) at org.h2.engine.Engine.createSession(Engine.java:136) at org.h2.engine.Engine.createSession(Engine.java:28) at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:349) at org.h2.jdbc.JdbcConnection. (JdbcConnection.java:107) at org.h2.jdbc.JdbcConnection. (JdbcConnection.java:91) at org.h2.Driver.connect(Driver.java:72) at com.mchange.v2.c3p0.DriverManagerDataSource.getConnection(DriverManagerDataSource.java:175) at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:220) at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:206) at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.acquireResource(C3P0PooledConnectionPool.java:203) at com.mchange.v2.resourcepool.BasicResourcePool.doAcquire(BasicResourcePool.java:1138) at com.mchange.v2.resourcepool.BasicResourcePool.doAcquireAndDecrementPendingAcquiresWithinLockOnSuccess(BasicResourcePool.java:1125) at com.mchange.v2.resourcepool.BasicResourcePool.access$700(BasicResourcePool.java:44) at com.mchange.v2.resourcepool.BasicResourcePool$ScatteredAcquireTask.run(BasicResourcePool.java:1870) at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:696)
/usr/share/tomcat7/.gitbucket
が作成できないらしい。パーミッションかls -al /usr/share/tomcat7rootになっとる。drwxr-xr-x 4 root root 4096 Apr 7 14:24 . drwxr-xr-x 155 root root 4096 Apr 7 14:25 .. drwxr-xr-x 2 root root 4096 Apr 7 14:24 bin -rw-r--r-- 1 root root 39 Feb 21 2014 defaults.md5sum -rw-r--r-- 1 root root 2030 Feb 21 2014 defaults.template drwxr-xr-x 2 root root 4096 Apr 7 14:24 lib -rw-r--r-- 1 root root 53 Feb 21 2014 logrotate.md5sum -rw-r--r-- 1 root root 118 Feb 21 2014 logrotate.template
/usr/share/tomcat7/.gitbuckeのパーミッション設定
sudo chown -R tomcat7:tomcat7 /usr/share/tomcat7再度再起動したら表示はされたが assets が効いていない。
assets有効化
どうやら assets のパスは固定になっているらしい。今回は VirtualHost でやったため、/gitbucket
が存在しないから /gitbucket/assets
も当然見えないわけだ。しかたないので
/etc/apache2/sites-available/gitbucket.conf
を書き換えた。
<VirtualHost *:443> ServerName gitbucket.my-domain:443 ProxyReverseHost On RewriteEngine On ProxyPass /gitbucket ajp://localhost:8009/gitbucket/ ProxyPassReverse /gitbucket ajp://localhost:8009/gitbucket/ ProxyPass /gitbucket/assets ! # 静的ファイルはAapacheに処理させる Redirect / /gitbucket # ルートにアクセスしても大丈夫なように RewriteRule ^/gitbucket/(.*) ajp://localhost:8009/gitbucket/$1 [P,L,QSA] SSLCertificateFile /etc/apache2/cert/ssl-cert.pem SSLCertificateKeyFile /etc/apache2/cert/ssl-cert.key </VirtualHost>RewriteRule がないとトップは表示されても、サインインできなかった。
もうちょっとスッキリした設定があるような気がするけど、まあとりあえず。
Ubuntu 12.04 on さくらのVPS に Jenkins を入れたメモ
Jenkinsのインストール
wget -q -O - http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add - sudo sh -c 'echo "deb http://pkg.jenkins-ci.org/debian binary/" > /etc/apt/sources.list.d/jenkins.list' sudo aptitude update sudo aptitude install -y jenkins
Jenkinsの設定変更
sudo vi /etc/default/jenkins
HTTP_PORT
を-1に、AJP_PORT
を8008に(Tomcat導入予定のため)
Apacheの設定
sudo vi /etc/apache2/sites-available/jenkins.conf<VirtualHost *:443> ServerName jenkins.my-domain:443 <Location /> ProxyPass ajp://localhost:8008/ </Location> SSLCertificateFile /etc/apache2/cert/ssl-cert.pem SSLCertificateKeyFile /etc/apache2/cert/ssl-cert.key </VirtualHost>sudo a2ensite jenkins
再起動
sudo service jenkins restart sudo service apache2 restart
とっても簡単だった
2016/04/06
git 2.0.0 → git 2.8.1
% git --versionとくに問題なし、前回と同じ。git version 2.0.0% cd /opt/src % wget https://www.kernel.org/pub/software/scm/git/git-2.8.1.tar.gz % tar xf git-2.8.1.tar.gz % cd git-2.8.1 % ./configure --prefix=/opt/git/git-2.8.1 --with-openssl --with-curl % make % make install % /opt/git/git-2.8.1/bin/git --versiongit version 2.8.1% ln -sfn /opt/git/git-2.8.1/bin/* /usr/bin % git --versiongit version 2.8.1
2016/03/12
よくあるテーブルのヘッダ固定の1つ
業務アプリを作っているとテーブルのヘッダを固定して欲しいという話はよくある。よくありすぎる。
2つのテーブルを作って列の幅を固定して、body担当テーブルはdivで囲って overflow-y 程度でできればいいんだけど、IEはスクロールバーを出しっぱなしなのでずれる。
仕方なくheader担当にもスクロールバーをだしっぱなすとかまあ色々苦労する。
今回は、ページの上部にヘッダが来たらそこでheader担当を固定させてやればいいよね。ということでやってみた。
(function() { | |
'use strict'; | |
angular.module('app').directive('fixedOnTop', function($window) { | |
return { | |
restrict: 'A', | |
link: function($scope, element, attrs) { | |
angular.element($window).on('scroll', function() { | |
var baseTop = element.get(0).offsetTop; | |
if (angular.element(this).scrollTop() >= baseTop) { | |
element.addClass('fixed-on-top'); | |
element.width(angular.element('#' + attrs.fixedOnTop).width()); | |
} else { | |
element.removeClass('fixed-on-top'); | |
element.width('100%'); | |
} | |
}); | |
} | |
} | |
}); | |
}()); | |
.fixed-on-top { | |
position: fixed; | |
top: 98px; | |
} |
<div> | |
<table id="table-header" fixed-on-top="table-body"> | |
<!-- header cells --> | |
</table> | |
<table id="table-body"> | |
<!-- data cells --> | |
</table> | |
</div> |
$(function() { | |
var baseTop = $('#table-header').get(0).offsetTop; | |
$(window).on('scroll', function() { | |
if ($(this).scrollTop() > baseTop) { | |
$('.header').addClass('fixed-on-top'); | |
} else { | |
$('.header').removeClass('fixed-on-top'); | |
} | |
}); | |
}); |
AngularJS の directive でやったけど、参考にした jQuery も備忘録的にメモっておいた
Bootstrapのpanelなんかの中にあった場合、固定した瞬間にはみ出て横幅がずれるので、body担当の横幅に合わせられるようにしている。
本当は thead に設定して1つのテーブルでやりたかったんだけどどうしても幅指定が出来なくて仕方なくテーブルを分けた。
横幅やスクロール距離、固定位置などパラメータは要件次第だけど結構手軽にできるもんだな

