Browse Source

Added test html for testing the following functions: adding new frame to local server storage, visualizing frame within the template and removing overlapping frames

Manuel Gall 3 years ago
parent
commit
4b6a9c5a28
8 changed files with 402 additions and 172 deletions
  1. 84 31
      frames
  2. 8 0
      frames.xml
  3. 33 0
      template/css/design.css
  4. 68 0
      template/js/test.js
  5. 78 119
      template/js/ui.js
  6. 54 21
      template/js/ui2.js
  7. 22 1
      template/template.html
  8. 55 0
      template/test.html

+ 84 - 31
frames

@@ -22,32 +22,26 @@ require 'xml/smart'
 require 'riddl/server'
 require 'fileutils'
 require 'typhoeus'
-
 class Get < Riddl::Implementation
   def response
-    Riddl::Parameter::Complex.new('ui','text/html',File.open(File.join(__dir__,'template','template.html')))
+    if @r[0] == 'test'
+      Riddl::Parameter::Complex.new('ui','text/html',File.open(File.join(__dir__,'template','test.html')))
+    else
+      Riddl::Parameter::Complex.new('ui','text/html',File.open(File.join(__dir__,'template','template.html')))
+    end
   end
 end
 
 class Put < Riddl::Implementation
   def response
+    puts "AAAAAAAAAAAAAAAAAAA"
     Dir.mkdir(File.join('data',@r.last)) rescue nil
-    File.write(File.join('data',@r.last,'num'),@p[0].value)
-    File.write(File.join('data',@r.last,'total'),@p[1].value)
-    File.write(File.join('data',@r.last,'style.url'),@p[2].value)
+    File.write(File.join('data',@r.last,'style.url'),@p[0].value)
+    File.write(File.join('data',@r.last,'document.xml'),@p[1].value)
+    File.write(File.join('data',@r.last,'frames.json'),JSON.dump(JSON.parse('{"data":[]}')))
 
-    image = Typhoeus.get(@p[3].value).response_body rescue '<image/>'
-    File.write(File.join('data',@r.last,'image.xml'),image)
-
-    if @p[4]&.name == 'errors_url'
-      errors = Typhoeus.get(@p[4].value).response_body rescue '<reasons/>'
-      File.write(File.join('data',@r.last,'errors.xml'),errors)
-    end
-    if @p[4]&.name == 'info'
-      File.write(File.join('data',@r.last,'info.json'),@p[4].value)
-    end
-    if @p[5]&.name == 'info'
-      File.write(File.join('data',@r.last,'info.json'),@p[5].value)
+    if @p[2]&.name == 'info'
+      File.write(File.join('data',@r.last,'info.json'),@p[2].value)
     end
 
     File.write(File.join('data',@r.last,'callback'),@h['CPEE_CALLBACK'])
@@ -60,15 +54,52 @@ class Put < Riddl::Implementation
     Riddl::Header.new('CPEE-CALLBACK', 'true')
   end
 end
+
+class NewFrame < Riddl::Implementation
+  def response    
+    path = File.join('data',@r.last,'frames.json')
+    file = File.read(path)
+    data_hash = JSON::parse(file)
+    
+    #puts "Before " + JSON.dump(data_hash);
+    
+    data_hash["data"].each do | c |
+      
+      if doOverlap(c['lx'], c['ly'], c['rx'], c['ry'], @p[0].value.to_i, @p[1].value.to_i, (@p[0].value.to_i + @p[2].value.to_i - 1), (@p[1].value.to_i + @p[3].value.to_i - 1))
+        data_hash["data"].delete(c)
+      end
+    end
+    
+    hash = {lx: @p[0].value.to_i, ly: @p[1].value.to_i, rx: (@p[0].value.to_i + @p[2].value.to_i - 1), ry: (@p[1].value.to_i + @p[3].value.to_i - 1), url: @p[4].value};
+    
+    
+    File.write(path, JSON.dump(data_hash))
+
+    @a[0].send(JSON.dump(hash))
+    nil
+ 
+  end
+end
+
+
+def doOverlap(l1x, l1y, r1x, r1y, l2x, l2y, r2x, r2y) 
+  if l1x > r2x || l2x > r1x
+      return false;
+  end
+  if l1y > r2y || l2y > r1y
+      return false;
+  end
+  return true; 
+end
+
+
 class Delete < Riddl::Implementation
   def response
     if cbu = File.read(File.join('data',@r.last,'callback'))
       send = { 'operation' => @p[0].value }
       case send['operation']
-        when 'jump'
-          send['target'] = @p[1].value
-        when 'error'
-          send['reason'] = @p[1].value
+        when 'result'
+          send['target'] = JSON::parse(@p[1].value.read)
       end
       cbu += '/' unless cbu[-1] == '/'
 
@@ -76,15 +107,11 @@ class Delete < Riddl::Implementation
     end
 
     File.unlink(File.join('data',@r.last,'callback')) rescue nil
-    File.unlink(File.join('data',@r.last,'num')) rescue nil
-    File.unlink(File.join('data',@r.last,'total')) rescue nil
     File.unlink(File.join('data',@r.last,'style.url')) rescue nil
-    File.unlink(File.join('data',@r.last,'image.xml')) rescue nil
-    File.unlink(File.join('data',@r.last,'errors.xml')) rescue nil
+    File.unlink(File.join('data',@r.last,'document.xml')) rescue nil
+    File.unlink(File.join('data',@r.last,'info.json')) rescue nil
 
-    if @p[0].value == 'finish' || @p[0].value == 'error'
-      @a[0].send('reset')
-    end
+    @a[0].send('reset')
     nil
   end
 end
@@ -99,9 +126,10 @@ class GetInfo < Riddl::Implementation #{{{
     end
   end
 end #}}}
+
 class GetLangs < Riddl::Implementation #{{{
   def response
-    fname = File.join('data',@r[-2],'image.xml')
+    fname = File.join('data',@r[-2],'document.xml')
     if File.exists? fname
       doc = XML::Smart.open_unprotected(fname)
       ndoc = XML::Smart.string('<languages/>')
@@ -126,7 +154,7 @@ class GetStyle < Riddl::Implementation #{{{
 end #}}}
 class GetDocument < Riddl::Implementation #{{{
   def response
-    fname = File.join('data',@r[-3],'image.xml')
+    fname = File.join('data',@r[-3],'document.xml')
     if File.exists? fname
       doc = XML::Smart.open_unprotected(fname)
       val = nil
@@ -143,6 +171,25 @@ class GetDocument < Riddl::Implementation #{{{
     end
   end
 end #}}}
+class GetButton < Riddl::Implementation #{{{
+  def response
+    fname = File.join('data',@r[-3],'document.xml')
+    if File.exists? fname
+      doc = XML::Smart.open_unprotected(fname)
+      val = nil
+      doc.find("//variant[@lang='#{@r[-1]}']").each do |e|
+        val = e.attributes['button']
+      end
+      if val
+        Riddl::Parameter::Complex.new('url','text/plain',val.strip)
+      else
+        @status = 404
+      end
+    else
+      @status = 404
+    end
+  end
+end #}}}
 
 class SSE < Riddl::SSEImplementation #{{{
   def onopen
@@ -201,6 +248,7 @@ server = Riddl::Server.new(File.join(__dir__,'/frames.xml'), :host => 'localhost
       opts[:signals][idx] ||= Signaling.new
 
       run Get if get
+      run NewFrame, opts[:signals][idx] if post 'frame'
       run Put, opts[:signals][idx] if put 'input'
       run Delete, opts[:signals][idx] if delete 'opa'
       run Delete, opts[:signals][idx] if delete 'opb'
@@ -216,6 +264,11 @@ server = Riddl::Server.new(File.join(__dir__,'/frames.xml'), :host => 'localhost
       on resource 'info.json' do
         run GetInfo if get
       end
+      on resource 'buttons' do
+        on resource '[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*' do
+          run GetButton if get
+        end
+      end
       on resource 'documents' do
         on resource '[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*' do
           run GetDocument if get
@@ -223,4 +276,4 @@ server = Riddl::Server.new(File.join(__dir__,'/frames.xml'), :host => 'localhost
       end
     end
   end
-end.loop!
+end.loop!

+ 8 - 0
frames.xml

@@ -24,6 +24,13 @@
       <parameter name="info" type="string"/>
     </optional>
   </message>
+  <message name="frame">
+    <parameter name="lx" type="string"/>
+    <parameter name="ly" type="string"/>
+    <parameter name="rx" type="string"/>
+    <parameter name="ry" type="string"/>
+    <parameter name="url" type="string"/>
+  </message>
   <message name="ui">
     <parameter name="ui" mimetype="text/html"/>
   </message>
@@ -54,6 +61,7 @@
     <resource>
       <get out="ui"/>
       <put in='input' out="callback"/>
+      <post in='frame'/>
       <delete in='opa'/>
       <delete in='opb'/>
       <resource relative='sse'>

+ 33 - 0
template/css/design.css

@@ -0,0 +1,33 @@
+*{
+  box-sizing: border-box;
+  padding: 0;
+  margin: 0;
+}
+
+
+:root {
+  --grid-cols: 1;
+  --grid-rows: 1;
+}
+
+#container {
+  display: grid;
+  grid-template-rows: repeat(var(--grid-rows), 1fr);
+  grid-template-columns: repeat(var(--grid-cols), 1fr);
+  width: 100vw;
+  height: 100vh;
+}
+
+.grid-item {
+  border: none;
+  background-color: #ddd;
+  text-align: center;
+}
+
+.grid-item-invis{
+  border: none;
+  text-align: center;
+  width: 0px;
+  height: 0px;
+  background-color: #fff;
+}

+ 68 - 0
template/js/test.js

@@ -0,0 +1,68 @@
+
+
+document.addEventListener('keyup', (event) => {
+  if (event.key == 'ArrowRight') {
+    $.ajax({
+      type: "PUT",
+      url: "../Manuel",
+      headers: {"content-id": "input"},
+      data: { style_url: "mystyleURL", document_url: 'www.nixdrin.at' },
+      success: function(res) {
+        location.reload();
+      },
+      error: function (request, status, error) {
+        alert(request.responseText + status + error);
+      }
+    });
+  }
+  
+    if (event.key == 'ArrowUp') {
+
+      $.ajax({
+        type: "POST",
+        url: "../Manuel",
+        headers: {"content-id": "frame"},
+        data: { lx: "2", ly: '0', rx: '1', ry: '2', url: 'https://centurio.work/' },
+        success: function(res) {
+          location.reload();
+        },
+        error: function (request, status, error) {
+          alert(request.responseText + status + error);
+        }
+      });
+    }
+    
+    
+    if (event.key == 'ArrowDown') {
+      $.ajax({
+        type: "POST",
+        url: "../Manuel",
+        headers: {"content-id": "frame"},
+        data: { lx: "0", ly: '0', rx: '2', ry: '2', url: 'https://centurio.work/flow-test/' },
+        success: function(res) {
+          location.reload();
+        },
+        error: function (request, status, error) {
+          alert(request.responseText + status + error);
+        }
+      });
+    }
+    
+    if (event.key == 'ArrowLeft') {
+      $.ajax({
+        type: "POST",
+        url: "../Manuel",
+        headers: {"content-id": "frame"},
+        data: { lx: "1", ly: '1', rx: '2', ry: '2', url: 'https://centurio.work/customers/evva/was/ui/' },
+        success: function(res) {
+          location.reload();
+        },
+        error: function (request, status, error) {
+          alert(request.responseText + status + error);
+        }
+      });
+    }
+  
+    
+});
+   

+ 78 - 119
template/js/ui.js

@@ -1,195 +1,154 @@
 var reason ="";
 
-function showImage() {
+
+function showDocument() {
+  
+  /*
   $.ajax({
     type: "GET",
     url: 'languages',
     success: function(ret) {
       $('#content .added').remove();
-      var template = $('#content template')[0];
+      $('#control .added').remove();
+      var ctemplate = $('#content template')[0];
+      var btemplate = $('#control template')[0];
       var promises = [];
       $('language',ret).each(function(i,e){
-        var clone = document.importNode(template.content, true);
+        var cclone = document.importNode(ctemplate.content, true);
+        var bclone = document.importNode(btemplate.content, true);
         promises.push(new Promise((resolve, reject) => {
-          $('> *',clone).each(function(j,c){
+          $('> *',cclone).each(function(j,c){
             $(c).addClass('added');
             $(c).attr('lang', e.textContent);
             $.ajax({
               type: "GET",
-              url: 'images/' + e.textContent,
-              success: function(img) {
-                $(c).attr('style','background-image: url("' + img +'")');
+              url: 'documents/' + e.textContent,
+              success: function(doc) {
+                if (c.nodeName == 'IFRAME') {
+                  $(c).attr('src',doc);
+                } else {
+                  $('iframe',c).attr('src',doc);
+                }
                 $('#content').append(c);
                 resolve(true);
               },
               error: function() {
                 reject(false);
-                setTimeout(function(){ showImage(); }, 500);
+                setTimeout(function(){ showDocument(); }, 500);
               }
             });
           });
         }));
-      });
-      Promise.all(promises).then((values) => {
-        $.ajax({
-          type: "GET",
-          url: 'style.url',
-          success: function(ret) {
-            $('head link.custom').attr('href',ret);
-          }
-        });
-        $.ajax({
-          type: "GET",
-          url: 'num',
-          success: function(num) {
-            if (num == 1) {
-              $("button[name=first]").addClass('hidden');
-              $("button[name=previous]").addClass('hidden');
-            } else {
-              $("button[name=first]").removeClass('hidden');
-              $("button[name=previous]").removeClass('hidden');
-            }
+        promises.push(new Promise((resolve, reject) => {
+          $('> *',bclone).each(function(j,c){
+            $(c).addClass('added');
+            $(c).attr('lang', e.textContent);
             $.ajax({
               type: "GET",
-              url: 'total',
-              success: function(total) {
-                if (num == total) {
-                  $("button[name=last]").addClass('hidden');
-                  $("button[name=next]").addClass('hidden');
+              url: 'buttons/' + e.textContent,
+              success: function(but) {
+                if (c.nodeName == 'BUTTON') {
+                  $(c).text(but);
                 } else {
-                  $("button[name=last]").removeClass('hidden');
-                  $("button[name=next]").removeClass('hidden');
+                  $('button',c).text(but);
                 }
+                $('#control').append(c);
+                resolve(true);
+              },
+              error: function() {
+                resolve(true);
               }
             });
-          }
-        });
+          });
+        }));
+      });
+      Promise.all(promises).then((values) => {
         $.ajax({
           type: "GET",
-          url: 'errors.xml',
+          url: 'style.url',
           success: function(ret) {
-            $("button[name=error]").removeClass('hidden');
+            $('head link.custom').attr('href',ret);
           }
         });
         lang_init('#content','#languages');
         $('#languages').removeClass('hidden');
-        $('#nav').removeClass('hidden');
         $('#nope').addClass('hidden');
       });
     },
     error: function() {
       reason = '';
-      clearImage();
+      clearDocument();
     }
   });
+  */
 }
-function clearImage() {
+
+
+function clearDocument() {
+  console.log('rrrr');
   $('#languages').addClass('hidden');
-  $('#reasons').addClass('hidden');
-  $('#nav').addClass('hidden');
-  $('#nav button').addClass('hidden');
   $('#nope').removeClass('hidden');
-  $("button").addClass('hidden');
+  $('#control .added').remove();
   $('#content .added').remove();
   $('#reason').text(reason);
 }
 
+
 function init() {
   es = new EventSource('sse/');
   es.onopen = function() {
-    showImage();
+    showDocument();
     // load
   };
   es.onmessage = function(e) {
     if (e.data == 'new') {
       reason = '';
-      showImage();
+      showDocument();
+      alert("Test1")
     }
     if (e.data == 'reset') {
       reason = '';
-      clearImage();
+      console.log('xxx');
+      clearDocument();
+      alert("TEST2")
+    }
+    else{
+      if(e.data != "keepalive" && e.data != "started"){
+      alert(e.data)
+        var frd = JSON.parse(e.data)
+        makeFrame(frd.lx,frd.ly,frd.rx,frd.ry, frd.url);
+      }
+        
     }
   };
   es.onerror = function() {
     reason = 'Server down.';
-    clearImage();
+    clearDocument();
     setTimeout(init, 10000);
   };
 }
 
+
+
+
+
+
+
+
 $(document).ready(function() {
+  $('#control').on('click','button[name=send]',b_send);
   init();
-  $("button[name=next]").click(b_next);
-  $("button[name=previous]").click(b_previous);
-  $("button[name=error]").click(b_error);
-  $("button[name=first]").click(b_first);
-  $("button[name=last]").click(b_last);
-  $("#reasons").on('click','button',b_reason);
-  $('body').keypress(function(e){
-    if (e.originalEvent.key == 'a' && !$("button[name=previous]").hasClass('hidden')) {
-      b_previous();
-    }
-    if (e.originalEvent.key == 'c' && !$("button[name=next]").hasClass('hidden')) {
-      b_next();
-    }
-  });
 });
 
-function b_previous() {
-  $.ajax({
-    type: "DELETE",
-    data: { op: "prev" },
-    url: location.href
-  });
-}
+function b_send() {
+  var formData = new FormData();
+  var content = JSON.stringify($('iframe:visible')[0].contentWindow.send_it());
+  var blob = new Blob([content], { type: "application/json"});
 
-function b_next() {
-  $.ajax({
-    type: "DELETE",
-    data: { op: "next" },
-    url: location.href
-  });
-}
-function b_first() {
-  $.ajax({
-    type: "DELETE",
-    data: { op: "jump", target: 1 },
-    url: location.href
-  });
-}
-function b_last() {
-  $.ajax({
-    type: "DELETE",
-    data: { op: "jump", target: -1 },
-    url: location.href
-  });
-}
+  formData.append("op", "result");
+  formData.append("value", blob);
 
-function b_reason() {
-  var reason = $(this).text();
-  $('#reasons').toggleClass('hidden');
-  $.ajax({
-    type: "DELETE",
-    data: { op: "error", reason: reason },
-    url: location.href
-  });
-}
-function b_error() {
-  $.ajax({
-    type: "get",
-    url: "errors.xml",
-    success: function(x) {
-      $('#reasons .added').remove();
-      var template = $('#reasons template')[0];
-      $('reason',x).each((k,v) => {
-        var clone = document.importNode(template.content, true);
-        $('> *',clone).each((j,c) => {
-          $(c).addClass('error added');
-          $('button',c).text(v.textContent);
-        });
-        $('#reasons').append(clone);
-      });
-      $('#reasons').toggleClass('hidden');
-    }
-  });
+  var request = new XMLHttpRequest();
+  request.open("DELETE", location.href);
+  request.send(formData);
 }

+ 54 - 21
template/js/ui2.js

@@ -1,44 +1,77 @@
 
 
-function removeElementsByClass(className){
-   alert(className)
-    var elements = document.getElementsByClassName(className);
-    while(elements.length > 0){
-        elements[0].parentNode.removeChild(elements[0]);
+var storage = []; //{col:1, row:1, colamount:1, rowamount: 1}];
+
+
+function doOverlap(l1x, l1y, r1x, r1y, l2x, l2y, r2x, r2y) 
+{ 
+    // If one rectangle is on left side of other 
+    if (l1x > r2x || l2x > r1x) 
+        return false;
+    // If one rectangle is above other 
+    if (l1y > r2y || l2y > r1y) 
+        return false;
+    return true; 
+}
+
+function clearRectangel(l1x, l1y, r1x, r1y){
+  for(var i = l1x; i <= r1x; ++i)
+    for(var k = l1y; k <= r1y; ++k){
+      $(".item" + (i) + "-" + (k)).css({"display": "block", "border-style": "none", "border-color": "black", "grid-area": "auto"});
+      $(".item" + (i) + "-" + (k)).text("");
     }
 }
 
+function hideRectangel(l1x, l1y, r1x, r1y){
+  for(var i = l1x; i <= r1x; ++i)
+    for(var k = l1y; k <= r1y; ++k)
+      if(!(i == l1x && k == l1y))
+        $(".item" + (i) + "-" + (k)).hide(100);
+}
 
-function makeFrame(col, row, colamount = 1, rowamount = 1) {
-  
-  var style = document.createElement('style');
-  style.innerHTML = "   .item" + col + "-" + row + " {          border-style: solid;          border-color: blue;          grid-column: " + col + " / span " + colamount + ";         grid-row: "+ row + " / span " + rowamount + ";        }          ";
-  document.head.appendChild(style);
+
+
+function makeFrame(lx, ly, rx, ry, content = "") {
   
-  var k = 1;
-  for(var i = 1; i < colamount || k < rowamount; ++i){
-    removeElementsByClass("item" + (col + i) + "-" + (row + k -1))
-    
-    if(i == colamount && k < rowamount){
-      i = 0;
-      ++k;
+  //check if rects overlap if they do remove old ones
+  for (i = 0; i < window.storage.length; i++) {
+    if(doOverlap(window.storage[i].lx, window.storage[i].ly, window.storage[i].rx, window.storage[i].ry, lx, ly, rx, ry)){
+      clearRectangel(window.storage[i].lx, window.storage[i].ly, window.storage[i].rx, window.storage[i].ry)
+      window.storage.splice(i,1);
+      --i;
     }
   }
   
+  //add new ellement to storage
+  window.storage.push({lx:lx, ly:ly, rx:rx, ry: ry})
+  
+  //Create new element with width, heigth and content
+  $(".item" + lx + "-" + ly).css({"display": "block", "border-style": "solid", "border-color": "blue", "grid-column": (lx+1) + " / span " + (rx-lx+1),  "grid-row": ly+1 + " / span " + (ry-ly+1)});
   
+  $(".item" + lx + "-" + ly).html("<iframe width=100% height=100% src='" + content + "' title=''></iframe>");
+  hideRectangel(lx, ly, rx, ry)
 };
 
-
+/*
 document.addEventListener('keyup', (event) => {
     if (event.key == 'ArrowUp') {
         alert("ArrowUp");
-        makeFrame(1,1,2,1)
+        makeFrame(0,0,0,0, "a")
     }
     if (event.key == 'ArrowDown') {
         alert("ArrowDown");
         
-        makeFrame(2,1,1,2)
+        makeFrame(0,0,1,1, "b")
+    }
+    if (event.key == 'ArrowLeft') {
+        alert("ArrowLeft");
+        
+        makeFrame(1,1,2,2, "c")
+    }
+    
+    if (event.key == 'ArrowRight') {
+        alert(JSON.stringify(window.storage));
     }
 });
-  
+*/
   

+ 22 - 1
template/template.html

@@ -40,7 +40,7 @@
     <script type="text/javascript" src="../js/ui.js"></script>
     <script type="text/javascript" src="../js/ui2.js"></script>
     <script type="text/javascript" src="../js/language.js"></script>
-    <link rel="stylesheet" href="../css/ui.css" type="text/css"/>
+    <link rel="stylesheet" href="../css/design.css" type="text/css"/>
     <link class='custom' rel="stylesheet" href="" type="text/css"/>
     <script>
       if (location.href.match(/\/$/) == null) {
@@ -52,6 +52,27 @@
     <div id="container">
     </div>
 
+<script>
+  const container = document.getElementById("container");
+
+  function makeRows(rows, cols) {
+    container.style.setProperty('--grid-rows', rows);
+    container.style.setProperty('--grid-cols', cols);
+    for (c = 0; c < (rows * cols); c++) {
+      let cell = document.createElement("div");
+      //cell.innerText = (c + 1);
+      cell.classList.add("item" + (c% cols) + "-" + (Math.floor(c / cols ))); 
+      
+      cell.classList.add("grid-item");
+
+      container.appendChild(cell);
+    };
+  };
+
+  makeRows(6, 3);
+  //makeRows(200, 300);
+
+</script>
 <!--
     <div id="languages" class="hidden"></div>
 

+ 55 - 0
template/test.html

@@ -0,0 +1,55 @@
+<!--
+  This file is part of centurio.work/out/frame.
+
+  centurio.work/out/frame 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/out/frame 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/out/frame (file LICENSE in the main directory). If not, see
+  <http://www.gnu.org/licenses/>.
+-->
+
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" lang="de" xml:lang="de">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+    <title>work frame</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>
+
+    <!-- custom stuff, play arround  -->
+    <script type="text/javascript" src="../js/test.js"></script>
+    <link rel="stylesheet" href="../css/design.css" type="text/css"/>
+    <link class='custom' rel="stylesheet" href="" type="text/css"/>
+    <script>
+      if (location.href.match(/\/$/) == null) {
+        location.href = location.href + '/';
+      }
+    </script>
+  </head>
+  <body is="x-ui">
+    <div id="container">
+    test
+    </div>
+
+  </body>
+</html>