corrade-nucleus-nucleons – Rev 20

Subversion Repositories:
Rev:
<!DOCTYPE html>

<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="Corrade Nucleon">
    <meta name="author" content="Wizardry and Steamworks">
    <link rel="icon" href="favicon.ico">

    <title>Corrade Nucleus - Pack Rat Inventory Manager</title>

    <!-- Bootstrap core CSS -->
    <link href="/node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" type="text/css">
    <!-- Corrade Nucleus Fonts -->
    <link href="/css/nucleus/fonts.css" rel="stylesheet" type="text/css">
    <!-- Customized bootstrap style. -->
    <link href="/css/nucleus/nucleus.css" rel="stylesheet" type="text/css">

    <!-- jsTree style -->
    <link href="/pack-rat/node_modules/jstree/dist/themes/default/style.min.css" rel="stylesheet" type="text/css">
    <!-- Bootstrap table -->
    <link href="/pack-rat/node_modules/bootstrap-table/dist/bootstrap-table.min.css" rel="stylesheet" type="text/css">
</script>
</head>

<body>
    <!-- Bootstrap Modal -->
    <div id="item-info-modal" class="modal fade bs-example-modal-lg" role="dialog">
        <div class="modal-dialog modal-lg">
            <!-- Modal content-->

            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal">&times;</button>

                    <h1 id="title" class="modal-title"></h1>
                </div>

                <div id="content" class="modal-body">
                    <table id="info" data-height="460">
                        <thead>
                            <tr>
                                <th data-field="AssetUUID">Asset UUID</th>
                                <th data-field="CreationDate">Creation Date</th>
                                <th data-field="Description">Description</th>
                                <th data-field="Permissions">Permissions</th>
                                <th data-field="UUID">Inventory UUID</th>
                            </tr>
                        </thead>
                    </table>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                </div>
            </div>
        </div>
    </div>
    
    <!-- Give Inventory Item Destination Dialog -->
    <div id="avatar-select-modal" class="modal fade bs-example-modal-lg" role="dialog">
        <div class="modal-dialog modal-lg">
            <!-- Modal content-->

            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal">&times;</button>

                    <h1 id="title" class="modal-title">Avatar Selection</h1>
                </div>

                <form id="avatar-select-form" class="form-inline" data-toggle="validator" onSubmit="event.preventDefault();">
                    <div id="content" class="modal-body">
                        <p>Please enter the avatar firstname and lastname to send the script to.</p>
                        <div class="form-group has-feedback">
                            <label for="avatar-firstname">First Name</label>
                            <input id="avatar-firstname" type="text" class="form-control" aria-describedby="basic-addon1" required>
                            <label for="avatar-lastname">Last Name</label>
                            <input id="avatar-lastname" type="text" class="form-control" aria-describedby="basic-addon1" required>
                        </div>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                        <button id="send-script" type="submit" class="btn btn-primary">Confirm</button>
                    </div>
                </form>
            </div>
        </div>
    </div>
    
    <!-- Texture Download Dialog -->
    <div id="texture-download-modal" class="modal fade bs-example-modal-lg" role="dialog">
        <div class="modal-dialog modal-lg">
            <!-- Modal content-->

            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal">&times;</button>

                    <h1 id="title" class="modal-title">Avatar Selection</h1>
                </div>
                
                <div id="content" class="modal-body">
                    <img src="" align="middle" id="texture">
                </div>
                
                <div class="modal-footer">
                    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                </div>
            </div>
        </div>
    </div>

    <div class="container">
        <div class="jumbotron">
        <h1>Corrade Pack Rat</h1>
        <p class="lead">Pack Rat is an inventory manager for Corrade Nucleus that allows you to sort your inventory and perform other management operations.</p>
        <img src="/pack-rat/img/pack-rat.png"></div>

        <!-- Will hold the inventory tree (completed dynamically). -->
        <div id="tree">
        </div>

        <footer class="footer">
            <p>&copy; 2017 Wizardry and Steamworks</p>
        </footer>
    </div>
    <!-- jQuery -->
    <script src="/node_modules/jquery/dist/jquery.min.js" type="text/javascript"></script>
    <!-- Wizardry and Steamworks JavaScript Includes -->
    <script src="/node_modules/was/dist/was.min.js" type="text/javascript"></script>
    <!-- Bootstrap Javascript -->
    <script src="/node_modules/bootstrap/dist/js/bootstrap.min.js" type="text/javascript"></script>
    <script src="/pack-rat/node_modules/bootstrap-table/dist/bootstrap-table.min.js" type="text/javascript"></script>
    <!-- Bootstrap Form Validator -->
    <script src="/node_modules/bootstrap-validator/dist/validator.min.js" type="text/javascript"></script>
    <!-- CryptoJS -->
    <script src="/node_modules/cryptojslib/lib/Crypto.js" type="text/javascript"></script>
    <script src="/node_modules/cryptojslib/lib/MD5.js" type="text/javascript"></script>
    <!-- Moment JS -->
    <script src="/pack-rat/node_modules/moment/min/moment.min.js" type="text/javascript"></script>
        <!-- JsTree -->
    <script src="/pack-rat/node_modules/jstree/dist/jstree.min.js" type="text/javascript"></script>
        <!-- JSON to Table -->
    <script src="/pack-rat/node_modules/json-to-table/json-to-table.js" type="text/javascript"></script>
    <!-- Main script -->
    <script type="text/javascript">
        $(function() {
            function customMenu(node) {
                // The default set of menu items for all types
                var items = {
                    // Grab information about the item.
                    infoItem: {
                        label: "Get Info",
                        action: function(obj) {
                            $.ajax({
                                //async: false,
                                type: 'POST',
                                url: '/',
                                dataType: 'json',
                                data: {
                                    command: 'getinventorydata',
                                    item: node.id,
                                    data: wasArrayToCSV([
                                        'AssetUUID',
                                        'CreationDate',
                                        'Description',
                                        'Permissions',
                                        'UUID' // part of InventoryBase
                                    ])
                                }
                            }).done(function(response) {
                                if(response.success !== 'True') {
                                    alert('Error moving item: ' + response.error);
                                    return;
                                }
                                $('#info').bootstrapTable({
                                    data: [ wasKeyValueObjectify(wasCSVToArray(response.data)) ]
                                });
                                $('#item-info-modal').modal('show');
                            });
                        }
                    }
                };

                // Give inventory items menu for anything but folders.
                // They could be supported too but would require first
                // counting the number of items inside the folder and
                // only accepting to send if the number is below max.
                if (node.data.type != "folder") {
                    $.extend(items, {
                        giveItem: {
                            label: "Give",
                            action: function(obj) {
                                $('#avatar-select-modal')
                                    .modal('show')
                                    .on('click', '#send-script', function(e) {
                                        $('#avatar-select-modal').modal('hide');
                                        $.ajax({
                                            type: 'POST',
                                            url: '/',
                                            data: {
                                                command: 'give',
                                                entity: 'avatar',
                                                item: node.id,
                                                firstname: $('#avatar-firstname').val(),
                                                lastname: $('#avatar-lastname').val()
                                            },
                                            dataType: 'json'
                                        }).done(function(response) {
                                            if(response.success !== 'True') {
                                                alert('Error sending item: ' + response.error);
                                                return;
                                            }
                                        });
                                    });
                            }
                        }
                    });
                }

                // The "download" menu item for textures.
                if (node.data.type == "texture" || node.data.type == "snapshot") {
                    $.extend(items, {
                        downloadItem: {
                            label: "Download",
                            "action": function(obj) {
                                $('#texture').attr('src', '/pack-rat/img/loader.gif');
                                $('#texture-download-modal').modal('show');
                                $.ajax({
                                    type: 'POST',
                                    url: '/',
                                    data: {
                                        command: 'download',
                                        item: node.id,
                                        format: 'Png',
                                        type: 'Texture'
                                    },
                                    dataType: 'json'
                                }).done(function(response) {
                                    $('#texture').attr('src', "data:image/png;base64," + response.data);
                                });
                            }
                        }
                    });
                }

                // The "download" menu item for notecards.
                if (node.data.type == "notecard") {
                    $.extend(items, {
                        downloadItem: {
                            label: "Download",
                            "action": function(obj) {
                                $('#texture').attr('src', 'images/loader.gif');
                                $('#popup').dialog({
                                    width: 800,
                                    height: 600,
                                    modal: true,
                                    resizable: false,
                                    dialogClass: 'no-close texture-dialog'
                                }).on('dialogclose', function(event) {
                                    $('#content').html('');
                                });
                                $.ajax({
                                    type: 'POST',
                                    url: "downloadNotecard.php?t=" + Math.random(),
                                    data: {
                                        uuid: node.id.split(/[\/]+/).pop()
                                    }
                                }).done(function(data) {
                                    $.base64.utf8decode = true;
                                    $('#content').html('<pre>' + $.base64.atob(data) + '</pre>');
                                });
                            }
                        }
                    });
                }

                // The "download" menu item for sounds.
                if (node.data.type == "sound") {
                    $.extend(items, {
                        downloadItem: {
                            label: "Download",
                            "action": function(obj) {
                                $('#texture').attr('src', 'images/loader.gif');
                                $('#popup').dialog({
                                    width: 800,
                                    height: 600,
                                    modal: true,
                                    resizable: false,
                                    dialogClass: 'no-close texture-dialog'
                                }).on('dialogclose', function(event) {
                                    $('#content').html('');
                                });
                                $.ajax({
                                    type: 'POST',
                                    url: "downloadSound.php?t=" + Math.random(),
                                    data: {
                                        uuid: node.id.split(/[\/]+/).pop()
                                    }
                                }).done(function(data) {
                                    $('#content').html('<audio controls="controls"><source id="source" src="" type="audio/mp3"></source></audio>');
                                    $('#source').attr('src', "data:audio/mp3;base64," + data);
                                });
                            }
                        }
                    });
                }

                return items;
            }

            $("#tree").jstree({
                // - sort will sort items by date
                // - state will store the open / closed state of the jstree
                'plugins': ["themes", "json_data", "ui", "contextmenu", "sort", "dnd", "state"],
                'contextmenu': {
                    "items": function(node) {
                        return customMenu(node);
                    }
                },
                'dnd': {
                    // Do not copy items.
                    'copy': false,
                    // Do not execute the check callback whilst dragging.
                    'check_while_dragging': true
                },
                'sort': function(a, b) {
                    return this.get_node(a).data.time < this.get_node(b).data.time ? 1 : -1;
                },
                'core': {
                    'check_callback': function(operation, node, parent, position, more) {
                        // Only allow move operations
                        if (operation !== 'move_node' ||
                            // Do not move system folders.
                            node.data.system !== false ||
                            // Do not allow moves above the root node.
                            parent.id === "#" ||
                            // Do not allow moving an item over another item.
                            (node.data.type !== 'folder' && parent.data.type !== 'folder'))
                            return false;
                        
                        var source = node.id;
                        var target = parent.id;
                        
                        // Normalize source and target.
                        if(source === '#')
                            source = '/';
                        
                        if(target === '#')
                            target = '/';
                        
                        if(source == '/' && target == '/')
                            return false;
                        
                        // Check if source path is sane.
                        if(source.split('/').some(
                            function(part) {
                                return /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/.test(part);
                            })) {
                            return false;
                        }
                        
                        // Check if target path is sane.
                        if(target.split('/').some(
                            function(part) {
                                return /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/.test(part);
                            })) {
                            return false;
                        }
                        
                        return true;
                    },
                    data: function(node, callback) {
                        if(node.id === '#') {
                            callback.call(this, [
                                { 
                                    "id" : "/My Inventory", 
                                    "parent" : "#", 
                                    "text" : "My Inventory", 
                                    "data" : { 
                                        "type" : "folder",
                                        'time' : Date.now(),
                                        'system' : true
                                    }, 
                                    "children" : true, 
                                    "opened" : false 
                                },
                                { 
                                    "id" : "/Library", 
                                    "parent" : "#", 
                                    "text" : "Library", 
                                    "data" : { 
                                        "type" : "folder",
                                        'time' : Date.now(),
                                        'system' : true
                                    }, 
                                    "children" : true, 
                                    "opened" : false 
                                }
                            ]);
                            return;
                        }
                        $.ajax({
                            //async: false,
                            type: 'POST',
                            url: '/',
                            dataType: 'json',
                            data: {
                                command: 'inventory',
                                action: 'ls',
                                path: node.id
                            }
                        }).done(function(response) {
                            var list = [];
                            $.each(wasCSVToArray(response.data)
                                .chunk(10),
                                function(i, e) {
                                    e = wasKeyValueObjectify(e);
                                    //alert(node.id + " to " + JSON.stringify(e, 4, null));
                                    list.push({
                                        'id' : node.id === '/' ? '/' + e['item'] : node.id + '/' + e['item'],
                                        'parent' : node.id,
                                        'data' : {
                                            'type' : e['type'],
                                            'time' : Date.parse(e['time']),
                                            // Check if this folder is a system folder.
                                            'system' : node.id === '/My Inventory' && (
                                                e['name'] === 'Trash' ||
                                                e['name'] === 'Notecards' ||
                                                e['name'] === 'Scripts' ||
                                                e['name'] === 'Lost And Found' ||
                                                e['name'] === 'Landmarks' ||
                                                e['name'] === 'Current Outfit' ||
                                                e['name'] === 'Calling Cards' ||
                                                e['name'] === 'Textures' ||
                                                e['name'] === 'Objects' ||
                                                e['name'] === 'My Outfits' ||
                                                e['name'] === 'Clothing' ||
                                                e['name'] === 'Body Parts' ||
                                                e['name'] === 'Photo Album' ||
                                                e['name'] === 'Favorites' ||
                                                e['name'] === 'Gestures' ||
                                                e['name'] === 'Animations'
                                            )
                                        },
                                        'text' : e['name'],
                                        'children' : e['type'] === 'folder',
                                        'icon' : '/pack-rat/img/icons/' + e['type'] + '.gif',
                                        'opened' : 'false'
                                });
                            });
                            callback.call(this, list);
                        });
                    }
                }
            }).bind('move_node.jstree', function(e, data) {
                $.ajax({
                        //async: false,
                        type: 'POST',
                        url: '/',
                        dataType: 'json',
                        data: {
                            command: 'inventory',
                            action: 'mv',
                            source: data.node.id,
                            target: data.parent
                        }
                }).done(function(response) {
                    if(response.success !== 'True') {
                        alert('Error moving item: ' + response.error);
                    }
                });
                // Once the node is moved, update the node ID to reflect the path change.
                var parentPath = data.parent != '/' ? data.parent : "";
                var item = data.node.id.split(/[\/]+/).pop();
                data.instance.set_id(data.node, parentPath + '/' + item);
            });
        });
    </script>
</body>
</html>