From 09229dffac9bf1e89981e658edada276b5e49f36 Mon Sep 17 00:00:00 2001 From: Valeriy Gavrilin Date: Wed, 23 Oct 2019 19:30:34 +0300 Subject: [PATCH] Drag-n-drop support in file upload form --- build.sbt | 2 +- project/WebDeps.scala | 74 +++++++++++++------ project/plugins.sbt | 5 +- .../webapp/components/common/Dropzone.scala | 25 +++++++ .../webapp/components/folder/UploadForm.scala | 22 +++--- tika-custom.xml | 2 + 6 files changed, 93 insertions(+), 37 deletions(-) create mode 100644 server/webapp/src/main/scala/com/karasiq/shadowcloud/webapp/components/common/Dropzone.scala diff --git a/build.sbt b/build.sbt index 998b1924..3f2e1cd0 100644 --- a/build.sbt +++ b/build.sbt @@ -305,7 +305,7 @@ lazy val `server-static-routes` = (project in file("server") / "static-routes") import com.karasiq.scalajsbundler.dsl._ Bundle( "index", - WebDeps.indexHtml, WebDeps.bootstrap, WebDeps.videoJS, WebDeps.markedJS, + WebDeps.indexHtml, WebDeps.bootstrap, WebDeps.videoJS, WebDeps.markedJS, WebDeps.dropzoneJS, scalaJsApplication(webapp, fastOpt = false, launcher = false).value ) }, diff --git a/project/WebDeps.scala b/project/WebDeps.scala index 7e16ca4e..1253157a 100644 --- a/project/WebDeps.scala +++ b/project/WebDeps.scala @@ -1,7 +1,6 @@ -import sbt._ - import com.karasiq.scalajsbundler.ScalaJSBundler.PageContent import com.karasiq.scalajsbundler.dsl.{Script, _} +import sbt._ private object JSModuleIDBuilder // Implicit fix @@ -23,7 +22,7 @@ object WebDeps { ) } - def style: String =""" + def style: String = """ |.glyphicon { | margin-right: 3px; |} @@ -35,10 +34,10 @@ object WebDeps { } private object Bootstrap { - private[this] val BootstrapV = "3.3.7" + private[this] val BootstrapV = "3.3.7" private[this] val BootstrapDatePickerV = "1.7.1" - private[this] val JQueryV = "3.2.1" - private[this] val FontAwesomeV = "4.7.0" + private[this] val JQueryV = "3.2.1" + private[this] val FontAwesomeV = "4.7.0" /* private def themes = Seq( "Cerulean", "Cosmo", "Cyborg", "Darkly", "Flatly", "Journal", "Lumen", "Paper", "Readable", @@ -63,14 +62,16 @@ object WebDeps { // Bootstrap // sys.props.get("bootstrap-theme").fold(Style from url(s"https://raw.githubusercontent.com/twbs/bootstrap/v$BootstrapV/dist/css/bootstrap.css"))(themeCss), Style from url(s"https://cdn.jsdelivr.net/webjars/org.webjars/bootstrap-datepicker/$BootstrapDatePickerV/css/bootstrap-datepicker3.min.css"), - // Font Awesome Style from url(s"https://raw.githubusercontent.com/FortAwesome/Font-Awesome/v$FontAwesomeV/css/font-awesome.css") ) } def fonts: Seq[PageContent] = { - fontPackage("glyphicons-halflings-regular", s"https://raw.githubusercontent.com/twbs/bootstrap/v$BootstrapV/dist/fonts/glyphicons-halflings-regular") ++ + fontPackage( + "glyphicons-halflings-regular", + s"https://raw.githubusercontent.com/twbs/bootstrap/v$BootstrapV/dist/fonts/glyphicons-halflings-regular" + ) ++ fontPackage("fontawesome-webfont", s"https://raw.githubusercontent.com/FortAwesome/Font-Awesome/v$FontAwesomeV/fonts/fontawesome-webfont") } @@ -87,44 +88,75 @@ object WebDeps { val videoJs = github("videojs", "video.js", "v5.8.0") / "dist" Seq( Script from url(videoJs % "video.min.js"), - Style from url(videoJs % "video-js.min.css") + Style from url(videoJs % "video-js.min.css") ) } def markedJS: Seq[PageContent] = { val highlightJSLanguages = Seq( - "bash", "clojure", "coffeescript", "cpp", "cs", "d", "delphi", "erlang", "fsharp", - "go", "groovy", "haskell", "java", "javascript", "json", "lua", "lisp", "markdown", - "objectivec", "perl", "php", "python", "ruby", "rust", "scala", "scheme", "sql", - "swift", "typescript", "css", "xml" + "bash", + "clojure", + "coffeescript", + "cpp", + "cs", + "d", + "delphi", + "erlang", + "fsharp", + "go", + "groovy", + "haskell", + "java", + "javascript", + "json", + "lua", + "lisp", + "markdown", + "objectivec", + "perl", + "php", + "python", + "ruby", + "rust", + "scala", + "scheme", + "sql", + "swift", + "typescript", + "css", + "xml" ) val highlightJSStyle = "github" - - val markedJS = "org.webjars.bower" % "marked" % "0.3.5" - val highlightJS = "org.webjars" % "highlightjs" % "9.2.0" + + val markedJS = "org.webjars.bower" % "marked" % "0.3.5" + val highlightJS = "org.webjars" % "highlightjs" % "9.2.0" val tabOverrideJS = github("wjbryant", "taboverride", "4.0.3") / "build" / "output" val scripts = Seq( // Marked Script from markedJS / "marked.min.js", - // Highlight.js Script from highlightJS / "highlight.min.js", Style from highlightJS / s"styles/$highlightJSStyle.css", - // Tab Override Script from tabOverrideJS / "taboverride.min.js" ) - val highlightJSModules = for (lang ← highlightJSLanguages) - yield Script from highlightJS / s"languages/$lang.min.js" + val highlightJSModules = + for (lang ← highlightJSLanguages) + yield Script from highlightJS / s"languages/$lang.min.js" scripts ++ highlightJSModules } + def dropzoneJS = Seq[PageContent]( + Script from "org.webjars" % "dropzone" % "5.5.0" / "min/dropzone.min.js", + Style from "org.webjars" % "dropzone" % "5.5.0" / "min/dropzone.min.css" + ) + def indexHtml: Seq[PageContent] = { Seq(Html from Assets.index, Style from Assets.style) } -} \ No newline at end of file +} diff --git a/project/plugins.sbt b/project/plugins.sbt index b94e77fb..822ac99f 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -19,5 +19,6 @@ addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.5.1") libraryDependencies ++= Seq( "com.lihaoyi" %% "scalatags" % "0.6.7", "org.webjars.bower" % "marked" % "0.3.5", - "org.webjars" % "highlightjs" % "9.2.0" -) \ No newline at end of file + "org.webjars" % "highlightjs" % "9.2.0", + "org.webjars" % "dropzone" % "5.5.0" +) diff --git a/server/webapp/src/main/scala/com/karasiq/shadowcloud/webapp/components/common/Dropzone.scala b/server/webapp/src/main/scala/com/karasiq/shadowcloud/webapp/components/common/Dropzone.scala new file mode 100644 index 00000000..4b08eb0c --- /dev/null +++ b/server/webapp/src/main/scala/com/karasiq/shadowcloud/webapp/components/common/Dropzone.scala @@ -0,0 +1,25 @@ +package com.karasiq.shadowcloud.webapp.components.common + +import com.karasiq.bootstrap.Bootstrap.default._ +import org.scalajs.dom +import scalaTags._ + +import scala.scalajs.js +import scala.scalajs.js.annotation.JSGlobal + +@js.native +@JSGlobal("Dropzone") +class Dropzone(element: js.Any, options: js.Object) extends js.Object { + def on[T <: js.Any](event: String, f: js.Function1[T, Unit]): Unit = js.native + def removeAllFiles(): Unit = js.native +} + +object Dropzone { + def apply(process: dom.File => Unit): Modifier = { e: dom.Element => + val dropzone = new Dropzone(e, js.Dynamic.literal(url = "/", autoProcessQueue = false).asInstanceOf[js.Object]) + dropzone.on("addedfile", { f: dom.File => + process(f) + dropzone.removeAllFiles() + }) + } +} diff --git a/server/webapp/src/main/scala/com/karasiq/shadowcloud/webapp/components/folder/UploadForm.scala b/server/webapp/src/main/scala/com/karasiq/shadowcloud/webapp/components/folder/UploadForm.scala index 8d1621ac..db90e6b3 100644 --- a/server/webapp/src/main/scala/com/karasiq/shadowcloud/webapp/components/folder/UploadForm.scala +++ b/server/webapp/src/main/scala/com/karasiq/shadowcloud/webapp/components/folder/UploadForm.scala @@ -2,17 +2,14 @@ package com.karasiq.shadowcloud.webapp.components.folder import scala.annotation.tailrec import scala.concurrent.Future - import org.scalajs.dom import rx.{Rx, Var} - import com.karasiq.bootstrap.Bootstrap.default._ import scalaTags.all._ - import com.karasiq.common.memory.SizeUnit import com.karasiq.shadowcloud.model.{File, Path, RegionId} import com.karasiq.shadowcloud.utils.Utils -import com.karasiq.shadowcloud.webapp.components.common.{AppComponents, AppIcons, TextEditor} +import com.karasiq.shadowcloud.webapp.components.common.{AppComponents, AppIcons, Dropzone, TextEditor} import com.karasiq.shadowcloud.webapp.context.{AppContext, FolderContext} import com.karasiq.shadowcloud.webapp.context.AppContext.JsExecutionContext import com.karasiq.shadowcloud.webapp.controllers.FileController @@ -53,14 +50,10 @@ class UploadForm(implicit appContext: AppContext, folderContext: FolderContext, uploading.triggerLater(processQueue()) def renderTag(md: ModifierT*): TagT = { - val uploadInput = FormInput.file(appContext.locale.file, multiple, md, onchange := Callback.onInput { input ⇒ - // Preserve context at click time - val newFiles = input.files.toList - .map(file ⇒ UploadRequest(folderContext.regionId, folderContext.selected.now, file)) - - uploadQueue() = uploadQueue.now ++ newFiles - input.form.reset() - }) +// val uploadInput = FormInput.file(appContext.locale.file, multiple, md, onchange := Callback.onInput { input ⇒ +// +// input.form.reset() +// }) val editor = TextEditor { editor ⇒ editor.submitting() = true @@ -75,7 +68,10 @@ class UploadForm(implicit appContext: AppContext, folderContext: FolderContext, } val navigation = Navigation.pills( - NavigationTab(appContext.locale.uploadFiles, "upload-files", NoIcon, Form(uploadInput)), + NavigationTab(appContext.locale.uploadFiles, "upload-files", NoIcon, Form(action := "/", `class` := "dropzone", Dropzone { file => + // Preserve context at click time + uploadQueue() = uploadQueue.now :+ UploadRequest(folderContext.regionId, folderContext.selected.now, file) + })), NavigationTab(appContext.locale.pasteText, "paste-text", NoIcon, editor) ) diff --git a/tika-custom.xml b/tika-custom.xml index b02ff1b6..f8749e24 100644 --- a/tika-custom.xml +++ b/tika-custom.xml @@ -11,6 +11,8 @@ + 3000 + 512000 rus