Elixir / Phoenix — CKEditor 5導入篇
CKEditor 5 重製版 — 自己動手包起來之後產生的重製版CKEditor 5,我們來把它加到專案裡來用吧!
Genesis
接續CKEditor 5 重製版 — 自己動手包起來之後已產生build files,如果還沒有產生重製版的朋友,建議從CKEditor 5 重製版 — 自己動手包起來開始收看喔,或者是從CKEditor 5 重製版 — 需求談起來更好,畢竟談得好的需求讓你上天堂…
Concept
由於Phoenix Framework有一種以上的方式來處理assets,詳情請看官方文件的Default Configuration And Workflow這段:
The
css
andjs
directories inside ofassets
are a convention. Brunch will simply look for all files inassets
excludingassets/static
and sort all found files by their type.Processed and concatenated javascript will be put into
priv/static/js/app.js
, styles will be inpriv/static/css/app.css
.
所以我們這次選用比較無痛的方式,而且也可以很快理解Phoenix在這個部分到底做了什麼。
Steps
Copy build files to phoenix
產生一個新專案ckeditor_integration_demo,然後把上一篇專案裡build出來的結果,複製到我們phoenix產生的新專案底下
$ cp -R ~/develop/ckeditor5-build-classic/build ~/develop/ckeditor_integration_demo/assets/vendor/ckeditor5/
Write some code
這裡我們可以感受到Phoenix快速開發的優點,直接產生一組模板出來修改成我們要的內容,我們只需定義資料庫欄位名稱與類別,其他的都會從標準CRUD來產生。
如果你想知道更詳細Phoenix可以幫我們做什麼?
$ mix phx
Phoenix v1.4.16
Productive. Reliable. Fast.
A productive web framework that does not compromise speed or maintainability.Available tasks:mix phx.digest # Digests and compresses static files
mix phx.digest.clean # Removes old versions of static assets.
mix phx.gen.cert # Generates a self-signed certificate for HTTPS testing
mix phx.gen.channel # Generates a Phoenix channel
mix phx.gen.context # Generates a context with functions around an Ecto schema
mix phx.gen.embedded # Generates an embedded Ecto schema file
mix phx.gen.html # Generates controller, views, and context for an HTML resource
mix phx.gen.json # Generates controller, views, and context for a JSON resource
mix phx.gen.presence # Generates a Presence tracker
mix phx.gen.schema # Generates an Ecto schema and migration file
mix phx.gen.secret # Generates a secret
mix phx.new # Creates a new Phoenix v1.4.16 application
mix phx.new.ecto # Creates a new Ecto project within an umbrella project
mix phx.new.web # Creates a new Phoenix web project within an umbrella project
mix phx.routes # Prints all routes
mix phx.server # Starts applications and their servers
這次我們來試試看完整產生到頁面再來修改成我們希望的內容吧!
$ mix phx.gen.html Content Post posts title:string content:string
* creating lib/ckeditor_integration_demo_web/controllers/post_controller.ex
* creating lib/ckeditor_integration_demo_web/templates/post/edit.html.eex
* creating lib/ckeditor_integration_demo_web/templates/post/form.html.eex
* creating lib/ckeditor_integration_demo_web/templates/post/index.html.eex
* creating lib/ckeditor_integration_demo_web/templates/post/new.html.eex
* creating lib/ckeditor_integration_demo_web/templates/post/show.html.eex
* creating lib/ckeditor_integration_demo_web/views/post_view.ex
* creating test/ckeditor_integration_demo_web/controllers/post_controller_test.exs
* creating lib/ckeditor_integration_demo/content/post.ex
* creating priv/repo/migrations/20200325180149_create_posts.exs
* creating lib/ckeditor_integration_demo/content.ex
* injecting lib/ckeditor_integration_demo/content.ex
* creating test/ckeditor_integration_demo/content_test.exs
* injecting test/ckeditor_integration_demo/content_test.exsAdd the resource to your browser scope in lib/ckeditor_integration_demo_web/router.ex:resources "/posts", PostControllerRemember to update your repository by running migrations:$ mix ecto.migrate
上面主要是產生一組controller, views, and context for an HTML resource;我們context命名為Content,modal命名為Post,而schema table name命名為posts;給他兩個欄位:Title、content,且兩個欄位都是string類別。
Phoenix有很貼心的提醒你要記得把下面這段加到lib/ckeditor_integration_demo_web/router.ex
# lib/ckeditor_integration_demo_web/router.exresources "/posts", PostController
跑一下ecto.migrate
$ mix ecto.migrate
Compiling 5 files (.ex)
.....
啟動一下server
$ mix phx.server
.....
打開瀏覽器的http://localhost:4000/posts,看看Phoenix幫我們做了什麼
$ open http://localhost:4000/posts
新增、修改、查詢都幫我們產生了,接下來我們先把頁面的content從text改成textarea吧。
# lib/ckeditor_integration_demo_web/templates/post/form.html.eex<%= text_input f, :title %> <---- 原本的
<%= textarea f, :content %> <---- 改成這樣
再來要是針對ckeditor5的步驟了,首先要先增加一個deps
$ cd assets && npm install --save-dev @babel/plugin-transform-runtime
接著把增加的@babel/plugin-transform-runtime以及原本就有的presets加到babel-loader裡
# assets/webpack.config.js.....
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-transform-runtime']
}
}
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader']
}
]
},
.....
在app.js裡追加我們自己寫的Javascript file — custom.js
# assets/js/app.js.....// Import local files
import './custom'.....
寫一下custom.js來啟動這個textarea,讓他可以被ckeditor使用;這裡就是上一篇提到的設定檔,產生出來的編輯器功能,可以在這裡再經過刪減。注意!是刪減喔,新增除非重製版編輯器裡已經有了,否則就只能再重製一版喔!
# assets/js/custom.js// CKEditor5
ClassicEditor
.create( document.querySelector( '#post_content' ), {
toolbar: ['bold', 'fontSize', 'fontColor', '|', 'bulletedList', 'numberedList', 'indent', 'outdent', '|', 'undo', 'redo'],
language: {
ui: 'zh',
content: 'zh'
},
})
.catch( error => {
console.log( error );
} );
這裡額外提一下這段
document.querySelector( '#post_content' )
為什麼這裡的ID是post_content,而不是content呢?
因為我們用了Phoenix.HTML.Tag,它會幫我們把Form的名字自動加在底線前面,就變成這種格式。如果不確定的人,建議你可以用檢視原始碼工具看一下那個欄位就知道ID是什麼了。
到這邊我們再來啟動一下server,確認一下目前改得如何了
$ mix phx.server
[info] Running CkeditorIntegrationDemoWeb.Endpoint with cowboy 2.7.0 at 0.0.0.0:4000 (http)
[info] Access CkeditorIntegrationDemoWeb.Endpoint at http://localhost:4000
.....
可以看到我們重製的CKEditor5被套進textarea裡了,而且功能也都正常,編輯器產生的效果,實際上是被轉換成HTML包起來,再存進DB。
Display Content
那寫入沒問題,讀取該怎麼在Elixir / Phoenix上呈現啊?很簡單,就是使用Phoenix.HTML.raw/1!
Marks the given content as raw.
This means any HTML code inside the given string won’t be escaped.
我們把剛剛的例子繼續改完看看吧!把#16改一下
# lib/ckeditor_integration_demo_web/templates/post/index.html.eex<td><%= post.content %></td> <----- 原本的
<td><%= raw post.content %></td> <----- 把內容喂給raw/1
太好了!顯示也沒問題囉!
One more thing…
其實我自己的Real world problem是我使用了Tailwind CSS,要怎麼在使用Tailwind CSS的情況之下,要支援CKEditor5產生出來的語法?
最後我的解法是在app.css裡,先引用@tailwind base之後,再去指定CKEditor5語法跟Tailwind CSS語法的關聯。
# assets/css/app.css@tailwind base;
h1 {
@apply text-2xl;
}
h2 {
@apply text-xl;
}
h3 {
@apply text-lg;
}
ul {
list-style-type: disc;
padding-left: theme('padding.4');
}
ol {
list-style-type: decimal;
padding-left: theme('padding.4');
}
@tailwind components;
.....
類似上面的例子,把HTML code與Tailwind CSS綁在一起就行了!是不是很簡單,這也是Tailwind CSS的好處之一吧!
找時間再來寫一篇,Elixir / Phoenix 與Tailwind CSS的整合篇吧!