Browse Source

Moved from Artifacts woups

Manuel Gall 3 years ago
commit
eb370ed1ca
57 changed files with 7276 additions and 0 deletions
  1. 3 0
      .gitignore
  2. 1 0
      .vimrc
  3. 0 0
      README.md
  4. 1 0
      server/.vimrc
  5. BIN
      server/database/stations.db
  6. BIN
      server/database/stations_cpy.db
  7. BIN
      server/database/stations_cpy2.db
  8. BIN
      server/database/stations_cpy3.db
  9. BIN
      server/database/stations_save.db
  10. 1 0
      server/models/.gitignore
  11. 1 0
      server/models/Ce-E-Pord_00.xml.author
  12. 1 0
      server/models/Ce-E-Pord_00.xml.creator
  13. 1 0
      server/models/Copy-Ce-E-Pord_00.xml.author
  14. 1 0
      server/models/Copy-Ce-E-Pord_00.xml.creator
  15. 1 0
      server/models/Die Regel Alternative 2.xml.author
  16. 1 0
      server/models/Die Regel Alternative 2.xml.creator
  17. 1 0
      server/models/testmodel.xml.author
  18. 1 0
      server/models/testmodel.xml.creator
  19. 1 0
      server/models/testmodel1.xml.author
  20. 1 0
      server/models/testmodel1.xml.creator
  21. 10 0
      server/rngs/error.rng
  22. 13 0
      server/rngs/errors.rng
  23. 16 0
      server/rngs/image.rng
  24. 11 0
      server/rngs/imageUpload.rng
  25. 12 0
      server/rngs/images.rng
  26. 16 0
      server/rngs/pattern.rng
  27. 13 0
      server/rngs/replacement.rng
  28. 12 0
      server/rngs/station.rng
  29. 11 0
      server/rngs/stations.rng
  30. 7 0
      server/rngs/t_error.rng
  31. 7 0
      server/rngs/t_errors.rng
  32. 7 0
      server/rngs/t_image.rng
  33. 7 0
      server/rngs/t_images.rng
  34. 7 0
      server/rngs/t_pattern.rng
  35. 7 0
      server/rngs/t_replacement.rng
  36. 7 0
      server/rngs/t_station.rng
  37. 7 0
      server/rngs/t_wizImg.rng
  38. 17 0
      server/rngs/wizImg.rng
  39. 26 0
      server/testset.xml
  40. 4 0
      server/was.conf
  41. 1062 0
      server/was.rb
  42. 164 0
      server/was.xml
  43. 150 0
      testset/EVVA E-Montage Johannes.xml
  44. 70 0
      ui/LICENSE
  45. 3 0
      ui/README.md
  46. 86 0
      ui/client.html
  47. 403 0
      ui/css/design.css
  48. BIN
      ui/favicon-96x96.png
  49. BIN
      ui/favicon.ico
  50. 166 0
      ui/imageReplacement.php
  51. 284 0
      ui/index.html
  52. 3 0
      ui/js/DateFormat.js
  53. 132 0
      ui/js/Regex.js
  54. 3709 0
      ui/js/Sortable.js
  55. 505 0
      ui/js/design.js
  56. 211 0
      ui/js/imageUpload.js
  57. 95 0
      ui/js/imgReplacement.js

+ 3 - 0
.gitignore

@@ -0,0 +1,3 @@
+images/
+server/was.pid
+

+ 1 - 0
.vimrc

@@ -0,0 +1 @@
+map <F9> :!./design.rb -v restart<CR>

+ 0 - 0
README.md


+ 1 - 0
server/.vimrc

@@ -0,0 +1 @@
+map <F9> :!./design.rb -v restart<CR>

BIN
server/database/stations.db


BIN
server/database/stations_cpy.db


BIN
server/database/stations_cpy2.db


BIN
server/database/stations_cpy3.db


BIN
server/database/stations_save.db


+ 1 - 0
server/models/.gitignore

@@ -0,0 +1 @@
+*.xml

+ 1 - 0
server/models/Ce-E-Pord_00.xml.author

@@ -0,0 +1 @@
+Juergen Mangler

+ 1 - 0
server/models/Ce-E-Pord_00.xml.creator

@@ -0,0 +1 @@
+Juergen Mangler

+ 1 - 0
server/models/Copy-Ce-E-Pord_00.xml.author

@@ -0,0 +1 @@
+Juergen Mangler

+ 1 - 0
server/models/Copy-Ce-E-Pord_00.xml.creator

@@ -0,0 +1 @@
+Juergen Mangler

+ 1 - 0
server/models/Die Regel Alternative 2.xml.author

@@ -0,0 +1 @@
+Juergen Mangler

+ 1 - 0
server/models/Die Regel Alternative 2.xml.creator

@@ -0,0 +1 @@
+Juergen Mangler

+ 1 - 0
server/models/testmodel.xml.author

@@ -0,0 +1 @@
+Juergen Mangler

+ 1 - 0
server/models/testmodel.xml.creator

@@ -0,0 +1 @@
+Test Ehrendorfer

+ 1 - 0
server/models/testmodel1.xml.author

@@ -0,0 +1 @@
+Juergen Mangler

+ 1 - 0
server/models/testmodel1.xml.creator

@@ -0,0 +1 @@
+Test Ehrendorfer

+ 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>

+ 13 - 0
server/rngs/errors.rng

@@ -0,0 +1,13 @@
+<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+  
+  <define name="reason">
+    <element name="reason">	  
+      <zeroOrMore>
+        <element name="reason">
+          <attribute name="lang"><text/></attribute>
+          <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>

+ 13 - 0
server/rngs/replacement.rng

@@ -0,0 +1,13 @@
+<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+  
+  <define name="replacement">
+    <element name="replacement">	  
+      <zeroOrMore>
+        <element name="item">	
+          <element name="abbreviation"><text/></element>
+          <element name="url"><text/></element>
+        </element>
+      </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_errors.rng

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

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

+ 7 - 0
server/rngs/t_wizImg.rng

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

+ 17 - 0
server/rngs/wizImg.rng

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

+ 26 - 0
server/testset.xml

@@ -0,0 +1,26 @@
+<testset>
+  <dataelements/>
+  <handlerwrapper>DefaultHandlerWrapper</handlerwrapper>
+  <endpoints>
+    <machine xmlns="http://riddl.org/ns/common-patterns/properties/1.0">machine</machine>
+    <sensor xmlns="http://riddl.org/ns/common-patterns/properties/1.0">sensor</sensor>
+    <human xmlns="http://riddl.org/ns/common-patterns/properties/1.0">human</human>
+    <subprocess xmlns="http://riddl.org/ns/common-patterns/properties/1.0">subprocess</subprocess>
+  </endpoints>
+  <description>
+    <description xmlns="http://cpee.org/ns/description/1.0"></description>
+  </description>
+  <transformation>
+    <description type="copy"/>
+    <dataelements type="none"/>
+    <endpoints type="none"/>
+  </transformation>
+  <attributes>
+    <info xmlns="http://riddl.org/ns/common-patterns/properties/1.0">diana</info>
+    <creator xmlns="http://riddl.org/ns/common-patterns/properties/1.0">Juergen Mangler</creator>
+    <author xmlns="http://riddl.org/ns/common-patterns/properties/1.0">Juergen Mangler</author>
+    <modeltype xmlns="http://riddl.org/ns/common-patterns/properties/1.0">CPEE</modeltype>
+    <theme xmlns="http://riddl.org/ns/common-patterns/properties/1.0">model</theme>
+    <status xmlns="http://riddl.org/ns/common-patterns/properties/1.0">model</status>
+  </attributes>
+</testset>

+ 4 - 0
server/was.conf

@@ -0,0 +1,4 @@
+:port: 9323
+:appconf:
+  wizurl: https://centurio.work/wiz/wiztest/
+  stations: [ 1, 2, 3, 8 ]

File diff suppressed because it is too large
+ 1062 - 0
server/was.rb


+ 164 - 0
server/was.xml

@@ -0,0 +1,164 @@
+<!--
+  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="replacement"> <!--{{{-->
+    <parameter name="replacement" mimetype="*/xml" handler="http://riddl.org/ns/handlers/relaxng">
+      <xi:include href="rngs/t_replacement.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><!--}}}-->
+  <message name="patternID"><!--}}}-->
+    <parameter name="patternID" mimetype="application/json"/>
+  </message><!--}}}-->
+  <message name="html"><!--}}}-->
+    <parameter name="html" mimetype="text/html"/>
+  </message><!--}}}-->
+  <message name="errors"> <!--{{{-->
+    <parameter name="errors" mimetype="*/xml" handler="http://riddl.org/ns/handlers/relaxng">
+      <xi:include href="rngs/t_errors.rng"/>
+    </parameter>
+  </message> <!--}}}-->
+  
+  
+  <resource>
+      <get out="stations"/>
+      <post />
+      <resource relative="\d+">
+        <get out="station"/>
+        <post in="pattern" out="list"/> 
+        <delete/>
+        <resource relative="\d+">
+          <get out="pattern"/>
+          <put in="pattern"/>
+          <delete/>
+          <put in="patternID" out="list"/>
+          <resource relative="error">
+            <get out="error"/>
+            <put in="error"/>
+          </resource>
+          <resource relative="replacement">
+            <get out="replacement"/>
+            <put in="replacement"/>
+          </resource>
+          <resource relative="images">
+            <get out="images"/>
+            <post />
+            <post in="imageUpload"/>
+            <resource relative="reorder">
+              <resource>
+                <put in="orderlist"/>
+              </resource>
+            </resource>
+            <resource relative="\d+">
+              <get out="image"/>
+              <resource>
+                <get out="theRealImage"/>
+                <put in="label"/>
+                <delete/>
+              </resource>
+            </resource>
+          </resource>
+        </resource>
+        <resource relative="search">
+          <get out="list"/> 
+          <resource relative="patternID">
+            <get out="list"/> 
+          </resource>
+          <resource relative="images">
+            <get out="list"/> 
+            <resource relative="\d+">
+              <get out="theRealImage"/> 
+            </resource>
+          </resource>
+          <resource relative="imagesServerSide">
+            <get out="list"/> 
+            <resource relative="\d+">
+              <get out="html"/> 
+            </resource>
+          </resource>
+          <resource relative="imagesWIZ">
+            <get out="list"/> 
+            <resource relative="\d+">
+              <get out="image"/>
+            </resource>
+          </resource>
+          <resource relative="errorsWIZ">
+            <get out="errors"/> 
+          </resource>
+          <resource relative="imagesReverse">
+            <get out="list"/> 
+          </resource>
+        </resource>
+      </resource>
+
+  </resource>
+</description>

+ 150 - 0
testset/EVVA E-Montage Johannes.xml

@@ -0,0 +1,150 @@
+<testset xmlns="http://cpee.org/ns/properties/2.0">
+  <dataelements>
+    <station>2</station>
+    <productcode>Te.st.1</productcode>
+    <tablets>{"1":"emontagea","2":"emontageb","3":"emontagec","8":"emontaged"}</tablets>
+    <finished>false</finished>
+  </dataelements>
+  <handlerwrapper>DefaultHandlerWrapper</handlerwrapper>
+  <endpoints>
+    <put>https-put://centurio.work/wiz/</put>
+    <get>https://centurio.work/customers/evva/was/server/</get>
+    <path>https://centurio.work/customers/evva/was/server/</path>
+  </endpoints>
+  <description>
+    <description xmlns="http://cpee.org/ns/description/1.0">
+      <call id="a1" endpoint="get">
+        <parameters>
+          <label>Get Images</label>
+          <method>:get</method>
+          <arguments/>
+          <stream>
+            <sensors/>
+            <aggregators/>
+            <costs/>
+          </stream>
+        </parameters>
+        <code>
+          <prepare>endpoints.get = File.join(endpoints.path,data.station.to_s,"search/imagesWIZ?pattern=" + data.productcode.gsub(/\//,'_'))</prepare>
+          <finalize output="result">data.num = 1
+data.images = result</finalize>
+          <update output="result"/>
+          <rescue output="result"/>
+        </code>
+        <annotations>
+          <_timing>
+            <_timing_wait/>
+            <_timing_threshold/>
+            <_timing_min/>
+            <_timing_max/>
+            <_timing_avg/>
+          </_timing>
+          <_notes>
+            <_notes_general/>
+          </_notes>
+        </annotations>
+      </call>
+      <loop mode="pre_test" condition="!data.finished">
+        <call id="a3" endpoint="get">
+          <parameters>
+            <label>Get Images2</label>
+            <method>:get</method>
+            <arguments/>
+            <stream>
+              <sensors/>
+              <aggregators/>
+              <costs/>
+            </stream>
+          </parameters>
+          <code>
+            <prepare>endpoints.get = File.join(endpoints.path,data.station.to_s,"search/imagesWIZ?pattern=" + data.productcode.gsub(/\//,'_'))</prepare>
+            <finalize output="result">data.images = result</finalize>
+            <update output="result"/>
+            <rescue output="result"/>
+          </code>
+          <annotations>
+            <_timing>
+              <_timing_wait/>
+              <_timing_threshold/>
+              <_timing_min/>
+              <_timing_max/>
+              <_timing_avg/>
+            </_timing>
+            <_notes>
+              <_notes_general/>
+            </_notes>
+          </annotations>
+        </call>
+        <_probability>
+          <_probability_min/>
+          <_probability_max/>
+          <_probability_avg/>
+        </_probability>
+        <call id="a2" endpoint="put">
+          <parameters>
+            <label>Set Image</label>
+            <method>:put</method>
+            <arguments>
+              <num>!data.num</num>
+              <total>!data.images.length</total>
+              <style_url>https://centurio.work/customers/evva/wiz/style.css</style_url>
+              <image_url>!File.join(endpoints.get,data.station.to_s,"search/imagesWIZ",(data.num-1).to_s, "?pattern=" + data.productcode.gsub(/\//,'_') + "&amp;*ProductCode=" + data.productcode.gsub(/\//,'_'))</image_url>
+              <errors_url>!File.join(endpoints.get,data.station.to_s,"search/errorsWIZ","?pattern=" + data.productcode.gsub(/\//,'_') + "&amp;*ProductCode=" + data.productcode.gsub(/\//,'_'))</errors_url>
+            </arguments>
+            <stream>
+              <sensors/>
+              <aggregators/>
+              <costs/>
+            </stream>
+          </parameters>
+          <code>
+            <prepare>endpoints.put = File.join(endpoints.put,"Johannes" + '/')</prepare>
+            <finalize output="result">case result['operation']
+  when 'next'
+    data.num += 1
+  when 'prev'
+    data.num -= 1
+  when 'jump'
+    if result['target'].to_i == -1
+      data.num = data.images.length
+    else
+      data.num = result['target'].to_i
+    end
+  when 'error'
+    data.reason = result['reason']
+    data.finished = true
+  when 'finish'
+    data.finished = true
+end</finalize>
+            <update output="result"/>
+            <rescue output="result"/>
+          </code>
+          <annotations>
+            <_timing>
+              <_timing_wait/>
+              <_timing_threshold/>
+              <_timing_min/>
+              <_timing_max/>
+              <_timing_avg/>
+            </_timing>
+            <_notes>
+              <_notes_general/>
+            </_notes>
+          </annotations>
+        </call>
+      </loop>
+    </description>
+  </description>
+  <transformation>
+    <description type="copy"/>
+    <dataelements type="none"/>
+    <endpoints type="none"/>
+  </transformation>
+  <attributes>
+    <info>EVVA E-Montage UI</info>
+    <modeltype>CPEE</modeltype>
+    <theme>preset</theme>
+    <customer>pilotfabrik</customer>
+    <status>development</status>
+  </attributes>
+</testset>

File diff suppressed because it is too large
+ 70 - 0
ui/LICENSE


+ 3 - 0
ui/README.md

@@ -0,0 +1,3 @@
+# cpee-designer
+
+issues & wiki for designer

+ 86 - 0
ui/client.html

@@ -0,0 +1,86 @@
+<!--
+  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>Design</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/design.css" type="text/css"/>  
+    
+    <script type="text/javascript" src="js/imageUpload.js"></script>
+    
+    <script type="text/javascript" src="js/Sortable.js"></script>
+    <script type="text/javascript" src="js/Regex.js"></script>
+    <script type="text/javascript" src="js/DateFormat.js"></script>
+    <script type="text/javascript" src="js/imgReplacement.js"></script>
+    <script src="https://d3js.org/d3.v5.min.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>
+    
+    <form id="urls">
+      <input type="text" id="url" name="url" style="width:100%" value="https://centurio.work/customers/evva/was/server/8/23/images/0/de-at/"><br>
+      <input type="text" id="replacement" name="replacement" style="width:100%" value="https://centurio.work/customers/evva/was/server/8/23/replacement"><br>
+      <input type="submit" value="Submit">
+    </form>
+    
+    
+    <svg id="svgEmbed" width="1280" height="720">
+    </svg>
+    
+    
+    <body >
+      
+      
+      
+    </html>
+    

+ 403 - 0
ui/css/design.css

@@ -0,0 +1,403 @@
+
+/*Stations*/
+
+/*hover color*/
+#stations tr:hover td {
+	background-color: #efefef;
+}
+
+#stations .stationAction {
+  width: 1em;
+  height: 1em;
+}
+
+#stations .stationAction a{
+  visibility:hidden;
+}
+
+#stations tr:hover .stationAction a{
+  visibility:visible;
+}
+
+#stations {
+  border-spacing: 0 5px; 
+  width: 100%
+}
+
+#stations tr td:not(:first-child){
+  padding-left: 5px;
+}
+
+td {
+  padding-right: 1em;
+}
+.wasGroup{
+  padding-top: 1em;
+}
+.wasGroup:after {
+  content: "";
+  display: table;
+  clear: both;
+}
+.wasLeft{
+	width: 14em;
+	float: left;
+}
+.wasRight{
+	overflow: hidden;
+	min-width: 20em !important;
+}
+
+.width100{
+	width: 100% !important;
+}
+
+[is="x-ui"] input, [is="x-ui"] button, [is="x-ui"] select{
+	-webkit-box-sizing: border-box !important;
+	-moz-box-sizing: border-box !important;
+	box-sizing: border-box !important; 
+}
+
+.imageInput, .abbreviation{
+	width: 9em !important;
+	/*
+	border: none !important;
+	padding: 0em !important;
+	*/
+}
+
+.removeImage{
+	font-size: 1.6em;
+}
+
+.removeImage a{
+	color:var(--x-ui-light-text-color) !important;
+	text-decoration:none !important;
+
+}
+
+.mouseOver{
+	cursor: help;
+	color:var(--x-ui-light-text-color) !important;
+	text-decoration:none !important;
+}
+
+.mouseOver::after{
+	content:"🛈";
+}
+
+
+
+.handle{
+	cursor: grab;
+	font-style: normal;
+	font-size:2em;
+	width: 1em;
+    height: 100px;
+}
+#error, #replacements {
+	background-color: #efefef;
+	padding-bottom: 1em;
+}
+#error,#images, #replacements{
+	margin-top: 2em;
+}
+
+.imageleft{
+    height: 103px;
+    display:table-cell;
+    vertical-align:middle;
+}
+
+.list-group-item {
+  position: relative;
+  display: block;
+  padding: $list-group-item-padding-y $list-group-item-padding-x;
+  // Place the border on the list items and negative margin up for better styling
+  margin-bottom: -$list-group-border-width;
+  background-color: $list-group-bg;
+  border: $list-group-border-width solid $list-group-border-color;
+}
+
+.patternPart:not(:last-child)::after{
+	content: ".";
+	padding-right: -5em;
+}
+
+.patternPart a{
+	display:block;
+	text-align: center;
+}
+
+.patternPart:not(:last-child) a{
+	margin-left: -0.5em;
+}
+
+
+.patternPart{
+	display: inline-block;
+	white-space: nowrap;
+	
+}
+.patternPartInput{
+	width: 3em !important;
+	text-align: center;
+}
+
+
+#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: 40px 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


+ 166 - 0
ui/imageReplacement.php

@@ -0,0 +1,166 @@
+<html>
+  <head>
+  </head>
+  <body style="margin: 0px">
+
+<?php
+    ini_set('display_errors', 1);
+    ini_set('display_startup_errors', 1);
+    error_reporting(E_ALL);
+  
+  
+  //header('Content-type: image/svg+xml'); //does not play video
+  
+  $svg_file = file_get_contents(dirname(__DIR__, 1) . "/images/uploads/" . $_GET["___image___"]);
+  
+  
+  $doc = new DOMDocument;
+  $doc->loadXML($svg_file);
+  $xpath = new DOMXPath($doc);
+  $xpath->registerNamespace('svg', 'http://www.w3.org/2000/svg');
+  
+  
+  $root = $xpath->query("/*");
+  $root[0]->setAttribute("viewBox", "0 0 1280 720");
+  
+  $widthq = $xpath->query("/*/@width");
+  $heightq = $xpath->query("/*/@height");
+  
+  
+  $root = $xpath->query("/*");
+  $root[0]->setAttribute("viewBox", "0 0 ". $widthq[0]->nodeValue . " " . $heightq[0]->nodeValue);
+  $widthq[0]->nodeValue = "100%";
+  $heightq[0]->nodeValue = "100%";
+  
+  
+  //Get all Text Nodes
+  $style = $xpath->query('//svg:text');
+  $keyValueStore=array();
+  
+  //Get all rect nodes before text nodes and store them in key value store to access them for manipulation
+  foreach ($style as $result) {
+    $style2 = $xpath->query('./preceding-sibling::*[1]', $result);
+    //echo $style2[0]->nodeName;
+    foreach ($style2 as $result3) {
+      //echo $result3->nodeName;
+      $keyValueStore[$result->nodeValue] = $result3;
+    }
+  } 
+  
+  
+  //$keyValueStore["*imga"]->setAttribute("fill", "#FFFFFF");
+  
+  
+  
+  //replace text from URL GET within image
+  foreach($_GET as $key => $value){
+    if($key != "___image___"){
+      $alltext = $xpath->query('//svg:text');
+      foreach ($alltext as $text) {
+        if($key == $text->nodeValue){
+          $text->nodeValue = $value;
+        }
+      }        
+    }
+  }
+  
+  //load image Replacements
+  $replacements = new DOMDocument();
+  
+  $newstr = substr( $_GET["___image___"], 0, strpos( $_GET["___image___"], '/', strpos( $_GET["___image___"], '/')+1));
+  
+  $urlreplacement = dirname('https://' . $_SERVER['HTTP_HOST']. $_SERVER['PHP_SELF'], 2) . "/server/" . $newstr . "/replacement";
+  $replacements->loadXML(file_get_contents($urlreplacement)); 
+  
+  $elements = $replacements->getElementsByTagName('item');
+  
+  foreach($elements as $node){
+    
+    if(array_key_exists($node->getElementsByTagName("abbreviation")[0]->nodeValue, $keyValueStore)){
+      
+      
+      $extension = pathinfo($node->getElementsByTagName("url")[0]->nodeValue, PATHINFO_EXTENSION);
+      
+      if($extension == "mp4"){
+        
+        $element = $doc->createElement('foreignObject');
+        $element->setAttribute("x", $keyValueStore[$node->getElementsByTagName("abbreviation")[0]->nodeValue]->getAttribute('x'));
+        $element->setAttribute("y", $keyValueStore[$node->getElementsByTagName("abbreviation")[0]->nodeValue]->getAttribute('y'));
+        $element->setAttribute("width", $keyValueStore[$node->getElementsByTagName("abbreviation")[0]->nodeValue]->getAttribute('width'));
+        $element->setAttribute("height", $keyValueStore[$node->getElementsByTagName("abbreviation")[0]->nodeValue]->getAttribute('height'));
+        
+        $element1 = $doc->createElement('video');
+        $element1->setAttribute("width", $keyValueStore[$node->getElementsByTagName("abbreviation")[0]->nodeValue]->getAttribute('width'));
+        $element1->setAttribute("height", $keyValueStore[$node->getElementsByTagName("abbreviation")[0]->nodeValue]->getAttribute('height'));
+        $element1->setAttribute("controls", "");
+        
+        $element2 = $doc->createElement('source');
+        $element2->setAttribute("type", "video/mp4");
+        $element2->setAttribute("src", $node->getElementsByTagName("url")[0]->nodeValue);
+        
+        $element1->appendChild($element2);
+        $element->appendChild($element1);
+        
+        $parent = $doc->getElementsByTagName('svg')->item(0);
+        $parent->appendChild($element);
+      }
+      else{
+      
+        
+        
+        //create image element (currently we use background image)
+        /*
+          $element = $doc->createElement('image');
+          $element->setAttribute("x", $keyValueStore[$node->getElementsByTagName("abbreviation")[0]->nodeValue]->getAttribute('x'));
+          $element->setAttribute("y", $keyValueStore[$node->getElementsByTagName("abbreviation")[0]->nodeValue]->getAttribute('y'));
+          $element->setAttribute("width", $keyValueStore[$node->getElementsByTagName("abbreviation")[0]->nodeValue]->getAttribute('width'));
+          $element->setAttribute("height", $keyValueStore[$node->getElementsByTagName("abbreviation")[0]->nodeValue]->getAttribute('height'));
+          $element->setAttribute("xlink:href", $node->getElementsByTagName("url")[0]->nodeValue);
+          
+          $doc->appendChild($element);
+          
+          $parent = $doc->getElementsByTagName('svg')->item(0);
+          $parent->appendChild($element);
+        */
+        
+        
+        //create pattern for rect-filling looks like this:
+        /*
+          <defs>
+          <pattern id="image" x="-32" y="-32" patternUnits="userSpaceOnUse" height="64" width="64">
+          <image x="0" y="0" height="64" width="64" xlink:href="http://0.gravatar.com/avatar/902a4faaa4de6f6aebd6fd7a9fbab46a?s=64"/>
+          </pattern>
+          </defs>
+        */
+        
+        
+        $element3 = $doc->createElement('pattern');
+        $element3->setAttribute("id", $node->getElementsByTagName("abbreviation")[0]->nodeValue);
+        $element3->setAttribute("x", "0");
+        $element3->setAttribute("y", "0");
+        $element3->setAttribute("width", "1");
+        $element3->setAttribute("height",  "1");
+        
+        
+        $element2 = $doc->createElement('image');
+        $element2->setAttribute("x", "0");
+        $element2->setAttribute("y", "0");
+        $element2->setAttribute("width", $keyValueStore[$node->getElementsByTagName("abbreviation")[0]->nodeValue]->getAttribute('width'));
+        $element2->setAttribute("height", $keyValueStore[$node->getElementsByTagName("abbreviation")[0]->nodeValue]->getAttribute('height'));
+        $element2->setAttribute("xlink:href", $node->getElementsByTagName("url")[0]->nodeValue);
+        
+        
+        $element3->appendChild($element2);
+        $parent = $doc->getElementsByTagName('defs')->item(0);
+        $parent->appendChild($element3);      
+        $keyValueStore[$node->getElementsByTagName("abbreviation")[0]->nodeValue]->setAttribute("fill", "url(#".$node->getElementsByTagName("abbreviation")[0]->nodeValue.")");
+      }
+    }
+  }
+  
+  
+  echo $doc->saveXML();
+?>
+
+  </body>
+</html>

+ 284 - 0
ui/index.html

@@ -0,0 +1,284 @@
+<!--
+  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>Design</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/design.css" type="text/css"/>
+    <script type="text/javascript" src="js/design.js"></script>
+    
+    
+    <script type="text/javascript" src="js/imageUpload.js"></script>
+    
+    <script type="text/javascript" src="js/Sortable.js"></script>
+    <script type="text/javascript" src="js/Regex.js"></script>
+    <script type="text/javascript" src="js/DateFormat.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="station" >Stations</ui-tab>
+      <!--<ui-tab class="inactive" data-tab="amount"  >Amount</ui-tab>
+      <ui-tab class="inactive" data-tab="production">Production</ui-tab>-->
+      <ui-behind                                  ></ui-behind>
+    </ui-tabbar>
+	  <ui-content>
+      <ui-area data-belongs-to-tab="station">
+        
+        <!--<input id="CreateStation" type="button" value="Create Station" onclick="saveStation();" disabled/> <- Disabled-->
+        <template id="line">
+          <tr >
+            <td data-class='station' style="width:1em"></td>
+            <td data-class='pattern'><a href=''></a></td>
+            <td data-class='date'></td>
+            <td data-class='duplicate' class="stationAction"><a href=''>⎘</a></td>
+            <td data-class='delete' class="stationAction"><a href=''>[⨯]</a></td>
+          </tr>
+        </template>
+        
+        <table id="stations">
+        </table>
+      </ui-area>
+      
+      <ui-resizehandle data-belongs-to-tab="station" data-label="drag to resize"></ui-resizehandle>
+      <ui-area data-belongs-to-tab="station" id="detailcolumn">
+        <div id="pattern_details" class='x-ui-layout' style="display: none; padding: 10px">
+          <form id="patternform">
+            <div class="wasGroup">
+              <div class="wasLeft">&nbsp;</div>
+              <div class="wasRight">
+                <div>
+                  <input class="width100" type="submit" value="save">
+                </div>
+              </div>
+            </div>
+            
+            <template id="patternClone">
+              <div class="patternPart">
+                <a href="#" onclick="removePatternPart($(this))">[⨯]</a>
+                <input data-class='part' type="text" class="patternPartInput" maxlength="2" size="2" name="pattern" value="*" required>
+              </div>
+            </template>
+            
+            <div class="wasGroup">
+              <div class="wasLeft">Pattern <a class="mouseOver" href="#" title="Press '.' or 'space' while editing to create a new pattern part."></a>
+              </div>
+              <div class="wasRight">
+                <span id="patternInput">
+                  <input  type="text" class="patternPart" maxlength="2" size="2" name="pattern" value="*" required>
+                </span>
+                <a href="#" onclick="addPatternPart(true)">[+]</a>
+              </div>
+            </div>
+            
+            
+            <div class="wasGroup">
+              <div class="wasLeft">Description</div>
+              <div class="wasRight">
+                <input type="text" class="width100" id="pattern_description" name="description">
+              </div>
+            </div>
+          </form>
+          
+          
+				  <template id="errorCode">
+            <div class="wasGroup" data-class='errorRow'>
+              <div data-class='options' class="wasLeft">
+                <span class="removeImage">[<a href="#" onclick="removeError($(this))">⨯</a>]</span>
+              </div>
+              <div class="wasRight">
+                <input type="text" class="errorInput width100" data-class='errorInput' name="errorInput">
+              </div>
+            </div>
+          </template>
+          
+          
+          <div id="error">	
+            <div class="wasGroup">
+              <div class="wasLeft">Error</div>
+              <div class="wasRight">
+                [<a href="#" onclick="addError()">Add Error</a>]
+              </div>
+            </div>
+            <div id="errorCodes">
+            </div>
+          </div>
+          
+          
+          
+          <div id="images">		
+            <template id="imagePreview">
+              <div class="wasGroup" data-class='imageRow'>
+                <div data-class='options' class="wasLeft">
+                  <div class="imageleft">
+                    <span style="display:none" data-class='imageId'></span>
+                    <input type="text" class="imageInput" data-class='label' name="label">
+                    <span class="removeImage">[<a  href=''>⨯</a>]</span>
+                  </div>
+                </div>
+                <div class="wasRight">
+                  <table style="width:100%">
+                    <tr>
+                      <td class="handle">⇅</td>
+                      <td data-class='image'></td>
+                    </tr>
+                  </table>
+                </div>
+              </div>
+            </template> 
+            
+            
+            <div class="wasGroup">
+              <div class="wasLeft">Language</div>
+              <div class="wasRight">
+                <select class="width100" name="image_language" id="image_language">
+                  <option value="de-at">de-at</option>
+                  <option value="en-us">en-us</option>
+                </select>
+              </div>
+            </div>
+            
+            
+            
+            
+            <div id="imageListing">
+            </div>
+            
+            
+            
+            <div class="wasGroup">
+              <div class="wasLeft">Image Upload</div>
+              <div class="wasRight">
+                <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>
+              </div>
+            </div>
+          </div>
+          
+          
+          
+				  <template id="imageReplacements">
+            <div class="wasGroup replaceInput" data-class='replacement'>
+              <div data-class='options' class="wasLeft">
+                <input type="text" class="abbreviation" data-class='abbreviation' name="abbreviation">
+                <span class="removeImage">[<a  href='#' onclick="removeReplacement($(this))">⨯</a>]</span>
+              </div>
+              <div class="wasRight">
+                <input type="text" class="abbreviationInput width100 url" data-class='url' name="abbreviationInput">
+                <a href="#" onclick="overlayOn($(this));">🔍</a>
+              </div>
+            </div>
+          </template>
+          
+          
+          <div id="replacements">	
+            <div class="wasGroup">
+              <div class="wasLeft">Image Replacement</div>
+              <div class="wasRight">
+                [<a href="#" onclick="addBlankReplacement()">Add Replacement</a>]
+              </div>
+            </div>
+            <div id="replaceImages">
+            </div>
+          </div>
+               
+               
+          <div class="wasGroup">
+            <div class="wasLeft">&nbsp;</div>
+            <div class="wasRight">
+              <button class="width100" id="remove_pattern" type="button">Remove Pattern</button>
+            </div>
+          </div>
+          
+          
+          
+          <div style="display:none">
+            <span id="image_count"></span>
+            Station <span id="pattern_station"></span> Pattern ID <span id="pattern_ID"></span></br>
+            <!--Pattern <input type="text" id="pattern" name="pattern"></br>-->
+          </div>
+        </div>
+        
+        
+        <div id="station_details" style="display: none; padding: 10px">
+        </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>

File diff suppressed because it is too large
+ 3 - 0
ui/js/DateFormat.js


+ 132 - 0
ui/js/Regex.js

@@ -0,0 +1,132 @@
+
+/*
+composed by Brian Jaeger
+home page: brianjaeger.com
+*/
+(function ($) {
+  $.fn.limitkeypress = function (options) {
+    var defaults = {
+		rexp: /^[-+]?\d*\.?\d*$/ //only positive or negitive decimal numbers are allowed 
+	};
+	var options = $.extend(defaults, options);
+	
+	return this.each(function() {
+		var regExpression = options.rexp; //get the regular expression
+		
+		$(this).blur(function() { 
+			//this fixes the problem of paste of invalid data then loss of focus ie clicked submit button or tab 
+			sanitize(this);
+		});
+		
+		$(this).keypress(function(e) {
+			//alow backspace(8), enter(13), and other non character keypress events
+			if (e.which == "0" || e.which == "8" || e.which == "13" || e.ctrlKey || e.altKey){ 
+				return;
+			}
+			
+			//this fixes the problem of blur not triggering on enter keypress and it alows valid keypress events after an invalid paste/auto complete
+			sanitizeWithSelection(this); 
+			
+			var pressedChar = String.fromCharCode(e.which),  //get string value for pressed char
+				//insert the pressed char at the caret/cursor location for testing
+				updatedInput = this.value.substring(0, getSelectionStart(this))
+				+ pressedChar
+				+ this.value.substring(getSelectionEnd(this), this.value.length);
+			if (!regExpression.test(updatedInput)) {
+				e.preventDefault(); //stop the keypress event
+				return;
+			}
+			return;
+		});
+		
+		//steps throu each char  of a text input value validating each char + the next if the add is valid... 
+		function sanitizeWithSelection(o) {
+			var startCaretPos = getSelectionStart(o),
+				endCaretPos = getSelectionEnd(o),
+				temp = "",
+				testPlusChar = "",
+				selectionCharInfo = [];
+			
+			//records selection information for each char
+			for (i=0;i<o.value.length;i++) {
+				if (startCaretPos > i){
+					selectionCharInfo[i] = 'beforeSelection';
+				} else if ((startCaretPos <= i) && (endCaretPos > i)) {
+					selectionCharInfo[i] = 'inSelection';
+				} //note: if a char after the selection is invalid the selection would not change if that char is removed...
+			}
+			
+			for (i=0;i<o.value.length;i++) {
+				var iPlusOne = i + 1;
+				testPlusChar += o.value.substring(i,iPlusOne);
+				if ((!regExpression.test(testPlusChar))) {
+					var lastChar = testPlusChar.length-1;
+					temp = testPlusChar.substring(0,lastChar);
+					testPlusChar = temp;
+					if (selectionCharInfo[i] == 'beforeSelection'){
+						startCaretPos = startCaretPos - 1;
+						endCaretPos = endCaretPos - 1;
+					} else if (selectionCharInfo[i] == 'inSelection'){
+						endCaretPos = endCaretPos - 1;
+					}
+				}
+			}
+			o.value = testPlusChar;
+			setSelectionRange (o,startCaretPos,endCaretPos);
+		}
+		
+		//steps throu each char  of a text input value validating each char + the next if the add is valid... 
+		function sanitize(o) {
+			var temp = "",
+				testPlusChar = "";
+				
+			for (i=0;i<o.value.length;i++) {
+				var iPlusOne = i+1;
+				testPlusChar += o.value.substring(i,iPlusOne);
+				if ((!regExpression.test(testPlusChar))) {
+					var lastChar = testPlusChar.length-1;
+					temp = testPlusChar.substring(0,lastChar);
+					testPlusChar = temp;
+				}
+			}
+			o.value = testPlusChar;
+		}
+		
+		//from: http://javascript.nwbox.com/cursor_position/
+		function getSelectionStart(o) {
+			if (o.createTextRange) {
+				var r = document.selection.createRange().duplicate()
+				r.moveEnd('character', o.value.length)
+				if (r.text == '') return o.value.length
+				return o.value.lastIndexOf(r.text)
+			} else return o.selectionStart
+		}
+		
+		//from: http://javascript.nwbox.com/cursor_position/
+		function getSelectionEnd(o) {
+			if (o.createTextRange) {
+				var r = document.selection.createRange().duplicate()
+				r.moveStart('character', -o.value.length)
+				return r.text.length
+			} else return o.selectionEnd
+		}
+		
+		//from http://www.codingforums.com/archive/index.php/t-90176.html
+		function setSelectionRange(input, selectionStart, selectionEnd){
+			if (input.setSelectionRange) {
+				input.focus();
+				input.setSelectionRange(selectionStart, selectionEnd);
+			}
+			else if (input.createTextRange) {
+				var range = input.createTextRange();
+				range.collapse(true);
+				range.moveEnd('character', selectionEnd);
+				range.moveStart('character', selectionStart);
+				range.select();
+			}
+		}
+    });
+  };
+  
+
+})(jQuery);

File diff suppressed because it is too large
+ 3709 - 0
ui/js/Sortable.js


+ 505 - 0
ui/js/design.js

@@ -0,0 +1,505 @@
+//delete = delets from DB
+//remove = removes from HTML
+
+//save = save to DB
+//add = changes HTML
+
+//get = get from DB
+//new = changes HTML
+
+
+function overlayOn(value) {
+  
+  url = "https://centurio.work/customers/evva/universal-storage/ui/?iframe"
+  document.getElementById("overlay").style.display = "block";
+  
+  var iframe = $('#overlaycontentsize').append("<iframe id='overlaycontent' src='" + url + "' width='900' height='600'></iframe>");
+  
+  iframe.find("#overlaycontent").bind('load',{"ka": value}, function(event){
+    var ref = this.contentWindow.ref;
+    //You can think that ref = $(this.contentWindow.test) but thery are different
+    //they are two diferent references this might be a bug
+    
+    ref.bind('getUrl',{"xyz": event.data.ka}, function(event, extra1){
+      var data = event.data                      
+      overlayOff();
+      //fill input with url
+      $(data.xyz).prev().val(extra1.url)
+    });
+  });
+}
+
+function overlayOnImg(data) {
+  var url = new URL("" + 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 saveStation() { //Save 2 DB
+  if (confirm('Are you really, really, REALLY sure you want to create a New Station?')) {
+    $.ajax({
+      type: "POST",
+      url: "../server/",
+      success: function(res) {
+        location.reload();
+      }
+    });
+  }
+}
+
+function getStations(stationID , patternID ){ //Get DB 2 HTML
+	$('#stations').text("");
+	
+	$.ajax({
+    type: "GET",
+    url: "../server/",
+	  dataType: "xml",
+    success: function(xml) {
+      $(xml).find('station').each(function(index){
+        
+        var clone = document.importNode(document.querySelector('#line').content,true);
+        $('[data-class=station]',clone).text($(this).attr('id'));
+        $('[data-class=pattern] a',clone).before("[");
+        $('[data-class=pattern] a',clone).text("Add Pattern");
+        $('[data-class=pattern] a',clone).after("]");
+        $('[data-class=pattern] a',clone).attr('href','javascript:newPattern('+ $(this).attr('id') + ');');
+        $('[data-class=duplicate]',clone).text("");
+        $('[data-class=delete]',clone).text("");
+        $('#stations').append(clone);
+        
+        
+        var curstation=$(this).attr('id');		  
+        $(this).find('pattern').each(function(index){
+          var clonePattern = document.importNode(document.querySelector('#line').content,true);
+          $('[data-class=pattern] a',clonePattern).text($(this).attr('value'));
+          $('[data-class=pattern] a',clonePattern).attr('href','javascript:getPattern(' + curstation + ','+ $(this).attr('id') + ');');
+          $('[data-class=date]',clonePattern).text($.format.date(Date.parse($(this).attr('changed')), 'yyyy/MM/dd HH:mm:ss'));
+          $('[data-class=duplicate] a',clonePattern).attr('href','javascript:duplicatePattern(' + curstation + ','+ $(this).attr('id') + ');');
+          $('[data-class=delete] a',clonePattern).attr('href','javascript:deletePattern(' + curstation + ','+ $(this).attr('id') + ');');
+          if (patternID != null && patternID == $(this).attr('id')){
+            $('tr',clonePattern).css("background-color","#99cce6");
+          }
+          $('#stations').append(clonePattern);
+        });
+      });
+    }
+  });
+}
+
+function newPattern(stationID) { //HTML
+	getPattern(stationID);
+}
+
+
+function getPattern(stationID, patternID){ //Get DB 2 HTML
+  getStations(stationID, patternID)
+  if (patternID == null){
+    $('#patternform').attr('onsubmit', "savePattern("+stationID+")");
+    $('#pattern_ID').text("");
+    $('#pattern_description').val("");
+    $('#imageListing').text("");
+    $('#images').css("display", "none");
+    $('#remove_pattern').css("display", "none");
+    $('#error').css("display", "none");
+    $('#replacements').css("display", "none");
+  }
+  else{
+    $('#patternform').attr('onsubmit', "saveChangedPattern("+stationID+","+ patternID +")");
+    $('#pattern_ID').text(patternID);
+    getImages(stationID, patternID);
+    $('#remove_pattern').css("display", "block");
+    $('#remove_pattern').attr('onclick', "javascript:deletePattern("+stationID+","+ patternID +")");
+    
+    
+    getError(stationID, patternID);
+    getReplaceImages(stationID, patternID);
+    
+    $.ajax({
+      type: "GET",
+      url: "../server/"+stationID+ "/" + patternID,
+      dataType: "xml",
+      success: function(xml) {
+        $(xml).find('pattern').each(function(index){
+          var pattern = $(this).attr('value').split(".")
+          for(var i = 0; i < pattern.length; i++)
+          {
+            if(i == 0){
+              $("#patternInput .patternPartInput").val(pattern[i]);
+            }
+            else{
+              var clone = document.importNode(document.querySelector('#patternClone').content,true);
+              $('[data-class=part]',clone).val(pattern[i]);
+              $('[data-class=part]',clone).limitkeypress({ rexp: keypressRegex() });
+              
+              $("#patternInput").append(clone);
+            }
+          }
+          
+          $('#pattern').val($(this).attr('value'));
+          $('#pattern_description').val($(this).attr('description'));
+        });
+      }
+    });
+  }
+  
+  $('#pattern_details').css("display", "block");
+  $('#pattern_station').text(stationID);
+  $('#pattern_description').text("");
+	
+  //Reset Pattern
+  $('#patternInput').text("");
+  var clone = document.importNode(document.querySelector('#patternClone').content,true);
+  $('[data-class=part]',clone).limitkeypress({rexp: keypressRegex()});
+  $("#patternInput").append(clone);
+}
+
+
+function keypressRegex(){ //Helper Function
+	return /^[A-Za-z0-9\*]*$/;
+}
+
+function removePatternPart(value) { //HTML
+  if($( ".patternPart" ).length > 1)
+  value.parent().remove();
+}
+
+function addPatternPart(useLast) { //HTML
+  var clone = document.importNode(document.querySelector('#patternClone').content,true);
+  $('[data-class=part]',clone).val("*");
+  $('[data-class=part]',clone).limitkeypress({rexp: keypressRegex()});
+  
+  if(useLast){
+    $('.patternPart').last().after(clone);
+    $('.patternPart').last().children(".patternPartInput").focus();
+    }else{
+    $(':focus').parent().after(clone);
+    $(':focus').parent().next().children(".patternPartInput").focus();
+  }
+}
+
+function getPatternString(){ //Helper Function
+	var val = "";
+	var first = true;
+	$(".patternPartInput").each(function() {
+		if(first){
+			first = false
+			val += $(this).val()
+    }
+		else{
+			val += "." + $(this).val()
+    }
+  });
+	return val;
+}
+
+function savePattern(stationID) { //Save 2 DB
+  var xmlDocument = $.parseXML("<pattern/>");
+  $(xmlDocument).find("pattern").attr('id','0');
+  $(xmlDocument).find("pattern").attr('value',getPatternString());
+  $(xmlDocument).find("pattern").attr('description',$('#pattern_description').val());
+  $(xmlDocument).find("pattern").attr('changed',new Date().toISOString());
+  $.ajax({
+    type: "POST",
+		headers: {"content-id": "pattern"},
+		data: (new XMLSerializer()).serializeToString(xmlDocument),
+    contentType: "application/xml; charset=utf-8",
+    url: "../server/"+stationID,
+    success: function(res) {
+		  getPattern(stationID, res.id)
+		  loadStations()
+    },
+    error: function (request, status, error) {
+      alert(request.responseText + status + error);
+    }
+  });
+}
+
+function saveChangedPattern(stationID, patternID) { //Save 2 DB
+  var xmlDocument = $.parseXML("<pattern/>");
+  $(xmlDocument).find("pattern").attr('id',$('#pattern_ID').text());
+  $(xmlDocument).find("pattern").attr('value',getPatternString());
+  $(xmlDocument).find("pattern").attr('description',$('#pattern_description').val());
+  $(xmlDocument).find("pattern").attr('changed',new Date().toISOString());
+  
+  //Save Pattern
+  $.ajax({
+    type: "PUT",
+		headers: {"content-id": "pattern"},
+		data: (new XMLSerializer()).serializeToString(xmlDocument),
+    contentType: "application/xml; charset=utf-8",
+    url: "../server/"+stationID + "/" + patternID,
+		//processData: false,
+    success: function(res) {
+    },
+    error: function (request, status, error) {
+      alert(request.responseText + status + error);
+    }
+  });
+  
+  //Update Labels 
+  $(".imageInput").each(function() {
+    //Optimization only update if lable changed
+		if($(this).val() != $(this).attr("origValue"))
+    $.ajax({
+      type: "PUT",
+      data: { 'label' : $(this).val()},
+      headers: {"content-id": "label"},
+      url: "../server/"+stationID + "/" + patternID + "/images/" + $(this).parent().find(".imageID").text() +"/" + $('#image_language option:selected').text(),
+      success: function(res) {
+      },
+      error: function (request, status, error) {
+        alert(request.responseText + status + error);
+      }
+    });
+  });
+  
+  //Update Image Ordering
+  var order = []
+  $(".imageID").each(function() {
+    order.push(parseInt($(this).text()))
+  });
+  $.ajax({
+    type: "PUT",
+		data: JSON.stringify(order),
+		headers: {"content-id": "orderlist"},
+    contentType: "application/json",
+    url: "../server/"+stationID + "/" + patternID + "/images/reorder/" + $('#image_language option:selected').text(),
+    success: function(res) {
+    },
+    error: function (request, status, error) {
+      alert(request.responseText + status + error);
+    }
+  });
+  
+  //Update Error
+  var errorList = $.parseXML("<error/>");
+  $(".errorInput").each(function() {
+    $(errorList).find("error").append("<reason>" +$(this).val()+"</reason>")
+  });
+  
+  $.ajax({
+    type: "PUT",
+		headers: {"content-id": "error"},
+		data: (new XMLSerializer()).serializeToString(errorList),
+    contentType: "application/xml; charset=utf-8",
+    url: "../server/"+stationID + "/" + patternID + "/error",
+    success: function(res) {
+    },
+    error: function (request, status, error) {
+      alert(request.responseText + status + error);
+    }
+  });
+  
+  
+  //Update Replacement
+  var replaceList = $.parseXML("<replacement/>");
+  $(".replaceInput").each(function() {
+    //console.log($(this).find('.abbreviation').val())
+    //console.log($(this).find('.url').val())
+    
+    $(replaceList).find("replacement").append("<item>" + "<abbreviation>" + $(this).find('.abbreviation').val() + "</abbreviation>" + "<url>" + $(this).find('.url').val() + "</url>"+"</item>")
+    
+  });
+  
+  $.ajax({
+    type: "PUT",
+    headers: {"content-id": "replacement"},
+    data: (new XMLSerializer()).serializeToString(replaceList),
+    contentType: "application/xml; charset=utf-8",
+    url: "../server/"+stationID + "/" + patternID + "/replacement",
+    success: function(res) {
+    },
+    error: function (request, status, error) {
+      alert(request.responseText + status + error);
+    }
+  });
+  
+  
+  getPattern(stationID, patternID)	  
+}
+
+function deletePattern(stationID, patternID) { //Delete From DB
+  if (confirm('Are you really, really, REALLY sure!')) {
+    $.ajax({
+      type: "DELETE",
+      url: "../server/" + stationID + "/" + patternID,
+      success: function(res) {
+        location.reload();
+      }
+    });
+  }
+}
+
+
+function duplicatePattern(stationID, patternID){ //Get DB 2 HTML
+  $.ajax({
+    type: "PUT",
+    headers: {"content-id": "patternID"},
+    data: { "patternID":patternID},
+    contentType: "application/json",
+    url: "../server/"+stationID + "/" + patternID,
+    success: function(res) {
+      getPattern(stationID, res["id"])
+    },
+    error: function (request, status, error) {
+      alert(request.responseText + status + error);
+    }
+  });
+}
+
+function getImages(stationID, patternID){ //Get From DB 2 HTML
+  $('#images').css("display", "block");
+  $('#imageListing').text("");
+  $('#imgUpload').attr("action", "../server/" + stationID + "/" + patternID + "/images");
+  
+  
+  $.ajax({
+	  type: "GET",
+	  url: "../server/"+stationID+ "/" + patternID + "/images",
+	  dataType: "xml",
+	  success: function(xml) {
+      var count = 0;
+      $(xml).find('image').each(function(index){
+        
+        curID = $(this).attr('id')
+        $(this).find('variant').each(function(){
+          
+          if($(this).attr('lang') == $('#image_language option:selected').text()){
+            ++count;
+            var clone = document.importNode(document.querySelector('#imagePreview').content,true);
+            
+            var imgsrcsingle = "../images/uploads/"+stationID+ "/" + patternID + "/" + curID + "/"+ $(this).attr('lang') + ".svg";
+            var imgsrc = imgsrcsingle + "?" + Date.now();
+            $('[data-class=image]',clone).append('<img id="theImg" src="' + imgsrc +'" onclick="overlayOnImg(\'' +imgsrcsingle + '\')" height="100px" />')
+            $('[data-class=label]',clone).val($(this).attr('label'));
+            $('[data-class=label]',clone).attr("origValue", $(this).attr('label'));			
+            $('[data-class=imageId]',clone).text(curID);
+            $('[data-class=imageId]',clone).attr("class", "imageID")
+            
+            $('[data-class=options] a',clone).attr('href','javascript:deleteImage(' + stationID + ','+ patternID + ',' + curID + ',"' + $(this).attr('lang') +  '");');
+            $('#imageListing').append(clone);
+          }
+        });
+      });
+	    $('#image_count').text(count);
+    }
+  });
+  new Sortable(document.getElementById('imageListing'),{
+	  handle: '.handle',
+	  animation: 150
+  });
+}
+
+function deleteImage(stationID, patternID, imageID, lang) { //Delete From DB
+  $.ajax({
+    type: "DELETE",
+    url: "../server/" + stationID + "/" + patternID + "/images/" + imageID + "/" + lang,
+    success: function(res) {
+      getPattern(stationID, patternID)	 
+    }
+  }); 
+}
+
+function addError() { //HTML
+  //Will be added from DB on save
+  var clone = document.importNode(document.querySelector('#errorCode').content,true);
+  $('#errorCodes').append(clone);
+}
+
+
+
+function getError(stationID, patternID){ //Get From DB 2 HTML
+  $('#error').css("display", "block");
+  $('#errorCodes').text("");  
+  $.ajax({
+	  type: "GET",
+	  url: "../server/"+stationID+ "/" + patternID + "/error",
+	  dataType: "xml",
+	  success: function(xml) {
+      $(xml).find('reason').each(function(index){
+        var clone = document.importNode(document.querySelector('#errorCode').content,true);
+        $('[data-class=errorInput]',clone).val($(this).text());
+        $('#errorCodes').append(clone);
+      });
+    }
+  });
+}
+
+function removeError(value) { //HTML
+  //Will be removed from DB on save
+  value.parent().parent().parent().remove();
+}
+
+
+
+
+function addBlankReplacement() { //HTML
+  //Will be added from DB on save
+  var clone = document.importNode(document.querySelector('#imageReplacements').content,true);
+  $('#replaceImages').append(clone);
+}
+
+
+function getReplaceImages(stationID, patternID){ //Get From DB 2 HTML
+  $('#replacements').css("display", "block");
+  $('#replaceImages').text("");  
+  $.ajax({
+	  type: "GET",
+	  url: "../server/"+stationID+ "/" + patternID + "/replacement",
+	  dataType: "xml",
+	  success: function(xml) {
+      $(xml).find('item').each(function(index){
+        var clone = document.importNode(document.querySelector('#imageReplacements').content,true);
+        $('[data-class=abbreviation]',clone).val($(this).find('abbreviation').text());
+        $('[data-class=url]',clone).val($(this).find('url').text());
+        $('#replaceImages').append(clone);
+      });
+    }
+  });
+}
+
+function removeReplacement(value) { //HTML
+  //Will be removed from DB on save
+  value.parent().parent().parent().remove();
+}
+
+//Go to next PatternInput on . or space keydown
+$(window).keydown(function(e) {
+  if ((e.which === 32 || e.which === 190) && $(':focus').attr('class') === "patternPartInput") {
+    e.preventDefault();
+    addPatternPart(false);
+  }
+});
+
+$(document).ready(function() {  
+  getStations(); //Get all Stations
+  $("#image_language" ).change(function() {
+    getImages($('#pattern_station').text(),  $('#pattern_ID').text())
+  });
+  $(document).on('submit', '#patternform', function() { //prevent page reload on form submit
+    return false;
+  });
+  $('.patternPartInput').limitkeypress({rexp: keypressRegex()});
+});

+ 211 - 0
ui/js/imageUpload.js

@@ -0,0 +1,211 @@
+//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 );
+					}
+					ajaxData.append("language", language)
+					
+					
+					// 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 )
+						{
+							getPattern(station, pattern)
+							
+							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();
+});

+ 95 - 0
ui/js/imgReplacement.js

@@ -0,0 +1,95 @@
+//https://stackoverflow.com/questions/35000435/how-can-i-put-all-the-url-parameters-in-array-of-objects-using-jquery/35000946
+function getParams(url) {
+  var queryString = url.substring(url.indexOf('?') + 1);
+  var paramsArr = queryString.split('&');
+  var params = [];
+  for (var i = 0, len = paramsArr.length; i < len; i++) {
+    var keyValuePair = paramsArr[i].split('=');
+    params.push({
+      name: keyValuePair[0],
+      value: keyValuePair[1]
+    });
+  }
+  return params;
+}
+
+
+$(function() {
+  $('#urls').on("submit",function(e) {
+    e.preventDefault(); // cancel the actual submit
+    loadImage($('#url').val(), $('#replacement').val())
+  });
+});
+
+
+function loadImage(url, replacement){
+  
+  //https://centurio.work/customers/evva/was/server/8/23/images/0/de-at/
+  //https://centurio.work/customers/evva/was/server/8/23/replacement
+  
+  
+  //https://stackoverflow.com/questions/27775579/how-to-fill-d3-svg-with-image-instead-of-colour-with-fill
+  
+  
+  //Embedd image so svg is accessible
+  //https://stackoverflow.com/questions/12975929/how-to-use-svg-file-for-image-source-in-d3
+  d3.svg(url).then(function(xml) {
+    d3.select("#svgEmbed").node().appendChild(xml.documentElement);
+    
+    var dict =  {};
+    
+    //get All Text and if Available Rect before
+    d3.select("#svgEmbed").selectAll("text").each(function(d,i){
+      dict[d3.select(this).text()] = d3.select(this.previousSibling).node().getBBox()
+    });
+    
+    var urlparameters = getParams(window.location.search)
+    
+    //replace text within image
+    for (const [key, value] of urlparameters.entries()) {
+      
+      d3.select("#svgEmbed").selectAll("text").each(function(d,i){
+        if(d3.select(this).text() == value.name){
+          d3.select(this).text(value.value);
+        }
+      });
+    }
+    //load image Replacements
+    $.ajax({
+      type: "GET",
+      url: replacement,
+      dataType: "xml",
+      success: function(xml) {
+        $(xml).find('item').each(function(index){
+          var extension = $(this).find('url').text().split('.').pop();
+          if(extension == "mp4"){
+            //https://stackoverflow.com/questions/38437834/append-foreignobject-containing-some-html-inside-an-svg-element
+            var video = d3.select("#svgEmbed").append("foreignObject")
+            video
+            .attr("x", dict[$(this).find('abbreviation').text()].x)
+            .attr("y", dict[$(this).find('abbreviation').text()].y)
+            .attr("width", dict[$(this).find('abbreviation').text()].width)
+            .attr("height", dict[$(this).find('abbreviation').text()].height)
+            .append("xhtml:video")
+            .attr("width", dict[$(this).find('abbreviation').text()].width)
+            .attr("height", dict[$(this).find('abbreviation').text()].height)
+            .attr("controls", "")
+            .append("xhtml:source")
+            .attr("type", "video/mp4")
+            .attr("src", $(this).find('url').text());
+          }
+          else{
+            d3.select("#svgEmbed").append("svg:image")
+            .attr('x', dict[$(this).find('abbreviation').text()].x)
+            .attr('y', dict[$(this).find('abbreviation').text()].y)
+            .attr('width', dict[$(this).find('abbreviation').text()].width)
+            .attr('height', dict[$(this).find('abbreviation').text()].height)
+            .attr("xlink:href", $(this).find('url').text())
+          }
+        });
+      }
+    });
+  });
+  
+  
+}