Create P2P Apps Using Nothing but HTML and Javascript Part 2

This video builds on the concepts we introduced in Part 1, focusing on the P2P and data oriented aspects of the Newbound Network API. In this installment we will walk you through creating a P2P private wiki app for the Newbound Network using HTML, CSS and Javascript.



Here's the code from the video:

<html>
<head>
    <title>Wiki Bot</title>
    <link rel='stylesheet' href='../botmanager/themes/font.css'>
    <link rel="stylesheet" href="../botmanager/themes/newbound.min.css" />
    <link rel="stylesheet" href="../botmanager/themes/jquery.mobile.icons.min.css" />
    <link rel="stylesheet" href="../botmanager/jquerymobile_1_4_2/jquery.mobile.structure-1.4.2.min.css" />
    <script src="../botmanager/jquerymobile/jquery-1.9.1.min.js"></script>
    <script src="../botmanager/jquerymobile_1_4_2/jquery.mobile-1.4.2.min.js"></script>
    <script src="../botmanager/nav.js"></script>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    
    <link rel="stylesheet" href="../peerbot/connections.css" />
    <script src="../peerbot/connections.js"></script>
    
<style>

a {
  cursor: pointer;
}

.sidebar {
  position: fixed;
  top: 80px;
  bottom: 0px;
  left: 0px;
  width: 120px;
  border-right-style: solid;
  border-right-width: thin;
  border-right-color: black;
  white-space:nowrap;
  overflow:hidden;
  font-size: small;
}

.edittopic {
  display: none;
  margin-left: 125px;
}

.displaytopic {
  margin-left: 125px;
}

.buttonbar {
  position: fixed;
  top: 100px;
  right: 0px;
  padding-left:15px;
  background-color: black;
}

a.dl_selected,a.dl_selected:hover {
    color:black;
}
  
#topictitle {
  margin-right: 125px;
}
  
#breadcrumbs {
  margin-left: 125px;
  font-size: xx-small;
}

#dt_meta {
  font-size: xx-small;
  margin-top: -20px;
  margin-bottom: 20px;
}

</style>

</head>
<body>
    <div id='botcontrols' data-role='page'>
        <div data-role="header">
            <h1 id="headertitle">Wiki Bot</h1>
            <a href="../botmanager/index.html" data-icon="gear" data-ajax="false"></a>
        </div>
        
        <br>
        <center>
          <div id='peerlist'></div>
        </center>

        <div class='sidebar'>
          <h3>Devices</h3>
          <div id='devicelist'></div>
          <h3>Topics</h3>
          <div id='topiclist'></div>
        </div>
        <br>
        <div id='breadcrumbs'></div>
        <div class='displaytopic'>
          <h2 id='dt_title'></h2>
          <div id='dt_meta'></div>
          <div id='dt_entry'></div>
          <hr>
          <h3>Subtopics:</h3>
          <div id='dt_children'></div>
          <br>
          <div data-role="fieldcontain">
            <label for='newtopic'>Subtopic:</label>
            <input type='text' id='newtopic' value=''>
          </div>
          <input type='button' value='add subtopic' onclick='addSubtopic();' data-inline='true' data-mini='true'>
          <div class='buttonbar' id='displaybuttonbar'>
            <input type='button' data-inline='true' data-mini='true' value='edit' onclick='$(".displaytopic").css("display", "none");$(".edittopic").css("display", "block");'>
          </div>
        </div>
        <div class='edittopic'>
          <div data-role="fieldcontain">
            <input type='text' id='topictitle' value=''>
          </div>
          <textarea id='topicentry'></textarea>
          <div class='buttonbar' id='editbuttonbar'>
            <input type='button' data-inline='true' data-mini='true' value='save' onclick='saveTopic();'>
            <input type='button' data-inline='true' data-mini='true' value='cancel' onclick='cancelEdit();'>
          </div>
        </div>

    </div>

<script type='text/javascript'>

function addSubtopic(){
    var o = new Object();
    o.title = $('#newtopic').val();
    o.text = "[CONTENT]";
    o.version = 1;
    o.username = USERNAME;
    o.author = USER;
    o.subtopics = [];
    o.parent = TOPIC;
    
    var now = new Date();
    o.timestamp = now.getTime();
    o.date = now;

    call('write', 'db=wiki&readers=["wiki"]&writers=["wiki"]&data='+JSON.stringify(o), function(result){
        o.id = result.id;
        DATA.subtopics.push(o.id);
        call('write', 'db=wiki&id='+TOPIC+'&readers=["wiki"]&writers=["wiki"]&data='+JSON.stringify(DATA), function(result){
            if (TOPIC == 'maintopic') {
                var newhtml = '<a onclick="selectTopic(\''+o.id+'\');">'+o.title+'<'+'/a><br>';
                $('#topiclist').append(newhtml);
            }
            setTopic(o);
            $('#newtopic').val('');
        });
    });
}

function saveTopic(){
    call('write', 'db=wiki&id='+TOPIC+'_'+DATA.version+'&readers=["wiki"]&writers=["wiki"]&data='+JSON.stringify(DATA), function(result){
        DATA.title = $('#topictitle').val();
        DATA.text = $('#topicentry').val();
        DATA.version++;
        DATA.username = USERNAME;
        DATA.author = USER;
        
        var now = new Date();
        DATA.timestamp = now.getTime();
        DATA.date = now;
    
        call('write', 'db=wiki&id='+TOPIC+'&readers=["wiki"]&writers=["wiki"]&data='+JSON.stringify(DATA), function(result){
            cancelEdit();
        });
    });
}

function cancelEdit(){
    setTopic(DATA);
    $(".displaytopic").css("display", "block");
    $(".edittopic").css("display", "none");
}

function selectTopic(topicid){
    call('read', 'db=wiki&id='+topicid, function(result){
        if (result.status == 'ok') {
            result.data.id = topicid;
            setTopic(result.data);
        }
        else alert(result.msg);
    });
}

function buildBreadcrumbs(topic){
    if (topic.parent){
        var id = topic.parent;
        call('read', 'db=wiki&id='+id, function(result){
            topic = result.data;
            var newhtml = $('#breadcrumbs').html();
            if (newhtml != '') newhtml = ' | '+newhtml;
            newhtml = '<a onclick="selectTopic(\''+id+'\');">'+topic.title+'<'+'/a>'+newhtml;
            $('#breadcrumbs').html(newhtml);
            buildBreadcrumbs(topic);
        });
    }
}

function buildSubtopics(index){
    var id = DATA.subtopics[index];
    call('read', 'db=wiki&id='+id, function(result){
        var topic = result.data;
        var newhtml = '<a onclick="selectTopic(\''+id+'\');">'+topic.title+'<'+'/a><br>';
        $('#dt_children').append(newhtml);
        if (TOPIC == 'maintopic') $('#topiclist').append(newhtml);
        if (++index < DATA.subtopics.length) buildSubtopics(index);
    });
}

function setTopic(topic){
    TOPIC = topic.id;
    DATA = topic;
    $('#dt_title').text(topic.title);
    $('#topictitle').val(topic.title);
    $('#dt_meta').text('Version '+topic.version+' by '+topic.author+' on '+topic.date);
    $('#dt_entry').html(topic.text);
    $('#topicentry').val(topic.text);
    
    $('#dt_children').html('');
    
    if (topic.subtopics.length == 0){
        $('#dt_children').html('<i>No Subtopics<'+'/i>');
    }
    else {
        if (TOPIC == 'maintopic') $('#topiclist').html('');
        buildSubtopics(0);
    }
    
    $('#breadcrumbs').html('');
    buildBreadcrumbs(topic);
}

function buildTopics(){
    call('read', 'db=wiki&id='+TOPIC, function(result){
        if (result.status == 'err'){
            call('newdb', 'db=wiki&readers=["wiki"]&writers=["wiki"]', function(result){
                var o = new Object();
                o.id = TOPIC;
                o.title = USER+"'s Wiki";
                o.text = "Welcome to "+USER+"'s Wiki";
                o.version = 1;
                o.username = USERNAME;
                o.author = USER;
                o.subtopics = [];
                
                var now = new Date();
                o.timestamp = now.getTime();
                o.date = now;
                
                call('write', 'db=wiki&id='+TOPIC+'&readers=["wiki"]&writers=["wiki"]&data='+JSON.stringify(o), function(result){});
                
                setTopic(o);
            });
        }
        else {
            setTopic(result.data);
        }
    });
}

function selectDevice(id){
    $('.dl_device').removeClass('dl_selected');
    $('#dl_'+id).addClass('dl_selected');
    DEVICE = id;
    if (id == 'local') PREFIX = '';
    else PREFIX = '../peerbot/remote/'+id+'/botmanager/';
    buildTopics();
}

function checkDevice(peer, id){
    if (peer.connected){
        $.getJSON('../peerbot/remote/'+id+'/botmanager/read?db=wiki&id=maintopic', function(result){
            if ($('#dl_'+id).length==0 && result.status == 'ok') {
                $('#devicelist').append('<a class="dl_device" id="dl_'+id+'" onclick="selectDevice(\''+id+'\');">'+peer.name+'<'+'/a<br>');
                if (DEVICE == id) $('#dl_'+id).addClass('dl_selected');
            }
        });
    }
}

function buildDevices(){
    $('.dl_device').removeClass('dl_selected');
    $('#devicelist').html('<a class="dl_device" id="dl_local" onclick="selectDevice(\'local\');">local<'+'/a><br>');
    if (DEVICE == 'local') $('#dl_local').addClass('dl_selected');
    var peers = document.getElementById('pc_peerlist').peers;
    for (var id in peers) {
        var peer = peers[id];
        checkDevice(peer, id);
    }
}

function call(cmd, params, cb){
    json(PREFIX+cmd, params, cb);
}

var USER = "Anonymous";
var USERNAME = "anonymous";
var TOPIC = 'maintopic';
var DATA = null;
var PREFIX = '';
var DEVICE = 'local';

$(document).on('pagecreate', function(){
    json('../securitybot/currentuser', null, function(result){
        USERNAME = result.username;
        if (USERNAME == 'anonymous') window.location = 'login.html';
        USER = result.displayname;
        buildConnectionBar('peerlist', buildDevices);
        buildTopics();
    });
});

</script>
        
</body>
</html>