1. Brent Tubbs
  2. schmarchive2

Commits

bren...@gmail.com  committed 62c6922

adding lsl files. removing unused css

  • Participants
  • Parent commits 6576ba8
  • Branches default

Comments (0)

Files changed (13)

File 960.css

-body{min-width:960px}.container_12,.container_16{margin-left:auto;margin-right:auto;width:960px}.grid_1,.grid_2,.grid_3,.grid_4,.grid_5,.grid_6,.grid_7,.grid_8,.grid_9,.grid_10,.grid_11,.grid_12,.grid_13,.grid_14,.grid_15,.grid_16{display:inline;float:left;margin-left:10px;margin-right:10px}.push_1,.pull_1,.push_2,.pull_2,.push_3,.pull_3,.push_4,.pull_4,.push_5,.pull_5,.push_6,.pull_6,.push_7,.pull_7,.push_8,.pull_8,.push_9,.pull_9,.push_10,.pull_10,.push_11,.pull_11,.push_12,.pull_12,.push_13,.pull_13,.push_14,.pull_14,.push_15,.pull_15{position:relative}.container_12 .grid_3,.container_16 .grid_4{width:220px}.container_12 .grid_6,.container_16 .grid_8{width:460px}.container_12 .grid_9,.container_16 .grid_12{width:700px}.container_12 .grid_12,.container_16 .grid_16{width:940px}.alpha{margin-left:0}.omega{margin-right:0}.container_12 .grid_1{width:60px}.container_12 .grid_2{width:140px}.container_12 .grid_4{width:300px}.container_12 .grid_5{width:380px}.container_12 .grid_7{width:540px}.container_12 .grid_8{width:620px}.container_12 .grid_10{width:780px}.container_12 .grid_11{width:860px}.container_16 .grid_1{width:40px}.container_16 .grid_2{width:100px}.container_16 .grid_3{width:160px}.container_16 .grid_5{width:280px}.container_16 .grid_6{width:340px}.container_16 .grid_7{width:400px}.container_16 .grid_9{width:520px}.container_16 .grid_10{width:580px}.container_16 .grid_11{width:640px}.container_16 .grid_13{width:760px}.container_16 .grid_14{width:820px}.container_16 .grid_15{width:880px}.container_12 .prefix_3,.container_16 .prefix_4{padding-left:240px}.container_12 .prefix_6,.container_16 .prefix_8{padding-left:480px}.container_12 .prefix_9,.container_16 .prefix_12{padding-left:720px}.container_12 .prefix_1{padding-left:80px}.container_12 .prefix_2{padding-left:160px}.container_12 .prefix_4{padding-left:320px}.container_12 .prefix_5{padding-left:400px}.container_12 .prefix_7{padding-left:560px}.container_12 .prefix_8{padding-left:640px}.container_12 .prefix_10{padding-left:800px}.container_12 .prefix_11{padding-left:880px}.container_16 .prefix_1{padding-left:60px}.container_16 .prefix_2{padding-left:120px}.container_16 .prefix_3{padding-left:180px}.container_16 .prefix_5{padding-left:300px}.container_16 .prefix_6{padding-left:360px}.container_16 .prefix_7{padding-left:420px}.container_16 .prefix_9{padding-left:540px}.container_16 .prefix_10{padding-left:600px}.container_16 .prefix_11{padding-left:660px}.container_16 .prefix_13{padding-left:780px}.container_16 .prefix_14{padding-left:840px}.container_16 .prefix_15{padding-left:900px}.container_12 .suffix_3,.container_16 .suffix_4{padding-right:240px}.container_12 .suffix_6,.container_16 .suffix_8{padding-right:480px}.container_12 .suffix_9,.container_16 .suffix_12{padding-right:720px}.container_12 .suffix_1{padding-right:80px}.container_12 .suffix_2{padding-right:160px}.container_12 .suffix_4{padding-right:320px}.container_12 .suffix_5{padding-right:400px}.container_12 .suffix_7{padding-right:560px}.container_12 .suffix_8{padding-right:640px}.container_12 .suffix_10{padding-right:800px}.container_12 .suffix_11{padding-right:880px}.container_16 .suffix_1{padding-right:60px}.container_16 .suffix_2{padding-right:120px}.container_16 .suffix_3{padding-right:180px}.container_16 .suffix_5{padding-right:300px}.container_16 .suffix_6{padding-right:360px}.container_16 .suffix_7{padding-right:420px}.container_16 .suffix_9{padding-right:540px}.container_16 .suffix_10{padding-right:600px}.container_16 .suffix_11{padding-right:660px}.container_16 .suffix_13{padding-right:780px}.container_16 .suffix_14{padding-right:840px}.container_16 .suffix_15{padding-right:900px}.container_12 .push_3,.container_16 .push_4{left:240px}.container_12 .push_6,.container_16 .push_8{left:480px}.container_12 .push_9,.container_16 .push_12{left:720px}.container_12 .push_1{left:80px}.container_12 .push_2{left:160px}.container_12 .push_4{left:320px}.container_12 .push_5{left:400px}.container_12 .push_7{left:560px}.container_12 .push_8{left:640px}.container_12 .push_10{left:800px}.container_12 .push_11{left:880px}.container_16 .push_1{left:60px}.container_16 .push_2{left:120px}.container_16 .push_3{left:180px}.container_16 .push_5{left:300px}.container_16 .push_6{left:360px}.container_16 .push_7{left:420px}.container_16 .push_9{left:540px}.container_16 .push_10{left:600px}.container_16 .push_11{left:660px}.container_16 .push_13{left:780px}.container_16 .push_14{left:840px}.container_16 .push_15{left:900px}.container_12 .pull_3,.container_16 .pull_4{left:-240px}.container_12 .pull_6,.container_16 .pull_8{left:-480px}.container_12 .pull_9,.container_16 .pull_12{left:-720px}.container_12 .pull_1{left:-80px}.container_12 .pull_2{left:-160px}.container_12 .pull_4{left:-320px}.container_12 .pull_5{left:-400px}.container_12 .pull_7{left:-560px}.container_12 .pull_8{left:-640px}.container_12 .pull_10{left:-800px}.container_12 .pull_11{left:-880px}.container_16 .pull_1{left:-60px}.container_16 .pull_2{left:-120px}.container_16 .pull_3{left:-180px}.container_16 .pull_5{left:-300px}.container_16 .pull_6{left:-360px}.container_16 .pull_7{left:-420px}.container_16 .pull_9{left:-540px}.container_16 .pull_10{left:-600px}.container_16 .pull_11{left:-660px}.container_16 .pull_13{left:-780px}.container_16 .pull_14{left:-840px}.container_16 .pull_15{left:-900px}.clear{clear:both;display:block;overflow:hidden;visibility:hidden;width:0;height:0}.clearfix:after{clear:both;content:' ';display:block;font-size:0;line-height:0;visibility:hidden;width:0;height:0}* html .clearfix,*:first-child+html .clearfix{zoom:1}

File animations.html

-<html>
-<head>
-    <meta http-equiv="content-type" content="text/html; charset=utf-8">
-
-    <title>Animations</title>
-<!-- 
-Plan: 
-- Wrapper div with overflow set to clip.
-- jquery template for block to stick in the wrapper.
-- a button to click to stick a thing in the wrapper.
-- click it again and build another thing in the overflow area, then slide it in from the right, while the first one slides out to the left.
--->    
-<script type="text/javascript" charset="utf-8" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js"></script>
-<script src="http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js"></script>
-<script id="block_template" type="text/html">
-    <div class="slidey_block ${classes}">
-        This is a slidey block!
-    </div>
-</script>
-
-<script>
-$(document).ready(function() {
-
-    var getReady = function() {
-        $('.slidey_block.shown').click(function() {
-            //make a new unshown guy.
-            addNew();
-            //slide self out, and slide him in.
-            doSlidey();
-        });
-    }
-    
-    $('#add_item').click(function() {
-        var data = {classes: 'shown'};
-        $('#block_template').tmpl(data).appendTo('#wrapper');
-        getReady(); 
-    });
-
-    var doSlidey = function() {
-        $('.slidey_block.shown').addClass('dying');
-        $('.slidey_block.shown').animate({
-            left: '-305px'
-        }, function() {
-            $('.slidey_block.dying').remove();
-            $('.slidey_block.new').addClass('shown').removeClass('new');
-            getReady();
-        });
-        $('.slidey_block.new').animate({left: '5px'});
-    }
-
-    $('#slideytown').click(function() {
-        doSlidey();
-    });
-
-    var addNew = function() {
-        console.log('add offscreen');
-        var data = {classes: 'new'};
-        $('#block_template').tmpl(data).appendTo('#wrapper');
-    }
-
-    $('#add_offscreen').click(function() {
-        addNew();
-    });
-
-    $('#pushstate').click(function(){
-        history.pushState({}, 'blerg', '?wut');
-    });
-});
-</script>
-
-<style>
-    #wrapper {
-        position: relative;
-        width: 300px;
-        min-height: 300px;
-        border-radius: 5px;
-        background: #2e2e2e;
-        padding: 5px;
-        overflow: hidden;
-    }
-
-    .slidey_block {
-        position: absolute;
-        color: white;
-        background-color: green;
-        border-radius: 5px;
-        margin: 5px 0;
-        width: 300px;
-    }
-
-    .slidey_block.new {
-        left: 315px;
-    }
-</style>
-</head>
-<body>
-<div id="wrapper">
-    
-</div>
-<button id="add_item">Add Item</button>
-<button id="add_offscreen">Add Offscreen</button>
-<button id="slideytown">Slidey Town!</button>
-<button id="pushstate">?wut</button>
-</body>
-</html>

File dash.css

-body {
-  background-color: #2e2e2e;
-  font-family: 'Droid Sans', arial, serif;
-  font-size: 15px;
-}
-body a { color: #0ca2ff; }
-#header {
-  background-color: #151515;
-  color: white;
-  padding: 10px;
-}
-#header h1 { margin: 0px; }
-#header a {
-  font-style: italic;
-  font-size: 11px;
-}
-#header #silklink {
-  float: right;
-  position: relative;
-  bottom: -10px;
-}
-#header #silklink a {
-  font-style: italic;
-  font-size: 15px;
-}
-#header .pagetitle {
-  font-weight: bold;
-  font-size: 25px;
-}
-#sitelist { color: #eeeeee; }
-#sitelist td {
-  padding: 10px;
-  border: 10px solid #2e2e2e;
-  background-color: #444444;
-  vertical-align: middle;
-}
-#sitelist .sitestatus {
-  text-align: center;
-  border-right: 0px none #2e2e2e;
-  font-weight: bold;
-}
-#sitelist .running { background-color: green; }
-#sitelist .stopped { background-color: #bbb31b; }
-#sitelist .fatal { background-color: red; }
-#sitelist .sitename {
-  text-align: right;
-  background-color: #2e2e2e;
-  font-size: 25px;
-}
-#sitelist .sitedesc {
-  font-size: 11px;
-  border-left: 0px none #2e2e2e;
-}
-#sitelist .sitelink { font-size: 10px; }
-#sitelist .sitelogs { font-size: 11px; }
-#sitelist .sitelogs table { margin-bottom: 0px; }
-#sitelist .sitelogs table td {
-  border: 0px none #2e2e2e;
-  padding: 2px;
-}
-#sitelist .siteactions input {
-  font-size: 9px;
-  display: inline;
-}
-#sitelist form { display: inline; }
-#loginform td {
-  padding: 10px;
-  vertical-align: middle;
-}
-#loginform td:first-child { text-align: right; }
-#loginform label {
-  color: white;
-  background-color: #2e2e2e;
-  font-size: 25px;
-}
-#loginform input { font-size: 25px; }
-#loginform input[type="text"] { border: 0px white none; }
-#loginform input[type="password"] { border: 0px white none; }
-#loginform input[type="submit"] {
-  color: #2e2e2e;
-  text-shadow: white 1px 1px 0px;
-  font-family: 'Droid Sans', arial, serif;
-}
-.loginlink {
-  font-size: 25px;
-  color: white;
-  margin: 10px 0 0 10px;
-}
-.form_error {
-  color: orange;
-  font-size: 20px;
-  margin: 10px 0 0 10px;
-}

File dash.less

-body {
-    background-color: #2e2e2e;
-    font-family: 'Droid Sans', arial, serif;
-    font-size: 15px;
-    a{
-        color: #0CA2FF;
-    }
-}
-
-#header {
-    background-color: #151515;
-    color: white;
-    padding: 10px;
-    h1 {
-        margin: 0px;
-    }
-    a {
-        font-style: italic;
-        font-size: 11px;
-    }
-    #silklink {
-        float: right;
-        position: relative;
-        bottom: -10px;
-        a {
-            font-style: italic;
-            font-size: 15px;
-        }
-    }
-    .pagetitle {
-        font-weight: bold;
-        font-size: 25px;
-    }
-
-}
-
-#sitelist {
-    color: #eee;
-    td {
-        padding: 10px;
-        border: 10px solid #2e2e2e;
-        background-color: #444;
-        vertical-align: middle;
-    }
-    .sitestatus {
-        text-align: center;
-        border-right: 0px none #2e2e2e;
-        font-weight: bold;
-    }
-    .running {
-        background-color: green;
-    }
-    .stopped {
-        background-color: #BBB31B;
-    }
-    .fatal {
-        background-color: red;
-    }
-    .sitename {
-        text-align: right;
-        background-color: #2e2e2e;
-        font-size: 25px;
-    }
-    .sitedesc {
-        font-size: 11px;
-        border-left: 0px none #2e2e2e;
-    }
-    .sitelink {
-        font-size: 10px;
-    }
-    .sitelogs {
-        font-size: 11px;
-        table {
-            margin-bottom: 0px;
-            td {
-                border: 0px none #2e2e2e;
-                padding: 2px;
-            }
-        }
-    }
-    .siteactions {
-        input {
-            font-size: 9px;
-            display: inline;
-        }
-    }
-    form {
-        display: inline;
-    }
-}
-
-#loginform {
-    td {
-        padding: 10px;
-        /*border: 10px solid #2e2e2e;*/
-        vertical-align: middle;
-    }
-    td:first-child {
-        text-align: right;
-    }
-    label {
-        color: white;
-        background-color: #2e2e2e;
-        font-size: 25px;
-    }
-    input {
-        font-size: 25px;
-    }
-    input[type="text"], input[type="password"] {
-        border: 0px white none;
-    }
-    input[type="submit"] {
-        color: #2e2e2e;
-        text-shadow: white 1px 1px 0px;
-        font-family: 'Droid Sans', arial, serif;
-    }
-}
-
-.loginlink {
-    font-size: 25px;
-    color: white;
-    margin: 10px 0 0 10px;
-}
-
-.form_error {
-    color: orange;
-    font-size: 20px;
-    margin: 10px 0 0 10px;
-}

File index.html

View file
   </section> <!-- #options --> 
 </div>
 <div id="frame">
-  <div class="inv_item about tmphide">
-    <div class="inv_item_name bodypart about">Me</div>
-    <p>
-      Schmarchive is the creation of Schmobag Hogfather (aka Brent Tubbs in real life).
-    </p>
-  </div>
-  <div class="inv_item about tmphide">
-    <div class="inv_item_name script about">Tech</div>
-    <p>
-      It's built entirely with LSL, Javascript, HTML and CSS.  There is no database or server side code.
-    </p>
-    <p>
-      <a href="http://en.wikipedia.org/wiki/JSONP">JSONP</a> is awesome.
-    </p>
-  </div>
   <div class="inv_item about double tmphide">
     <div class="inv_item_name gesture about">Thanks</div>
     <p>
       Schmarchive is <a href="http://bits.btubbs.com/schmarchive2/src">open source</a> and licensed under the GPL.
     </p>
     <p>
-      But if you want to set up a copy of Schmarchive on your own server, for commercial use, you'll need to buy a <a href="http://isotope.metafizzy.co/docs/license.html">license</a>
+      But if you want to set up a copy of Schmarchive on your own server, for commercial use, you'll need to <a href="http://isotope.metafizzy.co/docs/license.html">buy a license</a>
      for Isotope. 
     </p>
   </div>
+  <div class="inv_item about double tmphide">
+    <div class="inv_item_name texture about">Thumbnails</div>
+    <p>
+      Textures will automatically use search.secondlife.com thumbnails, except for textures with alpha in them (these aren't thumbnailed
+      by search.secondlife.com).
+    </p><p>
+      Or you can set your own thumbnail for <em>any</em> item by putting a texture inside the Schmarchive
+      and naming it like ".thumb:ITEM_NAME" (where you replace ITEM_NAME with the actual name of the item).  See the 
+      thumbnail for the README file as an example.
+    </p>
+  </div>
+  <div class="inv_item about double tmphide">
+    <div class="inv_item_name clothing about">Styling</div>
+    <p>
+      Schmarchive also lets you put your own custom CSS on the page.  There's a .css notecard inside the 
+      prim that will be served as a CSS stylesheet.
+    </p>
+  </div>
+  <div class="inv_item about double tmphide">
+    <div class="inv_item_name script about">Tech</div>
+    <p>
+      It's built entirely with LSL, Javascript, HTML and CSS.  There is no database or server side code.
+    </p>
+    <p>
+      <a href="http://en.wikipedia.org/wiki/JSONP">JSONP</a> is awesome.
+    </p>
+    <p>
+      Schmarchive is the creation of Schmobag Hogfather (aka Brent Tubbs in real life).
+    </p>
+  </div>
 </div>
 </body>
 </html>

File lsl/schmottp.lsl

View file
+string myurl;
+string base = "http://schmarchive.btubbs.com/";
+
+integer SAY_URL = -85431;
+integer HTTP_RESPONSE = -85432;
+
+integer INV_REQUEST = -85433;
+integer INFO_REQUEST = -85434;
+
+//You need to put a random string here.  You can make one in Linux with this:
+// head /dev/urandom | uuencode -m - | sed -n 2p | cut -c1-${1:-32};
+// If you're not in linux, try http://goo.gl/KW36t
+// string SECRET = "";
+string SECRET = "ek4dBCGEVTqiYdHEIryMr7Va+Y98eSjC";
+
+integer mychannel;
+
+list routes;
+
+debug(string text) {
+    //llOwnerSay(llGetScriptName() + ": " + text);
+}
+
+BuildRoutes() {
+    integer script_count = llGetInventoryNumber(INVENTORY_SCRIPT);
+    if (script_count <= 1) {
+        llOwnerSay("No plugins found");
+        return;
+    }
+    //clear the route list first
+    routes = [];
+    
+    //now build the new one
+    integer n;
+    for (n = 0; n < script_count; n++) {
+        string name = llGetInventoryName(INVENTORY_SCRIPT, n);
+        list parts = llParseStringKeepNulls(name, [":"], []);
+        //valid plugins have 3 parts, the first named .schmottp, and the last a non-0 integer
+        if (llGetListLength(parts) == 3 && 
+            llList2String(parts, 0) == ".schmottp" && 
+            (integer)llList2String(parts, 2) != 0) {
+            
+            string routename = llList2String(parts, 1);
+            integer channel = (integer)llList2String(parts, 2);
+            //only add route if name and channel not already present in list
+            if (llListFindList(routes, [routename]) != -1) {
+                llOwnerSay("Path " + routename + " already present in list. Skipping.");
+            } else if (llListFindList(routes, [channel]) != -1) {
+                llOwnerSay("Channel " + (string)channel + " already present in list. Skipping.");
+            } else {
+                routes += [routename, channel];
+            }
+        }
+    }
+    debug(llDumpList2String(routes, "\n"));
+}
+
+string List2JS(list things) {
+    string inner = llDumpList2String(things, ",");
+    return "[" + inner + "]";
+}
+
+string GetCallback(string qstring) {
+    list qparams = llParseString2List(qstring, ["&", "="], []);
+    return GetParam(qparams, "callback");
+}
+
+string GetParam(list things, string tok) {
+    //return "" if not found
+    integer index = llListFindList(things, [tok]);
+    if (index == -1) {
+        return "";
+    } else {
+        return llList2String(things, index + 1);
+    }
+}
+
+string WrapCallback(string resp, string callback) {
+    return callback + "(" + resp + ")";
+}
+
+string BuildURL(string toucher) {
+    string url = base + "?url=" + llEscapeURL(myurl);
+    url += "&av=" + toucher;
+    url += "&tok=" + llMD5String(toucher + SECRET, 0);
+    return url;
+}
+
+integer CheckToken(string av, string tok) {
+
+    return llMD5String(av + SECRET, 0) == tok;
+}
+
+default
+{
+    state_entry() {
+        if (SECRET == "") {
+            llOwnerSay("ERROR: Before you can use me, you need to open up the " + llGetScriptName() + " script and put a secret random string in the SECRET variable.");
+        } else {
+            llRequestURL();
+            BuildRoutes();
+            //set my channel from my script name
+            string myname = llGetScriptName();
+            list parts = llParseStringKeepNulls(myname, [":"], []);
+            mychannel = (integer)llList2String(parts, -1);                    
+        }
+    }
+    
+    on_rez( integer param ) {
+        llRequestURL();
+    }
+ 
+    changed( integer changes ) {
+        if( changes & (CHANGED_REGION|CHANGED_TELEPORT|CHANGED_REGION_START)) {
+            llRequestURL();            
+        }
+        
+        if (changes & CHANGED_INVENTORY) {
+            BuildRoutes();
+        }
+    }    
+    
+    touch_start(integer num) {
+        key id = llDetectedKey(0);
+        llInstantMessage(llDetectedKey(0), BuildURL(id));
+    }
+
+    http_request(key id, string method, string body) {
+        if (method == "URL_REQUEST_GRANTED") {
+            myurl = body;
+        } else {
+            string qstring = llGetHTTPHeader(id, "x-query-string");
+            list qparams = llParseString2List(qstring, ["&", "="], []);
+            string av = GetParam(qparams, "av");
+            string tok = GetParam(qparams, "tok");
+            
+            // Check the validity of the token passed in.
+            if (CheckToken(av, tok)) {
+                string path = llGetHTTPHeader(id, "x-path-info");
+                list pathparts = llParseString2List(path, ["/"], []);
+                //see if this top level path corresponds to a channel (integer) in ROUTES.
+                //if so, send link message on that channel
+                string root = llList2String(pathparts, 0);
+                integer index = llListFindList(routes, [root]);
+                
+                if (index != -1) {
+                    //we have a valid route for this request.  So let's send it out
+                    //stick the query string in the str field
+                    llMessageLinked(LINK_SET, llList2Integer(routes, index + 1), qstring, id);
+                }                
+            } else {
+                llHTTPResponse(id, 403, "Bad Key");
+            }
+        }
+    }
+    
+    link_message(integer sender, integer num, string str, key id) {       
+        if (num == HTTP_RESPONSE) {
+            llHTTPResponse(id, 200, str);
+        } else if (num == mychannel) {
+            //build a list of urls from routes
+            integer stop = llGetListLength(routes);
+            integer n;
+            list paths;
+            for (n = 0; n < stop; n+= 2) {
+                paths += ["\"" + myurl + "/" + llList2String(routes, n) + "\""];
+            }
+            string json = List2JS(paths);
+            string callback = GetCallback(str);
+            llMessageLinked(LINK_SET, HTTP_RESPONSE, WrapCallback(json, callback), id);    
+        }
+    }
+}
+

File lsl/schmottp_css.lsl

View file
+integer HTTP_RESPONSE = -85432;
+
+integer mychannel;
+
+string CSS_FILE = ".css";
+key CSS_FILE_KEY;
+string css;
+list lines;
+integer linecount;
+key linecountid;
+
+ReadCSS() {
+    // read the css file, if present
+    // experimenting with a new parallel line-reading method.
+    if (llGetInventoryType(CSS_FILE) == INVENTORY_NOTECARD) {
+        lines = [];
+        linecount = 0;
+        linecountid = llGetNumberOfNotecardLines(CSS_FILE);
+        CSS_FILE_KEY = llGetInventoryKey(CSS_FILE);
+    }    
+}
+
+default
+{
+    state_entry()
+    {
+        //set my channel from my script name
+        string myname = llGetScriptName();
+        list parts = llParseString2List(myname, [":"], []);
+        mychannel = (integer)llList2String(parts, -1);      
+        
+        ReadCSS();
+    }
+
+    link_message(integer sender, integer num, string str, key id) {
+        if (num == mychannel) {
+            llMessageLinked(LINK_SET, HTTP_RESPONSE, css, id);            
+        }
+    }
+    
+    dataserver(key id, string data) {
+        integer index = llListFindList(lines, [id]);
+        if (id == linecountid) {
+            // we got the number of lines.  Now request them all at once.
+            lines = [];
+            linecount = (integer)data;
+            integer n = 0;
+            for (n = 0; n < linecount; n++) {
+                lines += [llGetNotecardLine(CSS_FILE, n)];
+            }
+        } else if (index != -1) {
+            linecount--;
+            lines = llListReplaceList(lines, [data], index, index);
+            
+            if (linecount == 0) {
+                css = llDumpList2String(lines, "\n");
+                lines = [];
+            }
+        }
+    }
+    
+    changed(integer change) {
+        if (change & CHANGED_INVENTORY) {
+            // re-read the css file if it has changed.
+            if (llGetInventoryKey(CSS_FILE) != CSS_FILE_KEY) {
+                ReadCSS();
+            }
+        }
+    }
+}
+

File lsl/schmottp_give.lsl

View file
+integer HTTP_RESPONSE = -85432;
+
+integer mychannel;
+
+string Strided2JSON(list strided)
+{//takes a 2-strided list and returns a JSON-formatted string representing the list as an object
+    list outlist;
+    integer n;
+    integer stop = llGetListLength(strided);
+    for (n = 0; n < stop; n += 2)
+    {
+        string token = llList2String(strided, n);
+        string value = llList2String(strided, n + 1);
+        integer type = llGetListEntryType(strided, n + 1);
+        if (type != TYPE_INTEGER && type != TYPE_FLOAT)
+        {//JSON needs quotes around everything but integers and floats
+            value = "\"" + value + "\"";
+        }
+        token = "\"" + token + "\"";
+        
+        outlist += [token + ": " + value];
+    }
+    return "{" + llDumpList2String(outlist, ", ") + "}";
+}
+
+string WrapCallback(string resp, string callback) {
+    return callback + "(" + resp + ")";
+}
+
+string GetParam(list things, string tok) {
+    //return "-1" if not found
+    integer index = llListFindList(things, [tok]);
+    if (index == -1) {
+        return "";
+    } else {
+        return llList2String(things, index + 1);
+    }
+}
+
+debug(string text) {
+    //llOwnerSay(llGetScriptName() + ": " + text);
+}
+
+default
+{
+    state_entry()
+    {
+        //set my channel from my script name
+        string myname = llGetScriptName();
+        list parts = llParseString2List(myname, [":"], []);
+        mychannel = (integer)llList2String(parts, -1);
+    }
+
+    link_message(integer sender, integer num, string str, key id) {
+        if (num == mychannel) {
+            //get the userkey and item name from the qstring
+            list qparams = llParseString2List(str, ["&", "="], []);            
+            key av = (key)GetParam(qparams, "av");
+            string item = llUnescapeURL(GetParam(qparams, "item"));
+            list info;            
+            if (av != "" && item != "" && llGetInventoryType(item) != INVENTORY_NONE) {
+                llGiveInventory(av, item);
+                info = ["result", "success"];                
+            } else {
+                info = ["result", "failed"];
+            }
+            string json = Strided2JSON(info);
+            string callback = GetParam(qparams, "callback");
+            llMessageLinked(LINK_SET, HTTP_RESPONSE, WrapCallback(json, callback), id);
+        }
+    }
+}
+

File lsl/schmottp_info.lsl

View file
+integer HTTP_RESPONSE = -85432;
+
+integer mychannel;
+
+//strided list of key/value pairs for returning on INFO_REQUEST
+list info;
+
+string version = "2.3";
+
+string Strided2JSON(list strided)
+{//takes a 2-strided list and returns a JSON-formatted string representing the list as an object
+    list outlist;
+    integer n;
+    integer stop = llGetListLength(strided);
+    for (n = 0; n < stop; n += 2)
+    {
+        string token = llList2String(strided, n);
+        string value = llList2String(strided, n + 1);
+        integer type = llGetListEntryType(strided, n + 1);
+        if (type != TYPE_INTEGER && type != TYPE_FLOAT)
+        {//JSON needs quotes around everything but integers and floats
+            value = "\"" + value + "\"";
+        }
+        token = "\"" + token + "\"";
+        
+        outlist += [token + ": " + value];
+    }
+    return "{" + llDumpList2String(outlist, ", ") + "}";
+}
+
+string GetCallback(string qstring) {
+    list qparams = llParseString2List(qstring, ["&", "="], []);
+    return GetParam(qparams, "callback");
+}
+
+string WrapCallback(string resp, string callback) {
+    return callback + "(" + resp + ")";
+}
+
+string GetParam(list things, string tok) {
+    //return "-1" if not found
+    integer index = llListFindList(things, [tok]);
+    if (index == -1) {
+        return "-1";
+    } else {
+        return llList2String(things, index + 1);
+    }
+}
+
+list GetQuickInfo(string qstring) {
+    //return a list of information about this prim and request.
+    //only include info from functions that can be called synchronously.
+    list things = [
+        "objkey", llGetKey(),
+        "objname", llGetObjectName(),
+        "objdesc", llGetObjectDesc(),
+        "pos", llGetPos(),
+        "regioncorner", llGetRegionCorner(),
+        "regionname", llGetRegionName(),
+        "ownerkey", llGetOwner(),
+        "schmarchive_version", version
+    ];
+    
+    //add userkey if present in querystring
+    list qparams = llParseString2List(qstring, ["&", "="], []);
+    string userkey = GetParam(qparams, "userkey");
+    if (userkey != "-1") {
+        things += ["userkey", userkey];
+        string username = llGetUsername((key)userkey);
+        if (username != "") {
+            things += ["username", username];
+            things += ["displayname", llGetDisplayName(userkey)];
+        }
+    }
+    
+    return things;
+}
+
+//for fetching owner name reliably.
+key nameid;
+
+default
+{
+    state_entry()
+    {
+        //set my channel from my script name
+        string myname = llGetScriptName();
+        list parts = llParseString2List(myname, [":"], []);
+        mychannel = (integer)llList2String(parts, -1);
+        nameid = llRequestAgentData(llGetOwner(), DATA_NAME);
+    }
+
+    link_message(integer sender, integer num, string str, key id) {
+        if (num == mychannel) {
+            list all_info = info + GetQuickInfo(str);
+            string json = Strided2JSON(all_info);
+            string callback = GetCallback(str);
+            llMessageLinked(LINK_SET, HTTP_RESPONSE, WrapCallback(json, callback), id);
+        }
+    }
+    
+    dataserver(key id, string data) {
+        if (id == nameid) {
+            //update info list with name.  assume that it's not already in there.
+            info += ["ownername", data];
+        }
+    }
+}
+

File lsl/schmottp_inv.lsl

View file
+integer HTTP_RESPONSE = -85432;
+
+integer mychannel;
+
+list inv_types = [
+    "0", "texture",
+    "1", "sound",
+    "3", "landmark",
+    "5", "clothing",
+    "6", "object",
+    "7", "notecard",
+    "10", "script",
+    "13", "bodypart",
+    "20", "animation",
+    "21", "gesture"
+];
+
+integer LIMIT = 30;
+
+string CACHE;
+integer CACHE_PAGE = -1;
+
+string InventoryString(integer type, integer page) {
+    list out;
+    integer n;
+    integer stop = llGetInventoryNumber(type);
+    
+    if (page < 0) {
+        page = 0;
+    }
+    
+    //now calculate offset based on page
+    integer offset = page * LIMIT;
+    
+    integer more = FALSE;
+    // if offset + limit < stop, then stop sooner
+    if (offset + LIMIT < stop) {
+        stop = offset + LIMIT;
+        more = TRUE;
+    }
+    
+    for (n = offset; n < stop; n++) {
+        string name = llGetInventoryName(type, n);
+        out += [Item2JSON(name)];
+    }
+    
+    //last item is info about whether there are more things to request
+    out += Strided2JSON([
+        "page", page,
+        "more", more,
+        "type", "info"
+    ]);
+    
+    return List2JS(out);
+}
+
+string Item2JSON(string name) {
+    //return a JSON string with info about the item.
+    integer type = llGetInventoryType(name);
+    list info = [
+        "name", name, 
+        "type", GetParam(inv_types, (string)type),
+        "key", llGetInventoryKey(name),
+        "creatorkey", llGetInventoryCreator(name),
+        "owner_perms_mask", llGetInventoryPermMask(name, MASK_OWNER),
+        "next_perms_mask", llGetInventoryPermMask(name, MASK_NEXT)        
+    ];
+    
+    //add thumbnail if item is a texture, or if there's a .thumb image in the prim for it.
+    //if there's both, then .thumb wins (allows creating thumbnails for textures that aren't
+    //in sl search, like those with alpha in them.
+    string thumbname = ".thumb:" + name;
+    if (llGetInventoryType(thumbname) == INVENTORY_TEXTURE) {
+        info += ["thumb", llGetInventoryKey(thumbname)];
+    } else if (type == INVENTORY_TEXTURE) {
+        info += ["thumb", llGetInventoryKey(name)];
+    }
+
+    return Strided2JSON(info);   
+}
+
+string List2JS(list things) {
+    string inner = llDumpList2String(things, ",");
+    return "[" + inner + "]";
+}
+
+string Strided2JSON(list strided)
+{//takes a 2-strided list and returns a JSON-formatted string representing the list as an object
+    list outlist;
+    integer n;
+    integer stop = llGetListLength(strided);
+    for (n = 0; n < stop; n += 2)
+    {
+        string token = llList2String(strided, n);
+        string value = llList2String(strided, n + 1);
+        integer type = llGetListEntryType(strided, n + 1);
+        if (type != TYPE_INTEGER && type != TYPE_FLOAT)
+        {//JSON needs quotes around everything but integers and floats
+            value = "\"" + value + "\"";
+        }
+        token = "\"" + token + "\"";
+        
+        outlist += [token + ": " + value];
+    }
+    return "{" + llDumpList2String(outlist, ", ") + "}";
+}
+
+string GetParam(list things, string tok) {
+    //return "-1" if not found
+    integer index = llListFindList(things, [tok]);
+    if (index == -1) {
+        return "-1";
+    } else {
+        return llList2String(things, index + 1);
+    }
+}
+
+string WrapCallback(string resp, string callback) {
+    return callback + "(" + resp + ")";
+}
+
+debug(string text) {
+//    llOwnerSay(llGetScriptName() + ": " + text);
+}
+
+default {
+    state_entry()
+    {
+        //set my channel from my script name
+        string myname = llGetScriptName();
+        list parts = llParseString2List(myname, [":"], []);
+        mychannel = (integer)llList2String(parts, -1);
+        CACHE = InventoryString(INVENTORY_ALL, 0);
+        CACHE_PAGE = 0;
+    }    
+    
+    link_message(integer sender, integer num, string qstring, key id) {
+        if (num == mychannel) {
+            list qparams = llParseString2List(qstring, ["&", "="], []);
+            string callback = GetParam(qparams, "callback");
+            integer page = (integer)GetParam(qparams, "p");
+            if (page < 0) {
+                page = 0;
+            }
+            
+            if (page != CACHE_PAGE) {
+                CACHE = InventoryString(INVENTORY_ALL, page);
+                CACHE_PAGE = page;                
+            }
+
+            llMessageLinked(LINK_SET, HTTP_RESPONSE, WrapCallback(CACHE, callback), id);
+            
+            // keep page 0 around when not actively loading
+            if (CACHE_PAGE != 0) {
+                llSetTimerEvent(10);
+            }
+        }
+    }
+    
+    timer() {
+        llSetTimerEvent(0);
+        CACHE = InventoryString(INVENTORY_ALL, 0);
+        CACHE_PAGE = 0;        
+    }
+}
+

File schmarchive.css

View file
     background-image: url('gesture.png');
 }
 
-.inv_list {
-    margin-top: 10px;
-}
-
-.inv_list li {
-    padding: 2px 0;
-    list-style: none;
-}
-
-.inv_list li:nth-child(even) {
-    background: #222;
-}
-
-.inv_list li.highlight {
-    background: #324D00;
-}
-
-li.invisible {
-    display: none;
-}
-
-.child_list {
-    margin-top: 7px;
-}
-
-.child_list li {
-    background-image: url('folder-16.png');
-    padding: 2px 0 2px 21px;
-    background-repeat: no-repeat;
-    cursor: pointer;
-}
-
-.child_list li.active {
-    background-color: orange;
-}
-
 body {
     background-color: #151515;
     font-family: 'Droid Sans', arial, serif;
     font-size: 40px;
 }
 
-#livecontent {
-    min-height: 450px;
-}
-
-#livecontent, #textcontent {
-    padding: 10px;
-    margin-bottom: 20px;
-}
-
-.inset_block {
-    -moz-box-shadow:inset 0 0 5px #000000;
-    -webkit-box-shadow:inset 0 0 5px #000000;
-    box-shadow:inset 0 0 5px #000000;
-    margin-top: 10px;
-    color: white;
-    background: #151515;
-    padding: 5px;
-    float: left;
-    width: 300px;
-}
-
-.inset_block h4 {
-    margin-bottom: 7px;
-    /*display: inline;*/
-}
-
-#av_container h4 {
-    display: inline;
-    float: left;
-    margin-right: 4px;
-    margin-bottom: 0px;
-}
-
-#av_container .username {
-    color: #666;
-    float: left;
-    clear: left;
-    margin-bottom: 6px;
-}
-
-#av_container p {
-    clear: left;
-    font-size: 14px;
-    color: #ddd;
-}
-
-#info_container {
-    float: left;
-    background: #151515;
-    width: 300px;
-    padding: 5px;
-    border-radius: 5px;
-    /*min-height: 300px;*/
-}
-
-#info_container li {
-    list-style: none;
-}
-
 h4.inv_item {
     display: inline;
 }
     width: 100%;
 }
 
-#info_container .details {
-    font-size: 10px;
-    color: #888;
-    margin: 5px 0;
-}
-
-#info_container .details dt {
-    color: #eee;
-    font-size: 13px;
-    margin-top: 6px;
-}
-
-#info_container .bigassbutton {
-    background-color: orange;
-    border-radius: 5px;
-    border-style: none;
-    font-size: 20px;
-    float: left;
-    border-top-left-radius: 5px 5px;
-    border-top-right-radius: 5px 5px;
-    border-bottom-right-radius: 5px 5px;
-    border-bottom-left-radius: 5px 5px;
-    margin: 7px 0;
-}
-
-#info_container .bigassbutton:active {
-    background-color: #324D00;
-}
-
 .thumb {
   display: block;
   width: 150px;
   margin-top: 4px;
 }
 
-#item_send_status {
-    float: left;
-    height: 24px;
-    width: 24px;
-    background-position: center;
-    background-repeat: no-repeat;
-}
-#item_send_status.loading {
-    background-image: url('ajax-loader.gif');
-    margin: 7px 0 0 10px;
-}
-#item_send_status.success {
-    background-image: url('thumbs_up.png');
-    margin: 9px 0 0 10px;
-}
-
-.block_wrapper {
-    float: left;
-    margin: 10px 10px 30px 10px;
-    width: 310px;
-}
-
-.block_wrapper h3 {
-    display: inline;
-}
-
-#inv_wrap {
-    overflow: hidden;
-}
-
-#inv_container {
-    position: relative;
-    min-height: 300px;
-    height: 100%;
-}
-
-.inv_block {
-    position: absolute;
-    width: 300px;
-}
-
-.inv_block.child {
-    left: 310px;
-}
-
-.inv_block.parent {
-    left: -310px;
-}
-
-.inv_block h4 {
-    display: inline;
-    font-size: 20px;
-}
-
-.inv_parent {
-    float: right;
-    display: inline;
-    font-size: 10px;
-}
-
 p {
     margin-top: 20px;
     line-height: 19px;

File schmarchive.js

View file
       // hide broken images (any SL image with alpha in it will have no
       // search.secondlife.com thumbnail)
       $('img.thumb').error(function(ev) {
-              //console.log(ev);
               $(this).hide();
           });
       // call the isotope plugin on the frame
             }
             
             var panestr = $.tmpl($(this.itemTmpl), item);
-            console.log(item);
             var res = $(this.frame).isotope('insert', panestr);
-            console.log(res);
             var pane = $('.inv_item').last();
             pane.data('info', item);
         } else {
       // hide broken images (any SL image with alpha in it will have no
       // search.secondlife.com thumbnail)
       $('img.thumb').error(function(ev) {
-              //console.log(ev);
               $(this).hide();
           });
     },
       $(this.titleTmpl).tmpl(info).appendTo(this.titleContainer);
       // update the actual page title
       $.tmpl('<title>${objname}</title>', info).appendTo('head');
-      console.log(info);
     }
 };

File text.css

-body{font:13px/1.5 'Helvetica Neue',Arial,'Liberation Sans',FreeSans,sans-serif}a:focus{outline:1px dotted}hr{border:0 #ccc solid;border-top-width:1px;clear:both;height:0}h1{font-size:25px}h2{font-size:23px}h3{font-size:21px}h4{font-size:19px}h5{font-size:17px}h6{font-size:15px}ol{list-style:decimal}ul{list-style:disc}li{margin-left:30px}p,dl,hr,h1,h2,h3,h4,h5,h6,ol,ul,pre,table,address,fieldset{margin-bottom:20px}