nakome
6/19/2014 - 9:54 PM

A Pen by Moncho Varela.

A Pen by Moncho Varela.



/*      BASE
-------------------------------*/
body {
  position: relative;
  height: 100%;
  margin: 0;
  padding: 0;
  background: #ECF0F1;
  font-family: verdana,sans-serif;
  font-size: 13px;
  font-weight: 400;
  color: #BDC3C7;
}

pre {
  white-space: pre-wrap;    
  white-space: -moz-pre-wrap;  
  white-space: -pre-wrap;      
  white-space: -o-pre-wrap;   
  word-wrap: break-word;      
}
::-webkit-scrollbar {
  width: 5px;
}

::-webkit-scrollbar-track {
  background:#fff;
}

::-webkit-scrollbar-thumb {
  background:#ddd;
}

/*      MENU
-------------------------------*/
nav.menu {
  display: block;
  width: 100%;
  background: #FFFFFF;
  overflow: hidden;
  border-bottom: 1px solid #ECECEC;
  margin: 0;
  padding: 0;
  margin-bottom: 5px;
}
.right {
  float: right;
  margin-right: 10px;
}
.left {
  list-style: none;
  margin: 0;
  padding: 0;
  float: left;
  color: #BDC3C7;
}
.left li {
  display: inline-block;
  margin: 0;
  padding: 0;
  position: relative;
  vertical-align: middle;
}
.menu a {
  text-decoration: none;
  text-transform: capitalize; 
  font-size: 20px;
  margin: 0;
  margin-left: 5px;
  transition: color 0.5s ease;
  padding: 5px 10px;
  margin: 0 auto;
  display: block;
  border-left: 1px solid #ECECEC;
  color: #BDC3C7;
}
.menu a:hover {
  text-decoration: none;
  color: #3498DB;
  transition: color 0.5s ease;
}

.center {
  display: block;
  float: left;
  line-height: 50px;
  font-size: 16px;
  font-family: sans-serif;
  margin-left: 10px;
}

.download {
  margin-top: 5px;
}




/*                  CHECKBOX
------------------------------*/
.checkBox {
  width: 80px;
  height: 26px;
  background: #FFFFFF;
  margin: 0;
  position:relative;
  -moz-box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.5), 0px 1px 0px rgba(255, 255, 255, 0.2);
  -webkit-box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.5), 0px 1px 0px rgba(255, 255, 255, 0.2);
  box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.5), 0px 1px 0px rgba(255, 255, 255, 0.2);
}
.checkBox:after {
  content: 'OFF';
  color: #E74C3C;
  position: absolute;
  top: 0;
  right: 10px;
  z-index: 0;
  font: 12px/26px Arial, sans-serif;
  font-weight: bold;
  text-shadow: 1px 1px 0px rgba(255, 255, 255, 0.15);
}
.checkBox:before {
  content: 'ON';
  color: #3498DB;
  position: absolute;
  left: 10px;
  z-index: 0;
  font: 12px/26px Arial, sans-serif;
  font-weight: bold;
}
.checkBox label {
  display: block;
  width: 34px;
  height: 20px;
  cursor: pointer;
  position: absolute;
  top: 3px;
  left: 3px;
  z-index: 1;
  background: #FFFFFF;
  -moz-transition: all 0.4s ease;
  -o-transition: all 0.4s ease;
  -webkit-transition: all 0.4s ease;
  transition: all 0.4s ease;
  -moz-box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.23);
  -webkit-box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.23);
  box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.23);
}
.checkBox input[type=checkbox] {
  visibility: hidden;
}
.checkBox input[type=checkbox]:checked + label {
  left: 43px;
}







/*      WRAPPER
-------------------------------*/
.items {
  background:#fdfdfd;
  border: 1px solid #BDC3C7;
}
.items .meta {
  text-align:center;
  padding-top: 5px;
  padding-bottom:5px;
  background: #ECF0F1;
}
.items a {
  color: #3498DB;
  text-decoration:none;
}
.items a:hover, .items a:active {
  color:#16A085;
  -webkit-transition:all 0.5s ease;
  -moz-transition:all 0.5s ease;
  -o-transition:all 0.5s ease;
  transition:all 0.5s ease;
  text-decoration:none;
}
.items h3 {
  font-family: sans-serif;
  font-weight:900;
  line-height:28px;
  font-size:28px;
  margin:0;
  padding:9px 2px;
  margin-bottom:7px;
  color: #3498DB;
  border-bottom:1px solid #eee;
}
.items p {
  font-family: sans-serif;
  font-size:15px;
  font-weight:normal;
  line-height:17px;
  margin: 5px;
  color: #5A5A5A;
}
.items .btns {
  display:block;
  text-align:right;
  padding:3px 0;
  padding-right:3px;
}
.items .btn {
  margin: 3px;
  display:inline-block;
  padding:3px 5px;
  text-align:center;
  background-color: #FFFFFF;
  border: 1px solid #DFDFDF;
  color: #B8B8B8;
  border-radius: 3px;
  -webkit-transition:all 0.5s ease;
  -moz-transition:all 0.5s ease;
  -o-transition:all 0.5s ease;
  transition:all 0.5s ease;
}
.items .btn:hover, .items .btn:active {
  background: #ECF0F1;
  color: #3498DB;
  -webkit-transition:all 0.5s ease;
  -moz-transition:all 0.5s ease;
  -o-transition:all 0.5s ease;
  transition:all 0.5s ease;
}
.items .share {
  margin:1px;
  display:inline-block;
  background-color:#1D1D1D;
  color:#fff;
  padding:3px 5px;
  text-transform:uppercase;
  text-align:center;
  -webkit-transition:all 0.5s ease;
  -moz-transition:all 0.5s ease;
  -o-transition:all 0.5s ease;
  transition:all 0.5s ease;
}
.items .share:hover, .items .share:active {
  background:#f55;
  color:#fdfdfd;
  -webkit-transition:all 0.5s ease;
  -moz-transition:all 0.5s ease;
  -o-transition:all 0.5s ease;
  transition:all 0.5s ease;
}
.items .author {
  display:inline-block;
  margin-right:5px;
  width:50px;
  height:50px;
  -webkit-border-radius:50px;
  -moz-border-radius:50px;
  border-radius:50px;
  vertical-align:middle;
  border: 5px solid #3498DB;
}
.items .front {
  display:block;
  width:100%;
}
.loaded {
  position:relative;
  overflow:hidden;
  height: 93%;
  -webkit-transition:all 0.5s ease;
  -moz-transition:all 0.5s ease;
  -o-transition:all 0.5s ease;
  transition:all 0.5s ease;
}
.loaded:before {
  content:" loadding...";
  position:absolute;
  top:0;
  left:0;
  margin:0;
  padding:0;
  width:100%;
  height:100%;
  background:#ECF0F1;
  color:#95A5A6;
  text-align:center;
  line-height:10;
  z-index: 999999999;
  -webkit-transition:all 0.5s ease;
  -moz-transition:all 0.5s ease;
  -o-transition:all 0.5s ease;
  transition:all 0.5s ease;
}


.info_alert {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  margin: auto;
  text-align: center;
  font-size: 2em;
  color: #E74C3C;
}






/*      MODALS
-------------------------------*/
.modal {
  visibility: hidden;
  position:fixed;
  top:0;
  left: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  background: #FFFFFF;
  color: #A7A7A7;
  z-index: 9999;
}
.modal_inner {
  margin: 2% auto;
  padding: 0;
  width: 100%;
  max-width: 60em;
  height: 90%;
  min-height: 30em;
  display: block;
  position: relative;
  overflow: auto;
}
.close_modal {
  font-family: "consolas",monospace,cursive;
  font-size: 3em;
  font-weight: 400;
  text-decoration: none;
  float: right;
  margin-right: 10px;
  transition:all 0.5s ease;
  color: #BDC3C7;
}
.close_modal:hover {
  transition:all 0.5s ease;
  color: #777;
}
.opened{
  visibility: visible;
}






/*      PRETTY JSON 
-------------------------------*/
pre {
  padding: 0;
  margin: 0;
}
.string {
  color: #3498DB;
}
.number {
  color: darkorange;
}
.boolean {
  color: blue;
}
.null {
  color: magenta;
}
.key {
  color: #95A5A6;
}
pre {
  display:block;
  width:100%;
  word-break: break-word;
  color: #16A085;
}










/*      FORMS
-------------------------------*/
.add_modal form {
  padding: 10px;
}
.add_modal label{
  color: #BDC3C7;
  margin: 5px auto;
  display: block;
}
.add_modal input[type="text"],
.add_modal input[type="url"],
.add_modal input[type="date"]{
  width:100%;
  display:block;
  height: 3em;
  padding: 5px;
  background: #FFFFFF;
  color: #BDC3C7;
  border: 0;
  border-bottom: 1px solid #BDC3C7;
}
.add_modal input[type="text"]:focus,
.add_modal input[type="url"]:focus,
.add_modal input[type="date"]:focus,
.add_modal input[type="text"]:active,
.add_modal input[type="url"]:active,
.add_modal input[type="date"]:active{
  outline: none;

  border-color: #3498DB;
  background: white;
  color: #333;
}

.add_modal input[type="submit"]{
  width:100%;
  display:block;
  height: 3em;
  padding: 5px;
  background: #FFFFFF;
  color: #BDC3C7;
  border: 1px solid #BDC3C7;
  transition:all 0.5s ease;
}
.add_modal input[type="submit"]:hover,
.add_modal input[type="submit"]:active{
  border-color: #3498DB;
  background: white;
  color: #3498DB;
  transition:all 0.5s ease;
}

.add_modal textarea {
  width:100%;
  height:5em;
  display:block;
  background: #FFFFFF;
  color: #333;
  border: 0;
  border-bottom: 1px solid #BDC3C7;
}
.add_modal .inline {
  display: inline-block;
  margin: 5px;
  padding: 0;
  width: 40%;
}
.add_modal .block {
  display: block;
  margin: 5px auto;
}

input:-webkit-autofill, textarea:-webkit-autofill, select:-webkit-autofill {
  background-color: white;
  background-image: none;
  color: #f55;
}


/*           RESPONSIVE
-----------------------*/
.wrapper_inner {
  display:block;
  width:100%;
  margin:0;
  padding:0;
  -moz-column-gap:5px;
  -webkit-column-gap:5px;
  column-gap:5px;
  -moz-column-count:1;
  -webkit-column-count:1;
  column-count:1;
  box-sizing:border-box;
}
.wrapper_inner > .items {
  display:inline-block;
  width: 99%;
}
.items {
  position:relative;
  overflow:hidden;
  text-decoration:none;
}
@media screen and (min-width:240px) {
  .items .meta p {
    font-size:10px;
  }
  .items .author {
    display:inline-block;
    margin-right:4px;
    width:45px;
    height:45px;
    vertical-align:middle;
    border: 3px solid #3498DB;
  }
  .items h3 {
    line-height:20px;
    font-size:20px;
  }
  .items .btn, .items .share {
    padding:5px 9px;
    display:block;
  }
}
@media screen and (min-width:320px) {
  .items .meta p {
    font-size:12px;
  }
  .items .author {
    display:inline-block;
    margin-right:4px;
    width:45px;
    height:45px;
    vertical-align:middle;
    border: 3px solid #3498DB;
  }
  .items h3 {
    line-height:24px;
    font-size:24px;
  }
  .items .btn, .items .share {
    padding:2px 3px;
    display:inline-block;
  }
}
@media screen and (min-width:640px) {
  .wrapper_inner {
    -moz-column-count:2;
    -webkit-column-count:2;
    column-count:2;
  }
  .items .meta p {
    font-size:12px;
  }
  .items .author {
    display:inline-block;
    margin-right:4px;
    width:45px;
    height:45px;
    vertical-align:middle;
    border:3px solid #1ABC9C;
  }
  .items h3 {
    line-height:24px;
    font-size:24px;
  }
  .items .btn, .items .share {
    padding: 5px 10px;
    display:inline-block;
  }
}
@media screen and (min-width:768px) {
  .wrapper_inner {
    -moz-column-count:2;
    -webkit-column-count:2;
    column-count:2;
  }
}
@media screen and (min-width:1024px) {
  .wrapper_inner {
    -moz-column-count:3;
    -webkit-column-count:3;
    column-count:3;
  }
  .items .meta p {
    font-size: 13px;
  }
  .items .author {
    display:inline-block;
    margin-right:4px;
    width: 40px;
    height: 40px;
    vertical-align:middle;
    border: 3px solid #3498DB;
  }
  .items h3 {
    line-height:24px;
    font-size:24px;
  }
  .items .btn, .items .share {
    padding: 10px;
    display:inline-block;
  }
}
@media screen and (min-width:1200px) {
  .wrapper_inner {
    -moz-column-count:5;
    -webkit-column-count:5;
    column-count:5;
  }
}

var db = null;
  
var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange;
var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction;


if (IDBTransaction) {
  IDBTransaction.READ_WRITE = IDBTransaction.READ_WRITE || 'readwrite';
  IDBTransaction.READ_ONLY = IDBTransaction.READ_ONLY || 'readonly';
}


var data = {};

var app = (function() {

  'use sctrict';

  return {

    /*
    *   Options for app
    */
    options: {
      // json url
      'json_url': 'https://dl.dropboxusercontent.com/u/23834858/api/demo.json',
      // database name
      'database': 'demo',
      'version': 1,
      'not_support': 'Your Browser does not support IndexedDB!',
      'not_local': 'IndexedDB cannot run locally on some browsers. Try running this app from a server.',
      'btn_more_text': 'Read more',
      'del_btn_text': 'Delete',
      'show_ajax': false

    },

    /*
    * Shor function of querySelector
    * Exmaple : this._('.foo');
    */
    _: function(el) {
      return document.querySelector(el);
    },


    /*
    * Shor function of querySelector
    * Exmaple : this.refresh(1000);
    * Note: location:reload not work
    * please manually refresh
    */
    refresh: function(time) {
      /*
      var t = setTimeout(function() {
        location.reload();
        clearTimeout(t);
      }, time);
      */
    },


    /*
    * Animate function
    * Exmaple : self.animation(self._('.add_modal'), 'opacity',0,1,0,800);
    */
    animation: function(elem, style, unit, from, to, time) {
      if (!elem) return;
      var start = new Date().getTime(),
          timer = setInterval(function() {
            var step = Math.min(1, (new Date().getTime() - start) / time);
            elem.style[style] = (from + step * (to - from)) + unit;
            if (step == 1) clearInterval(timer);
          }, 25);
      elem.style[style] = from + unit;
    },

    /*
    * Delay function
    * Exmaple : self.wait(time,callback)
    */
    wait: function(callback, time) {
      var t = setTimeout(function() {
        clearTimeout(t);
        return callback();
      }, time);
    },
    /*
     * Init events
     */
    init: function() {
      var self = this;

      // initialize database 
      this.initialize_DB();

      // remove test
      //indexedDB.deleteDatabase('demo_DB'); 

      // on click add items 
      this._('#save').addEventListener('click', function() {
        items = {
          city: self._('#city').value,
          date: self._('#date').value,
          url: self._('#url').value,
          author: self._('#author').value,
          tumb: self._('#tumb').value,
          image: self._('#image').value,
          title: self._('#title').value,
          description: self._('#desc').value,
          content: self._('#content').value
        };

        // add items DB
        self.add_items_DB(items);
        // refresh 
        //self.refresh(1000);
      }, false);



      // if options show_ajax is true renders ajax request
      // if not render local DB
      if (this.options.show_ajax) {
        self._('#checkBox').checked = true;
        self._('.info').innerHTML = 'Show Ajax Request';
        this.jsn();
      } else {
        self._('#checkBox').checked = false;
        self._('.info').innerHTML = 'Show Local Request';
        this.localDb();
      }

      // on click checked or un checked
      this._('#checkBox').addEventListener('click', function() {
        if (this.checked) {
          self._('.info').innerHTML = 'Show Ajax Request';
          self.jsn();
        } else {
          self._('.info').innerHTML = 'Show Local Request';
          self.localDb();
        }
      });

      // show  add modal
      this._('.add_data').addEventListener('click', function(e) {
        e.preventDefault();
        self._('.add_modal').classList.add('opened');
        self.animation(self._('.add_modal'), 'opacity', 0, 0, 1, 800);
      });
      // close add modal
      this._('.add_modal .close_modal').addEventListener('click', function(e) {
        e.preventDefault();
        self.animation(self._('.add_modal'), 'opacity', 0, 1, 0, 800);
        self.wait(function() {
          self._('.add_modal').classList.remove('opened');
        }, 1000);
      });


      // show  json data
      this._('.json_info').addEventListener('click', function(e) {
        e.preventDefault();
        self._('.json_data').classList.add('opened');
        // animation
        self.animation(self._('.json_data'), 'opacity', 0, 0, 1, 800);
      });
      // close json modal
      this._('.json_data .close_modal').addEventListener('click', function(e) {
        e.preventDefault();
        // animation
        self.animation(self._('.json_data'), 'opacity', 0, 1, 0, 800);
        // wait 
        var t = setTimeout(function() {
          self._('.json_data').classList.remove('opened');
          clearTimeout(t);
        }, 1000);
      });


      // delete database
      this._('.del_db').addEventListener('click', function(e) {
        e.preventDefault();

        var confirm = window.confirm('Are you sure to delete ' + self.options.database + '_DB');
        if (confirm) {
          // delete database fn
          indexedDB.deleteDatabase(self.options.database + '_DB');
          self._('.json').innerHTML = 'the database has been deleted';
          // refresh
          self.refresh(1000);
        }
        return;
      });
    },


    /*
    *  init database
    *  inspired by http://codepen.io/girliemac/pen/iAvaz
    */
    initialize_DB: function() {
      var self = this;
      // if not support
      if (typeof indexedDB === 'undefined') {
        alert(self.options.not_support);
        return;
      }
      // if run in local and not support
      if (indexedDB === null) {
        alert(self.options.not_local);
        return;
      }
      // open database
      var open_database = indexedDB.open(this.options.database + '_DB');
      // success 
      open_database.onsuccess = function(e) {
        db = e.target.result;
        //console.log(db.name + ' is ready');
        // if setVersion is function
        if (typeof db.setVersion === 'function') {
          // if not exist create
          if (db.version != self.options.version) {
            var request_version = db.setVersion(self.options.version);
            request_version.onsuccess = function(e) {
              self.create_obj_DB(db);
              e.target.transaction.oncomplete = function() {
                self.get_items_DB();

                var time = setTimeout(function() {
                  self.remove_function();
                  clearTimeout(time);
                }, 200);
              };
            };
          } else { // Chrome >= 23
            self.get_items_DB();
            var time = setTimeout(function() {
              self.remove_function();
              clearTimeout(time);
            }, 200);
          } // setVersion
          // if setVersion is not function
        } else { // Firefox, IE10
          self.get_items_DB();
          var out = setTimeout(function() {
            self.remove_function();
            clearTimeout(out);
          }, 200);
        } // typeof
      }; // onsuccess

      // failure
      open_database.onfailure = function(e) {
        console.log(e);
      };
      // Newer browsers only - FF, Chrome (newer than ?), IE10
      open_database.onupgradeneeded = function(e) {
        self.create_obj_DB(e.target.result);
      };
    },


    /*
    *  create createObjectStore
    */
    create_obj_DB: function(db) {
      db.createObjectStore(this.options.database, {
        keyPath: 'id',
        autoIncrement: true
      });
    },


    /*
    *  get all items
    */
    get_items_DB: function() {
      var self = this,
          rq = db.transaction(
            this.options.database, IDBTransaction.READ_ONLY
          ).objectStore(this.options.database).openCursor(),
          arr = [];
      // sucess     
      rq.onsuccess = function(e) {
        var cursor = e.target.result;
        if (cursor) {
          arr.push(cursor.value);
          cursor.
          continue ();
        } else {
          self.render_html_DB(arr);
        }
      };
      // error
      rq.onerror = function(e) {
        console.log(e);
      };
    },

    /*
    *  add objetStore
    */
    add_items_DB: function(elements) {
      var self = this;
      // if value null
      if (elements === '') return;
      // add item
      data.item = elements;
      // request
      var req = db.transaction(
        self.options.database, IDBTransaction.READ_WRITE
      ).objectStore(self.options.database).put(data);
      // on success get all items
      req.onsuccess = function(e) {
        self.get_items_DB();
      };
      // failure
      req.onfailure = function(e) {
        console.log(e);
      };
    },

    /*
    *  remove handler
    */
    remove_function: function() {
      var self = this,
          elements = document.querySelectorAll('.del_item');
      // get all links
      Array.prototype.forEach.call(elements, function(el, idx) {
        el.addEventListener('click', function() {
          // get attribute id and remove id_
          var id = el.getAttribute('data-id').replace('id_', ''),
              confirm = window.confirm('Are you sure to delete ' + id);
          if (confirm) {
            self.delete_items_DB(id);
            self.refresh();
          }
          return;
        }, false);
      });
    },

    /*
    * delete unique items by id
    */
    delete_items_DB: function(id) {
      var self = this;
      // object store delete
      var r = db.transaction(
        self.options.database,
        IDBTransaction.READ_WRITE
      ).objectStore(self.options.database).delete(parseInt(id));
      // success
      r.onsuccess = function(e) {
        console.log('Deleted ID = ', parseInt(id));
        self.get_items_DB();
      };
      // error
      r.onerror = function(e) {
        console.log('Error deleting: ', e);
      };
      // blocked
      r.onblocked = function(e) {
        console.log('Deleting DB Blocked: ', e);
      };
    },


    /*
    * render to json
    */
    render_html_DB: function(arr) {
      var json = '';
      for (var i = 0; i < arr.length; i++) {
        var out = JSON.stringify(arr[i].item, undefined, 2);
        json += '\n"id_' + i + '":' + out + ',\n';
      }
      // structure
      var result = '{\n"' + this.options.database + '":{' + json.replace(/,\s*$/, "") + '}\n}',
          data = "text/json;charset=utf-8," + encodeURIComponent(result);
      // inner html
      this._('.json').innerHTML = '<pre>' + this.prettyJson(result) + '</pre>';
      this._('.download').innerHTML = '<a href="data:' + data + '" download="data.json"><i class="fa fa-download"></i></a>';

    },

    /*
         * local DB
         */
    localDb: function() {
      var self = this;
      var open_database_first = indexedDB.open(this.options.database + '_DB');
      open_database_first.onsuccess = function(e) {
        db = e.target.result;
        var request = db.transaction(
          self.options.database,
          IDBTransaction.READ_WRITE
        ).objectStore(self.options.database).openCursor();
        // init html 
        var html = '';
        // success
        request.onsuccess = function(e) {
          // get values
          var cursor = e.target.result;
          if (cursor) {
            var obj = cursor.value;
            html += '<div class="items" id="id_' + obj.id + '">' +
              '<img class="front" src="' + obj.item.image + '"/>' +
              '<div class="meta"><p>' +
              '<img class="author" src="' + obj.item.tumb + '"/>' +
              '<a href="' + obj.item.url + '">' + obj.item.author + '</a>' +
              '<span class="city"> - ' + obj.item.city + '</span>' +
              '<span class="date"> - ' + obj.item.date + '</span>' +
              '</p></div>' +

              '<h3>' + obj.item.title + '</h3>' +
              '<p>' + obj.item.description + '</p>' +
              // '' + jsonDB[item].content + ''+
              '<div class="btns">' +
              '<a href="' + obj.item.url + '" class="btn"><i class="fa fa-external-link "></i></a>' +
              '<a href="javascript:;" class="del_item btn" data-id="id_' + obj.id + '"><i class="fa fa-trash-o "></i></a>' +
              '</div>' +
              '</div>';
            cursor.
            continue ();
            // inner html
            self._('.wrapper').classList.remove('loaded');
            self._('.wrapper_inner').innerHTML = html;
          } 
        };
      };
    },

    /*
    * json ajax call
    */
    jsn: function() {
      var self = this,
          ajax = new XMLHttpRequest();
      ajax.open('GET', self.options.json_url, true);
      ajax.onreadystatechange = function() {
        if (ajax.readyState == 4) {
          if (ajax.status == 200) {
            // parse to json data
            var obj = JSON.parse(ajax.responseText),
                jsonDB = obj[self.options.database];
            // init html
            var html = '';
            // loop items
            for (var item in jsonDB) {
              html += '<div class="items" id="' + item + '">' +
                '<img class="front" src="' + jsonDB[item].image + '"/>' +
                '<div class="meta"><p>' +
                '<img class="author" src="' + jsonDB[item].tumb + '"/>' +
                '<a href="' + jsonDB[item].url + '">' + jsonDB[item].author + '</a>' +
                '<span class="city"> - ' + jsonDB[item].city + '</span>' +
                '<span class="date"> - ' + jsonDB[item].date + '</span>' +
                '</p></div>' +

                '<h3>' + jsonDB[item].title + '</h3>' +
                '<p>' + jsonDB[item].description + '</p>' +
                // '' + jsonDB[item].content + ''+
                '<div class="btns">' +
                '<a href="' + jsonDB[item].url + '" class="btn"><i class="fa fa-external-link "></i></a>' +
                '</div>' +
                '</div>';
            }
            // remove class and inner html
            self._('.wrapper').classList.remove('loaded');
            self._('.wrapper_inner').innerHTML = html;
          } else {
            // Error
            console.log(ajax.status);
            // unchecked checkbox and show local
            self._('#checkBox').checked = false;
            self.localDb();
          }
        }
      };
      ajax.send();
    },

    /*
    * prettyjson
    * http://stackoverflow.com/questions/4810841/how-can-i-pretty-print-json-using-javascript
    */
    prettyJson: function(json) {
      if (typeof json != 'string') {
        json = JSON.stringify(json, undefined, 2);
      }
      json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
      return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function(match) {
        var cls = 'number';
        if (/^"/.test(match)) {
          if (/:$/.test(match)) {
            cls = 'key';
          } else {
            cls = 'string';
          }
        } else if (/true|false/.test(match)) {
          cls = 'boolean';
        } else if (/null/.test(match)) {
          cls = 'null';
        }
        return '<span class="' + cls + '">' + match + '</span>';
      });
    }
  }; 

})();

// init
document.addEventListener('DOMContentLoaded', function() {
  app.init();
}, false);
<nav class="menu">
  <ul class="left">
    <li>
      <a href="javascript:;" class="add_data"><i class="fa fa-plus-circle"></i></a>
    </li>
    <li>
      <a href="javascript:;" class="json_info"><i class="fa fa-info-circle"></i></a>
    </li>
    <li>
      <a href="javascript:;" class="del_db"><i class="fa fa-trash-o "></i></a>
    </li>

    <li>
      <div class="checkBox">
        <input type="checkbox" value="None" id="checkBox" name="check" checked />
        <label for="checkBox"></label>
      </div>
    </li>

    <li>
      <p class="info"></p>
    </li>
  </ul>


  <div class="right">
    <div class="download"></div>
  </div>
</nav>



<div class="wrapper loaded">
  <div class="wrapper_inner">
    <!-- items -->
  </div>
</div>



<div class="add_modal modal">
  <a href="javascript:;" class="close_modal">X</a>
  <div class="modal_inner">


    <form>
      <div class="inline">
        <label>City</label>
        <input type="text" id="city" />
      </div>
      <div class="inline">
        <label>Date</label>
        <input type="date" id="date" />
      </div>
      <div class="inline">
        <label>Url</label>
        <input type="url" id="url" />
      </div class="inline">
      <div class="inline">
        <label>Author</label>
        <input type="text" id="author" />
      </div>
      <div class="inline">
        <label>Thumbnail</label>
        <input type="text" id="tumb" />
      </div>
      <div class="inline">
        <label>Image</label>
        <input type="text" id="image" />
      </div>
      <div class="block">
        <label>Title</label>
        <input type="text" id="title" />
      </div>
      <div class="block">
        <label>Description</label>
        <textarea name="desc" id="desc"></textarea>
      </div>
      <div class="block">
        <label>Content</label>
        <textarea name="content" id="content"></textarea>
      </div>
      <div class="inline">
        <input type="submit" id="save" value="save" />
      </div>
    </form>


  </div>
</div>



<div class="json_data modal">
  <a href="javascript:;" class="close_modal">X</a>
  <div class="modal_inner">
    <div class="json">
      <!-- json data -->
    </div>
  </div>
</div>

IndexedDB Json generator experiment

Yo can add data in indexedDB and convert and download in Json format and after testing in ajax only Javascript.

Sorry for my english :).

Note : location reload it's not good here, please manually refresh

A Pen by Moncho Varela on CodePen.

License.