diff --git a/.gitignore b/.gitignore index 9daa824..6423b8b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .DS_Store node_modules +.vscode diff --git a/README.md b/README.md index 7d0b330..c936a37 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Included actions: - Code - Horizontal Rule - Link -- Image +- Image (support uploading) Other available actions (listed at https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand): - Justify Center diff --git a/demo.html b/demo.html index 45583cb..8de87a4 100644 --- a/demo.html +++ b/demo.html @@ -50,6 +50,11 @@
")}},quote:{icon:"“ ”",title:"Quote",result:function(){return c("formatBlock","
")}},olist:{icon:"#",title:"Ordered List",result:function(){return c("insertOrderedList")}},ulist:{icon:"•",title:"Unordered List",result:function(){return c("insertUnorderedList")}},code:{icon:"</>",title:"Code",result:function(){return c("formatBlock","")}},line:{icon:"―",title:"Horizontal Line",result:function(){return c("insertHorizontalRule")}},link:{icon:"🔗",title:"Link",result:function(){var t=window.prompt("Enter the link URL");t&&c("createLink",t)}},image:{icon:"📷",title:"Image",result:function(){var t=window.prompt("Enter the image URL");t&&c("insertImage",t)}}},a={actionbar:"pell-actionbar",button:"pell-button",content:"pell-content",selected:"pell-button-selected"},s=function(t){var o=t.actions?t.actions.map(function(t){return"string"==typeof t?l[t]:l[t.name]?e({},l[t.name],t):t}):Object.keys(l).map(function(t){return l[t]}),s=e({},a,t.classes),f=t.defaultParagraphSeparator||"div",d=i("div");d.className=s.actionbar,r(t.element,d);var m=t.element.content=i("div");return m.contentEditable=!0,m.className=s.content,m.oninput=function(e){var n=e.target.firstChild;n&&3===n.nodeType?c("formatBlock","<"+f+">"):"
"===m.innerHTML&&(m.innerHTML=""),t.onChange(m.innerHTML)},m.onkeydown=function(t){"Tab"===t.key?t.preventDefault():"Enter"===t.key&&"blockquote"===u("formatBlock")&&setTimeout(function(){return c("formatBlock","<"+f+">")},0)},r(t.element,m),o.forEach(function(t){var e=i("button");if(e.className=s.button,e.innerHTML=t.icon,e.title=t.title,e.setAttribute("type","button"),e.onclick=function(){return t.result()&&m.focus()},t.state){var o=function(){return e.classList[t.state()?"add":"remove"](s.selected)};n(m,"keyup",o),n(m,"mouseup",o),n(e,"click",o)}r(d,e)}),t.styleWithCSS&&c("styleWithCSS"),c("defaultParagraphSeparator",f),t.element},f={exec:c,init:s};t.exec=c,t.init=s,t.default=f,Object.defineProperty(t,"__esModule",{value:!0})});
+!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e(t.pell={})}(this,function(t){"use strict";var e=Object.assign||function(t){for(var e=1;e1&&void 0!==arguments[1]?arguments[1]:null;return document.execCommand(t,!1,e)},a={bold:{icon:"B",title:"Bold",state:function(){return o("bold")},result:function(){return c("bold")}},italic:{icon:"I",title:"Italic",state:function(){return o("italic")},result:function(){return c("italic")}},underline:{icon:"U",title:"Underline",state:function(){return o("underline")},result:function(){return c("underline")}},strikethrough:{icon:"S",title:"Strike-through",state:function(){return o("strikeThrough")},result:function(){return c("strikeThrough")}},heading1:{icon:"H1",title:"Heading 1",result:function(){return c("formatBlock","")}},heading2:{icon:"H2",title:"Heading 2",result:function(){return c("formatBlock","")}},paragraph:{icon:"¶",title:"Paragraph",result:function(){return c("formatBlock","
")}},quote:{icon:"“ ”",title:"Quote",result:function(){return c("formatBlock","
")}},olist:{icon:"#",title:"Ordered List",result:function(){return c("insertOrderedList")}},ulist:{icon:"•",title:"Unordered List",result:function(){return c("insertUnorderedList")}},code:{icon:"</>",title:"Code",result:function(){return c("formatBlock","")}},line:{icon:"―",title:"Horizontal Line",result:function(){return c("insertHorizontalRule")}},link:{icon:"🔗",title:"Link",result:function(){var t=window.prompt("Enter the link URL");t&&c("createLink",t)}},image:{icon:"📷",title:"Image",result:function(){l()}}},l=function(){var t=document.querySelector('.pell input[type="file"]');if(t)t.click();else{var e=window.prompt("Enter the image URL");e&&c("insertImage",e)}},s=function(t,e,n){var r=t.api,i=t.data;window.fetch&&window.fetch(r,{method:"POST",body:i}).then(function(t){return t.json()}).then(function(t){t.success&&e(t.url)},function(t){return n(t)})},f=function(t){var e=t.upload&&t.upload.api;if(e){var o=i("input");o.type="file",o.hidden=!0,n(o,"change",function(t){var n=t.target.files[0],r=new window.FormData;r.append("pell-upload-image",n),s({api:e,data:r},function(t){return c("insertImage",t)},function(t){return window.alert(t)})}),r(t.element,o)}},d={actionbar:"pell-actionbar",button:"pell-button",content:"pell-content",selected:"pell-button-selected"},p=function(t){var o=t.actions?t.actions.map(function(t){return"string"==typeof t?a[t]:a[t.name]?e({},a[t.name],t):t}):Object.keys(a).map(function(t){return a[t]}),l=e({},d,t.classes),s=t.defaultParagraphSeparator||"div",p=i("div");p.className=l.actionbar,r(t.element,p);var m=t.element.content=i("div");return m.contentEditable=!0,m.className=l.content,m.oninput=function(e){var n=e.target.firstChild;n&&3===n.nodeType?c("formatBlock","<"+s+">"):"
"===m.innerHTML&&(m.innerHTML=""),t.onChange(m.innerHTML)},m.onkeydown=function(t){"Tab"===t.key?t.preventDefault():"Enter"===t.key&&"blockquote"===u("formatBlock")&&setTimeout(function(){return c("formatBlock","<"+s+">")},0)},r(t.element,m),o.forEach(function(t){var e=i("button");if(e.className=l.button,e.innerHTML=t.icon,e.title=t.title,e.setAttribute("type","button"),e.onclick=function(){return t.result()&&m.focus()},t.state){var o=function(){return e.classList[t.state()?"add":"remove"](l.selected)};n(m,"keyup",o),n(m,"mouseup",o),n(e,"click",o)}r(p,e)}),t.styleWithCSS&&c("styleWithCSS"),c("defaultParagraphSeparator",s),f(t),t.element},m={exec:c,init:p};t.exec=c,t.init=p,t.default=m,Object.defineProperty(t,"__esModule",{value:!0})});
diff --git a/src/pell.js b/src/pell.js
index 3e2fe64..ef159c6 100644
--- a/src/pell.js
+++ b/src/pell.js
@@ -85,12 +85,67 @@ const defaultActions = {
icon: '📷',
title: 'Image',
result: () => {
- const url = window.prompt('Enter the image URL')
- if (url) exec('insertImage', url)
+ // const url = window.prompt('Enter the image URL')
+ // if (url) exec('insertImage', url)
+ execInsertImageAction()
}
}
}
+// default for not set `upload` config
+const execInsertImageAction = function () {
+ const uploadImageInput = document.querySelector('.pell input[type="file"]')
+ if (!uploadImageInput) {
+ const url = window.prompt('Enter the image URL')
+ if (url) exec('insertImage', url)
+ } else {
+ uploadImageInput.click()
+ }
+}
+
+// just set `url`, `method` and `body` for fetch api
+const uploadImage = function ({ api, data }, success, error) {
+ window.fetch && window.fetch(
+ api,
+ {
+ method: 'POST',
+ body: data
+ }
+ )
+ .then(res => res.json())
+ .then(
+ data => {
+ // responsive data format:
+ // { success: true, url: 'xxx' }
+ if (data.success) success(data.url)
+ },
+ err => error(err)
+ )
+}
+
+const initUploadImageInput = function (settings) {
+ const uploadAPI = settings.upload && settings.upload.api
+ if (uploadAPI) {
+ const input = createElement('input')
+ input.type = 'file'
+ input.hidden = true
+ addEventListener(input, 'change', e => {
+ const image = e.target.files[0]
+ const fd = new window.FormData()
+ fd.append('pell-upload-image', image)
+ uploadImage(
+ {
+ api: uploadAPI,
+ data: fd
+ },
+ url => exec('insertImage', url),
+ err => window.alert(err)
+ )
+ })
+ appendChild(settings.element, input)
+ }
+}
+
const defaultClasses = {
actionbar: 'pell-actionbar',
button: 'pell-button',
@@ -155,6 +210,9 @@ export const init = settings => {
if (settings.styleWithCSS) exec('styleWithCSS')
exec(defaultParagraphSeparatorString, defaultParagraphSeparator)
+ // init a upload image input or not
+ initUploadImageInput(settings)
+
return settings.element
}
diff --git a/src/pell.scss b/src/pell.scss
index 16c1819..7130cda 100644
--- a/src/pell.scss
+++ b/src/pell.scss
@@ -38,4 +38,4 @@ $pell-content-padding: 10px !default;
.pell-button-selected {
background-color: $pell-button-selected-color;
-}
+}
\ No newline at end of file