Explorar el Código

Moved from Artifacts woups

Manuel Gall hace 4 años
commit
ff00daed28

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+storage/
+server/ustore.pid

+ 0 - 0
README.md


+ 10 - 0
server/rngs/error.rng

@@ -0,0 +1,10 @@
+<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+  
+  <define name="error">
+    <element name="error">	  
+      <zeroOrMore>
+        <element name="reason"><text/></element>
+      </zeroOrMore>
+    </element>
+  </define>
+</grammar>

+ 16 - 0
server/rngs/image.rng

@@ -0,0 +1,16 @@
+<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+
+
+  <define name="image">
+    <element name="image">
+      <attribute name="id"><data type="nonNegativeInteger"/></attribute>
+	  <zeroOrMore>
+        <element name="variant">
+          <attribute name="lang"><text/></attribute>
+          <attribute name="label"><text/></attribute>
+		  <text/>
+        </element>
+	  </zeroOrMore>
+    </element>
+  </define>
+</grammar>

+ 11 - 0
server/rngs/imageUpload.rng

@@ -0,0 +1,11 @@
+<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+
+
+  <start>
+  <define name="image">
+    <element name="ajax"> <text/> </element>
+    <element name="language"> <text/> </element>
+  </define>
+  
+  </start>
+</grammar>

+ 12 - 0
server/rngs/images.rng

@@ -0,0 +1,12 @@
+<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+  <include href="image.rng"/>
+
+  
+  <define name="images">
+    <element name="images">
+      <zeroOrMore>
+        <ref name="image"/>
+      </zeroOrMore>
+    </element>
+  </define>
+</grammar>

+ 16 - 0
server/rngs/pattern.rng

@@ -0,0 +1,16 @@
+<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+  <include href="images.rng"/>
+  
+  <define name="pattern">
+    <element name="pattern">
+      <attribute name="id"><data type="nonNegativeInteger"/></attribute>
+      <attribute name="value"><text/></attribute>
+      <attribute name="description"><text/></attribute>
+      <attribute name="changed"><data type="dateTime"/></attribute>
+	  
+      <zeroOrMore>
+        <ref name="images"/>
+      </zeroOrMore>
+    </element>
+  </define>
+</grammar>

+ 12 - 0
server/rngs/station.rng

@@ -0,0 +1,12 @@
+<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+  <include href="pattern.rng"/>
+
+  <define name="station">
+    <element name="station">
+      <attribute name="id"><data type="nonNegativeInteger"/></attribute>
+      <zeroOrMore>
+        <ref name="pattern"/>
+      </zeroOrMore>
+    </element>
+  </define>
+</grammar>

+ 11 - 0
server/rngs/stations.rng

@@ -0,0 +1,11 @@
+<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+  <include href="station.rng"/>
+
+  <start>
+    <element name="stations">
+      <zeroOrMore>
+        <ref name="station"/>
+      </zeroOrMore>
+    </element>
+  </start>
+</grammar>

+ 7 - 0
server/rngs/t_error.rng

@@ -0,0 +1,7 @@
+<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+  <include href="error.rng"/>
+
+  <start>
+    <ref name="error"/>
+  </start>
+</grammar>

+ 7 - 0
server/rngs/t_image.rng

@@ -0,0 +1,7 @@
+<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+  <include href="image.rng"/>
+
+  <start>
+    <ref name="image"/>
+  </start>
+</grammar>

+ 7 - 0
server/rngs/t_images.rng

@@ -0,0 +1,7 @@
+<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+  <include href="images.rng"/>
+
+  <start>
+    <ref name="images"/>
+  </start>
+</grammar>

+ 7 - 0
server/rngs/t_pattern.rng

@@ -0,0 +1,7 @@
+<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+  <include href="pattern.rng"/>
+
+  <start>
+    <ref name="pattern"/>
+  </start>
+</grammar>

+ 7 - 0
server/rngs/t_station.rng

@@ -0,0 +1,7 @@
+<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+  <include href="station.rng"/>
+
+  <start>
+    <ref name="station"/>
+  </start>
+</grammar>

+ 1 - 0
server/ustore.conf

@@ -0,0 +1 @@
+:port: 9328

+ 202 - 0
server/ustore.rb

@@ -0,0 +1,202 @@
+#!/usr/bin/ruby
+  #
+  # This file is part of centurio.work/ing/commands.
+  #
+  # centurio.work/ing/commands is free software: you can redistribute it and/or
+  # modify it under the terms of the GNU General Public License as published by
+  # the Free Software Foundation, either version 3 of the License, or (at your
+  # option) any later version.
+  #
+  # centurio.work/ing/commands is distributed in the hope that it will be useful,
+  # but WITHOUT ANY WARRANTY; without even the implied warranty of
+  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+  # Public License for more details.
+  #
+  # You should have received a copy of the GNU General Public License along with
+  # centurio.work/ing/commands (file COPYING in the main directory). If not, see
+# <http://www.gnu.org/licenses/>.
+
+require 'rubygems'
+require 'json'
+require 'riddl/server'
+require 'riddl/client'
+require 'fileutils'
+require 'nokogiri'
+
+
+class GetFolders < Riddl::Implementation
+  def response
+    Dir.chdir( __dir__  + '/../storage')
+    i = 1
+    while i < @r.length do
+      Dir.chdir(@r[i])   
+      i +=1
+    end
+    Riddl::Parameter::Complex.new('list','application/json',JSON::pretty_generate(Dir.glob('*/')))
+  end
+end
+
+class CreateFolder < Riddl::Implementation
+  def response
+    path = File.join(File.dirname(__dir__),'storage/', @r.drop(1).join("/"))
+    FileUtils.mkdir_p(path)
+  end
+end
+
+class DeleteFolder < Riddl::Implementation
+  def response
+    path = File.join(File.dirname(__dir__),'storage/', @r.drop(1).join("/"))
+    FileUtils.rm_rf(path)
+  end
+end
+
+class GetAllFolders < Riddl::Implementation
+  def response
+    Dir.chdir( __dir__  + '/../storage')
+    i = 1
+    while i < @r.length do
+      Dir.chdir(@r[i])   
+      i +=1
+    end
+    Riddl::Parameter::Complex.new('list','application/json',JSON::pretty_generate(Dir.glob('**/*/')))
+  end
+end
+
+
+class GetImages < Riddl::Implementation
+  def response
+    Dir.chdir( __dir__  + '/../storage')
+    i = 1
+    while i < @r.length do
+      Dir.chdir(@r[i])   
+      i +=1
+    end
+    
+    ret = [];
+    Dir.glob('*').select{ |e| 
+      if File.file? e 
+        ret.append(e)
+      end
+    }
+    Riddl::Parameter::Complex.new('list','application/json',JSON::pretty_generate(ret))
+  end
+end
+
+
+class UploadData < Riddl::Implementation
+  def response
+    
+    i = 0
+    while i < @p.length do
+	    item = @p[i]
+      if(item != nil && item.name == "files[]")
+        
+        #      puts item.inspect
+        
+        path = File.join(File.dirname(__dir__),'storage/', @r.drop(1).join("/"))
+        FileUtils.mkdir_p(path)
+        
+        readFile = File.read(item.value.inspect.to_s[/Tempfile:(.*?)>/m, 1])
+        File.open(File.join(path, item.filename), 'wb') do |file|
+          file.write(readFile.to_s)
+        end
+        
+        
+      end
+      i +=1
+    end
+  end
+end
+
+class DeleteData < Riddl::Implementation
+  def response
+    datalink = File.join(File.dirname(__dir__),'storage/', @r.drop(1).join("/"))
+    puts datalink
+    File.delete(datalink) if File.exist?(datalink)
+  end
+end
+
+
+
+class NewExternalFolder < Riddl::Implementation
+  def response
+    parsed = JSON.parse(@p[0].value.read)
+    
+    found = false;
+    path = File.join(File.dirname(__dir__),'server/ustore_Folders.txt')
+    text = File::readlines(path)
+    text.each do |line|
+      if line.chomp == parsed["folder"]
+        found = true
+      end
+    end
+    
+    if !found
+      File.open(path, 'a') do |file|
+        file.puts parsed["folder"]
+      end    
+    end
+  end
+end
+
+class GetAllExternalFolders < Riddl::Implementation
+  def response
+    
+    path = File.join(File.dirname(__dir__),'server/ustore_Folders.txt')
+    text = File::readlines(path)
+    text.each(&:chomp)
+    puts text
+    
+    Riddl::Parameter::Complex.new('list','application/json',JSON::pretty_generate(text))
+  end
+end
+
+
+server = Riddl::Server.new(File.join(__dir__,'/ustore.xml'), :host => 'localhost') do |opts|
+  accessible_description true
+  cross_site_xhr true
+  
+  
+  on resource do
+    on resource 'folders' do
+      run GetFolders if get
+      run CreateFolder if post
+      run DeleteFolder if delete
+      on resource '.*' do
+        run GetFolders if get
+        run CreateFolder if post
+        run DeleteFolder if delete
+      end
+    end
+    
+    on resource 'allfolders' do
+      run GetAllFolders if get
+      on resource '.*' do
+        run GetAllFolders if get
+      end
+    end
+    
+    on resource 'images' do
+      run GetImages if get
+      on resource '.*' do
+        run GetImages if get
+      end
+    end
+    
+    on resource 'data' do
+      run UploadData if post
+      run DeleteData if delete
+      on resource '.*' do
+        run UploadData if post
+        run DeleteData if delete
+      end
+    end
+    
+    on resource 'externalFolder' do
+      run NewExternalFolder if post
+      run GetAllExternalFolders if get
+    end
+    
+    
+  end
+end.loop!

+ 121 - 0
server/ustore.xml

@@ -0,0 +1,121 @@
+<!--
+  This file is part of centurio.work/ing/commands.
+
+  centurio.work/ing/commands is free software: you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or (at your
+  option) any later version.
+
+  centurio.work/ing/commands is distributed in the hope that it will
+  be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+  Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with
+  centurio.work/ing/commands (file COPYING in the main directory). If
+  not, see <http://www.gnu.org/licenses/>.
+-->
+
+<description xmlns="http://riddl.org/ns/description/1.0" xmlns:ann="http://riddl.org/ns/annotation/1.0" xmlns:xi="http://www.w3.org/2001/XInclude" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+  <message name="stations"><!--{{{-->
+    <parameter name="stations" mimetype="*/xml" handler="http://riddl.org/ns/handlers/relaxng">
+      <xi:include href="rngs/stations.rng"/>
+    </parameter>
+  </message> <!--}}}-->
+  <message name="num"> <!--{{{-->
+    <parameter name="num" type="nonNegativeInteger"/>
+  </message> <!--}}}-->
+  <message name="station"> <!--{{{-->
+    <parameter name="station" mimetype="*/xml" handler="http://riddl.org/ns/handlers/relaxng">
+      <xi:include href="rngs/t_station.rng"/>
+    </parameter>
+  </message> <!--}}}-->
+  <message name="pattern"> <!--{{{-->
+    <parameter name="pattern" mimetype="*/xml" handler="http://riddl.org/ns/handlers/relaxng">
+      <xi:include href="rngs/t_pattern.rng"/>
+    </parameter>
+  </message> <!--}}}-->
+  <message name="images"> <!--{{{-->
+    <parameter name="images" mimetype="*/xml" handler="http://riddl.org/ns/handlers/relaxng">
+      <xi:include href="rngs/t_images.rng"/>
+    </parameter>
+  </message> <!--}}}-->
+  <message name="image"> <!--{{{-->
+    <parameter name="image" mimetype="*/xml" handler="http://riddl.org/ns/handlers/relaxng">
+      <xi:include href="rngs/t_image.rng"/>
+    </parameter>
+  </message> <!--}}}-->
+  <message name="error"> <!--{{{-->
+    <parameter name="error" mimetype="*/xml" handler="http://riddl.org/ns/handlers/relaxng">
+      <xi:include href="rngs/t_error.rng"/>
+    </parameter>
+  </message> <!--}}}-->
+  <message name="imageUpload"> <!--{{{-->
+      <parameter name="imageUpload" mimetype="image/svg+xml"/>
+  </message> <!--}}}-->
+  <message name="amount"> <!--{{{-->
+    <parameter name="amount" type="nonNegativeInteger"/>
+  </message> <!--}}}-->
+  <message name="theRealImage"> <!--}}}-->
+    <parameter name="theRealImage" mimetype="image/svg+xml"/>
+  </message><!--}}}-->
+  <message name="imageid"> <!--{{{-->
+    <parameter name="imageid" type="nonNegativeInteger"/>
+  </message> <!--}}}-->
+  <message name="orderlist"> <!--{{{-->
+    <parameter name="orderlist" mimetype="application/json"/>
+  </message> <!--}}}-->
+  <message name="label"><!--}}}-->
+    <parameter name="label" type="string"/>
+  </message><!--}}}-->
+  <message name="list"><!--}}}-->
+    <parameter name="list" mimetype="application/json"/>
+  </message><!--}}}-->
+
+  
+  
+  <resource>
+    <resource relative="folders">
+      <get out="list"/>
+			<post />
+      <delete/>
+      <resource relative=".*">
+        <get out="list"/>
+        <post />
+        <delete/>
+      </resource>
+    </resource>
+    
+    <resource relative="allfolders">
+      <get out="list"/>
+      <resource relative=".*">
+        <get out="list"/>
+      </resource>
+    </resource>
+    
+    
+    <resource relative="images">
+      <get out="list"/>
+      <resource relative=".*">
+        <get out="list"/>
+      </resource>
+    </resource>
+    
+    <resource relative="data">
+			<post />
+      <post in="imageUpload"/>
+      <delete/>
+      <resource relative=".*">
+        <post />
+        <post in="imageUpload"/>
+        <delete/>
+      </resource>
+    </resource>
+    
+    <resource relative="externalFolder">
+			<post />
+      <get out="list"/>
+    </resource>
+    
+  </resource>
+</description>

+ 0 - 0
server/ustore_Folders.txt


+ 359 - 0
ui/css/ustore.css

@@ -0,0 +1,359 @@
+
+*[is=x-ui] ui-rest > ui-content > ui-resizehandle {
+  z-index: 1;
+}
+[is="x-ui"] ui-rest > ui-content > ui-area{
+  padding: 2em !important;
+}
+
+
+#selectfolders{
+  box-sizing: border-box;
+  width: 100%;
+}
+
+.Folder{
+  margin: 1em;
+  float: left;
+  text-align: center;
+  width: 8em;
+}
+
+.FolderImage{
+  font-size: 3em;
+}
+
+.FolderImageLink:hover  .FolderText{
+  text-decoration: underline;
+}
+
+.FolderTextNew{
+  margin-top: -2.1em;
+}
+
+#detailcolumn{
+  position: relative;
+  min-height: 95%;
+}
+
+#content-wrap {
+  min-height: 95%;
+  padding-bottom: -100px;    /* Footer height */
+}
+
+#RemoveFolder{
+  color: white;
+  background-color: #c6000094;
+  /*box-sizing: border-box;*/
+  left: 1em;
+  right: 1em;
+  height: 1em;
+  padding: 1em;
+}
+
+#RemoveFolder a{
+  color: black;
+}
+
+.DataItem{
+  position: relative;
+  margin: 1em;
+  padding-bottom: 1em;
+  float: left;
+  text-align: center;
+  width: 8em;
+}
+
+.spanwrapping{
+  position: relative;
+  height: 2.2em;
+
+}
+
+.DataItem span{
+  display:inline-block;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  display: -webkit-box;
+  -webkit-line-clamp: 2; /* number of lines to show */
+  -webkit-box-orient: vertical;
+  position: absolute;
+  bottom: 0;
+  right: 0;
+  left: 0;
+   
+}
+
+.DataImg{
+  text-align: center;
+  vertical-align: middle;
+  width: 8em;
+  height: 8em;
+}
+
+.DataImg img{
+  max-height: 100%;
+  max-width: 100%;
+}
+
+.imageAlternative {
+  vertical-align: middle;
+  font-size: 6em;
+  height: 100%;
+}
+
+#overlay {
+  position: fixed; /* Sit on top of the page content */
+  display: none; /* Hidden by default */
+  width: 100%; /* Full width (cover the whole page) */
+  height: 100%; /* Full height (cover the whole page) */
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background-color: rgba(0,0,0,0.5); /* Black background with opacity */
+  z-index: 2; /* Specify a stack order in case you're using a different order for other elements */
+  cursor: pointer; /* Add a pointer on hover */
+  text-align: center;
+  vertical-align: middle;
+}
+
+#overlaycontentsize{
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  font-size: 50px;
+  color: white;
+  transform: translate(-50%,-50%);
+  -ms-transform: translate(-50%,-50%);
+  background-color: rgba(255,255,255,1);
+  max-height: 100%;
+  max-width: 100%;
+}
+
+#overlaycontent{
+  max-height: 100%;
+  max-width: 100%;  
+}
+
+/*Image Upload CSS*/
+
+
+			.container
+			{
+				width: 100%;
+				max-width: 680px; /* 800 */
+				text-align: center;
+				margin: 0 auto;
+			}
+
+				.container h1
+				{
+					font-size: 42px;
+					font-weight: 300;
+					color: #0f3c4b;
+					margin-bottom: 40px;
+				}
+				.container h1 a:hover,
+				.container h1 a:focus
+				{
+					color: #39bfd3;
+				}
+
+				.container nav
+				{
+					margin-bottom: 40px;
+				}
+					.container nav a
+					{
+						border-bottom: 2px solid #c8dadf;
+						display: inline-block;
+						padding: 4px 8px;
+						margin: 0 5px;
+					}
+					.container nav a.is-selected
+					{
+						font-weight: 700;
+						color: #39bfd3;
+						border-bottom-color: currentColor;
+					}
+					.container nav a:not( .is-selected ):hover,
+					.container nav a:not( .is-selected ):focus
+					{
+						border-bottom-color: #0f3c4b;
+					}
+
+				.container footer
+				{
+					color: #92b0b3;
+					margin-top: 40px;
+				}
+					.container footer p + p
+					{
+						margin-top: 1em;
+					}
+					.container footer a:hover,
+					.container footer a:focus
+					{
+						color: #39bfd3;
+					}
+
+				.box
+				{
+					font-size: 1.25rem; /* 20 */
+					background-color: var(--x-ui-outside-color);
+					position: relative;
+					padding: 100px 20px;
+				}
+				.box.has-advanced-upload
+				{
+					outline: 2px dashed #92b0b3;
+					outline-offset: -10px;
+
+					-webkit-transition: outline-offset .15s ease-in-out, background-color .15s linear;
+					transition: outline-offset .15s ease-in-out, background-color .15s linear;
+				}
+				.box.is-dragover
+				{
+					outline-offset: -20px;
+					outline-color: #c8dadf;
+					background-color: #fff;
+				}
+					.box__dragndrop,
+					.box__icon
+					{
+						display: none;
+					}
+					.box.has-advanced-upload .box__dragndrop
+					{
+						display: inline;
+					}
+					.box.has-advanced-upload .box__icon
+					{
+						width: 100%;
+						height: 80px;
+						fill: #92b0b3;
+						display: block;
+						margin-bottom: 40px;
+					}
+
+					.box.is-uploading .box__input,
+					.box.is-success .box__input,
+					.box.is-error .box__input
+					{
+						visibility: hidden;
+					}
+
+					.box__uploading,
+					.box__success,
+					.box__error
+					{
+						display: none;
+					}
+					.box.is-uploading .box__uploading,
+					.box.is-success .box__success,
+					.box.is-error .box__error
+					{
+						display: block;
+						position: absolute;
+						top: 50%;
+						right: 0;
+						left: 0;
+
+						-webkit-transform: translateY( -50% );
+						transform: translateY( -50% );
+					}
+					.box__uploading
+					{
+						font-style: italic;
+					}
+					.box__success
+					{
+						-webkit-animation: appear-from-inside .25s ease-in-out;
+						animation: appear-from-inside .25s ease-in-out;
+					}
+						@-webkit-keyframes appear-from-inside
+						{
+							from	{ -webkit-transform: translateY( -50% ) scale( 0 ); }
+							75%		{ -webkit-transform: translateY( -50% ) scale( 1.1 ); }
+							to		{ -webkit-transform: translateY( -50% ) scale( 1 ); }
+						}
+						@keyframes appear-from-inside
+						{
+							from	{ transform: translateY( -50% ) scale( 0 ); }
+							75%		{ transform: translateY( -50% ) scale( 1.1 ); }
+							to		{ transform: translateY( -50% ) scale( 1 ); }
+						}
+
+					.box__restart
+					{
+						font-weight: 700;
+					}
+					.box__restart:focus,
+					.box__restart:hover
+					{
+						color: #39bfd3;
+					}
+
+					.js .box__file
+					{
+						width: 0.1px !important;
+						height: 0.1px;
+						opacity: 0;
+						overflow: hidden;
+						position: absolute;
+						z-index: -1;
+					}
+					.box__file{
+						width: 10.5em !important;
+						display: block !important;
+					}
+					.js .box__file + label
+					{
+						max-width: 80% !important;
+						text-overflow: ellipsis;
+						white-space: nowrap;
+						cursor: pointer;
+						display: inline-block;
+						overflow: hidden;
+					}
+					.js .box__file + label:hover strong,
+					.box__file:focus + label strong,
+					.box__file.has-focus + label strong
+					{
+						color: #39bfd3;
+					}
+					.js .box__file:focus + label,
+					.js .box__file.has-focus + label
+					{
+						outline: 1px dotted #000;
+						outline: -webkit-focus-ring-color auto 5px;
+					}
+						.js .box__file + label *
+						{
+							/* pointer-events: none; */ /* in case of FastClick lib use */
+						}
+
+					.no-js .box__file + label
+					{
+						display: none;
+					}
+
+					.no-js .box__button
+					{
+						display: block;
+					}
+					.box__button
+					{
+						font-weight: 700;
+						color: #e5edf1;
+						background-color: #39bfd3;
+						display: none;
+						padding: 8px 16px;
+						margin: 40px auto 0;
+					}
+						.box__button:hover,
+						.box__button:focus
+						{
+							background-color: #0f3c4b;
+						}

BIN
ui/favicon-96x96.png


BIN
ui/favicon.ico


+ 176 - 0
ui/index.html

@@ -0,0 +1,176 @@
+<!--
+  This file is part of centurio.work/commands.
+  
+  centurio.work/commands is free software: you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or (at your
+  option) any later version.
+  
+  centurio.work/commands is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  centurio.work/commands (file COPYING in the main directory).  If not, see
+  <http://www.gnu.org/licenses/>.
+-->
+
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+    <title>Universal Storage</title>
+    
+    <!-- libs, do not modify. When local than load local libs. -->
+    <script type="text/javascript" src="/js_libs/jquery.min.js"></script>
+    <script type="text/javascript" src="/js_libs/jquery.browser.js"></script>
+    <script type="text/javascript" src="/js_libs/jquery.svg.min.js"></script>
+    <script type="text/javascript" src="/js_libs/jquery.svgdom.min.js"></script>
+    <script type="text/javascript" src="/js_libs/vkbeautify.js"></script>
+    <script type="text/javascript" src="/js_libs/util.js"></script>
+    <script type="text/javascript" src="/js_libs/printf.js"></script>
+    <script type="text/javascript" src="/js_libs/strftime.min.js"></script>
+    <script type="text/javascript" src="/js_libs/parsequery.js"></script>
+    <script type="text/javascript" src="/js_libs/underscore.min.js"></script>
+    <script type="text/javascript" src="/js_libs/jquery.caret.min.js"></script>
+    <script type="text/javascript" src="/js_libs/jquery.cookie.js"></script>
+    
+    
+    <script type="text/javascript" src="/js_libs/relaxngui.js"></script>
+    
+    <script type="text/javascript" src="/js_libs/ui.js"></script>
+    <script type="text/javascript" src="/js_libs/custommenu.js"></script>
+    
+    <link   rel="stylesheet"      href="/js_libs/custommenu.css" type="text/css"/>
+    <link   rel="stylesheet"      href="/js_libs/ui.css" type="text/css"/>
+    
+    <link   rel="stylesheet"      href="/js_libs/relaxngui.css" type="text/css"/>
+    
+    <!-- custom stuff, play arround  -->
+    <link   rel="stylesheet"      href="css/ustore.css" type="text/css"/>
+    <script type="text/javascript" src="js/ustore.js"></script>
+    
+    
+    <script type="text/javascript" src="js/Upload.js"></script>
+    
+    <link   rel="stylesheet"      href="/cdp_ui/ui.css" type="text/css"/>
+    <link rel="icon" href="favicon.ico">
+    <link rel="icon" type="image/png" sizes="96x96" href="favicon-96x96.png">
+    
+    
+  </head>
+</body>
+
+
+
+
+<body is="x-ui">
+  <ui-rest id="main">
+    <ui-tabbar>
+      <ui-before                                  ><a class="logo" href="/customers/evva"></a></ui-before>
+      <ui-tab class=""         data-tab="storage" >Storage</ui-tab>
+      <ui-behind                                  ></ui-behind>
+    </ui-tabbar>
+	  <ui-content>
+      <ui-area data-belongs-to-tab="storage">
+        <div id="QuickSelection">
+          Quick Selection</br>
+          <select id="selectfolders">
+          </select>
+        </div>
+        
+        
+        <template id="cpyFolder">
+          <div class="Folder">
+            <a  class="FolderImageLink" data-class='link' style="text-decoration: none;" href="#" onclick="">
+              <span class="FolderImage" >🗀</span></br>
+              <span class="FolderText" data-class='text'></span>
+            </a>
+          </div>
+        </template>
+        
+        <template id="cpyFolderNew">
+          <div class="Folder">
+            <a  class="FolderImageLink" data-class='link' style="text-decoration: none;" href="#" onclick="">
+              <span class="FolderImage" >🗀</span></br>
+              <div class="FolderTextNew" data-class='text'></div>
+            </a>
+          </div>
+        </template>
+        </br>
+        
+        <div id="Folders">
+        </div>
+        
+        
+        
+        <a href="#" onclick="saveexternalfolder()">Add External Folder</a>
+        <div id="ExternalFolders">
+        </div>
+        
+        
+        
+        
+        
+      </ui-area>
+      
+      <ui-resizehandle data-belongs-to-tab="storage" data-label="drag to resize"></ui-resizehandle>
+      <ui-area data-belongs-to-tab="storage" id="detailcolumn">
+        
+        
+        
+        
+        
+        
+        <div id="content-wrap">
+          <form id="imgUpload" class="box" method="post" action="../images/imageUpload.php" enctype="multipart/form-data">
+					  <div class="box__input">
+              <input class="box__file" type="file" name="files[]" id="file" data-multiple-caption="{count} files selected" multiple />
+              <label for="file"><strong>Choose a file</strong><span class="box__dragndrop"> or drag it here</span>.</label>
+              <button class="box__button" type="submit">Upload</button>
+            </div>
+					  <div class="box__uploading">Uploading&hellip;</div>
+					  <div class="box__success">Done! 
+              <a href="https://centurio.work/customers/evva/was/ui//?" class="box__restart" role="button">Upload more?</a>
+            </div>
+					  <div class="box__error">Error! <span></span>.</div>
+          </form>
+          
+          
+          <template id="DataItem">
+            <div class="DataItem">
+              <div class="spanwrapping">
+                <span data-class='name'></span>
+              </div>
+              <div data-class='image' class="DataImg">
+              </div>
+              <a data-class='inspect' target="_blank" href="#" onclick="">🔍</a>
+              <a data-class='delete' href="#" onclick="">[⨯]</a>
+              <a data-class='getLink' href="#" onclick="">📎</a>
+              <a data-class='eventTrigger' href='#'style="visibility: hidden;" onclick=''>↧</a>
+            </div>
+          </template>
+          <div id="Data">
+          </div>
+          <div style ="clear:both"></div>
+        </div>
+        
+        
+        <div id="RemoveFolder">
+          <a href="" id="removeFolderLink" >Remove folder and content!</a>
+        </div>
+        
+        <div id="overlay" onclick="overlayOff()">
+          <div id="overlaycontentsize"></div>        
+        </div>
+        
+      </ui-area>
+      <ui-area data-belongs-to-tab="amount" class="inactive">
+      </ui-area>
+      <ui-area data-belongs-to-tab="production" class="inactive">
+      </ui-area>
+    </ui-content>
+  </ui-rest>
+</body>
+</html>

+ 210 - 0
ui/js/Upload.js

@@ -0,0 +1,210 @@
+//https://css-tricks.com/drag-and-drop-file-uploading/
+
+
+function imageInit(){
+	// feature detection for drag&drop upload
+		var isAdvancedUpload = function()
+			{
+				var div = document.createElement( 'div' );
+				return ( ( 'draggable' in div ) || ( 'ondragstart' in div && 'ondrop' in div ) ) && 'FormData' in window && 'FileReader' in window;
+			}();
+
+
+		// applying the effect for every form
+		var forms = document.querySelectorAll( '.box' );
+		Array.prototype.forEach.call( forms, function( form )
+		{
+			var input		 = form.querySelector( 'input[type="file"]' ),
+				label		 = form.querySelector( 'label' ),
+				errorMsg	 = form.querySelector( '.box__error span' ),
+				restart		 = form.querySelectorAll( '.box__restart' ),
+				droppedFiles = false,
+				showFiles	 = function( files )
+				{
+					label.textContent = files.length > 1 ? ( input.getAttribute( 'data-multiple-caption' ) || '' ).replace( '{count}', files.length ) : files[ 0 ].name;
+				},
+				triggerFormSubmit = function()
+				{
+					var event = document.createEvent( 'HTMLEvents' );
+					event.initEvent( 'submit', true, false );
+					form.dispatchEvent( event );
+				};
+
+			// letting the server side to know we are going to make an Ajax request
+			var ajaxFlag = document.createElement( 'input' );
+			ajaxFlag.setAttribute( 'type', 'hidden' );
+			ajaxFlag.setAttribute( 'name', 'ajax' );
+			ajaxFlag.setAttribute( 'value', 1 );
+			form.appendChild( ajaxFlag );
+
+			// automatically submit the form on file select
+			input.addEventListener( 'change', function( e )
+			{
+				showFiles( e.target.files );
+
+				
+				triggerFormSubmit();
+
+				
+			});
+
+			// drag&drop files if the feature is available
+			if( isAdvancedUpload )
+			{
+				form.classList.add( 'has-advanced-upload' ); // letting the CSS part to know drag&drop is supported by the browser
+
+				[ 'drag', 'dragstart', 'dragend', 'dragover', 'dragenter', 'dragleave', 'drop' ].forEach( function( event )
+				{
+					form.addEventListener( event, function( e )
+					{
+						// preventing the unwanted behaviours
+						e.preventDefault();
+						e.stopPropagation();
+					});
+				});
+				[ 'dragover', 'dragenter' ].forEach( function( event )
+				{
+					form.addEventListener( event, function()
+					{
+						form.classList.add( 'is-dragover' );
+					});
+				});
+				[ 'dragleave', 'dragend', 'drop' ].forEach( function( event )
+				{
+					form.addEventListener( event, function()
+					{
+						form.classList.remove( 'is-dragover' );
+					});
+				});
+				form.addEventListener( 'drop', function( e )
+				{
+					droppedFiles = e.dataTransfer.files; // the files that were dropped
+					showFiles( droppedFiles );
+
+					
+					triggerFormSubmit();
+
+									});
+			}
+
+
+			// if the form was submitted
+			form.addEventListener( 'submit', function( e )
+			{
+				
+				// preventing the duplicate submissions if the current one is in progress
+				if( form.classList.contains( 'is-uploading' ) ) return false;
+
+				form.classList.add( 'is-uploading' );
+				form.classList.remove( 'is-error' );
+				
+				var station = $('#pattern_station').text();
+				var pattern = $('#pattern_ID').text();
+				var curCount = $('#image_count').text();
+				var language = $('#image_language option:selected').text();
+				
+				
+
+				if( isAdvancedUpload ) // ajax file upload for modern browsers
+				{
+					e.preventDefault();
+					// gathering the form data
+					var ajaxData;
+					
+					
+					if( droppedFiles )
+					{
+						ajaxData = new FormData();
+						Array.prototype.forEach.call( droppedFiles, function( file )
+						{
+							ajaxData.append( input.getAttribute( 'name' ), file );
+						});
+					}
+					else{
+						ajaxData = new FormData( form );
+					}
+					
+					
+					// ajax request
+					var ajax = new XMLHttpRequest();
+					ajax.open( form.getAttribute( 'method' ), form.getAttribute( 'action' ), true );
+
+					ajax.onload = function()
+					{
+						form.classList.remove( 'is-uploading' );
+						if( ajax.status >= 200 && ajax.status < 400 )
+						{
+							listData($("#selectfolders").val())
+							
+							input.value = "";
+							//form.classList.add('is-success');
+							
+							//old upload php: saveImages(station, pattern, curCount, language, ajax.responseText);
+							
+							/*
+							var data = JSON.parse( ajax.responseText );
+							form.classList.add( data.success == true ? 'is-success' : 'is-error' );
+							if( !data.success ) errorMsg.textContent = data.error;
+							*/
+						}
+						else alert( 'Error. Please, contact the webmaster!' );
+					};
+
+					ajax.onerror = function()
+					{
+						form.classList.remove( 'is-uploading' );
+						alert( 'Error. Please, try again!' );
+					};
+
+					ajax.send( ajaxData );
+		            imageInit();
+				}
+				else // fallback Ajax solution upload for older browsers
+				{
+					var iframeName	= 'uploadiframe' + new Date().getTime(),
+						iframe		= document.createElement( 'iframe' );
+
+						$iframe		= $( '<iframe name="' + iframeName + '" style="display: none;"></iframe>' );
+
+					iframe.setAttribute( 'name', iframeName );
+					iframe.style.display = 'none';
+
+					document.body.appendChild( iframe );
+					form.setAttribute( 'target', iframeName );
+
+					iframe.addEventListener( 'load', function()
+					{
+						var data = JSON.parse( iframe.contentDocument.body.innerHTML );
+						form.classList.remove( 'is-uploading' )
+						form.classList.add( data.success == true ? 'is-success' : 'is-error' )
+						form.removeAttribute( 'target' );
+						if( !data.success ) errorMsg.textContent = data.error;
+						iframe.parentNode.removeChild( iframe );
+					});
+				}
+			});
+
+
+			// restart the form if has a state of error/success
+			Array.prototype.forEach.call( restart, function( entry )
+			{
+				entry.addEventListener( 'click', function( e )
+				{
+					e.preventDefault();
+					form.classList.remove( 'is-error', 'is-success' );
+					input.click();
+				});
+			});
+
+			// Firefox focus bug fix for file input
+			input.addEventListener( 'focus', function(){ input.classList.add( 'has-focus' ); });
+			input.addEventListener( 'blur', function(){ input.classList.remove( 'has-focus' ); });
+
+		});
+}
+
+
+
+$(document).ready(function() {
+		imageInit();
+});

+ 313 - 0
ui/js/ustore.js

@@ -0,0 +1,313 @@
+//delete = delets from DB
+//remove = removes from HTML
+
+//save = save to DB
+//add = changes HTML
+
+//get = get from DB
+//new = changes HTML
+
+
+//CrossSiteReference needed for WAS
+var test = {};
+var ref = $(test);
+
+$(document).on('change', '#selectfolders', function(e) {
+  //getFolders(this.options[e.target.selectedIndex].text);
+  listFolders(this.options[e.target.selectedIndex].text);
+});
+
+
+function listFolders(folder = ""){
+  $('#Folders').text("");
+  $('#CurFolder').text("");
+  
+  getAllFolders();
+  
+  if(folder != "" && folder != "." && folder != ".."){
+    $("#selectfolders").val(folder);
+  }
+  else{
+    $("#selectfolders").val(".");
+  }
+  
+  $.ajax({
+	  type: "GET",
+	  url: "../server/folders/" + folder,
+	  dataType: "json",
+	  success: function(data) {
+      
+      
+      if(folder != "" && folder != "." && folder != ".."){
+        var clone = document.importNode(document.querySelector('#cpyFolder').content,true);
+        $('[data-class=text]',clone).text("..");
+        $('[data-class=link]',clone).attr('onclick','listFolders("' + folder.substr(0, folder.lastIndexOf("/")) + '")');
+        $('#Folders').append(clone);
+      }
+      
+      
+      
+      $.each( data, function( key, value ) {
+        var clone = document.importNode(document.querySelector('#cpyFolder').content,true);
+        
+        //remove /
+        value = value.slice(0,-1)
+        $('[data-class=text]',clone).text(value);
+        
+        if(folder == ""){
+          $('[data-class=link]',clone).attr('onclick','listFolders("' + value + '")');
+        }
+        else{
+          $('[data-class=link]',clone).attr('onclick','listFolders("' + folder + "/" + value + '")');
+        }
+        $('#Folders').append(clone);
+      });
+      
+      //new Folder
+      var clone = document.importNode(document.querySelector('#cpyFolderNew').content,true);
+      $('[data-class=text]',clone).text("+");
+      $('[data-class=link]',clone).attr('onclick','createFolder("' + folder + '")');
+      $('#Folders').append(clone);
+    }
+  });
+  
+  listData(folder)
+}
+
+
+function createFolder(folder = ""){
+  var newFolder = window.prompt("Please enter a folder name.","");
+  if (newFolder != null && newFolder != "") {
+    $.ajax({
+      type: "Post",
+      url: "../server/folders/" + folder + "/" + newFolder,
+      success: function(res) {
+        listFolders(folder)
+      }
+    });
+  }  
+}
+
+function deleteFolder(datalink) {
+  if (datalink != "" && datalink != "." && datalink != ".." && confirm('Deleting ' + datalink)) {
+    $.ajax({
+      type: "DELETE",
+      url: "../server/folders/" + datalink,
+      success: function(res) {
+        listFolders(datalink.substr(0, datalink.lastIndexOf("/")))
+      } 
+    });
+  }
+}
+
+
+function listData(folder = ""){
+  $('#Data').text("");
+  const imageext = ["png", "jpg", "svg"]
+  const movieext = ["mp4"]
+  $('#imgUpload').attr("action", "../server/data/" + folder);
+  
+  $.ajax({
+	  type: "GET",
+	  url: "../server/images/" + folder,
+	  dataType: "json",
+	  success: function(data) {
+      $.each( data, function( key, value ) {
+        
+        var ext = value.substr(value.lastIndexOf('.') + 1);
+        if(folder == ""){
+          fullfolder =  value
+        }
+        else{
+          fullfolder =  folder + "/" + value;
+        }
+        
+        var clone = document.importNode(document.querySelector('#DataItem').content,true);
+        $('[data-class=name]',clone).text(value);
+        
+        //Image
+        if(imageext.includes(ext)){
+          $('[data-class=image]',clone).append("<img src='./../storage/"+ fullfolder + "' alt=''>")
+        }
+        else if(movieext.includes(ext)){
+          $('[data-class=image]',clone).append("<div class='imageAlternative' style='padding-top: 0.12em;'>▶</div>")
+        }
+        else{
+          $('[data-class=image]',clone).append("<div class='imageAlternative'>🗎</div>")
+        }
+        
+        $('[data-class=image]',clone).attr('onclick',"overlayOn('" + fullfolder + "')");
+        
+		    $('[data-class=inspect]',clone).attr('href','../storage/' + fullfolder + '');
+		    $('[data-class=delete]',clone).attr('href','javascript:deleteData("' + fullfolder + '");');
+		    $('[data-class=getLink]',clone).attr('href','javascript:copy2Clipboard("' + fullfolder + '");');
+        
+        
+        var queryString = window.location.search;
+        var urlParams = new URLSearchParams(queryString);
+        
+        if(urlParams.has('iframe')){
+          $('[data-class=eventTrigger]',clone).css("visibility", "visible")
+		      $('[data-class=eventTrigger]',clone).attr('href','javascript:triggerEvent("' + fullfolder + '");');
+          
+          console.log("I am an Iframe")
+        }
+        
+        $('#Data').append(clone);
+      });
+    }
+  });
+  
+  if(folder != "" && folder != "." && folder != ".."){
+    $('#RemoveFolder').css("display", "block")
+    $('#removeFolderLink').attr('href','javascript:deleteFolder("' + folder + '");');
+  }
+  else{
+    $('#RemoveFolder').css("display", "none")
+  }
+}
+function triggerEvent(data) {
+  //get url
+  var datalink = new URL("../storage/" + data, document.baseURI).href;
+  
+  ref = $(test);
+  setTimeout(function(){
+    ref.triggerHandler('getUrl', {"url": datalink});
+  },500);
+}
+
+function overlayOn(data) {
+  var url = new URL("../storage/" + data, document.baseURI).href
+  document.getElementById("overlay").style.display = "block";
+  const imageext = ["png", "jpg", "svg"]
+  const movieext = ["mp4"]
+  var ext = url.substr(url.lastIndexOf('.') + 1);
+  
+  if(imageext.includes(ext)){
+    $('#overlaycontentsize').append("<img id='overlaycontent' src=" + url + "></img>");    
+  }
+  else if(movieext.includes(ext)){
+    $('#overlaycontentsize').append("<video id='overlaycontent' controls> <source src=" + url + " type=\"video/mp4\">Your browser does not support the video tag.</video>");
+  }
+  else{
+    $('#overlaycontentsize').append("<iframe id='overlaycontent' src=" + url + "></iframe>");
+  }
+}
+
+function overlayOff() {
+  document.getElementById("overlay").style.display = "none";
+  $('#overlaycontentsize').text("");
+}
+
+function deleteData(datalink) {
+  if (confirm('Deleting ' + datalink)) {
+    $.ajax({
+      type: "DELETE",
+      url: "../server/data/" + encodeURIComponent(datalink),
+      success: function(res) {
+        listFolders(datalink.substr(0, datalink.lastIndexOf("/")))
+      } 
+    });
+  }
+}
+
+
+function copy2Clipboard(datalink) {
+  new URL("../storage/" + datalink, document.baseURI).href
+  datalink = new URL("../storage/" + datalink, document.baseURI).href;
+  const el = document.createElement('textarea');
+  el.value = datalink;
+  document.body.appendChild(el);
+  el.select();
+  document.execCommand('copy');
+  document.body.removeChild(el);
+}
+
+
+function getAllFolders(folder = ""){ //Get DB 2 HTML //has to be synchronus in order to update before loading the rest
+	$('#selectfolders').find('option').remove()
+  $('#selectfolders').append("<option>.</option>")
+  $.ajax({
+	  type: "GET",
+	  url: "../server/allfolders/" + folder,
+    async: false,
+	  dataType: "json",
+	  success: function(data) {
+      $.each( data, function( key, value ) {
+        $('#selectfolders').append("<option>" + value.slice(0,-1) +"</option>")
+        
+      });
+    }
+  });
+}
+
+
+function saveexternalfolder(folder = ""){
+  var newFolder = window.prompt("Please enter URL","");
+  if (newFolder != null && newFolder != "") {
+    $.ajax({
+      type: "Post",
+      data: JSON.stringify({"folder": newFolder}),
+      contentType: "application/json; charset=utf-8",
+      dataType: "json",
+      async:true,
+      url: "../server/externalFolder/",
+      success: function(res) {
+      }
+    });
+  }  
+}
+
+function listExternalFolders(folder = ""){
+  $('#ExternalFolders').text("");
+  if(folder == ""){
+    $.ajax({
+      type: "GET",
+      url: "../server/externalFolder",
+      dataType: "json",
+      success: function(data) { 
+        $.each( data, function( key, value ) {          
+          var clone = document.importNode(document.querySelector('#cpyFolder').content,true);
+          
+          //remove /
+          value = value.slice(0,-1)
+          $('[data-class=text]',clone).text(value);
+          $('[data-class=link]',clone).attr('onclick','listExternalFolders("' + value + '")');
+          $('#ExternalFolders').append(clone);
+        });
+      }
+    });
+  }
+  else{
+    $('#Folders').text("");
+    
+    
+    
+    //alert($.get(folder));
+    
+    /*
+      $.ajax({
+      type: "GET",
+      url: folder,
+      crossDomain: true,
+      success: function(data) {  
+      alert(data);
+      }
+      });
+    */
+    
+  }
+  
+  //listData(folder)
+}
+
+$(document).ready(function() { 
+  listFolders();
+  listExternalFolders();
+  getAllFolders();
+});
+
+
+
+
+