@@ -2,23 +2,28 @@ import 'codeflask-element'
22import 'prismjs/components/prism-markdown.min.js'
33import 'prismjs/components/prism-json.min.js'
44import { LitElement , html } from '@polymer/lit-element'
5- import { sharedStyles , icons , iconCode } from './util.js'
5+ import { upload , sharedStyles , icons , iconCode } from './util.js'
66import produce from 'immer'
77
88export default class MicroPanelEditorEntry extends LitElement {
99 static get properties ( ) {
1010 return {
11- entry : Object , setEntry : Function , openJsonEditors : Object , jsonParseError : Object
11+ entry : Object , setEntry : Function ,
12+ openUploaders : Object , uploadQueues : Object ,
13+ openJsonEditors : Object , jsonParseError : Object ,
14+ media : /* endpoint */ String , mediatoken : String ,
1215 }
1316 }
1417
1518 constructor ( ) {
1619 super ( )
20+ this . openUploaders = { }
21+ this . uploadQueues = { }
1722 this . openJsonEditors = { }
1823 this . jsonParseError = { }
1924 }
2025
21- _render ( { entry, openJsonEditors, jsonParseError } ) {
26+ _render ( { entry, openUploaders , uploadQueues , openJsonEditors, jsonParseError, media , mediatoken } ) {
2227 return html `
2328 ${ sharedStyles }
2429 < style >
@@ -66,6 +71,32 @@ export default class MicroPanelEditorEntry extends LitElement {
6671 padding : 0.5rem ;
6772 }
6873
74+ # upload-zone {
75+ position : relative;
76+ padding : 0.5rem ;
77+ }
78+ .drag-overlay {
79+ display : none;
80+ }
81+ .dragging .drag-overlay {
82+ display : flex;
83+ align-items : center;
84+ justify-content : center;
85+ text-align : center;
86+ position : absolute;
87+ top : 0 ;
88+ right : 0 ;
89+ bottom : 0 ;
90+ left : 0 ;
91+ background : rgba (60 , 60 , 60 , 0.8 );
92+ color : # fff ;
93+ }
94+ progress {
95+ display : block;
96+ width : 100% ;
97+ margin : 0.1rem 0 0.4rem ;
98+ }
99+
69100 @media screen and (min-width : 700px ) {
70101 fieldset { width : 70% ; }
71102 }
@@ -88,6 +119,12 @@ export default class MicroPanelEditorEntry extends LitElement {
88119 this . openJsonEditors = produce ( openJsonEditors , x => { x [ propname ] = ! ( x [ propname ] || false ) } )
89120 this . jsonParseError = produce ( jsonParseError , pes => { pes [ propname ] = null } )
90121 } } title ="Edit this property as JSON" class="icon-button"> ${ iconCode ( icons . json ) } </ button >
122+ ${ media && ! openUploaders [ propname ] ? html `
123+ < button on-click =${ _ => {
124+ this . uploadQueues = produce ( uploadQueues , x => { x [ propname ] = [ ] } )
125+ this . openUploaders = produce ( openUploaders , x => { x [ propname ] = true } )
126+ } } title ="Upload media files" class="icon-button"> ${ iconCode ( icons . cloudUpload ) } </ button >
127+ ` : '' }
91128 < button on-click =${ _ =>
92129 this . _modify ( entry , draft => draft . properties [ propname ] . push ( '' ) )
93130 } title ="Add new value to this property" class="icon-button"> ${ iconCode ( icons . plus ) } </ button >
@@ -101,6 +138,7 @@ export default class MicroPanelEditorEntry extends LitElement {
101138 } title ="Delete this value" class="icon-button"> ${ iconCode ( icons . minus ) } </ button >
102139 </ div >
103140 ` ) ) }
141+ ${ openUploaders [ propname ] ? this . _mediaUploader ( entry , propname , media , mediatoken , uploadQueues ) : '' }
104142 </ fieldset >
105143 ` ) }
106144
@@ -161,6 +199,104 @@ export default class MicroPanelEditorEntry extends LitElement {
161199 `
162200 }
163201
202+ _mediaUploader ( entry , propname , media , mediatoken , uploadQueues ) {
203+ return html `
204+ < div id ="upload-zone "
205+ on-dragenter =${ e => {
206+ e . stopPropagation ( )
207+ e . preventDefault ( )
208+ console . log ( this )
209+ if ( this . dragFirst ) {
210+ this . dragSecond = true
211+ } else {
212+ this . dragFirst = true
213+ e . dataTransfer . dropEffect = 'copy'
214+ this . shadowRoot . getElementById ( 'upload-zone' ) . classList . add ( 'dragging' )
215+ }
216+ } }
217+ on-dragover =${ e => {
218+ e . stopPropagation ( )
219+ e . preventDefault ( )
220+ } }
221+ on-dragleave=${ e => {
222+ e . stopPropagation ( )
223+ e . preventDefault ( )
224+ if ( this . dragSecond ) {
225+ this . dragSecond = false
226+ } else {
227+ this . dragFirst = false
228+ }
229+ if ( ! this . dragFirst && ! this . dragSecond ) {
230+ this . shadowRoot . getElementById ( 'upload-zone' ) . classList . remove ( 'dragging' )
231+ }
232+ } }
233+ on-drop=${ e => {
234+ e . stopPropagation ( )
235+ e . preventDefault ( )
236+ this . dragFirst = false
237+ this . dragSecond = false
238+ this . shadowRoot . getElementById ( 'upload-zone' ) . classList . remove ( 'dragging' )
239+ this . uploadQueues = produce ( uploadQueues , x => {
240+ for ( const file of e . dataTransfer . files ) {
241+ x [ propname ] . push ( { file } )
242+ console . log ( file )
243+ }
244+ } )
245+ } } >
246+ Drag'n'drop or select < input type ="file " multiple on-change =${ e => {
247+ this . uploadQueues = produce ( uploadQueues , x => {
248+ for ( const file of e . target . files ) {
249+ x [ propname ] . push ( { file } )
250+ console . log ( file )
251+ }
252+ } )
253+ } } >
254+ to upload.
255+ ${ uploadQueues [ propname ] . length > 0 ? html `
256+ < div class ="upload-queue ">
257+ ${ uploadQueues [ propname ] . map ( ( { file, progress } , idx ) => html `
258+ < div class ="upload-queue-file bar ">
259+ < div class ="stretchy ">
260+ < div > ${ file . name } </ div >
261+ ${ progress ? html `< progress max ="100 " value =${ progress } > ${ progress } %</ progress > ` : '' }
262+ </ div >
263+ < button on-click =${ _ =>
264+ this . uploadQueues = produce ( uploadQueues , x => { x [ propname ] . splice ( idx , 1 ) } )
265+ } title ="Delete this file from the queue" class="icon-button"> ${ iconCode ( icons . minus ) } </ button >
266+ </ div >
267+ ` ) }
268+ </ div >
269+ < button on-click =${ async e => {
270+ for ( const [ idx , wrapper ] of uploadQueues [ propname ] . entries ( ) ) {
271+ try {
272+ const result = await upload ( media , mediatoken , wrapper . file , e =>
273+ this . uploadQueues = produce ( this . uploadQueues , x => {
274+ const idxx = x [ propname ] . findIndex ( y => y . file === wrapper . file )
275+ if ( e . lengthComputable ) {
276+ x [ propname ] [ idxx ] . progress = e . loaded / e . total * 100
277+ } else {
278+ x [ propname ] [ idxx ] . progress = 'ind'
279+ }
280+ } ) )
281+ this . _modify ( this . entry , draft => {
282+ draft . properties [ propname ] . push ( result )
283+ } )
284+ this . uploadQueues = produce ( this . uploadQueues , x => {
285+ x [ propname ] . splice ( x [ propname ] . findIndex ( y => y . file === wrapper . file ) , 1 )
286+ } )
287+ } catch ( e ) {
288+ alert ( e )
289+ }
290+ }
291+ } } > Upload!</ button >
292+ ` : '' }
293+ < div class ="drag-overlay ">
294+ Drop files here!
295+ </ div >
296+ </ div >
297+ `
298+ }
299+
164300 addNewProp ( e , entry ) {
165301 if ( 'key' in e && e . key !== 'Enter' ) {
166302 return
0 commit comments