Page MenuHomeCode

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
This document is not UTF8. It was detected as ISO-8859-1 (Latin 1) and converted to UTF8 for display.
diff --git a/content/scenes/B00001001.tpl b/content/scenes/B00001001.tpl
index a13ccac..b4d5a12 100644
--- a/content/scenes/B00001001.tpl
+++ b/content/scenes/B00001001.tpl
@@ -1,63 +1,156 @@
- <!-- JQuery -->
- <script src="{#StaticContentURL#}/js/jquery-1.3.2.min.js"></script>
-
- <!-- Tower navigation CSS -->
+ <!-- Tower navigation and passage CSS -->
<style>
+ body {
+ overflow: hidden;
+ }
+
+ /* Tower map */
+
#tower {
background-image: url({$SCENE_URL}/{$CurrentPerso->location_global}/all.png);
background-position: left;
background-repeat: no-repeat;
height: 442px;
}
#tower_hl {
position: relative;
}
+
+ /* Passage */
+
+ #passage {
+ width: 960px;
+ height: 401px;
+
+ background-image: url({$SCENE_URL}/{$CurrentPerso->location_global}/couloir/bay/void.png);
+ background-position: top left;
+ background-repeat: no-repeat;
+ }
+
+ #passage_left {
+ position: relative;
+ background-image: url({$SCENE_URL}/{$CurrentPerso->location_global}/couloir/GoLeft.png);
+ width: 38px;
+ height: 38px;
+ }
+
+ #passage_right {
+ position: relative;
+ background-image: url({$SCENE_URL}/{$CurrentPerso->location_global}/couloir/GoRight.png);
+ width: 38px;
+ height: 38px;
+ }
+
+ #passage_gallery ul {
+ position: relative;
+ top: 145px;
+ left: 120px;
+
+ margin-top: inherit;
+ margin-bottom: inherit;
+ }
+
+ #passage_gallery li {
+ display: block;
+ float: left;
+ margin-right: 60px;
+
+ width: 170px;
+ height: 170px;
+
+ padding: 4px 4px;
+
+ background-image: url({$SCENE_URL}/{$CurrentPerso->location_global}/couloir/frame.png);
+ background-repeat: no-repeat;
+ background-position: top left;
+ }
+
+ #screen {
+ position: absolute;
+ left: 10%;
+ top: 10%;
+ width: 80%;
+ height: 80%;
+ }
+
+ #screen img {
+ position: absolute;
+ cursor: pointer;
+ visibility: hidden;
+ width: 0px;
+ height: 0px;
+ }
+
+ #screen .tvover {
+ border: solid #343434;
+ opacity: 1;
+ filter: alpha(opacity=100);
+ }
+
+ #screen .tvout {
+ border: solid #fff;
+ opacity: 0.7;
+ }
+
+ #bankImages {
+ display: none;
+ }
</style>
+ <!-- Tower -->
+ <!--
<div id="tower"></div>
+ -->
+
+ <!-- Passage -->
+ <div class="grid_16 alpha omega">
+ <div id="passage">
+ <div id="passage_gallery"></div>
+ </div>
+ </div>
- <!-- Tower navigation JQuery code -->
+ <!-- Upload dialog -->
+ <div dojoType="dijit.Dialog" id="uploadDialog" style="display: none;" title="{#UploadNewArtwork#}">
+ <p>{#UploadNewArtworkDescription#}</p>
+ <form method="post" id="test" action="{get_xhr_hashed_url('upload_content', {$CurrentPerso->location_global})}" enctype="multipart/form-data">
+ <input type="hidden" id="location_local" name="location_local" value='{$CurrentPerso->location_local}' />
+ <input type="hidden" id="i" name="location_k" value="-1">
+ <div class="row">
+ <label for="artwork" class="firstLabel">Picture (max. {ini_get('upload_max_filesize')})</label>
+ <input type="file" name="artwork" id="artwork" class="long" />
+ </div>
+ <div class="row">
+ <label for="title" class="firstLabel">Title</label>
+ <input dojoType="dijit.form.TextBox" name="title" id="title" type="text" class="long" />
+ </div>
+ <div class="row center">
+ <button dojoType="dijit.form.Button" iconClass="dijitEditorIcon dijitEditorIconSave" type="submit" value="Save" />OK</button>
+ </div>
+ </form>
+ </div>
+
+ <!-- Javascript bits: script.aculo.us -->
+ <script src="{#StaticContentURL#}/js/prototype.js"></script>
+ <script src="{#StaticContentURL#}/js/effects.js"></script>
+ <!-- Javascript bits: dojo -->
<script>
- var tower = {
- //The source to highlight picture
- hl: '{$SCENE_URL}/{$CurrentPerso->location_global}/hl.png',
-
- //The highlighted corridor (1-6). 0 = no hl
- i: 0,
-
- //The corridor 4 (top) hl starts at:
- hlStartPosition: [163, 93],
+ dojo.require("dojo.parser");
+ dojo.require("dijit.Dialog");
+ dojo.require("dijit.form.Button");
+ dojo.require("dijit.form.TextBox");
+ </script>
+ <!-- Javascript bits: tower and couloir/passage/corridor/gallery/whatNameYouGiveToIt -->
+ <script src="{$SCENE_URL}/{$CurrentPerso->location_global}/tower.js"></script>
+ <script>
+ //Initializes tower map
+ //tower.hl = '{$SCENE_URL}/{$CurrentPerso->location_global}/hl.png';
+ //tower.highlight(3);
- //Gets CurrentPerso html code
- getHighlightCode: function () {
- return "<img id='tower_hl' src='" + this.hl + "' alt='Corridor " + this.i + "' />";
- },
+ //Initializes passage view
+ passage.bayPath = '{$SCENE_URL}/{$CurrentPerso->location_global}/couloir/bay/';
+ passage.initialize('{$location->global}', '{$CurrentPerso->location_local}');
- highlight: function (i) {
- //If already there, nothing to do
- if (this.i == i) return;
-
- //Puts hl
- this.i = i;
- $('#tower').html(this.getHighlightCode());
- var o = document.getElementById("tower_hl");
- o.style.left = this.hlStartPosition[0] + "px";
- o.style.top = this.hlStartPosition[1] + "px";
-
- //The 4 is okay
- if (i == 4) return;
-
- //Gets rotation angle
- if (i > 4) {
- angle = 60 * (i - 4);
- } else {
- angle = 180 + (i -1) * 60;
- }
- }
- }
-
- $(document).ready(function() {
- tower.highlight(3);
- });
+ //Initializes gallery
+ gallery.initialize('{#StaticContentURL#}', '{get_xhr_hashed_url('get_content', {$CurrentPerso->location_global})}');
</script>
\ No newline at end of file
diff --git a/content/scenes/B00001001/couloir/Frame.png b/content/scenes/B00001001/couloir/Frame.png
new file mode 100644
index 0000000..8971d6e
Binary files /dev/null and b/content/scenes/B00001001/couloir/Frame.png differ
diff --git a/content/scenes/B00001001/couloir/GoLeft.png b/content/scenes/B00001001/couloir/GoLeft.png
new file mode 100644
index 0000000..4d83d4f
Binary files /dev/null and b/content/scenes/B00001001/couloir/GoLeft.png differ
diff --git a/content/scenes/B00001001/couloir/GoRight.png b/content/scenes/B00001001/couloir/GoRight.png
new file mode 100644
index 0000000..f830abb
Binary files /dev/null and b/content/scenes/B00001001/couloir/GoRight.png differ
diff --git a/content/scenes/B00001001/couloir/bay/B00002.png b/content/scenes/B00001001/couloir/bay/B00002.png
new file mode 100644
index 0000000..26ccc62
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/B00002.png differ
diff --git a/content/scenes/B00001001/couloir/bay/B00003.png b/content/scenes/B00001001/couloir/bay/B00003.png
new file mode 100644
index 0000000..cc39002
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/B00003.png differ
diff --git a/content/scenes/B00001001/couloir/bay/default.png b/content/scenes/B00001001/couloir/bay/default.png
new file mode 100644
index 0000000..cceaee1
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/default.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/01.png b/content/scenes/B00001001/couloir/bay/hyper/01.png
new file mode 100644
index 0000000..eee5d4c
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/hyper/01.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/02.png b/content/scenes/B00001001/couloir/bay/hyper/02.png
new file mode 100644
index 0000000..f9cd2c8
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/hyper/02.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/03.png b/content/scenes/B00001001/couloir/bay/hyper/03.png
new file mode 100644
index 0000000..591c772
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/hyper/03.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/04.png b/content/scenes/B00001001/couloir/bay/hyper/04.png
new file mode 100644
index 0000000..17ac961
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/hyper/04.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/05.png b/content/scenes/B00001001/couloir/bay/hyper/05.png
new file mode 100644
index 0000000..1d4a641
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/hyper/05.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/06.png b/content/scenes/B00001001/couloir/bay/hyper/06.png
new file mode 100644
index 0000000..b491b3b
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/hyper/06.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/07.png b/content/scenes/B00001001/couloir/bay/hyper/07.png
new file mode 100644
index 0000000..e73bffa
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/hyper/07.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/08.png b/content/scenes/B00001001/couloir/bay/hyper/08.png
new file mode 100644
index 0000000..9f8adda
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/hyper/08.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/09.png b/content/scenes/B00001001/couloir/bay/hyper/09.png
new file mode 100644
index 0000000..9b7fd81
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/hyper/09.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/10.png b/content/scenes/B00001001/couloir/bay/hyper/10.png
new file mode 100644
index 0000000..00e2d74
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/hyper/10.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/11.png b/content/scenes/B00001001/couloir/bay/hyper/11.png
new file mode 100644
index 0000000..74bef58
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/hyper/11.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/12.png b/content/scenes/B00001001/couloir/bay/hyper/12.png
new file mode 100644
index 0000000..990e51e
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/hyper/12.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/13.png b/content/scenes/B00001001/couloir/bay/hyper/13.png
new file mode 100644
index 0000000..745c07e
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/hyper/13.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/14.png b/content/scenes/B00001001/couloir/bay/hyper/14.png
new file mode 100644
index 0000000..849a117
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/hyper/14.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/15.png b/content/scenes/B00001001/couloir/bay/hyper/15.png
new file mode 100644
index 0000000..6624dd8
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/hyper/15.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/16.png b/content/scenes/B00001001/couloir/bay/hyper/16.png
new file mode 100644
index 0000000..31e3f45
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/hyper/16.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/17.png b/content/scenes/B00001001/couloir/bay/hyper/17.png
new file mode 100644
index 0000000..38a02cc
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/hyper/17.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/18.png b/content/scenes/B00001001/couloir/bay/hyper/18.png
new file mode 100644
index 0000000..1083b1f
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/hyper/18.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/19.png b/content/scenes/B00001001/couloir/bay/hyper/19.png
new file mode 100644
index 0000000..043467a
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/hyper/19.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/20.png b/content/scenes/B00001001/couloir/bay/hyper/20.png
new file mode 100644
index 0000000..95fdfc8
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/hyper/20.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/21.png b/content/scenes/B00001001/couloir/bay/hyper/21.png
new file mode 100644
index 0000000..60eae99
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/hyper/21.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/22.png b/content/scenes/B00001001/couloir/bay/hyper/22.png
new file mode 100644
index 0000000..9e60b9f
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/hyper/22.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/23.png b/content/scenes/B00001001/couloir/bay/hyper/23.png
new file mode 100644
index 0000000..de158d9
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/hyper/23.png differ
diff --git a/content/scenes/B00001001/couloir/bay/hyper/index.html b/content/scenes/B00001001/couloir/bay/hyper/index.html
new file mode 100644
index 0000000..96c56d4
--- /dev/null
+++ b/content/scenes/B00001001/couloir/bay/hyper/index.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd"
+ >
+<html lang="en">
+<head>
+ <title>Restricted directory</title>
+ <link rel="Stylesheet" href="../../../../../../css/zed/theme.css" type="text/css" />
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+</head>
+<body>
+ <div style="width: 960px; margin: auto; margin-top: 3em;">
+ <h1 style="font-size: 3em;">Zed</h1>
+ <h2>Content directory</h2>
+ <p>As you can guess from the URL, this directory contains the bays for B00001001 couloirs scene content, when in hyperspace.</p>
+ <p>To browse it, you've to use the Zed application.</p>
+ <h3>Did you know?</h3>
+ <p>B00001001 is the geocode for the hypership.</p>
+ </div>
+</body>
+</html>
\ No newline at end of file
diff --git a/content/scenes/B00001001/couloir/bay/index.html b/content/scenes/B00001001/couloir/bay/index.html
new file mode 100644
index 0000000..4e6c1f5
--- /dev/null
+++ b/content/scenes/B00001001/couloir/bay/index.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd"
+ >
+<html lang="en">
+<head>
+ <title>Restricted directory</title>
+ <link rel="Stylesheet" href="../../../../../css/zed/theme.css" type="text/css" />
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+</head>
+<body>
+ <div style="width: 960px; margin: auto; margin-top: 3em;">
+ <h1 style="font-size: 3em;">Zed</h1>
+ <h2>Content directory</h2>
+ <p>As you can guess from the URL, this directory contains the bays for B00001001 couloirs scene content.</p>
+ <p>To browse it, you've to use the Zed application.</p>
+ <h3>Did you know?</h3>
+ <p>B00001001 is the geocode for the hypership.</p>
+ </div>
+</body>
+</html>
\ No newline at end of file
diff --git a/content/scenes/B00001001/couloir/bay/void.png b/content/scenes/B00001001/couloir/bay/void.png
new file mode 100644
index 0000000..b663d5a
Binary files /dev/null and b/content/scenes/B00001001/couloir/bay/void.png differ
diff --git a/content/scenes/B00001001/couloir/index.html b/content/scenes/B00001001/couloir/index.html
new file mode 100644
index 0000000..459f699
--- /dev/null
+++ b/content/scenes/B00001001/couloir/index.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd"
+ >
+<html lang="en">
+<head>
+ <title>Restricted directory</title>
+ <link rel="Stylesheet" href="../../../../css/zed/theme.css" type="text/css" />
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+</head>
+<body>
+ <div style="width: 960px; margin: auto; margin-top: 3em;">
+ <h1 style="font-size: 3em;">Zed</h1>
+ <h2>Content directory</h2>
+ <p>As you can guess from the URL, this directory contains the couloirs scene content for B00001001.</p>
+ <p>To browse it, you've to use the Zed application.</p>
+ <h3>Did you know?</h3>
+ <p>B00001001 is the geocode for the hypership.</p>
+ </div>
+</body>
+</html>
\ No newline at end of file
diff --git a/content/scenes/B00001001/tower.js b/content/scenes/B00001001/tower.js
new file mode 100644
index 0000000..f0adf57
--- /dev/null
+++ b/content/scenes/B00001001/tower.js
@@ -0,0 +1,581 @@
+/* -------------------------------------------------------------
+ Zed hypership tower javascript code
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ Authors: Dereckson (tower, passage and gallery classes)
+ G. Fernandez (tv, Library classes)
+ Tags: animation
+ Filename: login.js
+ Version: 1.0
+ Created: 2010-01-31
+ Updated: 2010-02-23
+ Licences: Dereckson code is dual licensed:
+ BSD and Creative Commons BY 3.0.
+ G. Fernandez code is licensed under CC-BY-NC 2.0.
+ Dependencies: dojo (xhr calls, dialog ui)
+ ------------------------------------------------------------- */
+
+/* -------------------------------------------------------------
+ Tower class
+ Prints a tower map, with hl on current corridor
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+var tower = {
+ //The source to highlight picture
+ hl: 'hl.png',
+
+ //The highlighted corridor (1-6). 0 = no hl
+ i: 0,
+
+ //The corridor 4 (top) hl starts at:
+ hlStartPosition: [163, 93],
+
+ //Gets CurrentPerso html code
+ getHighlightCode: function () {
+ return '<img id="tower_hl" src="' + this.hl + '" alt="Corridor ' + this.i + '" />';
+ },
+
+ highlight: function (i) {
+ //If already there, nothing to do
+ if (this.i == i) return;
+
+ //Puts hl
+ this.i = i;
+ var tower = document.getElementById("tower");
+ if (tower != null) {
+ tower.innerHTML = this.getHighlightCode();
+ var towerHl = document.getElementById("tower_hl");
+ if (towerHl != null) {
+ towerHl.style.left = this.hlStartPosition[0] + "px";
+ towerHl.style.top = this.hlStartPosition[1] + "px";
+
+ //The 4 is okay
+ if (i == 4) return;
+
+ //Gets rotation angle
+ if (i > 4) {
+ angle = 60 * (i - 4);
+ } else {
+ angle = 180 + (i -1) * 60;
+ }
+ }
+ }
+ }
+}
+
+/* -------------------------------------------------------------
+ Passage class
+ Prints relevant bay
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+//Corridors are like art galleries
+var passage = {
+ //Parameters
+ shipGlobalLocation: null,
+ persoLocalLocation: null,
+ bayPath: '',
+ id: 'passage',
+
+ //gets hyperspace bay
+ //randomly selected from 23 choices
+ getHyperspaceBay: function () {
+ var n = Math.floor(Math.random() * 23 + 1);
+ return 'hyper/' + ((n.toString().length == 1) ? "0" + n : n) + '.png';
+ },
+
+ getBay: function () {
+ //The bay depends of ship location
+ if (this.shipGlobalLocation[0] == 'B') {
+ //TODO: handle orientation of the ship and objects
+ //{$bay = substr($location->global, 0, 6)}
+ return this.shipGlobalLocation.substring(0, 6) + '.png';
+ } else {
+ //TODO: check if we're really in hyperspace.
+ //If not, we should fallback on default.png
+ return this.getHyperspaceBay();
+ }
+
+ return 'default.png'; //will be reachable, cf. upper
+ },
+
+ updateBay: function () {
+ var bgImage = 'url("' + this.bayPath + this.getBay() + '")';
+ document.getElementById(this.id).style.backgroundImage = bgImage;
+ },
+
+ getLocalLocation: function () {
+ //Splits TtCc expression at C
+ // '0' => "T2"
+ // '1' => "1"
+ var location = this.persoLocalLocation.split('C');
+
+ if (location.length == 2 && location[0][0] == 'T') {
+ //Current t, c coordinates
+ var t = location[0].substring(1);
+ var c = location[1];
+ }
+
+ return [t, c];
+ },
+
+ //TODO: t and c are strings, parse them into numbers
+
+ goLeft: function () {
+ //TxC1 -> TxC6 -> TxC5 -> TxC4 -> TxC3 -> TxC2 -> TxC1
+ tc = this.getLocalLocation();
+ t = tc[0];
+ c = tc[1];
+
+ //New c coordinates
+ var nc = (c == 1) ? 6 : c - 1;
+
+ this.moveTo('T' + t + 'C' + nc);
+ },
+
+ goRight: function () {
+ //TxC1 -> TxC2 -> TxC3 -> TxC4 -> TxC5 -> TxC6 -> TxC1
+ tc = this.getLocalLocation();
+ t = tc[0];
+ c = tc[1];
+
+ //New c coordinates
+ var nc = (c == 6) ? 1 : eval(c) + 1;
+
+ this.moveTo('T' + t + 'C' + nc);
+ },
+
+ moveTo: function (local_location) {
+ //New local location
+ passage.persoLocalLocation = local_location;
+ document.getElementById('location_local').value = local_location;
+
+ //Updates bays
+ //passage.updateBay();
+
+ //TODO: make url parameter compatible to any URL scheme
+ //TODO: check in dojo doc if the local_location have to be encoded
+ dojo.xhrGet({
+ handleAs: "json",
+ url: "/do.php/set_local_location/" + local_location,
+ preventCache: true,
+ handle: function (response, ioArgs) {
+ //Loads new gallery content
+ if (gallery.initialized) {
+ gallery.loadPics();
+ }
+ }
+ });
+ },
+
+ onGalleryInitialized: function () {
+ //Adds left and right arrows
+ this.addLeftArrow();
+ this.addRightArrow();
+ },
+
+ addLeftArrow: function () {
+ //Adds left arrow
+ var element = document.getElementById(this.id);
+ var left = element.offsetLeft + 28;
+ var top = element.offsetTop + 173;
+
+ element.innerHTML += '<div id="passage_left" onClick="passage.goLeft()" style="display: none; position: absolute; top: ' + top + 'px; left: ' + left + 'px"></div>';
+ },
+
+ addRightArrow: function () {
+ //Adds right arrow
+ var element = document.getElementById(this.id);
+ var left = element.offsetLeft + 898;
+ var top = element.offsetTop + 173;
+
+ element.innerHTML += '<div id="passage_right" onClick="passage.goRight()" style="display: none; position: absolute; top: ' + top + 'px; left: ' + left + 'px"></div>';
+ },
+
+ displayArrows: function (state) {
+ //Displays left and right arrows?
+ var display = [false, false];
+
+ switch (state) {
+ case "left":
+ display[0] = true;
+ break;
+
+ case "right":
+ display[1] = true;
+ break;
+ }
+
+ document.getElementById("passage_left").style.display = display[0] ? 'block' : 'none';
+ document.getElementById("passage_right").style.display = display[1] ? 'block' : 'none';
+ },
+
+ onmousemove: function () {
+ var element = document.getElementById(this.id);
+ var left = element.offsetLeft;
+ var top = element.offsetTop;
+
+ //alert(element.offsetWidth);
+ var inPassage = (
+ mouse.x >= left && mouse.y >= top &&
+ mouse.x <= left + element.offsetWidth &&
+ mouse.y <= top + element.offsetHeight
+ )
+
+ if (inPassage) {
+ var x = mouse.x - left;
+ var y = mouse.y - top;
+ if (x < 130) {
+ this.displayArrows('left');
+ } else if (x > 830) {
+ this.displayArrows('right');
+ } else {
+ this.displayArrows('none');
+ }
+ }
+ },
+
+ initialize: function (shipGlobalLocation, persoLocalLocation) {
+ this.shipGlobalLocation = shipGlobalLocation;
+ this.persoLocalLocation = persoLocalLocation;
+ if (persoLocalLocation == "") {
+ this.moveTo('T2C1');
+
+ //Notify (this code requires prototype.js (or jquery, but in this case, simplify it with a insertAfter call))
+ //TODO: ensure this code have dojo as only dependency
+ $("header").replace('<div id="header">' + $("header").innerHTML + '</div><div class="container_16"><div class="grid_16 alpha omega"><div class="notify">As you were losing yourself in the hypership tower, your paths guide you to the second floor.</div></div></div>');
+ }
+ this.updateBay();
+ }
+}
+
+/* -------------------------------------------------------------
+ Gallery class
+ Prints the gallery and calls artwork script
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+var gallery = {
+ pics: [],
+
+ initialized: false,
+
+ artworkDisplayMode: false,
+
+ currentPic: -1,
+
+ path: '',
+
+ loadXhrUrl: null,
+
+ getSquare: function (url) {
+ //Gets extension position (last . position)
+ var pos = url.lastIndexOf('.');
+
+ return url.substring(0, pos) + 'Square' + url.substring(pos);
+ },
+
+ showGallery: function () {
+ var html = '<ul>';
+ for (var i = 0 ; i < this.pics.length ; i++) {
+ if (this.pics[i] != null) {
+ //Shows artwork
+ html += '\n\t<li><img src="' + this.getSquare(this.pics[i]) + '" onClick="gallery.show(' + i + ')" /></li>';
+ } else {
+ //Shows placeholder
+ html += '\n\t<li onClick="gallery.uploadDialog(' + i + ');"></li>';
+ }
+ }
+ html += '\n</ul>';
+ document.getElementById('passage_gallery').innerHTML = html;
+ passage.onGalleryInitialized();
+ },
+
+ hideGallery: function () {
+ var elem = document.getElementById('passage_gallery');
+ Effect.Puff(elem);
+ },
+
+ loadPics: function () {
+ dojo.xhrGet({
+ handleAs: 'json',
+ url: this.loadXhrUrl + '?location_local=' + passage.persoLocalLocation,
+ preventCache: true,
+ handle: function (response, ioArgs) {
+ //TODO: in the future, we should print some metadata,
+ // and the objects will be useful.
+ // Meanwhile, we transform it to an array line.
+
+ var pics = [null, null, null];
+
+ //Builds pics array
+ for (var i = 0 ; i < response.length ; i++) {
+ if (response[i]['location_k'] > -1 && response[i]['location_k'] < 3) {
+ pics[response[i]['location_k']] = gallery.path + '/' + response[i]['path'];
+ }
+ }
+
+ //alert(dump(response));
+ gallery.loadPicsCallback(pics);
+
+ }
+ });
+ },
+
+ loadPicsCallback: function (pics) {
+ //Sets pics array
+ this.pics = pics;
+
+ //Show gallery
+ this.showGallery();
+
+ //Init done
+ if (!this.initialized) {
+ this.initialized = true;
+ }
+ },
+
+ show: function (i) {
+ //Hides gallery
+ this.hideGallery();
+
+ //Shows image
+ setTimeout('gallery.showImage(' + i + ')', 800);
+ },
+
+ showImage: function (i) {
+ //Sets image information
+ this.currentPic = i; //currently not used
+ this.artworkDisplayMode = true; //to handle properly ESC key down.
+
+ //New HTML passage code
+ document.getElementById('passage').innerHTML = '<div id="screen"></div><div id="bankImages"><img src="' + this.pics[i] + '" /></div>';
+
+ //Calls Photo3D script
+ onresize = tv.resize;
+ tv.init();
+ },
+
+ backToGallery: function () {
+ //Fades current picture
+ Effect.Fade(document.getElementById('screen'));
+
+ //Rebuilds gallery (in 800 ms, to let time to fading effect)
+ setTimeout("document.getElementById('passage').innerHTML = '<div id=\"passage_gallery\"></div>'; gallery.showGallery()", 800);
+
+ //Sets image information
+ this.currentPic = -1; //currently not used
+ this.artworkDisplayMode = false; //to handle properly ESC key down.
+ },
+
+ uploadDialog: function (i) {
+ document.getElementById('i').value = i;
+ dijit.byId('uploadDialog').show();
+ },
+
+ initialize: function (path, loadXhrUrl) {
+ //Sets load xhr url
+ this.path = path;
+ this.loadXhrUrl = loadXhrUrl;
+
+ //Loads pics
+ this.loadPics();
+
+ //Listens ESC key
+ document.onkeydown = function (e) {
+ if (e.keyCode == 27) {
+ if (gallery.artworkDisplayMode) {
+ gallery.backToGallery();
+ } else {
+ gallery.hideGallery();
+ }
+ }
+ }
+ }
+}
+
+/* -------------------------------------------------------------
+ Photo3D G. Fernandez script
+ http://www.dhteumeuleu.com/runscript.php?scr=photo3D.html
+
+ TODO: simplify code to handle one picture, and not an array
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+var gridsize = 1;
+
+var Library = {};
+Library.ease = function() {
+ this.target = 0;
+
+ this.position = 0;
+
+ this.move = function(_1, _2) {
+ this.position += (_1 - this.position) * _2;
+ };
+};
+
+var tv = {
+ O: [],
+
+ screen: {},
+
+ grid: {
+ size: gridsize,
+ borderSize: 6,
+ zoomed: false
+ },
+
+ angle: {
+ x: new Library.ease(),
+ y: new Library.ease()
+ },
+
+ camera: {
+ x: new Library.ease(),
+ y: new Library.ease(),
+ zoom: new Library.ease(),
+ focalLength: 750
+ },
+
+ init: function() {
+ this.screen.obj = document.getElementById("screen");
+ var images = document.getElementById("bankImages").getElementsByTagName("img");
+
+ this.screen.obj.onselectstart = function () {
+ return false;
+ };
+ this.screen.obj.ondrag = function () {
+ return false;
+ };
+ var ni = 0;
+ var n = (tv.grid.size / 2) - 0.5;
+ for (var y = - n ; y <= n ; y++) {
+ for (var x = - n ; x <= n; x++) {
+ var o = document.createElement("img");
+ var i = images[(ni++) % images.length];
+ o.className = "tvout";
+ o.src = i.src;
+ tv.screen.obj.appendChild(o);
+ o.point3D = {
+ x: x,
+ y: y,
+ z: new Library.ease()
+ };
+ o.point2D = {};
+ o.ratioImage = 1;
+ tv.O.push(o);
+
+ o.onmouseover = function () {
+ if (!tv.grid.zoomed) {
+ if (tv.o) {
+ tv.o.point3D.z.target = 0;
+ tv.o.className = "tvout";
+ }
+ this.className = "tvover";
+ this.point3D.z.target = - 0.5;
+ tv.o = this;
+ }
+ };
+
+ o.onclick = function () {
+ if (!tv.grid.zoomed) {
+ tv.camera.x.target = this.point3D.x;
+ tv.camera.y.target = this.point3D.y;
+ tv.camera.zoom.target = tv.screen.w * 1.25;
+ tv.grid.zoomed = this;
+ } else {
+ if (this == tv.grid.zoomed) {
+ tv.camera.x.target = 0;
+ tv.camera.y.target = 0;
+ tv.camera.zoom.target = tv.screen.w / (tv.grid.size + 0.1);
+ tv.grid.zoomed = false;
+ }
+ }
+ };
+
+ o.calc = function () {
+ this.point3D.z.move(this.point3D.z.target, 0.5);
+ var x = (this.point3D.x - tv.camera.x.position) * tv.camera.zoom.position;
+ var y = (this.point3D.y - tv.camera.y.position) * tv.camera.zoom.position;
+ var z = this.point3D.z.position * tv.camera.zoom.position;
+ var xy = tv.angle.cx * y - tv.angle.sx * z;
+ var xz = tv.angle.sx * y+tv.angle.cx * z;
+ var yz = tv.angle.cy * xz - tv.angle.sy * x;
+ var yx = tv.angle.sy * xz+tv.angle.cy * x;
+ this.point2D.scale = tv.camera.focalLength / (tv.camera.focalLength+yz);
+ this.point2D.x = yx * this.point2D.scale;
+ this.point2D.y = xy * this.point2D.scale;
+ this.point2D.w = Math.round(Math.max(0, this.point2D.scale * tv.camera.zoom.position * 0.8));
+ if (this.ratioImage > 1) {
+ this.point2D.h = Math.round(this.point2D.w / this.ratioImage);
+ } else {
+ this.point2D.h = this.point2D.w;this.point2D.w = Math.round(this.point2D.h * this.ratioImage);
+ }
+ };
+
+ o.draw = function () {
+ if (this.complete) {
+ if (!this.loaded) {
+ if (!this.img) {
+ this.img = new Image();
+ this.img.src = this.src;
+ }
+ if (this.img.complete) {
+ this.style.visibility = "visible";
+ this.ratioImage = this.img.width / this.img.height;
+ this.loaded = true;this.img = false;
+ }
+ }
+ this.style.left = Math.round(this.point2D.x * this.point2D.scale + tv.screen.w - this.point2D.w * 0.5) + "px";
+ this.style.top = Math.round(this.point2D.y * this.point2D.scale + tv.screen.h - this.point2D.h * 0.5) + "px";
+ this.style.width = this.point2D.w + "px";
+ this.style.height = this.point2D.h + "px";
+ this.style.borderWidth = Math.round(Math.max(this.point2D.w, this.point2D.h) * tv.grid.borderSize * 0.01) + "px";
+ this.style.zIndex = Math.floor(this.point2D.scale * 100);
+ }
+ };
+ }
+ }
+ tv.resize();
+ mouse.y = tv.screen.y+tv.screen.h;
+ mouse.x = tv.screen.x+tv.screen.w;
+ tv.run();
+ },
+
+ resize: function() {
+ var o = tv.screen.obj;
+ tv.screen.w = o.offsetWidth / 2;
+ tv.screen.h = o.offsetHeight / 2;
+ tv.camera.zoom.target = tv.screen.w / (tv.grid.size + 0.1);
+ for (tv.screen.x = 0, tv.screen.y = 0 ; o != null ; o = o.offsetParent) {
+ tv.screen.x += o.offsetLeft;
+ tv.screen.y = o.offsetTop;
+ }
+ },
+
+ run: function () {
+ tv.angle.x.move(-(mouse.y - tv.screen.h - tv.screen.y) * 0.0025, 0.1);
+ tv.angle.y.move((mouse.x - tv.screen.w - tv.screen.x) * 0.0025, 0.1);
+ tv.camera.x.move(tv.camera.x.target, tv.grid.zoomed ? 0.25: 0.025);
+ tv.camera.y.move(tv.camera.y.target, tv.grid.zoomed ? 0.25: 0.025);
+ tv.camera.zoom.move(tv.camera.zoom.target, 0.05);
+ tv.angle.cx = Math.cos(tv.angle.x.position);
+ tv.angle.sx = Math.sin(tv.angle.x.position);
+ tv.angle.cy = Math.cos(tv.angle.y.position);
+ tv.angle.sy = Math.sin(tv.angle.y.position);
+ for (var i = 0, o ; o = tv.O[i] ; i++) {
+ o.calc();
+ o.draw();
+ }
+ setTimeout(tv.run, 32);
+ }
+};
+
+var mouse = {x: 0, y: 0};
+
+document.onmousemove = function (e) {
+ if (window.event) {
+ e = window.event;
+ }
+ mouse.x = e.clientX;
+ mouse.y = e.clientY;
+ passage.onmousemove();
+ return false;
+};
\ No newline at end of file
diff --git a/content/stories/B00003001.xml b/content/stories/B00003001.xml
index d3f32c3..eefcd5f 100644
--- a/content/stories/B00003001.xml
+++ b/content/stories/B00003001.xml
@@ -1,48 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Zeta, Kaos
Dereckson, 2010-01-31
TODO: It's a start location. So it should provide a way to to reach hypership
TODO: <section id="spatioport.entry"></section>
TODO: <section id="mines.entry"></section>
TODO: .en
TODO: Écrire les chapitres The hole
-->
<story>
<title>Zeta, Kaos</title>
<section start="true" id="panorama">
<title>Panorama</title>
<description>
Zeta est une ville venteuse, plongée dans la nuit et le bruit.
À la surface travaillent d'honnêtes mineur de cobalt et de davyrium, ceinturant le sud de la ville.
Au nord de la ville, the hole, une ancienne mine dont les mineurs évitent de parler.
À l'est, un petit spatioport.
</description>
<choices>
<choice goto="hole.entry">Se diriger vers le hole</choice>
<choice goto="spatioport.entry">Se rendre au spatioport</choice>
<choice goto="mines.entry">Vers les mines</choice>
</choices>
<local>1</local>
</section>
<section id="hole.entry">
<title>The hole</title>
<description>
The hole. Une ancienne mine désaffectée depuis trois siècles. Aujourd'hui, un squat. L'endroit où tout se passe sur Zeta. Refuge des rebelles. Lieu d'exil de ce secteur de la galaxie. Lieu de tous les traffics. The hole.
- Une bande d'une douzaine jeunes armés de laser et de fouets neuroniques en garde l'entrée, deux vous regardant d'un œil plutôt menaçant.
+ Une bande d'une douzaine jeunes armés de laser et de fouet neuroniques en garde l'entrée, deux vous regardant d'un œil plutôt menaçant.
Ils vous refusent le passage.
</description>
<choices>
<choice goto="spatioport.entry">Se rendre au spatioport</choice>
<choice goto="mines.entry">Vers les mines</choice>
<choice goto="panorama">Retourner en ville</choice>
</choices>
<local>2</local>
</section>
+ <section id="spatioport.entry">
+ <title>Spatioport</title>
+ <description>
+ Le spatioport se présente sous la forme d'un large dôme cobalt où se reflète la lueur de Thétys, un astéroïde gravitant autour de Kaos tel une lune.
+
+ À l'arrière, un cratère évasé peut accueillir une trentaine de vaisseaux de taille modeste et de conception variée.
+ </description>
+ <hooks>
+ <hook type="spatioport" />
+ </hooks>
+ <choices>
+ <choice goto="panorama">Retourner en ville</choice>
+ </choices>
+ <local>3</local>
+ </section>
</story>
\ No newline at end of file
diff --git a/content/users/1148/30052009(078).jpg b/content/users/1148/30052009(078).jpg
new file mode 100644
index 0000000..94ce501
Binary files /dev/null and b/content/users/1148/30052009(078).jpg differ
diff --git a/content/users/1148/30052009(078)Square.jpg b/content/users/1148/30052009(078)Square.jpg
new file mode 100644
index 0000000..37dd67a
Binary files /dev/null and b/content/users/1148/30052009(078)Square.jpg differ
diff --git a/content/users/1148/NeuromancerIceDream1440x900Square.jpg b/content/users/1148/NeuromancerIceDream1440x900Square.jpg
new file mode 100644
index 0000000..dd6b48d
Binary files /dev/null and b/content/users/1148/NeuromancerIceDream1440x900Square.jpg differ
diff --git a/content/users/1148/Tunnel1440x900.jpg b/content/users/1148/Tunnel1440x900.jpg
new file mode 100644
index 0000000..ad8034b
Binary files /dev/null and b/content/users/1148/Tunnel1440x900.jpg differ
diff --git a/content/users/1148/Tunnel1440x900Square.jpg b/content/users/1148/Tunnel1440x900Square.jpg
new file mode 100644
index 0000000..550f240
Binary files /dev/null and b/content/users/1148/Tunnel1440x900Square.jpg differ
diff --git a/content/users/1148/riennestsurmaiscestunepiste.jpg b/content/users/1148/riennestsurmaiscestunepiste.jpg
new file mode 100644
index 0000000..e740905
Binary files /dev/null and b/content/users/1148/riennestsurmaiscestunepiste.jpg differ
diff --git a/content/users/1148/riennestsurmaiscestunepisteSquare.jpg b/content/users/1148/riennestsurmaiscestunepisteSquare.jpg
new file mode 100644
index 0000000..40dd340
Binary files /dev/null and b/content/users/1148/riennestsurmaiscestunepisteSquare.jpg differ
diff --git a/content/users/_avatars/1148_LoupAvatar80.jpg b/content/users/_avatars/1148_LoupAvatar80.jpg
new file mode 100644
index 0000000..f0e7935
Binary files /dev/null and b/content/users/_avatars/1148_LoupAvatar80.jpg differ
diff --git a/content/users/_avatars/5555_S.png b/content/users/_avatars/5555_S.png
new file mode 100644
index 0000000..a93ca07
Binary files /dev/null and b/content/users/_avatars/5555_S.png differ
diff --git a/controllers/explore.php b/controllers/explore.php
index 1c5403f..8159326 100644
--- a/controllers/explore.php
+++ b/controllers/explore.php
@@ -1,109 +1,111 @@
<?php
/*
* Zed
* (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* Explore current location
* For now, it's a storytelling engine like in livres dont vous êtes le héro
*/
//
// Helper method
//
/*
* Gets section to print to the user
* @param Story the story the section to get (yep, we could've global $story)
* @return StorySection the section, or null if not found
*/
function get_section ($story) {
global $url, $smarty, $CurrentPerso;
//If the URL contains a choice guid, use it as story progress source
//e.g. /explore/143f7200-766b-7b8b-e3f4-9fbfeeaeb5dd
if (count($url) > 1) {
$guid = $url[1];
//Ensures we've a StorySection object in the Story variable
- if (!array_key_exists('Story', $_SESSION)) {
+ if (!array_key_exists('StoryChoices', $_SESSION)) {
$smarty->assign('WAP', lang_get('ExpiredStorySession'));
} else {
- //Gets StoryChoice matching the guid
- if (!$choice = $_SESSION['Story']->get_choice($guid)) {
+ //Gets StoryChoice (creating a dummy section to use get_choice method)
+ $section = new StorySection("void");
+ $section->choices = $_SESSION['StoryChoices'];
+ if (!$choice = $section->get_choice($guid)) {
$smarty->assign('WAP', lang_get('InvalidStoryGUID'));
}
//TODO: add code here to handle actions defined in choices
//e.g. item added to inventory
//Gets section
if ($section_id = $choice->goto) {
if (!array_key_exists($section_id, $story->sections)) {
message_die(GENERAL_ERROR, "Choice <em>$choice->text</em> redirects to <em>$section_id</em> but this section doesn't exist.", "Story error");
}
return $story->sections[$section_id];
}
}
}
if (!$CurrentPerso->location_local) {
//Gets start section
return $story->get_start_section();
}
//Gets section matching perso location
return $story->get_section_from_location($CurrentPerso->location_local);
}
//
// Opens .xml file
//
$file = STORIES_DIR . '/' . $CurrentPerso->location_global . '.xml';
if (!file_exists($file)) {
message_die(GENERAL_ERROR, "If you want to write a story for this place, contact Dereckson — $file", "No story defined");
}
//
// Gets story
//
//Loads story and tries to get the section
require_once('includes/story/story.php');
$story = new Story($file);
$section = get_section($story);
//Ensures we've a section
if (!$section) {
message_die(GENERAL_ERROR, "Nothing to do at this location. Contact Dereckson if you think it's a bug or you want to write a story here.", "Story");
}
//Performs section actions
if ($section->location_local) {
//Moves perso to section local location
$CurrentPerso->move_to(null, $section->location_local);
}
//Saves section in session, for choices handling
-$_SESSION['Story'] = $section;
+$_SESSION['StoryChoices'] = $section->choices;
//
// HTML output
//
//Serves header
$smarty->assign('PAGE_TITLE', $story->title);
include('header.php');
//Serves content
$smarty->assign("section", $section);
$smarty->display('story.tpl');
//Serves footer
$smarty->assign('screen', "Story, section $section->id");
include('footer.php');
?>
\ No newline at end of file
diff --git a/controllers/footer.php b/controllers/footer.php
index 948c271..f1ae766 100644
--- a/controllers/footer.php
+++ b/controllers/footer.php
@@ -1,31 +1,33 @@
<?php
/*
* Zed
* (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* Footer
*/
///
/// Tutorials div
///
if ($CurrentPerso->flags['hypership.reached'] < 1 && $controller != 'explore') {
if (!DOJO) $smarty->display('tutorial/dojo.tpl');
lang_load("tutorials.conf", "ReachHypership");
+ $smarty->assign('controller', $controller);
$smarty->display('tutorial/hypership_reach.tpl');
}
///
/// HTML output
///
$smarty->assign('MultiPerso', isset($_SESSION['UserWithSeveralPersos']) && $_SESSION['UserWithSeveralPersos']);
+$smarty->assign('SmartLinePrint', (string)$CurrentPerso->get_flag('site.smartline.show') != "0");
$smarty->assign('SmartLineFormMethod', $CurrentPerso->get_flag('site.smartline.method'));
lang_load('footer.conf');
$smarty->display('footer.tpl');
?>
\ No newline at end of file
diff --git a/controllers/home.php b/controllers/home.php
index 772b5f3..5160686 100644
--- a/controllers/home.php
+++ b/controllers/home.php
@@ -1,62 +1,68 @@
<?php
/*
* Zed
* (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* Homepage
*/
//
// Gets and manage messages
//
require_once('includes/objects/message.php');
//Deletes a message if user have clicked the X
if ($_GET['action'] == 'msg_delete') {
//Deletes message $_GET['id']
$id = $_GET['id'];
$messageToDelete = new Message($id);
if ($messageToDelete->to != $CurrentPerso->id) {
//Not one of user message
$smarty->assign('WAP', lang_get('NotYourMessage'));
} elseif ($messageToDelete->flag == 2) {
//Already deleted
$smarty->assign('WAP', lang_get('MessageAlreadyDeleted'));
} else {
$messageToDelete->delete();
$smarty->assign('NOTIFY', lang_get('MessageDeleted'));
}
}
//Gets messages
$messages = Message::get_messages($CurrentPerso->id);
$smarty->assign('MESSAGES', $messages);
//Gets scene
require_once("includes/geo/scene.php");
$scene = new GeoScene($CurrentPerso->location);
$smarty->assign('SCENE', $scene);
//
// HTML output
//
//Serves header
+
+//TODO: Dojo loading here is currently a kludge, as dojo is required by
+//hypership .tpl scene. We should create an optionnal .meta xml file format
+//to set this kind of options
+if (!defined('DIJIT')) define('DIJIT', true);
+
$smarty->assign('PAGE_TITLE', lang_get('Welcome'));
include('header.php');
//Serves content
if (!$scene->lastError)
$scene->render();
$smarty->display('home.tpl');
if ($messages)
$smarty->display('messages.tpl');
//Serves footer
$smarty->assign("screen", "Home console");
include('footer.php');
?>
\ No newline at end of file
diff --git a/controllers/page.php b/controllers/page.php
index b522a2a..afa8d5d 100644
--- a/controllers/page.php
+++ b/controllers/page.php
@@ -1,109 +1,109 @@
<?php
/*
* Zed
* (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* HTML content
*/
if (!$code = $db->sql_escape($url[1])) {
message_die(HACK_ERROR, "/page/ must be followed by page code");
}
//
// Handles editor form
//
if ($_POST['code']) {
//Ask flag admin.pages.editor
$CurrentPerso->request_flag('admin.pages.editor');
//Gets version
$sql = "SELECT MAX(page_version) + 1 FROM " . TABLE_PAGES_EDITS .
" WHERE page_code = '$code'";
if (!$result = $db->sql_query($sql)) message_die(SQL_ERROR, "Can't fetch pages", '', __LINE__, __FILE__, $sql);
$row = $db->sql_fetchrow($result);
$page_version = ($row[0] == "") ? 0 : $row[0];
//Gets other fields
$page_code = $db->sql_escape($code);
$page_title = $db->sql_escape($_POST['title']);
$page_content = $db->sql_escape($_POST['content']);
$page_edit_reason = $db->sql_escape($_POST['edit_reason']);
$page_edit_user_id = $CurrentPerso->user_id;
$page_edit_time = time();
//Saves archive version
$sql = "INSERT INTO " . TABLE_PAGES_EDITS . " (`page_code`, `page_version`, `page_title`, `page_content`, `page_edit_reason`, `page_edit_user_id`, `page_edit_time`) VALUES ('$page_code', '$page_version', '$page_title', '$page_content', '$page_edit_reason', '$page_edit_user_id', '$page_edit_time')";
if (!$db->sql_query($sql)) {
message_die(SQL_ERROR, "Can't save page", '', __LINE__, __FILE__, $sql);
}
//Saves prod version
$sql = "REPLACE INTO " . TABLE_PAGES . " (`page_code`, `page_title`, `page_content`) VALUES ('$page_code', '$page_title', '$page_content')";
if (!$db->sql_query($sql)) {
message_die(SQL_ERROR, "Can't save page", '', __LINE__, __FILE__, $sql);
}
$smarty->assign('NOTIFY', "Page $page_code saved, version $page_version.");
}
//
// Gets page
//
$sql = "SELECT page_title, page_content, page_code FROM " . TABLE_PAGES . " WHERE page_code LIKE '$code'";
if ( !($result = $db->sql_query($sql)) ) message_die(SQL_ERROR, "Can't get pages", '', __LINE__, __FILE__, $sql);
$row = $db->sql_fetchrow($result);
switch ($_GET['mode']) {
case 'edit':
$CurrentPerso->request_flag('admin.pages.editor');
$template = 'page_edit.tpl';
if ($row) {
$smarty->assign('PAGE_TITLE', $row['page_title']);
$smarty->assign('page', $row);
} else {
$smarty->assign('PAGE_TITLE', $code);
$page['page_code'] = $code;
$smarty->assign('page', $page);
unset($page);
}
$smarty->assign('PAGE_JS', 'FCKeditor/fckeditor.js');
break;
default:
if ($row) {
$smarty->assign('PAGE_TITLE', $row['page_title']);
- $content = "<h1>$row[page_title]</h1>\n$row[page_content]";
+ $content = $row['page_content'];
} else {
$smarty->assign('PAGE_TITLE', lang_get('PageNotFound'));
$content = lang_get('PageNotFound');
}
//Adds edit link
if ($CurrentPerso->flags['admin.pages.editor']) {
$content .= '<p class="info" style="text-align: right">[ <a href="?mode=edit">Edit page</a> ]</p>';
}
$template = 'raw.tpl';
$smarty->assign('CONTENT', $content);
break;
}
//
// HTML output
//
//Serves header
include('header.php');
//Serves content
$smarty->display($template);
//Serves footer
include('footer.php');
?>
\ No newline at end of file
diff --git a/controllers/profile.php b/controllers/profile.php
index 36068b4..3b9dcc7 100644
--- a/controllers/profile.php
+++ b/controllers/profile.php
@@ -1,307 +1,308 @@
<?php
/*
* Zed
* (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* This code is maintained in // with Azhàr
*
* User profile
*/
//Loads language file
lang_load('profile.conf');
//Gets perso nickname from URL
$who = $url[1];
switch ($who) {
case 'edit':
$mode = 'edit';
$who = $CurrentPerso->nickname;
break;
case 'random':
$mode = 'view';
$who = $db->sql_query_express("SELECT perso_id FROM " . TABLE_PROFILES . " ORDER BY rand() LIMIT 1");
break;
default:
$mode = 'view';
}
if (!$who) {
message_die(GENERAL_ERROR, "Who?", "URL error");
}
//Libs
require_once('includes/objects/profile.php');
require_once('includes/objects/profilecomment.php');
require_once('includes/objects/profilephoto.php');
//Gets perso information
require_once('includes/objects/perso.php');
$perso = Perso::get($who);
if ($perso->lastError) {
message_die(GENERAL_ERROR, $perso->lastError, "Error");
}
+$smarty->assign('perso', $perso);
//Gets profile
$profile = new Profile($perso->id);
//Handles form
if ($_POST['EditProfile']) {
$profile->load_from_form();
$profile->updated = time();
$profile->save_to_database();
$mode = 'view';
} elseif ($_POST['UserAccount']) {
$smarty->assign('WAP', "Your form haven't been handled. Remember Dereckson to code this, profile.php line 59.");
//$perso->load_from_form(false);
$mode = 'view';
} elseif ($_POST['message_type'] == 'private_message') {
//Sends a message
require_once('includes/objects/message.php');
$msg = new Message();
$msg->from = $CurrentPerso->id;
$msg->to = $perso->id;
$msg->text = $_POST['message'];
$msg->send();
if ($msg->from == $msg->to) {
$smarty->assign('NOTIFY', lang_get('MessageSentSelf'));
} else {
$smarty->assign('NOTIFY', lang_get('MessageSent'));
}
} elseif ($_POST['message_type'] == 'profile_comment') {
//New profile comment
$comment = new ProfileComment();
$comment->author = $CurrentPerso->id;
$comment->perso_id = $perso->id;
$comment->text = $_POST['message'];
$comment->publish();
$smarty->assign('NOTIFY', lang_get('CommentPublished'));
} elseif ($_FILES['photo']) {
#We've a file !
$hash = md5(microtime() . serialize($_FILES));
$extension = get_extension($_FILES['photo']['name']);
$filename = $CurrentPerso->id . '_' . $hash . '.' . $extension;
#We ignore $_FILES[photo][error] 4, this means no file has been uploaded
#(so user doesn't want upload a new file)
#See http:/www.php.net/features.file-upload and http://www.php.net/manual/en/features.file-upload.errors.php about common errors
#Not valid before PHP 4.2.0
switch ($_FILES['photo']['error']) {
case 0:
#There is no error, the file uploaded with success.
if (!move_uploaded_file($_FILES['photo']['tmp_name'], PHOTOS_DIR . '/' . $filename)) {
$errors[] = "Upload successful, but error saving it.";
} else {
//Attaches the picture to the profile
$photo = new ProfilePhoto();
$photo->name = $filename;
$photo->perso_id = $CurrentPerso->id;
$photo->description = $_POST['description'];
if ($photo->avatar) $photo->promote_to_avatar();
$photo->save_to_database();
//Generates thumbnail
if (!$photo->generate_thumbnail()) {
$smarty->assign('WAP', "Error generating thumbnail.");
}
$smarty->assign('NOTIFY', lang_get('PhotoUploaded'));
$mode = 'view';
}
break;
case 1:
$errors[] = "The file is too large.";
break;
#TODO : more explicit error messages
default:
$errors[] = "Unknown error (#" . $_FILES['photo']['error'] . ")";
break;
}
if (count($errors)) {
$smarty->assign('WAP', join($errors, '<br />'));
}
} elseif ($_POST['id']) {
//Edits photo properties
$photo = new ProfilePhoto($_POST['id']);
if ($photo->lastError) {
$smarty->assign('WAP', $photo->lastError);
$mode = 'view';
} elseif ($photo->perso_id != $CurrentPerso->id) {
$smarty->assign('WAP', lang_get('NotYourPic'));
$mode = 'view';
} else {
//OK
$wereAvatar = $photo->avatar;
$photo->load_from_form();
if (!$wereAvatar && $photo->avatar) {
//Promote to avatar
$photo->promote_to_avatar();
}
$photo->save_to_database();
}
}
//Prepares output
if ($profile->text) {
//Profile
$smarty->assign('PROFILE_TEXT', $profile->text);
$smarty->assign('PROFILE_FIXEDWIDTH', $profile->fixedwidth);
}
if ($mode == 'view') {
require_once('includes/objects/profilephoto.php');
//Self profile?
$self = $CurrentPerso->id == $profile->perso_id;
//Gets profiles comments, photos
$comments = ProfileComment::get_comments($profile->perso_id);
$photos = ProfilePhoto::get_photos($profile->perso_id);
//Records timestamp, to be able to track new comments
if ($self) $CurrentPerso->set_flag('profile.lastvisit', time());
//Template
$smarty->assign('PROFILE_COMMENTS', $comments);
$smarty->assign('PROFILE_SELF', $self);
$smarty->assign('USERNAME', $perso->username);
$smarty->assign('NAME', $perso->name ? $perso->name : $perso->nickname);
$template = 'profile.tpl';
} elseif ($mode == 'edit') {
switch ($url[2]) {
case 'profile':
$smarty->assign('USERNAME', $perso->name);
$smarty->assign('DIJIT', true);
- $css[] = 'forms.css';
+ $css[] = THEME . '/forms.css';
$template = 'profile_edit.tpl';
break;
case 'account':
$smarty->assign('user', $CurrentUser);
$smarty->assign('DIJIT', true);
- $css[] = 'forms.css';
+ $css[] = THEME . '/forms.css';
$template = 'user_account.tpl';
break;
case '':
$smarty->assign('NOTIFY', "What do you want to edit ? Append /profile, /account or /photos to the URL");
break;
case 'photo':
case 'photos':
$smarty->assign('USERNAME', $perso->name);
switch ($action = $url[3]) {
case '':
//Nothing to do
break;
case 'delete':
//Deletes a picture
if (!$id = $url[4]) {
$smarty->assign('WAP', "URL error. Parameter missing: picture id.");
} else {
$photo = new ProfilePhoto($id);
if ($photo->lastError) {
//Probably an non existent id (e.g. double F5, photo already deleted)
$smarty->assign('WAP', $photo->lastError);
} elseif ($photo->perso_id != $CurrentPerso->id) {
$smarty->assign('WAP', lang_get('NotYourPic'));
} else {
//OK we can delete it
$photo->delete();
$smarty->assign('NOTIFY', lang_get('PictureDeleted'));
}
}
break;
case 'edit':
if (!$id = $url[4]) {
$smarty->assign('WAP', "URL error. Parameter missing: picture id.");
} else {
$photo = new ProfilePhoto($id);
if ($photo->lastError) {
//Probably an non existent id (e.g. double F5, photo already deleted)
$smarty->assign('WAP', $photo->lastError);
} elseif ($photo->perso_id != $CurrentPerso->id) {
$smarty->assign('WAP', lang_get('NotYourPic'));
} else {
//Photo information edit form
$smarty->assign('photo', $photo);
$template = 'profile_photo_edit.tpl';
}
}
break;
case 'avatar':
//Promotes a picture to avatar
if (!$id = $url[4]) {
$smarty->assign('WAP', "URL error. Parameter missing: picture id.");
} else {
$photo = new ProfilePhoto($id);
if ($photo->lastError) {
$smarty->assign('WAP', $photo->lastError);
} elseif ($photo->perso_id != $CurrentPerso->id) {
$smarty->assign('WAP', lang_get('NotYourPic'));
} else {
//OK, promote it to avatar
$photo->promote_to_avatar();
$photo->save_to_database();
$smarty->assign('NOTIFY', lang_get('PromotedToAvatar'));
}
}
break;
default:
$smarty->assign('WAP', "Unknown URL. To delete a picture it's /delete/<picture id>. To edit it /edit/<picture id>");
break;
}
if (!$template) {
$photos = ProfilePhoto::get_photos($profile->perso_id);
if (!$smarty->_tpl_vars['NOTIFY'])
$smarty->assign('NOTIFY', "Your feedback is valued. Report any bug or suggestion on the graffiti wall.");
$template = 'profile_photo.tpl';
}
break;
default:
$smarty->assign('WAP', "URL error. You can use /edit with profile, account or photos.");
break;
}
}
//
// HTML output
//
//Photos
if (count($photos) || $photo) {
$smarty->assign('URL_PICS', PHOTOS_URL);
$css[] = 'lightbox.css';
$smarty->assign('PAGE_JS', array('prototype.js', 'effects.js', 'lightbox.js'));
$smarty->assign('PICS', $photos);
}
//Serves header
-$css[] = "profile.css";
+$css[] = THEME . "/profile.css";
$smarty->assign('PAGE_CSS', $css);
$smarty->assign('PAGE_TITLE', $perso->name);
include('header.php');
//Serves content
if ($template) $smarty->display($template);
//Serves footer
include('footer.php');
?>
\ No newline at end of file
diff --git a/controllers/ship.php b/controllers/ship.php
new file mode 100644
index 0000000..a234d10
--- /dev/null
+++ b/controllers/ship.php
@@ -0,0 +1,64 @@
+<?php
+
+/*
+ * Zed
+ * (c) 2010, Dereckson, some rights reserved
+ * Released under BSD license
+ *
+ * Raw text or HTML content
+ */
+
+//
+// Ship information
+//
+
+//Gets ship from URL
+if (count($url) < 2) {
+ //No parameter, gets ship perso is onboard
+ if (!$code = $CurrentPerso->location->ship_code) {
+ message_die(GENERAL_ERROR, "/ship/ must be followed by valid ship code.<br />/ship alone only works when you're aboard a ship", "URL error");
+ }
+ $code = 'S' . $code;
+} else {
+ //Code have been specified
+ $code = $url[1];
+ if (!ereg("^S[0-9]{5}$", $code)) {
+ message_die(GENERAL_ERROR, "/ship/ must be followed by valid ship code", "URL error");
+ }
+}
+
+//Gets ship information
+$ship = Ship::get($code);
+
+//Gets perso note about this ship
+$note = $CurrentPerso->get_note($code);
+
+//Determines the spatial relation between perso and ship
+//dieprint_r($CurrentPerso->location->ship_code);
+
+//
+// Actions handling
+//
+if ($_REQUEST['action'] == 'ship.setnote' && $_REQUEST['note'] != $note) {
+ //Updates note content
+ $CurrentPerso->set_note($code, $_REQUEST['note']);
+ $note = $_REQUEST['note'];
+}
+
+//
+// HTML output
+//
+
+//Serves header
+$smarty->assign('PAGE_TITLE', $ship->name);
+include('header.php');
+
+//Serves content
+$smarty->assign('note', $note);
+$smarty->assign('ship', $ship);
+$smarty->display('ship.tpl');
+
+//Serves footer
+include('footer.php');
+
+?>
\ No newline at end of file
diff --git a/cron.php b/cron.php
new file mode 100644
index 0000000..3ee5bc8
--- /dev/null
+++ b/cron.php
@@ -0,0 +1,41 @@
+<?php
+
+/*
+ * Zed
+ * (c) 2010, Dereckson, some rights reserved
+ * Released under BSD license
+ *
+ * Cron
+ */
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Initialization
+///
+
+//Pluton library
+include('includes/core.php');
+
+//Debug mode?
+$debug = false;
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Daily tasks
+///
+
+//Orders perso table by nickname.
+//Rationale: prints an ordered perso select list, help for new persos, printed at end
+$queries[] = "ALTER TABLE " . TABLE_PERSOS . " ORDER BY perso_nickname";
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Executes tasks
+///
+
+foreach ($queries as $query) {
+ if (!$db->sql_query($sql) && $debug)
+ message_die(SQL_ERROR, "Can't execute query", '', __LINE__, __FILE__, $sql);
+}
+
+?>
\ No newline at end of file
diff --git a/css/zed/forms.css b/css/zed/forms.css
index b434302..5411dd3 100644
--- a/css/zed/forms.css
+++ b/css/zed/forms.css
@@ -1,82 +1,84 @@
@charset "utf-8";
/* -------------------------------------------------------------
Zed
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Author: Dereckson
Tags: space retro futurist
Filename: forms.css
Version: 1.0
Created: 2010-01-27
Updated: 2010-01-27
Licence: Creative Commons BY 3.0
------------------------------------------------------------- */
/* ------
Import dojo CSS
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
@import "/js/dojo/dijit/themes/tundra/tundra.css";
/* -------------------------------------------------------------
Forms rows
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
form .row {
margin-bottom: 0.8em;
}
hr {
width: 90%;
color: lightgray;
margin: 2em auto 2em auto;
}
/* -------------------------------------------------------------
input tags width
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
.small {
width: 5em;
}
+
.medium {
width: 12em;
}
+
.long {
width: 20em;
}
/* -------------------------------------------------------------
Labels (from dojo CSS)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
.firstLabel {
display: inline-block;
display: -moz-inline-box;
width: 10em;
min-width: 10em;
vertical-align: top;
}
.secondLabel {
width: auto;
margin-left: 5em;
margin-right: 1em;
}
fieldset label {
margin-right: 1em;
}
/* -------------------------------------------------------------
Misc
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Doesn't display DOJO tooltips provider if JS disabled */
.dojotooltip {
display: none;
}
.dijitButton {
color: black;
}
diff --git a/css/zed/profile.css b/css/zed/profile.css
new file mode 100644
index 0000000..4ae1874
--- /dev/null
+++ b/css/zed/profile.css
@@ -0,0 +1,168 @@
+@charset "utf-8";
+
+/* -------------------------------------------------------------
+ Zed
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ Author: Dereckson
+ Tags: space retro futurist
+ Filename: profile.css
+ Version: 1.0
+ Created: 2010-01-27
+ Updated: 2010-02-11
+ Licence: Creative Commons BY 3.0
+ ------------------------------------------------------------- */
+
+/* -------------------------------------------------------------
+ Profile header
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+.profile_id {
+ height: 40px;
+ line-height: 1.2em;
+ background-color: black;
+ color: white;
+}
+
+.profile_id H1 {
+ color: #04acf8;
+}
+
+.profile_info {
+ float: right;
+ font-size: 0.90em;
+ padding-right: 1em;
+}
+
+.profile_info a {
+ color: white;
+}
+
+.profile_info a:hover {
+ color: white;
+ font-weight: bold;
+}
+
+.profile_nick {
+ float: left;
+ margin-top: 0;
+ height: 30px;
+ padding-left: 12px;
+ padding-top: 10px;
+ font-size: 1.25em;
+ font-weight: 500;
+ border-left: solid #04acf8 6px;
+}
+
+/* -------------------------------------------------------------
+ Profile
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+.profile {
+ background-color: black;
+ color: white;
+ margin-bottom: 20px;
+ border: 2px solid #04acf8;
+}
+
+.profile_text {
+ margin-left: 10px;
+ margin-right: 10px;
+ padding-top: 1em;
+ font-size: 1em;
+ text-align: justify;
+}
+
+.profile_text img {
+ border: 0px;
+}
+
+.profile_text.fixedwidth {
+ font-family: Fixedsys, Fixed;
+ white-space: pre;
+}
+
+
+/* -------------------------------------------------------------
+ Profile CSS I wrote for faeries.folleterre.org
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/*
+.profile a {
+ color: white;
+ text-decoration: none;
+}
+
+.profile a:hover {
+ font-weight: 900;
+}
+
+.profile h1 {
+ color: white;
+}
+
+.profile h2 {
+ color: white;
+}
+
+.profile_separator {
+ height: 2px;
+ margin-top:2px;
+ background-color: black;
+}
+
+.profile_separator_light {
+ height: 1px;
+ margin-top:8px;
+ background-color: black;
+}
+
+.profile_photos {
+ border-bottom: solid 1px black;
+}
+
+.profile_photos img {
+ margin: 8px 0px 12px 20px;
+ border: 0px;
+}
+
+.profile_message {
+ margin-left: 10px;
+ margin-right: 10px;
+}
+
+.profile_message h2 {
+ font-size: 1.25em;
+}
+*/
+
+/* -------------------------------------------------------------
+ Profile comments
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+.profile_comments {
+ background-color: #fafafa;
+ border: solid 1px #dedede;
+}
+
+.profile_comments_info {
+ font-style: italic;
+}
+
+.profile_comments_text {
+ font-size: 1.25em;
+}
+
+/* -------------------------------------------------------------
+ Profile editor
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+.photos {
+}
+
+.photo img {
+ margin: 8px 0px 12px 20px;
+ border: 0;
+}
+
+.photo {
+ float: left;
+}
\ No newline at end of file
diff --git a/css/zed/theme.css b/css/zed/theme.css
index b62ddba..11e57e8 100644
--- a/css/zed/theme.css
+++ b/css/zed/theme.css
@@ -1,401 +1,418 @@
@charset "utf-8";
/* -------------------------------------------------------------
Zed
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Author: Dereckson
Tags: space retro futurist
Filename: theme.css
Version: 1.0
Created: 2010-01-27
Updated: 2010-01-27
Licence: Creative Commons BY 3.0
------------------------------------------------------------- */
/* -------------------------------------------------------------
Page settings
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
body {
- margin: 0 0 0 0;
+ margin: 0.5em 0 0 0;
background-attachment: fixed;
background-color: #343434;
background-image: url("../../img/zed/bg.jpg");
background-position: top left;
background-repeat: no-repeat;
font-family: "Calibri", "Lucida Sans Unicode", "Trebuchet MS", "Helvetica", "Arial", sans-serif;
min-height: 1200px;
-
- color: white;
+}
+
+.container_16 {
+ color: white;
}
#content {
width: 980px;
background-image: url("../../img/zed/bg_content.jpg");
background-position: top left;
background-repeat: no-repeat;
}
-h1, h2, h3, h4, h5, h6 {
- color: #04acf8;
- font-weight: normal;
-}
h1 {
color: #19B5E7;
font-size: 21px;
font-weight: normal;
}
+h2, h3, h4, h5, h6 {
+ color: #04acf8;
+ font-weight: normal;
+}
+
h2 {
font-size: 19px;
}
+h3 {
+ color: #04acf8;
+ font-size: 16px;
+}
+
pre {
font-family: FixedSys, monospace;
}
/* -------------------------------------------------------------
Links
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
a {
color: #1AC8E8;
text-decoration: none;
}
a:visited {
color: gray;
}
a:hover {
color: red;
text-decoration: none;
}
/* -------------------------------------------------------------
Notify messages
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
.notify {
padding-top: 25px;
padding-bottom: 25px;
margin-bottom: 10px;
text-align: center;
background: #eeeeee;
font-size: 1.5em;
color: black;
border: 5px solid #1AC8E8;
width: 950px;
}
.wap {
padding-top: 50px;
padding-bottom: 50px;
margin-bottom: 10px;
text-align: center;
background: #eeeeee;
font-size: 2em;
color: black;
border: 5px solid indianred;
width: 950px;
}
/* -------------------------------------------------------------
Header
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#header {
- background-color: #1fbeba;
- background-image: url("../../img/zed/bg_header.jpg");
- background-repeat: repeat-x;
- background-position: top left;
- height: 81px;
- margin-bottom: 3.14em;
+ background-image: url("../../img/zed/bg_header.png");
+ background-repeat: no-repeat;
+ margin: auto auto;
+ margin-bottom: 0.5em;
+ height: 104px;
+ width: 978px;
}
#header_content {
- background-image: url("../../img/zed/bg_header_content.jpg");
- height: 74px;
+ padding-top: 26px;
+}
+
+#HypershipTime {
+ color: white;
+ font-size: 0.8em;
+ background-image: url("../../img/zed/time.png");
+ background-position: center left;
+ background-repeat: no-repeat;
+ text-indent: 2em;
}
/* -------------------------------------------------------------
Header - wall
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
.wall {
text-align: left;
- float: right;
+ float:left;
+ color: white;
+ font-size: 0.8em;
+ background-image: url("../../img/zed/quote.png");
+ background-position: top left;
+ background-repeat: no-repeat;
+ text-indent: 2em;
+ margin-bottom: 0.8em;
}
.wall_info {
display: block;
text-align: right;
- font-size: 80%;
+ /* font-size: 80%; */
}
.wall a {
- color: white;
+ color: #a9a49e;
}
.wall a:hover {
- color: #cae2fd;
+ color: #fd9800;
}
/* -------------------------------------------------------------
- Info
+ Content (e.g. stories in /explore)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-.info {
- width: 584px;
- height: 25px;
- background-image: url(/img/zed/bg_meta.png);
- margin-bottom: 1em;
- padding-top: 7px;
-
- font-size: 90%;
+.content_wrapper {
+ background-color: #171717;
+ border: solid 5px black;
+ margin-bottom: 1em;
}
-.info strong {
- display: inline-block;
- display: -moz-inline-box;
- width: 9em;
- min-width: 9em;
- font-weight: 600;
- color: #fd9800;
+.content_wrapper .content {
+ padding: 0 2em 0 2em;
}
-.info_left {
- float: left;
- width: 415px;
- margin-left: 20px;
- margin-right: 18px;
-}
-
-#HypershipTime {
- color: red;
-}
-
-.info_right {
- float: left;
- width: 130px;
+.content_wrapper H1 {
+ margin-top: 0;
+ padding: 0.25em 0 0.75em 1em;
+ background-color: black;
+ height: 1em;
}
/* -------------------------------------------------------------
Avatars wall
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
.avatar {
float: left;
margin-bottom: 2em;
margin-right: 2em;
text-align: center;
}
.avatar_name {
display: block;
}
+.avatar a:hover {
+ color: white;
+}
+
/* -------------------------------------------------------------
Messages
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
.message {
margin-bottom: 17px;
padding: 8px 9px 8px 9px;
width: 940px;
font-size: 80%;
}
.message.light {
background-color: #fafafa;
border: 3px solid #dedede;
width: 938px;
color: black;
}
.message.light a {color: #343434;}
.message.dark {
background-color: #acc0c3;
border: solid 3px #4e5758;
width: 938px;
color: #000033;
}
.message.dark a {color: #154c4c;}
.message a:hover {
font-weight: 900;
}
.message_info {
text-align: right;
margin-bottom: 1em;
}
.message_text {
font-size: 1.25em;
}
.message_info {
color: #343434;
}
+/* -------------------------------------------------------------
+ Helper classes
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+.center {
+ text-align: center;
+}
+
/* -------------------------------------------------------------
Color boxes
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
.plum {
background-color: plum;
border: 1px solid #800080;
color: black;
}
.plum a { color: #800080; }
.green {
background-color: beige;
border: 1px solid darkgreen;
color: black;
}
.green a { color: darkgreen; }
.skyblue {
background-color: lightskyblue;
border: 1px solid #6e47fe;
}
.skyblue a { color:navy }
.indigo {
background-color: #AE97E1;
border: 1px solid #C97FFF;
}
.indigo a {color: #800080;}
.yellow {
background-color: #FFFFCC;
border: 1px solid #C4B963;
}
.yellow a {color: navy;}
.orange {
background-color: #FDD9AC;
border: 1px solid #eaaf67;
}
.orange a {color: #43392e;}
.red {
background-color: #FFE4E1;
border: solid 1px #DC7777;
}
.red a {color: #993333;}
.black {
background-color: black;
color: #ccc;
border: solid 2px #555;
}
.plum a:hover,
.green a:hover,
.skyblue a:hover,
.indigo a:hover,
.yellow a:hover,
.orange a:hover,
.red a:hover{
font-weight: bold;
}
/* -------------------------------------------------------------
SmartLine
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#SmartLine {
width: 100%;
}
#SmartLine .left {
}
#SmartLine .right {
float: right;
text-align: right;
}
/* TODO: ajouter un sélecteur de SmarLine pour chat/commandes (60px) */
/* grid_1 alpha -> sélecteur, grid_3 -> history, grid_12 > bar */
#SmartLineHistory {
width: 115%; /* dépasse de sa bordure */
}
#SmartLineBar{
/* 99.6% for alignment with .message.light */
width: 99.6%;
}
#SmartLineResults {
font-family: "Fixedsys Excelsior 3.01", FixedSys, Terminal;
font-size: 12pt;
}
#SmartLineResults .highlight {
color: #16c3cc;
}
#SmartLineResults .error {
color: red;
}
#SmartLineResults p {
padding-left: 1em;
}
/* -------------------------------------------------------------
Floating panes
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
.floatingPaneTutorial {
width: 957.5px;
margin-bottom: 1em;
color: black;
}
.floatingPaneTutorial a {
color: navy;
}
.floatingPaneTutorial a:hover {
color: #5f0505;
}
.floatingPaneTutorial p {
color: black;
margin: 0;
padding: 5px 10px 0px 10px;
}
.dojoxDockList {
color: black;
}
/* -------------------------------------------------------------
Footer
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#footer {
font-size: 80%;
}
\ No newline at end of file
diff --git a/dev/quux.php b/dev/quux.php
index a615415..78acb9f 100644
--- a/dev/quux.php
+++ b/dev/quux.php
@@ -1,13 +1,48 @@
<?php
- //dieprint_r($CurrentPerso->location);
-
require_once('includes/objects/ship.php');
- $ship = new Ship(1);
- Ship::clean_ship_sessions();
-
+ require_once('includes/objects/port.php');
+ require_once('includes/objects/application.php');
+
include('controllers/header.php');
- echo "<p>Sessions cleaned</p>";
+
+ $case = 'pushdata';
+ switch ($case) {
+ case 'pushdata';
+ echo '
+<h2>/api.php/app/pushdata</h2>
+<form method="post" action="/api.php/app/pushdata?mode=file&key=37d839ba-f9fc-42ca-a3e8-28053e979b90" enctype="multipart/form-data">
+ <input type="file" name="datafile" /><br />
+ <input type="submit" value="Send file" />
+</form>
+ ';
+
+ case 'port':
+ echo '<h2>Port::from_location test</h2>';
+ $locations = array("B00002", "B00002123", "B00001001", "xyz: [800, 42, 220]");
+ foreach ($locations as $location) {
+ dprint_r(Port::from_location($location));
+ }
+ break;
+
+ case 'ext':
+ $file = 'dev/foo.tar';
+ echo "<h2>$file</h2>";
+ echo "<h3>.tar.bz2</h3>";
+ echo ereg('\.tar\.bz2$', $file);
+ echo "<h3>.tar</h3>";
+ echo ereg('\.tar$', $file);
+ break;
+
+ case 'app':
+ echo Application::from_api_key("37d839ba-f9fc-42ca-a3e8-28053e979b90")->generate_userkey();
+ break;
+
+ case '':
+ dieprint_r("No case currently selected.");
+ break;
+ }
+
include('controllers/footer.php');
?>
\ No newline at end of file
diff --git a/do.php b/do.php
index 60e66ad..1191d08 100644
--- a/do.php
+++ b/do.php
@@ -1,188 +1,256 @@
<?php
/*
* Zed
* (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* AJAX callbacks
*
* As main controller could potentially be interrupted (e.g. if site.requests
* flag is at 1, user is redirected to controllers/userrequest.php), all AJAX
* queries should be handled by this script and not directly by the controllers.
*
* Standard return values:
* -7 user is logged but perso isn't selected
* -9 user is not logged
*
*/
////////////////////////////////////////////////////////////////////////////////
///
/// Initialization
///
//Standard return values
-define('USER_NOT_LOGGED', -9);
+define('USER_NOT_LOGGED', -9);
define('PERSO_NOT_SELECTED', -7);
//Pluton library
include('includes/core.php');
//Session
$IP = encode_ip($_SERVER["REMOTE_ADDR"]);
require_once('includes/story/story.php'); //this class can be stored in session
session_start();
$_SESSION[ID] = session_id();
session_update(); //updates or creates the session
include("includes/login.php"); //login/logout
$CurrentUser = get_logged_user(); //Gets current user infos
//Gets current perso
require_once('includes/objects/perso.php');
if ($perso_id = $CurrentUser->session['perso_id']) {
$CurrentPerso = new Perso($perso_id);
}
//Requires user and perso
if ($CurrentUser->id < 1000) {
echo USER_NOT_LOGGED;
exit;
}
if (!$CurrentPerso) {
echo PERSO_NOT_SELECTED;
exit;
}
//Loads Smarty (as it handles l10n, it will be used by lang_get)
require('includes/Smarty/Smarty.class.php');
$smarty = new Smarty();
$current_dir = dirname(__FILE__);
+$smarty->template_dir = $current_dir . '/skins/zed';
$smarty->compile_dir = $current_dir . '/cache/compiled';
$smarty->cache_dir = $current_dir . '/cache';
$smarty->config_dir = $current_dir;
//Loads language files
initialize_lang();
lang_load('core.conf');
-
////////////////////////////////////////////////////////////////////////////////
///
/// Actions definitions
///
/*
* Actions class
* Each method is called by first part of your URL, other parts are arguments
* e.g. /do.php/validate_quux_request/52 = Actions::validate_quux_request(52);
*
* You can also use $_GET, $_POST or better $_REQUEST.
*
* Don't echo the value but return it, so we can in the future implement custom
* formats like api_output();
*/
class Actions {
/*
* Checks the arguments hash
* @param Array $args the arguments, the last being the hash
*/
static private function is_hash_valid ($args) {
global $Config;
return array_pop($args) == md5($_SESSION['ID'] . $Config['SecretKey'] . implode('', $args));
}
/*
* Handles a allow/deny perso request
* @param string $request_flag the request flag to clear
* @param string $store 'perso' or 'registry'
* @param string $key the perso flag or registry key
* @param string $value the value to store
* @param string $hash the security hash
* @return boolean true if the request is valid and have been processed ; otherwise, false.
*/
static function perso_request ($request_flag, $store, $key, $value, $hash) {
global $CurrentPerso;
//Ensures we've the correct amount of arguments
if (func_num_args() < 4) return false;
//Checks hash
$args = func_get_args();
if (!self::is_hash_valid($args)) {
return false;
}
//Sets flag
switch ($store) {
case 'perso':
$CurrentPerso->set_flag($key, $value);
break;
case 'registry':
registry_set($key, $value);
break;
default:
//Unknown storage location
return false;
}
//Clears request flag
if ((string)$request_flag !== "0") {
$CurrentPerso->delete_flag($request_flag);
}
return true;
}
+
+ /*
+ * Sets current perso's local location
+ * @param string $location_local the local location
+ * @return GeoLocation the current perso's GeoLocation object
+ *
+ * We don't require a security hash. If the users want to play with it, no problem.
+ * You generally moves inside a global location as you wish.
+ * So, if you write a story capturing a perso, use flags to handle this escape!
+ */
+ static function set_local_location ($location_local) {
+ global $CurrentPerso;
+
+ //Ensures we've the correct amount of arguments
+ if (func_num_args() < 1) return null;
+
+ //Moves current perso to specified location
+ $CurrentPerso->move_to(null, $location_local);
+
+ //Returns GeoLocation relevant instance
+ return $CurrentPerso->location;
+ }
+
+ /*
+ * Handles upload content form
+ * @return string new content path
+ */
+ static function upload_content () {
+ global $CurrentPerso, $CurrentUser;
+ require_once('includes/objects/content.php');
+
+ //Initializes a new content instance
+ $content = new Content();
+
+ //Reads form
+ $content->load_from_form();
+
+ //Sets current user/perso parameters
+ $content->user_id = $CurrentUser->id;
+ $content->perso_id = $CurrentPerso->id;
+ $content->location_global = $CurrentPerso->location_global;
+
+ //Saves file
+ if ($content->handle_uploaded_file($_FILES['artwork'])) {
+ $content->save_to_database();
+ $content->generate_thumbnail();
+ return true;
+ }
+
+ return false;
+ }
+ /*
+ *
+ * @return Array content files
+ */
+ static function get_content ($location_global) {
+ //Ensures we've the correct amount of arguments
+ if (func_num_args() < 1) return null;
+
+ //Checks hash
+ $args = func_get_args();
+ if (!self::is_hash_valid($args)) {
+ return false;
+ }
+
+ require_once('includes/objects/content.php');
+ return Content::get_local_content($location_global, $_GET['location_local']);
+ }
}
////////////////////////////////////////////////////////////////////////////////
///
/// Handles request
///
//You really should use $_SERVER['PATH_INFO']
//i.e. calling /do.php/your request without any mod rewrite intervention
//
//If you choose otherwise, uncomment and tweak one of the following lines:
//$Config['SiteURL'] = 'http://yourserver/zed/do.php';
//$Config['SiteURL'] = get_server_url() . '/do.php';
$args = get_current_url_fragments();
$method = array_shift($args);
if ($_REQUEST['debug']) {
//Debug version
//Most of E_STRICT errors are evaluated at the compile time thus such errors
//are not reported
ini_set('display_errors', 'stderr');
error_reporting(-1);
if (method_exists('Actions', $method)) {
$result = call_user_func_array(array('Actions', $method), $args);
echo json_encode($result);
} else {
echo "<p>Method doesn't exist: $method</p>";
}
if (array_key_exists('redirectTo', $_REQUEST)) {
//If user JS disabled, you can add ?redirectTo= followed by an URL
echo "<p>Instead to print a callback value, redirects to <a href=\"$_REQUEST[redirectTo]\">$_REQUEST[redirectTo]</a></p>";
}
} else {
//Prod version doesn't prints warning <== silence operator
if (method_exists('Actions', $method)) {
$result = @call_user_func_array(array('Actions', $method), $args);
if (array_key_exists('redirectTo', $_REQUEST)) {
//If user JS disabled, you can add ?redirectTo= followed by an URL
header("location: " . $_REQUEST['redirectTo']);
} else {
echo json_encode($result);
}
}
}
?>
\ No newline at end of file
diff --git a/img/misc/start.png b/img/misc/start.png
new file mode 100644
index 0000000..574d93b
Binary files /dev/null and b/img/misc/start.png differ
diff --git a/img/zed/bg.jpg b/img/zed/bg.jpg
index 7ac4268..ea607f4 100644
Binary files a/img/zed/bg.jpg and b/img/zed/bg.jpg differ
diff --git a/img/zed/bg_header.png b/img/zed/bg_header.png
new file mode 100644
index 0000000..39f6d02
Binary files /dev/null and b/img/zed/bg_header.png differ
diff --git a/img/zed/logo.png b/img/zed/logo.png
index a689bdd..dfa476f 100644
Binary files a/img/zed/logo.png and b/img/zed/logo.png differ
diff --git a/img/zed/opaque_20.png b/img/zed/opaque_20.png
new file mode 100644
index 0000000..866e0ef
Binary files /dev/null and b/img/zed/opaque_20.png differ
diff --git a/img/zed/opaque_5.png b/img/zed/opaque_5.png
new file mode 100644
index 0000000..12f31fd
Binary files /dev/null and b/img/zed/opaque_5.png differ
diff --git a/img/zed/quote.png b/img/zed/quote.png
new file mode 100644
index 0000000..cee94e8
Binary files /dev/null and b/img/zed/quote.png differ
diff --git a/img/zed/quote_hl.png b/img/zed/quote_hl.png
new file mode 100644
index 0000000..e57df0e
Binary files /dev/null and b/img/zed/quote_hl.png differ
diff --git a/img/zed/time.png b/img/zed/time.png
new file mode 100644
index 0000000..942fc0a
Binary files /dev/null and b/img/zed/time.png differ
diff --git a/img/zed/time_hl.png b/img/zed/time_hl.png
new file mode 100644
index 0000000..1d675e3
Binary files /dev/null and b/img/zed/time_hl.png differ
diff --git a/includes/config.php b/includes/config.php
index 36ad987..7370b37 100644
--- a/includes/config.php
+++ b/includes/config.php
@@ -1,177 +1,181 @@
<?php
/*
* Zed
* (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* Autogenerable configuration file
*/
////////////////////////////////////////////////////////////////////////////////
/// ///
/// I. SQL configuration ///
/// ///
////////////////////////////////////////////////////////////////////////////////
//SQL configuration
$Config['sql']['product'] = 'MySQL'; //Only MySQL is currently implemented
$Config['sql']['host'] = 'localhost';
$Config['sql']['username'] = 'zed';
$Config['sql']['password'] = 'zed';
$Config['sql']['database'] = 'zed';
//SQL tables
$prefix = '';
define('TABLE_API_KEYS', $prefix . 'api_keys');
define('TABLE_COMMENTS', $prefix . 'comments');
+define('TABLE_LOG', $prefix . 'log');
define('TABLE_LOG_SMARTLINE', $prefix . 'log_smartline');
define('TABLE_MESSAGES', $prefix . 'messages');
define('TABLE_MOTD', $prefix . 'motd');
define('TABLE_PAGES', $prefix . 'pages');
define('TABLE_PAGES_EDITS', $prefix . 'pages_edits');
define('TABLE_PERSOS', $prefix . 'persos');
define('TABLE_PERSOS_FLAGS', $prefix . 'persos_flags');
+define('TABLE_PERSOS_NOTES', $prefix . 'persos_notes');
define('TABLE_PROFILES', $prefix . 'profiles');
define('TABLE_PROFILES_COMMENTS', $prefix . 'profiles_comments');
define('TABLE_PROFILES_PHOTOS', $prefix . 'profiles_photos');
define('TABLE_REGISTRY', $prefix . 'registry');
define('TABLE_SESSIONS', $prefix . 'sessions');
+define('TABLE_SHIPS', $prefix . 'ships');
define('TABLE_USERS', $prefix . 'users');
+define('TABLE_USERS_INVITES', $prefix . 'users_invites');
define('TABLE_USERS_OPENID', $prefix . 'users_openid');
//Geo tables
define('TABLE_BODIES', $prefix . 'geo_bodies');
-define('TABLE_LOCATIONS', $prefix . 'geo_locations'); //Well... it's view
+define('TABLE_LOCATIONS', $prefix . 'geo_locations'); //Well... it's a view
define('TABLE_PLACES', $prefix . 'geo_places');
////////////////////////////////////////////////////////////////////////////////
/// ///
/// II. Site configuration ///
/// ///
////////////////////////////////////////////////////////////////////////////////
//Default theme
$Config['DefaultTheme'] = "Zed";
//Dates
date_default_timezone_set("UTC");
//Secret key, used for some verification hashes in URLs or forms.
$Config['SecretKey'] = 'Je balaye les petits ewoks comme le vent balaye les feuilles mortes';
//When reading files, buffer size
define('BUFFER_SIZE', 4096);
////////////////////////////////////////////////////////////////////////////////
/// ///
/// III. Script URLs ///
/// ///
////////////////////////////////////////////////////////////////////////////////
/*
* Without mod_rewrite:
*
* Subdirectory:
* - $Config['SiteURL'] = 'http://zed.dereckson.be/hypership/index.php';
* - $Config['BaseURL'] = '/hypership/index.php';
*
* Root directory:
* - $Config['SiteURL'] = 'http://zed.dereckson.be/index.php';
* - $Config['BaseURL'] = '/index.php';
*
* With mod_rewrite:
*
* Subdirectory:
* - $Config['SiteURL'] = 'http://zed.dereckson.be/hypership';
* - $Config['BaseURL'] = '/hypership';
*
* In .htaccess or your vhost definition:
* RewriteEngine On
* RewriteBase /hypership/
* RewriteCond %{REQUEST_FILENAME} !-f
* RewriteCond %{REQUEST_FILENAME} !-d
* RewriteRule . /hypership/index.php [L]
*
* Root directory:
* - $Config['SiteURL'] = 'http://zed.dereckson.be';
* - $Config['BaseURL'] = '';
*
* In .htaccess or your vhost definition:
* RewriteEngine On
* RewriteBase /
* RewriteCond %{REQUEST_FILENAME} !-f
* RewriteCond %{REQUEST_FILENAME} !-d
* RewriteRule . /index.php [L]
*
*
* If you don't want to specify the server domain, you can use get_server_url:
* $Config['SiteURL'] = get_server_url() . '/hypership';
* $Config['SiteURL'] = get_server_url();
*
* !!! No trailing slash !!!
*
*/
$Config['SiteURL'] = get_server_url();
$Config['BaseURL'] = '';
//AJAX callbacks URL
$Config['DoURL'] = $Config['SiteURL'] . "/do.php";
////////////////////////////////////////////////////////////////////////////////
/// ///
/// IV. Static content ///
/// ///
////////////////////////////////////////////////////////////////////////////////
//Where the static content is located?
//Static content = 4 directories: js, css, img and content
//On default installation, those directories are at site root.
//To improve site performance, you can use a CDN for that.
//To use
//
//Recommanded setting: $Config['StaticContentURL'] = $Config['SiteURL'];
//Or if Zed is the site root: $Config['StaticContentURL'] = '';
//With CoralCDN: $Config['StaticContentURL'] = . '.nyud.net';
//
$Config['StaticContentURL'] = '';
//$Config['StaticContentURL'] = get_server_url() . '.nyud.net';
//Scenes
define('SCENE_DIR', 'content/scenes');
define('SCENE_URL', $Config['StaticContentURL'] . '/' . SCENE_DIR);
//Stories
define('STORIES_DIR', "content/stories");
//Profile's photos
define('PHOTOS_DIR', 'content/users/_photos');
define('PHOTOS_URL', $Config['StaticContentURL'] . '/' . PHOTOS_DIR);
//ImageMagick paths
//Be careful on Windows platform convert could match the NTFS convert command.
$Config['ImageMagick']['convert'] = 'convert';
$Config['ImageMagick']['mogrify'] = 'mogrify';
$Config['ImageMagick']['composite'] = 'composite';
$Config['ImageMagick']['identify'] = 'identify';
////////////////////////////////////////////////////////////////////////////////
/// ///
/// V. Sessions ///
/// ///
////////////////////////////////////////////////////////////////////////////////
//Sessions
//If you want to use a common table of sessions / user handling
//with several websites, specify a different resource id for each site.
$Config['ResourceID'] = 21;
//PHP variables
ini_set('session.serialize_handler', 'wddx');
ini_set('session.save_path', 'cache/sessions');
ini_set('session.gc_maxlifetime', 345600); //4 days, for week-end story pause and continue url
?>
\ No newline at end of file
diff --git a/includes/core.php b/includes/core.php
index ca7bfa5..1a49a18 100644
--- a/includes/core.php
+++ b/includes/core.php
@@ -1,488 +1,548 @@
<?php
/*
* Zed
* (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* Core
*/
////////////////////////////////////////////////////////////////////////////////
/// ///
/// Configures PHP and loads site-wide used libraries ///
/// ///
////////////////////////////////////////////////////////////////////////////////
//No register globals
ini_set('register_globals', 'off');
error_reporting(E_ALL & ~E_NOTICE);
//Load libraries
include_once("config.php"); //Site config
include_once("error.php"); //Error management
include_once("mysql.php"); //MySQL layer
include_once("sessions.php"); //Sessions handler
////////////////////////////////////////////////////////////////////////////////
/// ///
/// Information helper methods ///
/// ///
////////////////////////////////////////////////////////////////////////////////
//Gets username from specified user_id
function get_name ($id) {
global $db;
$id = $db->sql_escape($id);
$sql = 'SELECT perso_nickname FROM '. TABLE_PERSOS . " WHERE perso_id = '$id'";
if (!$result = $db->sql_query($sql)) message_die(SQL_ERROR, "Can't query persos table.", '', __LINE__, __FILE__, $sql);
$row = $db->sql_fetchrow($result);
return $row['perso_nickname'];
}
//Gets user_id from specified username
function get_userid ($username) {
global $db;
$username = $db->sql_escape($username);
$sql = 'SELECT user_id FROM '. TABLE_USERS . " WHERE username LIKE '$username'";
if (!$result = $db->sql_query($sql)) message_die(SQL_ERROR, "Can't query users table.", '', __LINE__, __FILE__, $sql);
$row = $db->sql_fetchrow($result);
return $row['user_id'];
}
function registry_get ($key) {
global $db;
$key = $db->sql_escape($key);
$sql = "SELECT registry_value FROM " . TABLE_REGISTRY . " WHERE registry_key = '$key'";
if (!$result = $db->sql_query($sql)) message_die(SQL_ERROR, "Can't read registry.", '', __LINE__, __FILE__, $sql);
$row = $db->sql_fetchrow($result);
return $row['registry_value'];
}
function registry_set ($key, $value) {
global $db;
$key = $db->sql_escape($key);
$value = $db->sql_escape($value);
$sql = "REPLACE INTO " . TABLE_REGISTRY . " (registry_key, registry_value) VALUES ('$key', '$value')";
if (!$db->sql_query($sql))
message_die(SQL_ERROR, "Can't update registry", '', __LINE__, __FILE__, $sql);
}
////////////////////////////////////////////////////////////////////////////////
/// ///
/// Misc helper methods ///
/// ///
////////////////////////////////////////////////////////////////////////////////
/*
* Generates a random string
* @author Pierre Habart <p.habart@ifrance.com>
*
* @param string $format The format e.g. AAA111
* @return string a random string
*/
function genereString ($format) {
mt_srand((double)microtime()*1000000);
$str_to_return="";
$t_alphabet=explode(",","A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z");
$t_number=explode(",","1,2,3,4,5,6,7,8,9,0");
for ($i=0;$i<strlen($format);$i++)
{
if (ereg("^[a-zA-Z]",$format[$i]))
{
$add=$t_alphabet[mt_rand() % sizeof($t_alphabet)];
if (ereg("^[a-z]",$format[$i]))
$add=strtolower($add);
}
elseif(ereg("^[0-9]",$format[$i]))
$add=$t_number[mt_rand() % sizeof($t_number)];
else $add="?";
$str_to_return.=$add;
}
return $str_to_return;
}
function generer_hexa($longueur) {
mt_srand((double)microtime()*1000000);
$str_to_return="";
$t_number=explode(",","1,2,3,4,5,6,7,8,9,0,A,B,C,D,E,F");
for ($i = 0 ; $i < $longueur ; $i++) {
$str_to_return .= $t_number[mt_rand() % sizeof($t_number)];
}
return $str_to_return;
}
//Plural management
function s ($amount) {
if ($amount > 1) return "s";
}
function x ($amount) {
if ($amount > 1) return "x";
}
//Debug
function dprint_r ($mixed) {
echo "<pre>", print_r($mixed, true), "</pre>";
}
//GUID
function new_guid() {
$characters = explode(",","a,b,c,d,e,f,0,1,2,3,4,5,6,7,8,9");
$guid = "";
for ($i = 0 ; $i < 36 ; $i++) {
if ($i == 8 || $i == 13 || $i == 18 || $i == 23) {
$guid .= "-";
} else {
$guid .= $characters[mt_rand() % sizeof($characters)];
}
}
return $guid;
}
function is_guid ($expression) {
//We avoid regexp to speed up the check
//A guid is a 36 characters string
if (strlen($expression) != 36) return false;
$expression = strtolower($expression);
for ($i = 0 ; $i < 36 ; $i++) {
if ($i == 8 || $i == 13 || $i == 18 || $i == 23) {
//with dashes
if ($expression[$i] != "-") return false;
} else {
//and numbers
if (!is_numeric($expression[$i]) && $expression[$i] != 'a' && $expression[$i] != 'b' && $expression[$i] != 'c' && $expression[$i] != 'd' && $expression[$i] != 'e' && $expression[$i] != 'f' ) return false;
}
}
return true;
}
/*
* Gets file extension
* @param string $file the file to get the extension
*/
function get_extension ($file) {
$dotPosition = strrpos($file, ".");
return substr($file, $dotPosition + 1);
}
/*
* Determines if a string starts with specified substring
* @param string $haystack the string to check
* @param string $needle the substring to determines if it's the start
* @param boolean $case_sensitive determines if the search must be case sensitive
* @return boolean true if $haystack starts with $needle ; otherwise, false.
*/
function string_starts_with ($haystack, $needle, $case_sensitive = true) {
if (!$case_sensitive) {
$haystack = strtoupper($haystack);
$needle = strtoupper($needle);
}
if ($haystack == $needle) return true;
return strpos($haystack, $needle) === 0;
}
+/*
+ * Inserts a message into the supralog
+ * @param string $category the entry category
+ * @param string $message the message to log
+ * @param string $source the entry source.
+ */
+function supralog ($category, $message, $source = null) {
+ global $db, $CurrentUser, $CurrentPerso;
+ $category = $db->sql_query_express($category);
+ $message = $db->sql_query_express($message);
+ $source = $db->sql_query_express($source ? $source : $_SERVER['SERVER_ADDR']);
+ $ip = $_SERVER['REMOTE_ADDR'];
+ $sql = "INSERT INTO " . TABLE_LOG .
+ " (entry_ip, user_id, perso_id, entry_category, entry_message, entry_source) VALUES
+ ('$ip', $CurrentUser->id, $CurrentPerso->id, '$category', '$message', '$source')";
+ if ( !($result = $db->sql_query($sql)) )
+ message_die(SQL_ERROR, "Can't log this entry.", '', __LINE__, __FILE__, $sql);
+}
+
////////////////////////////////////////////////////////////////////////////////
/// ///
/// Localization (l10n) ///
/// ///
////////////////////////////////////////////////////////////////////////////////
/*
* Defines LANG constant to lang to print
*/
function initialize_lang () {
//If $_SESSION['lang'] doesn't exist yet, find a common language
if (!array_key_exists('lang', $_SESSION)) {
$lang = find_lang();
$_SESSION['lang'] = $lang ? $lang : '-';
}
if ($_SESSION['lang'] != '-')
define('LANG', $_SESSION['lang']);
}
/*
* Gets a common lang spoken by the site and the user
* @return string the language
*/
function find_lang () {
if (file_exists('lang') && is_dir('lang')) {
//Gets lang/ subdirectories: this is the list of available languages
$handle = opendir('lang');
while ($file = readdir($handle)) {
if ($file != '.' && $file != '..' && is_dir("lang/$file")) {
$langs[] = $file;
}
}
//The array $langs contains now the language available.
//Gets the langs the user should want:
if (!$userlangs = get_http_accept_languages())
return;
//Gets the intersection between the both languages arrays
//If it matches, returns first result
$intersect = array_intersect($userlangs, $langs);
if (count($intersect)) {
return $intersect[0];
}
- //Now it's okay with Opera and Firefox but Internet Explorer
- //will return en-US and not en or fr-BE and not fr, so second pass
+ //Now it's okay with Opera and Firefox but Internet Explorer will
+ //by default return en-US and not en or fr-BE and not fr, so second pass
foreach ($userlangs as $userlang) {
$lang = explode('-', $userlang);
if (count($lang) > 1)
$userlangs2[] = $lang[0];
}
$intersect = array_intersect($userlangs2, $langs);
if (count($intersect)) {
return $intersect[0];
}
}
}
/*
* Returns the languages accepted by the browser, by order of priority
* @return Array a array of languages string
*/
function get_http_accept_languages () {
//What language to print is sent by browser in HTTP_ACCEPT_LANGUAGE var.
//This will be something like en,fr;q=0.8,fr-fr;q=0.5,en-us;q=0.3
if (!array_key_exists('HTTP_ACCEPT_LANGUAGE', $_SERVER)) {
return null;
}
$http_accept_language = explode(',', $_SERVER["HTTP_ACCEPT_LANGUAGE"]);
foreach ($http_accept_language as $language) {
$userlang = explode(';q=', $language);
if (count($userlang) == 1) {
$userlangs[] = array(1, $language);
} else {
$userlangs[] = array($userlang[1], $userlang[0]);
}
}
rsort($userlangs);
foreach ($userlangs as $userlang) {
$result[] = $userlang[1];
}
return $result;
}
/*
* Loads specified language Smarty configuration file
*
* @param string $file the file to load
* @param mixed $sections array of section names, single section or null
*/
function lang_load ($file, $sections = null) {
global $smarty;
//Loads English file as fallback if some parameters are missing
if (file_exists("lang/en/$file"))
$smarty->config_load("lang/en/$file", $sections);
//Loads wanted file (if it exists and a language have been defined)
if (defined('LANG') && LANG != 'en' && file_exists('lang/' . LANG . '/' . $file))
$smarty->config_load('lang/' . LANG . '/' . $file, $sections);
}
/*
* Gets a specified language expression defined in configuration file
*
* @param string $key the configuration key matching the value to get
* @return string The value in the configuration file
*/
function lang_get ($key) {
global $smarty;
$smartyConfValue = $smarty->config_vars[$key];
return $smartyConfValue ? $smartyConfValue : "#$key#";
}
////////////////////////////////////////////////////////////////////////////////
/// ///
/// Zed date and time helper methods ///
/// ///
////////////////////////////////////////////////////////////////////////////////
/*
* Converts a YYYYMMDD or YYYY-MM-DD timestamp to unixtime
*/
function to_unixtime ($timestamp) {
switch (strlen($timestamp)) {
case 8:
//YYYYMMDD
return mktime(0, 0, 0, substr($timestamp, 4, 2), substr($timestamp, 6, 2), substr($timestamp, 0, 4));
case 10:
//YYYY-MM-DD
return mktime(0, 0, 0, substr($timestamp, 5, 2), substr($timestamp, 8, 2), substr($timestamp, 0, 4));
default:
throw new Exception("timestamp is not a valid YYYYMMDD or YYYY-MM-DD timestamp: $timestamp");
}
}
/*
* Converts a unixtime to the YYYYMMDD or YYYY-MM-DD timestamp format
*
* @param int $unixtime the time to convert
* @param int $format 8 or 10. If 8 (default), will output YYYYMMDD. If 10, YYYY-MM-DD.
*/
function to_timestamp ($unixtime = null, $format = 8) {
//If no parameter is specified (or null, or false), current time is used
//==== allows to_timestamp(0) to return correct 1970-1-1 value.
if ($unixtime === null || $unixtime === false) $unixtime = time();
switch ($format) {
case 8:
//YYYYMMDD
return date('Ymd', $unixtime);
case 10:
//YYYY-MM-DD
return date('Y-m-d', $unixtime);
default:
throw new Exception("format must be 8 (YYYYMMDD) or 10 (YYYY-MM-DD) and not $format.");
}
}
/*
* Converts a unixtime to the Hypership time format.
*/
function get_hypership_time ($unixtime = null) {
//If unixtime is not specified, it's now
if ($unixtime === null) $unixtime = time();
//Hypership time is a count of days since launch @ 2010-01-25 00:00:00
//Followed by a fraction of the current day /1000, like the internet time
//but in UTC timezone and not Switzerland CET/CEST.
//We don't need to use floor(), as we output the result at int, truncating
//automatically decimal values instead of round it (like in C).
$seconds = $unixtime - 1264377600;
$days = $seconds / 86400;
$fraction = ($seconds % 86400) / 86.4;
return sprintf("%d.%03d", $days, $fraction);
}
////////////////////////////////////////////////////////////////////////////////
/// ///
/// URL helpers functions ///
/// ///
////////////////////////////////////////////////////////////////////////////////
/*
* Gets URL
* @return string URL
*/
function get_url () {
global $Config;
if (func_num_args() > 0) {
$pieces = func_get_args();
return $Config['BaseURL'] . '/' . implode('/', $pieces);
} elseif ($Config['BaseURL'] == "" || $Config['BaseURL'] == "/index.php") {
return "/";
} else {
return $Config['BaseURL'];
}
}
/*
* Gets page URL
* @return string URL
*/
function get_page_url () {
$url = $_SERVER['SCRIPT_NAME'] . $_SERVER['PATH_INFO'];
if (substr($url, -10) == "/index.php") {
return substr($url, 0, -9);
}
return $url;
}
/*
* Gets server URL
* @todo find a way to detect https:// on non standard port
* @return string the server URL
*/
function get_server_url () {
switch ($port = $_SERVER['SERVER_PORT']) {
case '80':
return "http://$_SERVER[SERVER_NAME]";
case '443':
return "https://$_SERVER[SERVER_NAME]";
default:
return "http://$_SERVER[SERVER_NAME]:$_SERVER[SERVER_PORT]";
}
}
/*
* Gets $_SERVER['PATH_INFO'] or computes the equivalent if not defined.
* @return string the relevant URL part
*/
function get_current_url () {
global $Config;
//Gets relevant URL part from relevant $_SERVER variables
if (array_key_exists('PATH_INFO', $_SERVER)) {
//Without mod_rewrite, and url like /index.php/controller
//we use PATH_INFO. It's the easiest case.
return $_SERVER["PATH_INFO"];
}
//In other cases, we'll need to get the relevant part of the URL
$current_url = get_server_url() . $_SERVER['REQUEST_URI'];
//Relevant URL part starts after the site URL
$len = strlen($Config['SiteURL']);
//We need to assert it's the correct site
if (substr($current_url, 0, $len) != $Config['SiteURL']) {
dieprint_r(GENERAL_ERROR, "Edit includes/config.php and specify the correct site URL<br /><strong>Current value:</strong> $Config[SiteURL]<br /><strong>Expected value:</strong> a string starting by " . get_server_url(), "Setup");
}
if (array_key_exists('REDIRECT_URL', $_SERVER)) {
//With mod_rewrite, we can use REDIRECT_URL
//We takes the end of the URL, ie *FROM* $len position
return substr(get_server_url() . $_SERVER["REDIRECT_URL"], $len);
}
//Last possibility: use REQUEST_URI, but remove QUERY_STRING
//If you need to edit here, use $_SERVER['REQUEST_URI']
//but you need to discard $_SERVER['QUERY_STRING']
//We takes the end of the URL, ie *FROM* $len position
$url = substr(get_server_url() . $_SERVER["REQUEST_URI"], $len);
//But if there are a query string (?action=... we need to discard it)
if ($_SERVER['QUERY_STRING']) {
return substr($url, 0, strlen($url) - strlen($_SERVER['QUERY_STRING']) - 1);
}
return $url;
}
/*
* Gets an array of url fragments to be processed by controller
*/
function get_current_url_fragments () {
$url_source = get_current_url();
if ($url_source == '/index.php') return array();
return explode('/', substr($url_source, 1));
}
+////////////////////////////////////////////////////////////////////////////////
+/// ///
+/// URL xmlHttpRequest helpers functions ///
+/// ///
+////////////////////////////////////////////////////////////////////////////////
+
+/*
+ * Gets an hash value to check the integrity of URLs in /do.php calls
+ * @param Array $args the args to compute the hash
+ * @return the hash paramater for your xmlHttpRequest url
+ */
+function get_xhr_hash ($args) {
+ global $Config;
+
+ array_shift($args);
+ return md5($_SESSION['ID'] . $Config['SecretKey'] . implode('', $args));
+}
+
+/*
+ * Gets the URL to call do.php, the xmlHttpRequest controller
+ * @return string the xmlHttpRequest url, with an integrity hash
+ */
+function get_xhr_hashed_url () {
+ global $Config;
+
+ $args = func_get_args();
+ $args[] = get_xhr_hash($args);
+ return $Config['DoURL'] . '/' . implode('/', $args);
+}
+
+/*
+ * Gets the URL to call do.php, the xmlHttpRequest controller
+ * @return string the xmlHttpRequest url
+ */
+function get_xhr_url () {
+ global $Config;
+
+ $args = func_get_args();
+ return $Config['DoURL'] . '/' .implode('/', $args);
+}
+
?>
\ No newline at end of file
diff --git a/includes/geo/body.php b/includes/geo/body.php
index 8306270..c6d6c57 100644
--- a/includes/geo/body.php
+++ b/includes/geo/body.php
@@ -1,144 +1,148 @@
<?php
/*
* Geo body class
*
* 0.1 2010-01-27 21:51 Autogenerated by Pluton Scaffolding
*
* @package Zed
* @subpackage Geo
* @copyright Copyright (c) 2010, Dereckson
* @license Released under BSD license
* @version 0.1
*
*/
class GeoBody {
public $code;
public $name;
public $hypership;
public $asteroid;
public $moon;
public $planet;
public $star;
public $orbital;
public $hidden;
public $location;
public $description;
public $lastError;
/*
* Initializes a new instance
* @param int $code the primary key
*/
function __construct ($code = null) {
if ($code) {
$this->code = $code;
$this->load_from_database();
}
}
/*
* Loads the object body (ie fill the properties) from the $_POST array
*/
function load_from_form ($readBoolean = true) {
if (array_key_exists('name', $_POST)) $this->name = $_POST['name'];
if ($readBoolean) {
if (array_key_exists('hypership', $_POST)) $this->hypership = $_POST['hypership'];
if (array_key_exists('star', $_POST)) $this->start = $_POST['star'];
if (array_key_exists('asteroid', $_POST)) $this->hypership = $_POST['asteroid'];
if (array_key_exists('moon', $_POST)) $this->start = $_POST['moon'];
if (array_key_exists('planet', $_POST)) $this->start = $_POST['planet'];
if (array_key_exists('orbital', $_POST)) $this->start = $_POST['orbital'];
if (array_key_exists('hidden', $_POST)) $this->start = $_POST['hidden'];
}
if (array_key_exists('location', $_POST)) $this->location = $_POST['location'];
if (array_key_exists('description', $_POST)) $this->description = $_POST['description'];
}
/*
* Loads the object body (ie fill the properties) from the database
*/
function load_from_database () {
global $db;
$sql = "SELECT * FROM " . TABLE_BODIES . " WHERE body_code = '" . $this->code . "'";
if ( !($result = $db->sql_query($sql)) ) message_die(SQL_ERROR, "Unable to query geo_bodies", '', __LINE__, __FILE__, $sql);
if (!$row = $db->sql_fetchrow($result)) {
$this->lastError = "body unkwown: " . $this->code;
return false;
}
$this->name = $row['body_name'];
$this->location = $row['body_location'];
$this->description = $row['body_description'];
if ($row['body_status']) {
$flags = explode(',', $row['body_status']);
foreach ($flags as $flag) {
$this->$flag = true;
}
}
return true;
}
/*
* Gets status
*/
function get_status () {
$flags = array('hypership','asteroid','moon','planet','star','orbital','hidden');
foreach ($flags as $flag) {
if ($this->$flag) {
$status[] = $flag;
}
}
return implode(',', $status);
}
/*
* Gets the kind of place the body is (e.g. asteroid)
*/
function kind () {
//If a location can be described by 2 flags, order the relevant flags list
//by priority, as it'll return the first trigerred.
//e.g. a moon converted in hypership will be "hypership" and not "moon".
$relevantFlags = array('hypership','asteroid','moon','planet','star','orbital');
foreach ($relevantFlags as $flag) {
if ($this->$flag) {
return $flag;
}
}
return "";
}
+ function __toString () {
+ return $this->name;
+ }
+
/*
* Saves to database
*/
function save_to_database () {
global $db;
$code = $this->code ? "'" . $db->sql_escape($this->code) . "'" : 'NULL';
$name = $db->sql_escape($this->name);
$status = get_status();
$location = $db->sql_escape($this->location);
$description = $db->sql_escape($this->description);
//Updates or inserts
$sql = "REPLACE INTO " . TABLE_BODIES . " (`body_code`, `body_name`, `body_status`, `body_location`, `body_description`) VALUES ($code, '$name', '$status', '$location', '$description')";
if (!$db->sql_query($sql)) {
message_die(SQL_ERROR, "Unable to save", '', __LINE__, __FILE__, $sql);
}
if (!$code) {
//Gets new record code value
$this->code = $db->sql_nextid();
}
}
}
?>
\ No newline at end of file
diff --git a/includes/geo/location.php b/includes/geo/location.php
index 475b841..951e3c8 100644
--- a/includes/geo/location.php
+++ b/includes/geo/location.php
@@ -1,306 +1,340 @@
<?php
require_once('body.php');
require_once('place.php');
+require_once('point3D.php');
require_once('includes/objects/ship.php');
/*
* Geo location class
*
* 0.1 2010-01-28 18:52 DcK
*
* @package Zed
* @subpackage Geo
* @copyright Copyright (c) 2010, Dereckson
* @license Released under BSD license
* @version 0.1
*
+ * @todo initializes $point3D from $body or $ship own locations;
+ *
*/
class GeoLocation {
private $data;
/*
* @var GeoBody a body object
*/
public $body = null;
/*
* @var GeoPlace a place object
*/
public $place = null;
+
+ /*
+ * @var GeoPoint3D a point identified by x, y, z coordinates
+ */
+ public $point3D = null;
/*
* @var Ship a ship object
*/
public $ship = null;
function __construct ($global = null, $local = null) {
if (!$global) {
$this->data = array();
} elseif (ereg("[BS][0-9]{5}[0-9]{3}", $global)) {
$this->data[0] = $global;
} elseif (ereg("[BS][0-9]{5}", $global)) {
$this->data[0] = $global;
+ } elseif (ereg("^xyz\:", $global)) {
+ $coords = sscanf($global, "xyz: [%d, %d, %d]");
+ if (count($coords) == 3) {
+ $this->data[0] = $global;
+ } else {
+ throw new Exception("Invalid expression: $global");
+ }
} else {
global $db;
$name = $db->sql_escape($global);
$sql = "SELECT location_code FROM " . TABLE_LOCATIONS . " WHERE location_name LIKE '$name'";
$code = $db->sql_query_express($sql);
if ($code) {
$this->data[0] = $code;
return;
}
throw new Exception("Invalid expression: $global");
}
//TODO: handle $local in a better way: from the global location, gets
//a local location handler. Or a some inheriance, like a class
//HypershipGeoLocation extending GeoLocation.
if ($local !== null) $this->data[1] = $local;
$this->load_classes();
}
function load_classes () {
//No data, no class to load
if (!count($this->data))
return;
//Loads global classes
$global = $this->data[0];
$code = substr($global, 1, 5);
switch ($global[0]) {
case 'B':
switch (strlen($global)) {
case 9:
$this->place = GeoPlace::from_code($global);
case 6:
$this->body = new GeoBody($code);
break;
}
break;
case 'S':
$this->ship = new Ship($code);
break;
+
+ case 'x':
+ $coords = sscanf($global, "xyz: [%d, %d, %d]");
+ if (count($coords) == 3) {
+ $this->point3D = new GeoPoint3D($coords[0], $coords[1], $coords[2]);
+ }
+ break;
}
}
function __get ($variable) {
switch ($variable) {
/* main variables */
case 'global':
return $this->data[0];
break;
case 'local':
return $this->data[1];
break;
/* global location */
case 'type':
return $this->data[0][0];
case 'body_code':
if ($this->data[0][0] == 'B') {
return substr($this->data[0], 1, 5);
}
return null;
case 'place_code':
if ($this->data[0][0] == 'B') {
return substr($this->data[0], 6, 3);
}
return null;
case 'ship_code':
if ($this->data[0][0] == 'S') {
return substr($this->data[0], 1, 5);
}
return null;
case 'body_kind':
if ($this->data[0][0] == 'B' && $this->body != null) {
if ($kind = $this->body->kind()) {
return $kind;
}
} elseif ($this->data[0][0] == 'S') {
return 'ship';
}
return 'place';
case 'containsGlobalLocation':
return count($this->data) > 0;
case 'containsLocalLocation':
return count($this->data) > 1;
default:
throw new Exception("Unknown variable: $variable");
break;
}
}
/*
* Checks if the place exists
*
* @return boolean true if the place exists ; false otherwise
*/
function exists () {
$n = count($this->data);
//If not defined, it doesn't exist
if ($n == 0) return false;
//Checks global location
switch ($this->data[0][0]) {
case 'B':
switch (strlen($this->data[0])) {
case 9:
if (!$place = GeoPlace::from_code($this->data[0]))
return false;
break;
case 6:
$body = new GeoBody(substr($this->data[0], 1));
if ($body->lastError) return false;
break;
default:
message_die(GENERAL_ERROR, "Invalid global location expression size: " . $this->data[0], "GeoLocation exists method", __LINE__, __FILE__);
}
break;
case 'S':
$ship = new Ship(substr($this->data[0], 1));
if ($body->lastError) return false;
break;
default:
message_die(GENERAL_ERROR, "Invalid global location expression size: " . $this->data[0], "GeoLocation exists method", __LINE__, __FILE__);
return false;
}
if ($n > 1) {
message_die(GENERAL_ERROR, "Can't check if a local place exists yet.", "GeoLocation exists method", __LINE__, __FILE__);
}
return true;
}
function equals ($expression) {
+ //Are global location equals?
+
+ //TODO: creates a better set of rules to define when 2 locations are equa l.
+ if (is_a($expression, 'GeoLocation')) {
+ if (!$this->equals($expression->data[0])) {
+ return false;
+ }
+ if (count($expression->data) + count($this->data) > 2) {
+ return $expression->data[1] == $this->data[1];
+ }
+ }
+
if ($expression == $this->data[0]) return true;
$n1 = strlen($expression);
$n2 = strlen($this->data[0]);
if ($n1 > $n2) {
return substr($expression, 0, $n2) == $this->data[0];
}
return false;
}
function __toString () {
if (!$this->data[0])
return "";
switch ($this->data[0][0]) {
case 'S':
$ship = new Ship($this->ship_code);
$location[] = $ship->name;
break;
case 'B':
$body = new GeoBody($this->body_code);
$location[] = $body->name ? $body->name : lang_get('UnknownBody');
if (strlen($this->data[0]) == 9) {
$place = GeoPlace::from_code($this->data[0]);
$location[] = $place->name ? $place->name : lang_get('UnknownPlace');
}
break;
default:
message_die(GENERAL_ERROR, "Unknown location identifier: $type.<br />Expected: B or S.");
}
return implode(", ", array_reverse($location));
}
function __set ($variable, $value) {
switch ($variable) {
/* main variables */
case 'global':
$this->data[0] = $value;
break;
case 'local':
$this->data[1] = $value;
break;
/* global location */
case 'type':
if ($value == 'B' || $value == 'S') {
if (!$this->data[0]) {
$this->data[0] = $value;
} else {
$this->data[0][0] = $value;
}
}
break;
case 'body_code':
if (ereg("[0-9]{1,5}", $value)) {
$value = sprintf("%05d", $value);
if (!$this->data[0]) {
$this->data[0] = "B" . $value;
return;
} elseif ($this->data[0][0] == 'B') {
$this->data[0] = "B" . $value . substr($this->data[0], 6);
return;
}
throw new Exception("Global location isn't a body.");
}
throw new Exception("$value isn't a valid body code");
case 'ship_code':
if (ereg("[0-9]{1,5}", $value)) {
$value = sprintf("%05d", $value);
if (!$this->data[0]) {
$this->data[0] = "S" . $value;
return;
} elseif ($this->data[0][0] == 'S') {
$this->data[0] = "S" . $value . substr($this->data[0], 6);
return;
}
throw new Exception("Global location isn't a ship.");
}
throw new Exception("$value isn't a valid ship code");
case 'place_code':
if (!ereg("[0-9]{1,3}", $value)) {
throw new Exception("$value isn't a valid place code");
}
$value = sprintf("%03d", $value);
if ($this->data[0][0] == 'B') {
$this->data[0] = substr($this->data[0], 0, 6) . $value;
}
throw new Exception("Global location isn't a body.");
default:
throw new Exception("Unknown variable: $variable");
break;
}
}
}
?>
\ No newline at end of file
diff --git a/includes/geo/point3D.php b/includes/geo/point3D.php
new file mode 100644
index 0000000..5df9b29
--- /dev/null
+++ b/includes/geo/point3D.php
@@ -0,0 +1,68 @@
+<?php
+
+/*
+ * Geo point 3D class
+ *
+ * 0.1 2010-02-23 14:14 DcK
+ *
+ * @package Zed
+ * @subpackage Geo
+ * @copyright Copyright (c) 2010, Dereckson
+ * @license Released under BSD license
+ * @version 0.1
+ *
+ */
+class GeoPoint3D implements IteratorAggregate {
+ //
+ // x, y, z public properties
+ //
+
+ /*
+ * @var integer the x coordinate
+ */
+ public $x;
+
+ /*
+ * @var integer the y coordinate
+ */
+ public $y;
+
+ /*
+ * @var integer the z coordinate
+ */
+ public $z;
+
+ //
+ // constructor / toString
+ //
+
+ /*
+ * Initializes a new instance of GeoPoint3D class
+ */
+ function __construct ($x, $y, $z) {
+ $this->x = $x;
+ $this->y = $y;
+ $this->z = $z;
+ }
+
+ /*
+ * Returns a xyz: [x, y, z] string representation of the point coordinates
+ */
+ function __toString () {
+ return sprintf("xyz: [%d, %d, %d]", $this->x, $this->y, $this->z);
+ }
+
+ //
+ // Implementing IteratorAggregate
+ //
+
+ /*
+ * Retrieves class iterator. It traverses x, y and z.
+ * @return Traversable the iterator
+ */
+ function getIterator () {
+ return new ArrayIterator($this);
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/includes/geo/scene.php b/includes/geo/scene.php
index ecc1393..bb55810 100644
--- a/includes/geo/scene.php
+++ b/includes/geo/scene.php
@@ -1,130 +1,142 @@
<?php
/*
* Geo scene class
*
* 0.1 2010-01-30 17:42 DcK
*
* @package Zed
* @subpackage Geo
* @copyright Copyright (c) 2010, Dereckson
* @license Released under BSD license
* @version 0.1
*
*/
require_once('location.php');
if (!defined('SCENE_DIR')) define('SCENE_DIR', 'content/scenes');
class GeoScene {
/*
* @var string Last error warning
*/
public $lastError;
/*
* @var string File scene to serve
*/
public $sceneFile;
/*
* @var GeoLocation the location to print the scene
*/
public $location;
/*
* Initializes a new GeoScene instance
* @param GeoLocation $location location the scene is to print
*/
function __construct ($location) {
$this->location = $location;
//Gets local scene
if ($location->containsLocalLocation) {
if ($this->get_local_scene()) return;
}
//Gets global scene
if ($location->containsGlobalLocation) {
if ($this->get_global_scene()) return;
}
//If not scene found, let's set a warning
$this->lastError = "No scene found.";
}
/*
* Gets local scene
* @return boolean true if a scene have been found ; otherwise, false.
*/
private function get_local_scene () {
return false;
}
/*
* Gets global scene
* @return boolean true if a scene have been found ; otherwise, false.
*/
private function get_global_scene () {
$location = $this->location;
if ($location->place) {
if ($this->try_get_scene($location->global)) {
return true;
}
}
if ($location->body) {
if ($this->try_get_scene('B' . $location->body->code)) {
return true;
}
}
return false;
}
public static function get_file_extension ($file) {
$pathinfo = pathinfo($file);
return $pathinfo['extension'];
}
public function render () {
if ($file = $this->sceneFile) {
switch ($ext = GeoScene::get_file_extension($file)) {
case 'png':
case 'jpg':
case 'gif':
case 'bmp':
echo "<img src=\"$file\" />";
break;
case 'tpl':
global $smarty;
$template_dir = $smarty->template_dir;
$smarty->template_dir = getcwd();
+
+ //$this->location is the object reference
+ //Some objects like the hypership move, so we also need to know where there are.
+ //From the template, this object location is assigned to $location
+ //To get $this->location from template, use $CurrentPerso->location
+ if ($this->location->body) {
+ $smarty->assign("location", new GeoLocation($this->location->body->location));
+ } elseif ($this->location->ship) {
+ $smarty->assign("location", new GeoLocation($this->location->ship->location));
+ }
+
$smarty->assign("SCENE_URL", defined('SCENE_URL') ? SCENE_URL : '/' . SCENE_DIR);
+ lang_load('scenes.conf', $this->location->global);
$smarty->display($file);
$smarty->template_dir = $template_dir;
break;
case 'php':
message_die(HACK_ERROR, ".php scene files not allowed without review", '', __LINE__, __FILE__);
default:
message_die(GENERAL_ERROR, "Can't handle $ext extension for $file scene", 'GeoScene render error', __LINE__, __FILE__);
}
echo "\n\n";
}
}
private function try_get_scene ($code) {
$file = SCENE_DIR . "/$code";
$extensions = array('tpl', 'png', 'jpg', 'gif', 'bmp', 'swf', 'html', 'php');
foreach ($extensions as $ext) {
if (file_exists("$file.$ext")) {
$this->sceneFile = "$file.$ext";
return true;
}
}
return false;
}
}
?>
\ No newline at end of file
diff --git a/includes/login.php b/includes/login.php
index cf211dc..d6b35b4 100644
--- a/includes/login.php
+++ b/includes/login.php
@@ -1,106 +1,117 @@
<?php
/*
* Zed
* (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* Login/logout
*/
if (!file_exists('/dev/urandom')) {
//We're on Windows, without reliable source of random numbers
define('Auth_OpenID_RAND_SOURCE', null);
}
require_once('Auth/OpenID/Consumer.php');
require_once('Auth/OpenID/DumbStore.php');
//require_once('Auth/OpenID/FileStore.php');
/*
function get_openid_consumer () {
if (!file_exists('/dev/urandom')) {
//We're on Windows, without reliable source of random numbers
define('Auth_OpenID_RAND_SOURCE', null);
}
$fs = new Auth_OpenID_FileStore('cache/openid');
return new Auth_OpenID_Consumer($fs);
}
*/
function openid_login ($url) {
global $db, $_SESSION, $LoginError, $LoginSuccessful;
$url = $db->sql_escape($url);
$sql = 'SELECT user_id FROM ' . TABLE_USERS_OPENID
. " WHERE openid_url LIKE '$url'";
if ($user_id = $db->sql_query_express($sql)) {
$sql = "UPDATE " . TABLE_SESSIONS . " SET user_id = '$user_id' WHERE session_id LIKE '$_SESSION[ID]'";
if (!$db->sql_query($sql)) message_die(SQL_ERROR, "Impossible de procéder à la connexion", '', __LINE__, __FILE__, $sql);
$LoginSuccessful = true;
setcookie("LastOpenID", $url, time() + 2592000);
header("location: " . get_url());
} else {
$LoginError = "To join Zed, you need an invite. Read the source to get one.";
}
}
if ($_GET['action'] == 'openid.login') {
//Gets Auth_OpenID_Consumer instance
$fs = new Auth_OpenID_DumbStore("rien n'est sûr mais c'est une piste");
//$fs = new Auth_OpenID_FileStore('cache/openid');
$consumer = new Auth_OpenID_Consumer($fs);
//$consumer = get_openid_consumer();
//Completes the OpenID transaction
$reply = $consumer->complete(get_server_url() . $_SERVER['REQUEST_URI']);
if ($reply->status == Auth_OpenID_SUCCESS) {
openid_login($reply->endpoint->claimed_id);
} elseif ($reply->message) {
$LoginError = "[OpenID] $reply->message";
} else {
$LoginError = "[OpenID] $reply->status";
}
} elseif ($_POST['LogIn']) {
//User have filled login form
if ($_POST['openid']) {
//Gets Auth_OpenID_Consumer instance
$fs = new Auth_OpenID_DumbStore("rien n'est sûr mais c'est une piste");
//$fs = new Auth_OpenID_FileStore('cache/openid');
$consumer = new Auth_OpenID_Consumer($fs);
//$consumer = get_openid_consumer();
//Starts the OpenID transaction and redirects user to provider url
if ($request = $consumer->begin($_POST['openid'])) {
- $url = $request->redirectURL(get_server_url(), "$Config[SiteURL]/?action=openid.login", false);
+ $url = $request->redirectURL(get_server_url(), "$Config[SiteURL]/?action=openid.login", false);
header("location: $url");
$LoginError = '<a href="' . $url . '">Click here to continue login</a>';
} else {
$LoginError = 'Invalid OpenID URL.';
}
} else {
//GESTION LOGIN
$Login = $_POST['username'];
$sql = "SELECT user_password, user_id FROM " . TABLE_USERS . " WHERE username = '$Login'";
if ( !($result = $db->sql_query($sql)) ) message_die(SQL_ERROR, "Impossible d'interroger le listing des utilisateurs", '', __LINE__, __FILE__, $sql);
if ($row = $db->sql_fetchrow($result)) {
if (!$row['user_password']) {
$LoginError = "This account exists but haven't a password defined. Use OpenID or contact dereckson (at) espace-win.org to fix that.";
} elseif ($row['user_password'] != md5($_POST['password'])) {
//PASS NOT OK
$LoginError = "Incorrect password.";
} else {
$sql = "UPDATE " . TABLE_SESSIONS . " SET user_id = '$row[user_id]' WHERE session_id LIKE '$_SESSION[ID]'";
if (!$db->sql_query($sql)) message_die(SQL_ERROR, "Impossible de procéder à la connexion", '', __LINE__, __FILE__, $sql);
$LoginSuccessful = true;
setcookie("LastUsername", $Login, time() + 2592000);
}
} else {
- //Login n'existe pas
+ //Idiot proof facility
+ //Redirects people using login page as invitation claim page
+ $sql = "SELECT * FROM " . TABLE_USERS_INVITES . " WHERE invite_for = '$Login'";
+ if (!$result = $db->sql_query($sql)) {
+ message_die(SQL_ERROR, "Can't get invites", '', __LINE__, __FILE__, $sql);
+ }
+ if ($row = $db->sql_fetchrow($result)) {
+ $url = get_url('invite', $Login, $_POST['password']);
+ header('location: ' . $url);
+ }
+
+ //Login not found
$LoginError = "Login not found.";
}
}
} elseif ($_POST['LogOut'] || $_GET['action'] == "user.logout") {
Logout();
}
?>
\ No newline at end of file
diff --git a/includes/mysql.php b/includes/mysql.php
index 319dc76..b6b5928 100644
--- a/includes/mysql.php
+++ b/includes/mysql.php
@@ -1,93 +1,98 @@
<?php
/*
* MySQL layer and helper class
*
* @package Zed
* @subpackage Pluton
* @copyright Copyright (c) 2010, Dereckson
* @license Released under BSD license
* @version 0.1
*
*/
if (!defined('SQL_LAYER')) {
define('SQL_LAYER', 'mysql');
class sql_db {
private $id;
function __construct($host = 'localhost', $username = 'root', $password = '' , $database = '') {
- $this->id = @mysql_connect($host, $username, $password) or die ("Can't connect to SQL server.");
+ $this->id = @mysql_connect($host, $username, $password) or $this->sql_die(); //or die ("Can't connect to SQL server.");
if ($database != '') {
mysql_select_db($database, $this->id);
}
}
+ function sql_die () {
+ include('start.html');
+ exit;
+ }
+
function sql_query ($query) {
return mysql_query($query, $this->id);
}
function sql_fetchrow ($result) {
return mysql_fetch_array($result);
}
function sql_error () {
$error['code'] = mysql_errno($this->id);
$error['message'] = mysql_error($this->id);
return $error;
}
function sql_numrows ($result) {
return mysql_num_rows($result);
}
function sql_nextid () {
return mysql_insert_id($this->id);
}
/*
* Express query method, returns an immediate and unique result
*
* @param string $query the query to execute
* @param string $error_message the error message
* @param boolean $return_as_string return result as string, and not as an array
*
* @return mixed the row or the scalar result
*/
function sql_query_express ($query = '', $error_message = "Impossible d'exécuter cette requête.", $return_as_string = true) {
if (!$query) {
return '';
} elseif (!$result = $this->sql_query($query)) {
message_die(SQL_ERROR, $error_message, '', __LINE__, __FILE__, $query);
} else {
$row = $this->sql_fetchrow($result);
return $return_as_string ? $row[0] : $row;
}
}
/*
* Escapes a SQL expression
*
* @param string expression The expression to escape
* @return string The escaped expression
*/
function sql_escape ($expression) {
return mysql_real_escape_string($expression);
}
function set_charset ($encoding) {
mysql_set_charset('utf8', $this->id);
}
}
}
$db = new sql_db($Config['sql']['host'], $Config['sql']['username'], $Config['sql']['password'], $Config['sql']['database']);
unset($Config['sql']);
//Sets SQL connexion in UTF8. PHP 5.2.3+
$db->set_charset('utf8');
?>
\ No newline at end of file
diff --git a/includes/objects/content.php b/includes/objects/content.php
new file mode 100644
index 0000000..ff4f37c
--- /dev/null
+++ b/includes/objects/content.php
@@ -0,0 +1,259 @@
+<?php
+
+/*
+ * Content class
+ *
+ * 0.1 2010-02-24 15:57 Autogenerated by Pluton Scaffolding
+ *
+ * @package Zed
+ * @copyright Copyright (c) 2010, Dereckson
+ * @license Released under BSD license
+ * @version 0.1
+ * @todo remove dbc temporary limitations (cf. /do.php upload_content and infra)
+ * @todo create a class ContentLocation and move location fields there
+ * @todo validate SQL schema and add in config.php TABLE_CONTENT tables
+ *
+ * [DESIGN BY CONTRACT] This class works only with the following assertions:
+ * i. Each content have EXACTLY ONE location
+ * ii. Location fields will not be modified
+ *
+ * If a content have more than one location, only the first occurence in
+ * content_locations table will be considered.
+ *
+ * If a content have no location, it will be ignored.
+ *
+ * If you edit content location, then call saveToDatabase, you will create
+ * a new location but future instances will contain first not deleted location.
+ *
+ */
+class Content {
+
+/* -------------------------------------------------------------
+ Properties
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+ public $id;
+ public $path;
+ public $user_id;
+ public $perso_id;
+ public $title;
+
+ public $location_global = null;
+ public $location_local = null;
+ public $location_k = null;
+
+ public $perso_name;
+ public $perso_nickname;
+
+/* -------------------------------------------------------------
+ Constructor, __toString
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+ /*
+ * Initializes a new Content instance
+ * @param int $id the primary key
+ */
+ function __construct ($id = null) {
+ if ($id) {
+ $this->id = $id;
+ $this->load_from_database();
+ }
+ }
+
+ /*
+ * Returns a string representation of current Content instance
+ * @return string the content title or path if title is blank.
+ */
+ function __toString () {
+ return $this->title ? $this->title : $this->path;
+ }
+
+/* -------------------------------------------------------------
+ Load/save class
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+ /*
+ * Loads the object Content (ie fill the properties) from the $_POST array
+ * @param boolean $allowSensibleFields if false, allow only location_local, location_k and title to be defined ; otherwise, allow all fields.
+ */
+ function load_from_form ($allowSensibleFields = false) {
+ if (array_key_exists('title', $_POST)) $this->title = $_POST['title'];
+ if (array_key_exists('location_local', $_POST)) $this->location_local = $_POST['location_local'];
+ if (array_key_exists('location_k', $_POST)) $this->location_k = $_POST['location_k'];
+
+ if ($allowSensibleFields) {
+ if (array_key_exists('path', $_POST)) $this->path = $_POST['path'];
+ if (array_key_exists('user_id', $_POST)) $this->user_id = $_POST['user_id'];
+ if (array_key_exists('perso_id', $_POST)) $this->perso_id = $_POST['perso_id'];
+ if (array_key_exists('location_global', $_POST)) $this->location_global = $_POST['location_global'];
+ }
+ }
+
+ /*
+ * Loads the object Content (ie fill the properties) from the database
+ */
+ function load_from_database () {
+ global $db;
+ $id = $db->sql_escape($this->id);
+ $sql = "SELECT * FROM content WHERE content_id = '" . $id . "'";
+ if ( !($result = $db->sql_query($sql)) ) message_die(SQL_ERROR, "Unable to query content", '', __LINE__, __FILE__, $sql);
+ if (!$row = $db->sql_fetchrow($result)) {
+ $this->lastError = "Content unkwown: " . $this->id;
+ return false;
+ }
+ $this->load_from_row($row);
+ return true;
+ }
+
+ /*
+ * Loads the object from row
+ */
+ function load_from_row ($row) {
+ $this->id = $row['content_id'];
+ $this->path = $row['content_path'];
+ $this->user_id = $row['user_id'];
+ $this->perso_id = $row['perso_id'];
+ $this->title = $row['content_title'];
+ $this->location_global = $row['location_global'];
+ $this->location_local = $row['location_local'];
+ $this->location_k = $row['location_k'];
+
+ if (array_key_exists('perso_name', $row)) $this->perso_name = $row['perso_name'];
+ if (array_key_exists('perso_nickname', $row)) $this->perso_nickname = $row['perso_nickname'];
+ }
+
+ /*
+ * Saves to database
+ */
+ function save_to_database () {
+ global $db;
+
+ $id = $this->id ? "'" . $db->sql_escape($this->id) . "'" : 'NULL';
+ $path = $db->sql_escape($this->path);
+ $user_id = $db->sql_escape($this->user_id);
+ $perso_id = $db->sql_escape($this->perso_id);
+ $title = $db->sql_escape($this->title);
+
+ $location_global = ($this->location_global !== null) ? "'" . $db->sql_escape($this->location_global) . "'" : 'NULL';
+ $location_local = ($this->location_local !== null) ? "'" . $db->sql_escape($this->location_local) . "'" : 'NULL';
+ $location_k = ($this->location_k !== null) ? "'" . $db->sql_escape($this->location_k) . "'" : 'NULL';
+
+ //Updates or inserts
+ $sql = "REPLACE INTO content_files (`content_id`, `content_path`, `user_id`, `perso_id`, `content_title`) VALUES ($id, '$path', '$user_id', '$perso_id', '$title')";
+ if (!$db->sql_query($sql)) {
+ message_die(SQL_ERROR, "Can't save content", '', __LINE__, __FILE__, $sql);
+ }
+
+ if (!$this->id) {
+ //Gets new record id value
+ $this->id = $db->sql_nextid();
+ }
+
+ //Saves location
+ $id = $this->id ? "'" . $db->sql_escape($this->id) . "'" : 'NULL';
+ $sql = "REPLACE INTO content_locations (location_global, location_local, location_k, content_id) VALUES ($location_global, $location_local, $location_k, $id)";
+ if (!$db->sql_query($sql))
+ message_die(SQL_ERROR, "Can't save content location", '', __LINE__, __FILE__, $sql);
+ }
+
+/* -------------------------------------------------------------
+ File handling helper methods
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+ /*
+ * Determines if the extension is valid
+ * @param string $ext The extension (without dot)
+ * @return boolean true if this extension is valid ; otherwise, false.
+ */
+ function is_valid_extension ($ext) {
+ switch ($ext = strtolower($ext)) {
+ //Pictures
+ case 'jpg':
+ case 'gif':
+ case 'png':
+ case 'bmp':
+ case 'xbm':
+ return true;
+
+ //Denied extension
+ default:
+ return false;
+ }
+ }
+
+ /*
+ * @return boolean true if the file have been handled
+ */
+ function handle_uploaded_file ($fileArray) {
+ if (count($fileArray) && $fileArray['error'] == 0) {
+ $this->path = "content/users/$this->user_id/$fileArray[name]";
+ if (!self::is_valid_extension(get_extension($file))) {
+ return false;
+ }
+ if (move_uploaded_file($fileArray['tmp_name'], $this->path)) {
+ return true;
+ } else {
+ $this->path = null;
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ /*
+ * Generates a thumbnail using ImageMagick binary
+ * @return boolean true if the thumbnail command returns 0 as program exit code ; otherwise, false
+ */
+ function generate_thumbnail () {
+ global $Config;
+
+ //Builds thumbnail filename
+ $sourceFile = $this->path;
+ $pos = strrpos($this->path, '.');
+ $thumbnailFile = substr($sourceFile, 0, $pos) . 'Square' . substr($sourceFile, $pos);
+
+ //Executes imagemagick command
+ $command = $Config['ImageMagick']['convert'] . " $sourceFile -resize 162x162 $thumbnailFile";
+ @system($command, $code);
+
+ //Returns true if the command have exited with errorcode 0 (= ok)
+ return ($code == 0);
+ }
+
+/* -------------------------------------------------------------
+ Gets content
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+ /*
+ * Gets content at specified location
+ * @param string $location_global global content location
+ * @param string $location_local local content location
+ * @return Array array of Content instances
+ */
+ static function get_local_content ($location_global, $location_local) {
+ global $db;
+
+ //Get contents at this location
+ $location_global = $db->sql_escape($location_global);
+ $location_local = $db->sql_escape($location_local);
+
+ $sql = "SELECT c.*, p.perso_nickname, p.perso_name FROM content c, persos p WHERE c.location_global = '$location_global' AND c.location_local = '$location_local' AND p.perso_id = c.perso_id ORDER BY location_k ASC";
+ if (!$result = $db->sql_query($sql)) {
+ message_die(SQL_ERROR, "Can't get content", '', __LINE__, __FILE__, $sql);
+ }
+
+ //Fills content array
+ $contents = array();
+ while ($row = $db->sql_fetchrow($result)) {
+ $content = new Content();
+ $content->load_from_row($row);
+ $contents[] = $content;
+ }
+
+ return $contents;
+ }
+
+}
+
+?>
\ No newline at end of file
diff --git a/includes/objects/message.php b/includes/objects/message.php
index aad4e31..242e0bc 100644
--- a/includes/objects/message.php
+++ b/includes/objects/message.php
@@ -1,132 +1,135 @@
<?php
/*
* Message class
*
* 0.1 2010-01-28 01:47 Autogenerated by Pluton Scaffolding
*
* @package Zed
* @copyright Copyright (c) 2010, Dereckson
* @license Released under BSD license
* @version 0.1
*
*/
class Message {
public $id;
public $date;
public $from;
public $to;
public $text;
public $flag;
/*
* Initializes a new instance
* @param int $id the primary key
*/
function __construct ($id = null) {
if ($id) {
$this->id = $id;
$this->load_from_database();
+ } else {
+ $this->date = time();
+ $this->flag = 0; //unread
}
}
/*
* Loads the object Message (ie fill the properties) from the $_POST array
*/
function load_from_form () {
if (array_key_exists('date', $_POST)) $this->date = $_POST['date'];
if (array_key_exists('from', $_POST)) $this->from = $_POST['from'];
if (array_key_exists('to', $_POST)) $this->to = $_POST['to'];
if (array_key_exists('text', $_POST)) $this->text = $_POST['text'];
if (array_key_exists('flag', $_POST)) $this->flag = $_POST['flag'];
}
/*
* Loads the object Message (ie fill the properties) from the database
*/
function load_from_database () {
global $db;
$sql = "SELECT * FROM messages WHERE message_id = '" . $this->id . "'";
if ( !($result = $db->sql_query($sql)) ) message_die(SQL_ERROR, "Unable to query messages", '', __LINE__, __FILE__, $sql);
if (!$row = $db->sql_fetchrow($result)) {
$this->lastError = "Message unkwown: " . $this->id;
return false;
}
$this->date = $row['message_date'];
$this->from = $row['message_from'];
$this->to = $row['message_to'];
$this->text = $row['message_text'];
$this->flag = $row['message_flag'];
return true;
}
/*
* Saves to database
*/
function save_to_database () {
global $db;
$id = $this->id ? "'" . $db->sql_escape($this->id) . "'" : 'NULL';
$date = $db->sql_escape($this->date);
$from = $db->sql_escape($this->from);
$to = $db->sql_escape($this->to);
$text = $db->sql_escape($this->text);
$flag = $db->sql_escape($this->flag);
//Updates or inserts
$sql = "REPLACE INTO messages (`message_id`, `message_date`, `message_from`, `message_to`, `message_text`, `message_flag`) VALUES ($id, '$date', '$from', '$to', '$text', '$flag')";
if (!$db->sql_query($sql)) {
message_die(SQL_ERROR, "Unable to save", '', __LINE__, __FILE__, $sql);
}
if (!$id) {
//Gets new record id value
$this->id = $db->sql_nextid();
}
}
/*
* Sends the message
*/
function send () {
- $this->saveToDatabase();
+ $this->save_to_database();
//TODO: triggers new message notifier
}
/*
* Deletes a message
*/
function delete () {
//A message is deleted if its flag value is 2
if ($this->flag != 2) {
$this->flag = 2;
$this->save_to_database();
}
}
/*
* Gets messages from the specified perso
*/
static function get_messages ($perso_id, $mark_as_read = true) {
global $db;
$sql = "SELECT message_id FROM " . TABLE_MESSAGES . " WHERE message_to = " . $db->sql_escape($perso_id) . " AND message_flag < 2 ORDER BY message_id DESC";
if (!$result = $db->sql_query($sql)) {
message_die(SQL_ERROR, "Unable to get messages", '', __LINE__, __FILE__, $sql);
}
while ($row = $db->sql_fetchrow($result)) {
$message = new Message($row[0]);
$messages[] = $message;
$ids[] = $message->id;
}
if ($mark_as_read && count($ids)) {
$ids = join($ids, ', ');
$sql = "UPDATE " . TABLE_MESSAGES . " SET message_flag = '1' WHERE message_id IN ($ids)";
$db->sql_query($sql);
}
return $messages;
}
}
?>
diff --git a/includes/objects/perso.php b/includes/objects/perso.php
index 0761b10..0d1d0b8 100644
--- a/includes/objects/perso.php
+++ b/includes/objects/perso.php
@@ -1,396 +1,453 @@
<?php
/*
* Perso class
*
* 0.1 2010-01-27 00:39 Autogenerated by Pluton Scaffolding
* 0.2 2010-01-29 14:39 Adding flags support
* 0.3 2010-02-06 17:50 Adding static perso hashtable
*
* @package Zed
* @copyright Copyright (c) 2010, Dereckson
* @license Released under BSD license
* @version 0.3
*
*/
require_once("includes/geo/location.php");
class Perso {
public $id;
public $user_id;
public $name;
public $nickname;
public $race;
public $sex;
public $avatar;
public $location_global;
public $location_local;
public $flags;
public static $hashtable_id = array();
public static $hashtable_name = array();
/*
* Initializes a new instance
* @param mixed $data perso ID or nickname
*/
function __construct ($data = null) {
if ($data) {
if (is_numeric($data)) {
$this->id = $data;
} else {
$this->nickname = $data;
}
$this->load_from_database();
} else {
$this->generate_id();
}
}
/*
* Initializes a new Perso instance if needed or get already available one.
* @param mixed $data perso ID or nickname
* @eturn Perso the perso instance
*/
static function get ($data = null) {
if ($data) {
//Checks in the hashtables if we already have loaded this instance
if (is_numeric($data)) {
if (array_key_exists($data, Perso::$hashtable_id)) {
return Perso::$hashtable_id[$data];
}
} else {
if (array_key_exists($data, Perso::$hashtable_name)) {
return Perso::$hashtable_name[$data];
}
}
}
$perso = new Perso($data);
return $perso;
}
/*
* Loads the object Perso (ie fill the properties) from the $_POST array
*/
function load_from_form () {
if (array_key_exists('user_id', $_POST)) $this->user_id = $_POST['user_id'];
if (array_key_exists('name', $_POST)) $this->name = $_POST['name'];
if (array_key_exists('nickname', $_POST)) $this->nickname = $_POST['nickname'];
if (array_key_exists('race', $_POST)) $this->race = $_POST['race'];
if (array_key_exists('sex', $_POST)) $this->sex = $_POST['sex'];
if (array_key_exists('avatar', $_POST)) $this->avatar = $_POST['avatar'];
if (array_key_exists('location_global', $_POST)) $this->location_global = $_POST['location_global'];
if (array_key_exists('location_local', $_POST)) $this->location_local = $_POST['location_local'];
}
/*
* Loads the object Perso (ie fill the properties) from the database
*/
function load_from_database () {
global $db;
//Gets perso
$sql = "SELECT * FROM " . TABLE_PERSOS;
if ($this->id) {
$id = $db->sql_escape($this->id);
$sql .= " WHERE perso_id = '" . $id . "'";
} else {
$nickname = $db->sql_escape($this->nickname);
$sql .= " WHERE perso_nickname = '" . $nickname . "'";
}
if ( !($result = $db->sql_query($sql)) ) message_die(SQL_ERROR, "Unable to query persos", '', __LINE__, __FILE__, $sql);
if (!$row = $db->sql_fetchrow($result)) {
$this->lastError = "Perso unkwown: " . $this->id;
return false;
}
$this->id = $row['perso_id'];
$this->user_id = $row['user_id'];
$this->name = $row['perso_name'];
$this->nickname = $row['perso_nickname'];
$this->race = $row['perso_race'];
$this->sex = $row['perso_sex'];
$this->avatar = $row['perso_avatar'];
$this->location_global = $row['location_global'];
$this->location_local = $row['location_local'];
//Gets flags
$sql = "SELECT flag_key, flag_value FROM " . TABLE_PERSOS_FLAGS .
" WHERE perso_id = $this->id";
if (!$result = $db->sql_query($sql)) {
message_die(SQL_ERROR, "Can't get flags", '', __LINE__, __FILE__, $sql);
}
while ($row = $db->sql_fetchrow($result)) {
$this->flags[$row["flag_key"]] = $row["flag_value"];
}
//Gets location
$this->location = new GeoLocation(
$this->location_global,
$this->location_local
);
//Puts object in hashtables
Perso::$hashtable_id[$this->id] = $this;
Perso::$hashtable_name[$this->nickname] = $this;
return true;
}
/*
* Saves to database
*/
function save_to_database () {
global $db;
$id = $this->id ? "'" . $db->sql_escape($this->id) . "'" : 'NULL';
$user_id = $db->sql_escape($this->user_id);
$name = $db->sql_escape($this->name);
$nickname = $db->sql_escape($this->nickname);
$race = $db->sql_escape($this->race);
$sex = $db->sql_escape($this->sex);
$avatar = $db->sql_escape($this->avatar);
$location_global = $this->location_global ? "'" . $db->sql_escape($this->location_global) . "'" : 'NULL';
$location_local = $this->location_local ? "'" . $db->sql_escape($this->location_local) . "'" : 'NULL';
//Updates or inserts
$sql = "REPLACE INTO " . TABLE_PERSOS . " (`perso_id`, `user_id`, `perso_name`, `perso_nickname`, `perso_race`, `perso_sex`, `perso_avatar`, `location_global`, `location_local`) VALUES ($id, '$user_id', '$name', '$nickname', '$race', '$sex', '$avatar', $location_global, $location_local)";
if (!$db->sql_query($sql)) {
message_die(SQL_ERROR, "Unable to save", '', __LINE__, __FILE__, $sql);
}
if (!$id) {
//Gets new record id value
$this->id = $db->sql_nextid();
}
}
/*
* Updates the specified field in the database record
*/
function save_field ($field) {
global $db;
if (!$this->id) {
message_die(GENERAL_ERROR, "You're trying to update a perso record not yet saved in the database: $field");
}
$id = $db->sql_escape($this->id);
$value = $db->sql_escape($this->$field);
$sql = "UPDATE " . TABLE_PERSOS . " SET `$field` = '$value' WHERE perso_id = '$id'";
if (!$db->sql_query($sql)) {
message_die(SQL_ERROR, "Unable to save $field field", '', __LINE__, __FILE__, $sql);
}
}
/*
* Gets perso location
* @return string The location names
*/
public function where () {
return $this->location->__toString();
}
/*
* Moves the perso to a new location
*/
public function move_to ($global = null, $local = null) {
//Sets global location
if ($global != null) {
$this->location_global = $global;
}
//Sets local location
if ($local != null) {
$this->location_local = $local;
}
//Updates database record
if ($global != null && $local != null) {
global $db;
$perso_id = $db->sql_escape($this->id);
$g = $db->sql_escape($this->location_global);
$l = $db->sql_escape($this->location_local);
$sql = "UPDATE " . TABLE_PERSOS .
" SET location_global = '$g', location_local = '$l'" .
" WHERE perso_id = '$perso_id'";
if (!$db->sql_query($sql))
message_die(SQL_ERROR, "Can't save new $global $local location.", '', __LINE__, __FILE__, $sql);
} elseif ($global != null) {
$this->save_field('location_global');
} elseif ($local != null) {
$this->save_field('location_local');
}
//Updates location member
$this->location = new GeoLocation(
$this->location_global,
$this->location_local
);
}
/*
* Gets the specified flag value
* @param string $key flag key
+ * @param mixed $defaultValue default value if the flag doesn't exist
* @return mixed the flag value (string) or null if not existing
*/
- public function get_flag ($key) {
- if (array_key_exists($key, $this->flags)) {
- return $this->flags[$key];
- }
- return null;
+ public function get_flag ($key, $defaultValue = null) {
+ return $this->flag_exists($key) ? $this->flags[$key] : $defaultValue;
+ }
+
+ /*
+ * Determines if the specified flag exists
+ * @param string $key the flag key to check
+ * @return boolean true if the specified flag exists ; otherwise, false.
+ */
+ public function flag_exists ($key) {
+ return array_key_exists($key, $this->flags);
}
/*
* Sets the specified flag
* @param string $key flag key
* @param string $value flag value (optional, default value: 1)
*/
public function set_flag ($key, $value = 1) {
//Checks if flag isn't already set at this value
if (array_key_exists($key, $this->flags) && $this->flags[$key] === $value)
return;
//Saves flag to database
global $db;
$id = $db->sql_escape($this->id);
$key = $db->sql_escape($key);
$value = $db->sql_escape($value);
$sql = "REPLACE " . TABLE_PERSOS_FLAGS . " SET perso_id = '$id', flag_key = '$key', flag_value = '$value'";
if (!$db->sql_query($sql))
message_die(SQL_ERROR, "Can't save flag", '', __LINE__, __FILE__, $sql);
//Sets flag in this perso instance
$this->flags[$key] = $value;
}
/*
* Deletes the specified flag
* @param string $key flag key
*/
public function delete_flag ($key) {
global $db;
if (!array_key_exists($key, $this->flags)) return;
$id = $db->sql_escape($this->id);
$key = $db->sql_escape($key);
$sql = "DELETE FROM " . TABLE_PERSOS_FLAGS .
" WHERE flag_key = '$key' AND perso_id = '$id' LIMIT 1";
if (!$db->sql_query($sql))
message_die(SQL_ERROR, "Can't delete flag", '', __LINE__, __FILE__, $sql);
}
/*
* Ensures the current perso have the flag or dies.
* @param string $flag XXXX
* @param string $$threshold YYYY
*/
public function request_flag ($flag, $threshold = 0) {
if (!array_key_exists($flag, $this->flags) || $this->flags[$flag] <= $threshold) {
message_die(HACK_ERROR, "You don't have $flag permission.", "Permissions");
}
}
+ /*
+ * Gets the specified note
+ * @param string $code the note code
+ * @return string the note content
+ */
+ public function get_note ($code) {
+ global $db;
+ $id = $db->sql_escape($this->id);
+ $code = $db->sql_escape($code);
+ $sql = "SELECT note_text FROM " . TABLE_PERSOS_NOTES . " WHERE perso_id = '$id' AND note_code LIKE '$code'";
+ return $db->sql_query_express($sql);
+ }
+
+ /*
+ * Sets the specified note
+ * @param string $code the note code
+ * @param string $text the note content
+ */
+ public function set_note ($code, $text) {
+ global $db;
+ $id = $db->sql_escape($this->id);
+ $code = $db->sql_escape($code);
+ $text = $db->sql_escape($text);
+ $sql = "REPLACE INTO " . TABLE_PERSOS_NOTES . " (perso_id, note_code, note_text) VALUES ('$id', '$code', '$text')";
+ if (!$db->sql_query($sql))
+ message_die(SQL_ERROR, "Can't save note", '', __LINE__, __FILE__, $sql);
+ }
+
+ /*
+ * Counts the amount of notes the perso have saved
+ * @return int the amount of notes assigned to the this perso
+ */
+ public function count_notes () {
+ global $db;
+ $id = $db->sql_escape($this->id);
+ $sql = "SELECT COUNT(*) FROM " . TABLE_PERSOS_NOTES . " WHERE perso_id = '$id'";
+ return $db->sql_query_express($sql);
+ }
+
/*
* Determines if the specified ID is available
* @param integer $id The perso ID to check
* @return boolean true if the specified ID is available ; otherwise, false
*/
public static function is_available_id ($id) {
global $db;
$sql = "SELECT COUNT(*) FROM " . TABLE_PERSOS . " WHERE perso_id = $id LOCK IN SHARE MODE";
if (!$result = $db->sql_query($sql)) {
message_die(SQL_ERROR, "Can't access users table", '', __LINE__, __FILE__, $sql);
}
$row = $db->sql_fetchrow($result);
return ($row[0] == 0);
}
/*
* Generates a unique ID for the current object
*/
private function generate_id () {
do {
$this->id = rand(2001, 5999);
} while (!Perso::is_available_id($this->id));
}
/*
* Checks if the nickname is available
* @param string $nickname the nickname to check
*/
public static function is_available_nickname ($nickname) {
global $db;
$nickname = $db->sql_escape($nickname);
$sql = "SELECT COUNT(*) FROM " . TABLE_PERSOS . " WHERE perso_nickname LIKE '$nickname' LOCK IN SHARE MODE;";
if (!$result = $db->sql_query($sql)) {
message_die(SQL_ERROR, "Utilisateurs non parsable", '', __LINE__, __FILE__, $sql);
}
$row = $db->sql_fetchrow($result);
return ($row[0] == 0);
}
/*
* Counts the perso a user have
*
* @param int user_id the user ID
* @return the user's perso count
*/
public static function get_persos_count ($user_id) {
global $db;
$sql = "SELECT COUNT(*) FROM " . TABLE_PERSOS . " WHERE user_id = $user_id";
return $db->sql_query_express($sql);
}
/*
* Gets an array with all the perso of the specified user
*/
public static function get_persos ($user_id) {
global $db;
$user_id = $db->sql_escape($user_id);
$sql = "SELECT perso_id FROM " . TABLE_PERSOS . " WHERE user_id = $user_id";
if (!$result = $db->sql_query($sql)) {
message_die(SQL_ERROR, "Can't get persos", '', __LINE__, __FILE__, $sql);
}
while ($row = $db->sql_fetchrow($result)) {
$persos[] = Perso::get($row[perso_id]);
}
return $persos;
}
/*
* Gets the first perso a user have
* (typically to be used when get_persos_count returns 1 to autoselect)
*
* @param int user_id the user ID
*/
public static function get_first_perso ($user_id) {
global $db;
- $sql = "SELECT perso_id FROM " . TABLE_PERSOS . " WHERE user_id = $user_id LIMIT 1";
+ $sql = "SELECT perso_id FROM " . TABLE_PERSOS ." WHERE user_id = $user_id LIMIT 1";
if ($perso_id = $db->sql_query_express($sql)) {
return new Perso($perso_id);
}
}
+ public function is_online () {
+ global $db;
+ $id = $db->sql_escape($this->id);
+ $sql = "SELECT MAX(online) FROM " . TABLE_SESSIONS ." WHERE perso_id = $id";
+ if (!$result = $db->sql_query($sql)) {
+ message_die(SQL_ERROR, "Unable to query the table", '', __LINE__, __FILE__, $sql);
+ }
+ $row = $db->sql_fetchrow($result);
+ return ($row[0] == 1);
+ }
+
public function on_select () {
//Session
set_info('perso_id', $this->id);
$this->set_flag("site.lastlogin", $_SERVER['REQUEST_TIME']);
define("PersoSelected", true);
}
public function on_logout () {
//Clears perso information in $_SESSION and session table
set_info('perso_id', null);
clean_session();
}
}
?>
\ No newline at end of file
diff --git a/includes/objects/profilephoto.php b/includes/objects/profilephoto.php
index 6cc75a5..bdcb4d1 100644
--- a/includes/objects/profilephoto.php
+++ b/includes/objects/profilephoto.php
@@ -1,159 +1,153 @@
<?php
/*
* Zed
* (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* photo class.
*
* 0.1 2010-01-03 21:00 Autogenerated by Pluton Scaffolding
* 0.2 2010-02-02 00:52 Thumbnail ImageMagick generation code
*
*/
class ProfilePhoto {
public $id;
public $perso_id;
public $name;
public $description;
public $avatar;
function __construct ($id = '') {
if ($id) {
$this->id = $id;
$this->load_from_database();
}
}
//Loads the object photo (ie fill the properties) from the $_POST array
function load_from_form ($readBoolean = true) {
if (array_key_exists('perso_id', $_POST)) $this->perso_id = $_POST['perso_id'];
if (array_key_exists('name', $_POST)) $this->name = $_POST['name'];
if (array_key_exists('description', $_POST)) $this->description = $_POST['description'];
if ($readBoolean) {
$this->avatar = $_POST['avatar'] ? true : false;
}
}
//Loads the object photo (ie fill the properties) from the database
function load_from_database () {
global $db;
$id = $db->sql_escape($this->id);
$sql = "SELECT * FROM " . TABLE_PROFILES_PHOTOS . " WHERE photo_id = '" . $id . "'";
if ( !($result = $db->sql_query($sql)) ) message_die(SQL_ERROR, "Unable to query azhar_profiles_photos", '', __LINE__, __FILE__, $sql);
if (!$row = $db->sql_fetchrow($result)) {
$this->lastError = "photo unkwown: " . $this->id;
return false;
}
$this->perso_id = $row['perso_id'];
$this->name = $row['photo_name'];
$this->description = $row['photo_description'];
$this->avatar = $row['photo_avatar'];
return true;
}
function promote_to_avatar () {
global $db;
$sql = "UPDATE " . TABLE_PROFILES_PHOTOS . " SET photo_avatar = 0 WHERE perso_id = " . $this->perso_id;
$db->sql_query_express($sql);
$this->avatar = true;
}
//Saves the object to the database
function save_to_database () {
global $db;
- $id = $db->sql_escape($this->id);
+ //Escapes fields
+ $id = $this->id ? "'" . $db->sql_escape($this->id) . "'" : 'NULL';
$perso_id = $db->sql_escape($this->perso_id);
$name = $db->sql_escape($this->name);
$description = $db->sql_escape($this->description);
- $safe = $this->safe ? 1 : 0;
$avatar = $this->avatar ? 1 : 0;
- if ($id) {
- //Updates
- $sql = "REPLACE INTO " . TABLE_PROFILES_PHOTOS . " (`photo_id`, `perso_id`, `photo_name`, `photo_description`, `photo_safe`, `photo_avatar`) VALUES ('$id', '$perso_id', '$name', '$description', $safe, $avatar)";
- } else {
- //Inserts
- $sql = "INSERT INTO " . TABLE_PROFILES_PHOTOS . " (`perso_id`, `photo_name`, `photo_description`, `photo_safe`, `photo_avatar`) VALUES ('$perso_id', '$name', '$description', $safe, $avatar)";
- }
-
+ //Saves
+ $sql = "REPLACE INTO " . TABLE_PROFILES_PHOTOS . " (`photo_id`, `perso_id`, `photo_name`, `photo_description`, `photo_avatar`) VALUES ($id, '$perso_id', '$name', '$description', $avatar)";
if (!$db->sql_query($sql)) {
message_die(SQL_ERROR, "Unable to save", '', __LINE__, __FILE__, $sql);
}
if (!$id) {
//Gets new record id value
$this->id = $db->sql_nextid();
}
}
function delete () {
global $db;
//Deletes from disk
$pic_tn = PHOTOS_DIR . '/' . $this->name;
$pic_genuine = PHOTOS_DIR . '/tn/' . $this->name;
unlink($pic_tn);
unlink($pic_genuine);
//Deletes from database
$id = $db->sql_escape($this->id);
$sql = "DELETE FROM " . TABLE_PROFILES_PHOTOS . " WHERE photo_id = '$id' LIMIT 1";
if (!$db->sql_query($sql)) {
message_die(SQL_ERROR, "Can't delete photo", '', __LINE__, __FILE__, $sql);
}
}
/*
* Generates a thumbnail using ImageMagick binary
* @return boolean true if the thumbnail command returns 0 as program exit code ; otherwise, false
*/
function generate_thumbnail () {
global $Config;
$sourceFile = PHOTOS_DIR . DIRECTORY_SEPARATOR . $this->name;
$thumbnailFile = PHOTOS_DIR . DIRECTORY_SEPARATOR . 'tn' . DIRECTORY_SEPARATOR . $this->name;
$command = $Config['ImageMagick']['convert'] . " $sourceFile -resize 1000x80 $thumbnailFile";
@system($command, $code);
return ($code == 0);
}
static function get_photos ($perso_id, $allowUnsafe = true) {
global $db;
$sql = "SELECT photo_id FROM " . TABLE_PROFILES_PHOTOS . " WHERE perso_id = " . $db->sql_escape($perso_id);
if (!$allowUnsafe) $sql .= " AND photo_safe = 0";
if (!$result = $db->sql_query($sql)) {
message_die(SQL_ERROR, "Unable to get photos", '', __LINE__, __FILE__, $sql);
}
while ($row = $db->sql_fetchrow($result)) {
$photos[] = new ProfilePhoto($row[0]);
}
return $photos;
}
/*
* Gets perso avatar
* @param integer $perso_id the perso to get the avatar ID
* @param string $username the username to put in title tag
*/
static function get_avatar ($perso_id, $username = '') {
global $db;
$perso_id = $db->sql_escape($perso_id);
$sql = "SELECT photo_description, photo_name FROM " . TABLE_PROFILES_PHOTOS . " WHERE perso_id = '$perso_id' and photo_avatar = 1";
if (!$result = $db->sql_query($sql)) {
message_die(SQL_ERROR, "Unable to get avatar", '', __LINE__, __FILE__, $sql);
}
if ($row = $db->sql_fetchrow($result)) {
if (!$username) $username = get_name($perso_id);
$description = $row['photo_description'] ? "$row[photo_description] ($username's avatar)" : "$username's avatar";
$url = PHOTOS_URL . '/tn/' . $row['photo_name'];
return "<img src=\"$url\" title=\"$username\" alt=\"$description\" />";
} else {
return null;
}
}
}
?>
\ No newline at end of file
diff --git a/includes/objects/ship.php b/includes/objects/ship.php
index 6345d6b..bf1ae69 100644
--- a/includes/objects/ship.php
+++ b/includes/objects/ship.php
@@ -1,225 +1,280 @@
<?php
/*
* Ship class
*
* 0.1 2010-02-05 18:51 Autogenerated by Pluton Scaffolding
* 0.2 2010-02-06 17:30 Ship API
*
* @package Zed
* @copyright Copyright (c) 2010, Dereckson
* @license Released under BSD license
* @version 0.1
*
*/
require_once("perso.php");
+require_once("includes/geo/location.php");
class Ship {
/*
* ----------------------------------------------------------------------- *
* Ship class definition
* ----------------------------------------------------------------------- *
*/
public $id;
public $name;
public $location_global;
public $location_local;
public $api_key;
public $description;
+ private static $hashtable = array();
+
/*
* Initializes a new instance
* @param int $id the primary key
*/
function __construct ($id = null) {
if ($id) {
+ if (ereg("^S[0-9]{5}$", $id)) {
+ $id = substr($id, 1);
+ }
+
$this->id = $id;
$this->load_from_database();
}
}
+ /*
+ * Initializes a new Ship instance if needed or gets already available one.
+ * @param mixed $data ship ID
+ * @eturn Ship the ship instance
+ */
+ static function get ($data = null) {
+ if ($data !== null) {
+ //Checks in the hashtable if we already have loaded this instance
+ if (array_key_exists($data, self::$hashtable)) {
+ return self::$hashtable[$data];
+ }
+ }
+
+ $ship = new Ship($data);
+ return $ship;
+ }
+
/*
* Loads the object Ship (ie fill the properties) from the $_POST array
*/
function load_from_form () {
if (array_key_exists('name', $_POST)) $this->name = $_POST['name'];
- if (array_key_exists('location', $_POST)) $this->location = $_POST['location'];
+ if (array_key_exists('location_global', $_POST)) $this->location = $_POST['location_global'];
+ if (array_key_exists('location_local', $_POST)) $this->location = $_POST['location_local'];
if (array_key_exists('api_key', $_POST)) $this->api_key = $_POST['api_key'];
if (array_key_exists('description', $_POST)) $this->description = $_POST['description'];
}
/*
* Loads the object Ship (ie fill the properties) from the database
*/
function load_from_database () {
global $db;
$id = $db->sql_escape($this->id);
$sql = "SELECT * FROM ships WHERE ship_id = '" . $id . "'";
if ( !($result = $db->sql_query($sql)) ) message_die(SQL_ERROR, "Unable to query Ships", '', __LINE__, __FILE__, $sql);
if (!$row = $db->sql_fetchrow($result)) {
$this->lastError = "Ship unkwown: " . $this->id;
return false;
}
$this->name = $row['ship_name'];
- $this->location = $row['ship_location'];
+ $this->location_global = $row['location_global'];
+ $this->location_local = $row['location_local'];
$this->api_key = $row['api_key'];
$this->description = $row['ship_description'];
+
+
+ //Puts object in hashtables
+ self::$hashtable[$this->id] = $this;
+
return true;
}
/*
* Saves to database
*/
function save_to_database () {
global $db;
$id = $this->id ? "'" . $db->sql_escape($this->id) . "'" : 'NULL';
$name = $db->sql_escape($this->name);
$location = $db->sql_escape($this->location);
$api_key = $db->sql_escape($this->api_key);
$description = $db->sql_escape($this->description);
//Updates or inserts
$sql = "REPLACE INTO ships (`ship_id`, `ship_name`, `ship_location`, `api_key`, `ship_description`) VALUES ($id, '$name', '$location', '$api_key', '$description')";
if (!$db->sql_query($sql)) {
message_die(SQL_ERROR, "Unable to save", '', __LINE__, __FILE__, $sql);
}
if (!$id) {
//Gets new record id value
$this->id = $db->sql_nextid();
}
}
function __toString () {
return $this->get_code();
}
+ /*
+ * Get ships at specified location
+ * @param string $location_global global location
+ * @param string $location_local local location
+ */
+ static function get_ships_at ($location_global, $location_local = null) {
+ global $db;
+
+ //Gets ships
+ $sql = "SELECT ship_id, location_global, location_local FROM " . TABLE_SHIPS . " WHERE location_global IS NOT NULL";
+ if (!$result = $db->sql_query($sql)) {
+ message_die(SQL_ERROR, "Can't get ships", '', __LINE__, __FILE__, $sql);
+ }
+ $ships = array();
+ $location = new GeoLocation($location_global, $location_local);
+ while ($row = $db->sql_fetchrow($result)) {
+ $shipLocation = new GeoLocation($row['location_global'], $row['location_local']);
+ if ($location->equals($shipLocation)) {
+ $ships[] = self::get($row['ship_id']);
+ }
+ }
+ return $ships;
+ }
+
/*
* ----------------------------------------------------------------------- *
* Helper methods
* ----------------------------------------------------------------------- *
*/
/*
* Gets ship code, e.g. S00001
* @return string the ship code
*/
function get_code () {
return sprintf("S%05d", $this->id);
}
/*
* Determines if the ship is at a spatioport (or assimilated)
* @return boolean true if the ship is at a spatioport ; false if the ship is in space
*/
function in_spatioport () {
return $this->location_local !== null;
}
/*
*
* @param string $location_local the spatioport location
*/
function fly_in ($location_local = null) {
//TODO: completes location global e.g. B00001 -> B00001003
$this->location_local = ($location_local == null) ? 0 : $location_local;
}
function fly_out () {
$this->location_local = null;
}
/*
* ----------------------------------------------------------------------- *
* Ship API methods
* ----------------------------------------------------------------------- *
*/
/*
* Requests the specified perso to authenticate to this ship
* @param mixed $perso_data the perso id or name
*/
function request_perso_authenticate ($perso_data) {
$perso = Perso::get($perso_data);
$flag = sprintf("request.api.ship.auth.%s", $this->get_code());
$perso->set_flag($flag);
$perso->set_flag("site.requests");
}
/*
* Determines if a perso is authenticated to this ship
* @param mixed $perso_data the perso id or name
* @return boolean true if the specified perso name is authenticated to this ship ; otherwise, false.
*/
function is_perso_authenticated ($perso_data) {
$flag = sprintf("api.ship.auth.%s", $this->get_code());
return Perso::get($perso_data)->flags[$flag] == 1;
}
/*
* Requests the specified perso to confirm the ship API session
* @param string $session_id a session ID provided by calling application
* @param mixed $perso_data the perso id or name
*/
function request_perso_confirm_session ($session_id, $perso_data) {
$perso = Perso::get($perso_data);
$flag = sprintf("request.api.ship.session.%s.%s", $this->get_code(), $session_id);
$perso->set_flag($flag);
$perso->set_flag("site.requests");
}
/*
* Cleans ship API temporary sessions
*/
static function clean_ship_sessions () {
//Cleans old sessions
global $db;
$sql = "DELETE FROM " . TABLE_REGISTRY . " WHERE registry_key LIKE 'api.ship.session.%' AND registry_updated < NOW() - 7200";
if (!$db->sql_query($sql))
message_die(SQL_ERROR, "Can't delete old ship API sessions", '', __LINE__, __FILE__, $sql);
}
/*
* Gets perso id from specified session
* @param string $session_id a session ID provided by calling application
* @return mixed the session
*/
function get_perso_from_session ($session_id) {
//Cleands old session
self::clean_ship_sessions();
//Reads api.ship.session.S00001.$session_id
//This registry key contains perso_id if it exists and valid
$key = sprintf("api.ship.session.%s.%s", $this->get_code(), $session_id);
return registry_get($key);
}
/*
* Loads a Ship object from its API key
* @param string $key API key GUID
* @return Ship the ship matching the API key
*/
static function from_api_key ($key) {
global $db;
$key = $db->sql_escape($key);
$sql = "SELECT * FROM ships WHERE api_key = '" . $key . "'";
if ( !($result = $db->sql_query($sql)) ) message_die(SQL_ERROR, "Unable to query ships", '', __LINE__, __FILE__, $sql);
if (!$row = $db->sql_fetchrow($result))
return null;
//Fills ship information
$ship = new Ship();
$ship->id = $row['ship_id'];
$ship->name = $row['ship_name'];
$ship->location = $row['ship_location'];
$ship->api_key = $row['api_key'];
$ship->description = $row['ship_description'];
return $ship;
}
}
?>
\ No newline at end of file
diff --git a/includes/objects/user.php b/includes/objects/user.php
index d889f43..7666ee7 100644
--- a/includes/objects/user.php
+++ b/includes/objects/user.php
@@ -1,153 +1,169 @@
<?php
/*
* User class
*
* 0.1 2010-01-27 00:33 Autogenerated by Pluton Scaffolding
+ * 0.2 2010-02-18 11:25 Compliance with strict mode
*
* @package Zed
* @copyright Copyright (c) 2010, Dereckson
* @license Released under BSD license
* @version 0.1
*
*/
class User {
public $id;
public $name;
public $password;
- public $active;
+ public $active = 0;
public $actkey;
public $email;
public $regdate;
/*
* Initializes a new instance
* @param int $id the primary key
*/
function __construct ($id = null) {
if ($id) {
$this->id = $id;
$this->load_from_database();
}
}
/*
* Loads the object User (ie fill the properties) from the $_POST array
*/
function load_from_form () {
if (array_key_exists('name', $_POST)) $this->name = $_POST['name'];
if (array_key_exists('password', $_POST)) $this->password = $_POST['password'];
if (array_key_exists('active', $_POST)) $this->active = $_POST['active'];
if (array_key_exists('actkey', $_POST)) $this->actkey = $_POST['actkey'];
if (array_key_exists('email', $_POST)) $this->email = $_POST['email'];
if (array_key_exists('regdate', $_POST)) $this->regdate = $_POST['regdate'];
}
/*
* Loads the object User (ie fill the properties) from the database
*/
function load_from_database () {
global $db;
$sql = "SELECT * FROM " . TABLE_USERS . " WHERE user_id = '" . $this->id . "'";
if ( !($result = $db->sql_query($sql)) ) message_die(SQL_ERROR, "Unable to query users", '', __LINE__, __FILE__, $sql);
if (!$row = $db->sql_fetchrow($result)) {
$this->lastError = "User unkwown: " . $this->id;
return false;
}
$this->name = $row['username'];
$this->password = $row['user_password'];
$this->active = $row['user_active'];
$this->actkey = $row['user_actkey'];
$this->email = $row['user_email'];
$this->regdate = $row['user_regdate'];
return true;
}
/*
* Saves to database
*/
function save_to_database () {
global $db;
$id = $this->id ? "'" . $db->sql_escape($this->id) . "'" : 'NULL';
$name = $db->sql_escape($this->name);
$password = $db->sql_escape($this->password);
$active = $db->sql_escape($this->active);
$actkey = $db->sql_escape($this->actkey);
$email = $db->sql_escape($this->email);
- $regdate = $db->sql_escape($this->regdate);
+ $regdate = $this->regdate ? "'" . $db->sql_escape($this->regdate) . "'" : 'NULL';
//Updates or inserts
- $sql = "REPLACE INTO " . TABLE_USERS . " (`user_id`, `username`, `user_password`, `user_active`, `user_actkey`, `user_email`, `user_regdate`) VALUES ($id, '$name', '$password', '$active', '$actkey', '$email', '$regdate')";
+ $sql = "REPLACE INTO " . TABLE_USERS . " (`user_id`, `username`, `user_password`, `user_active`, `user_actkey`, `user_email`, `user_regdate`) VALUES ($id, '$name', '$password', '$active', '$actkey', '$email', $regdate)";
if (!$db->sql_query($sql)) {
message_die(SQL_ERROR, "Unable to save", '', __LINE__, __FILE__, $sql);
}
if (!$id) {
//Gets new record id value
$this->id = $db->sql_nextid();
}
}
/*
* Updates the specified field in the database record
*/
function save_field ($field) {
global $db;
if (!$this->id) {
message_die(GENERAL_ERROR, "You're trying to update a record not yet saved in the database");
}
$id = $db->sql_escape($this->id);
$value = $db->sql_escape($this->$field);
$sql = "UPDATE " . TABLE_USERS . " SET `$field` = '$value' WHERE user_id = '$id'";
if (!$db->sql_query($sql)) {
message_die(SQL_ERROR, "Unable to save $field field", '', __LINE__, __FILE__, $sql);
}
}
//Generates a unique user id
- private function generate_id () {
+ function generate_id () {
global $db;
do {
$this->id = rand(2001, 5999);
$sql = "SELECT COUNT(*) FROM " . TABLE_USERS . " WHERE user_id = $this->id LOCK IN SHARE MODE;";
if (!$result = $db->sql_query($sql)) {
message_die(SQL_ERROR, "Can't access users table", '', __LINE__, __FILE__, $sql);
}
$row = $db->sql_fetchrow($result);
} while ($row[0]);
}
//Fills password field with encrypted version of the specified clear password
public function set_password ($newpassword) {
$this->password = md5($newpassword);
}
-
+
+ /*
+ * Sets OpenID for this user
+ * @param string $url OpenID endpoint URL
+ */
+ public function set_OpenID ($url) {
+ if (!$this->id) $this->save_to_database();
+ $url = $db->sql_escape($url);
+ $sql = "DELETE FROM " . TABLE_USERS_OPENID . " WHERE user_id = $this->id";
+ if (!$db->sql_query($sql))
+ message_die(SQL_ERROR, "Can't delete old OpenID", '', __LINE__, __FILE__, $sql);
+ $sql = "INSERT INTO " . TABLE_USERS_OPENID . " (openid_url, user_id) VALUES ('$url', $this->id)";
+ if (!$db->sql_query($sql))
+ message_die(SQL_ERROR, "Can't add new OpenID", '', __LINE__, __FILE__, $sql);
+ }
+
//Checks if a login is available
public static function is_available_login ($login) {
global $db;
$sql = "SELECT COUNT(*) FROM " . TABLE_USERS . " WHERE username LIKE '$login' LOCK IN SHARE MODE;";
if (!$result = $db->sql_query($sql)) {
message_die(SQL_ERROR, "Utilisateurs non parsable", '', __LINE__, __FILE__, $sql);
}
$row = $db->sql_fetchrow($result);
return ($row[0] ? false : true);
}
//Gets username from specified e-mail
public static function get_username_from_email ($mail) {
global $db;
$sql = "SELECT username FROM " . TABLE_USERS . " WHERE user_email LIKE '$mail' LOCK IN SHARE MODE;";
if (!$result = $db->sql_query($sql)) {
message_die(SQL_ERROR, "Utilisateurs non parsable", '', __LINE__, __FILE__, $sql);
}
if ($row = $db->sql_fetchrow($result)) {
- return $row[username];
+ return $row['username'];
}
return false;
}
}
?>
\ No newline at end of file
diff --git a/includes/settings/page.php b/includes/settings/page.php
new file mode 100644
index 0000000..5ea239c
--- /dev/null
+++ b/includes/settings/page.php
@@ -0,0 +1,120 @@
+<?php
+
+/*
+ * Zed
+ * (c) 2010, Dereckson, some rights reserved
+ * Released under BSD license
+ *
+ * Settings page
+ */
+
+require_once("setting.php");
+
+/*
+ * @package Zed
+ * @subpackage settings
+ */
+class SettingsPage {
+ /*
+ * @var string the page ID
+ */
+ public $id;
+
+ /*
+ * @var string the page title
+ */
+ public $title;
+
+ /*
+ * @var Array the settings (array of Setting items)
+ */
+ public $settings = array();
+
+ /*
+ * Initializes a new instance of SettingsPage class
+ */
+ function __construct ($id) {
+ $this->id = $id;
+ }
+
+ /*
+ * Intializes a settings page from an SimpleXMLElement XML fragment
+ * @param SimpleXMLElement $xml the XML fragment
+ * @return SettingsPage the section instance
+ */
+ static function from_xml ($xml) {
+ //Reads attributes
+ $id = ''; $title = '';
+ foreach ($xml->attributes() as $key => $value) {
+ switch ($key) {
+ case 'title':
+ case 'id':
+ $$key = (string)$value;
+ break;
+
+ default:
+ message_die(GENERAL_ERROR, "Unknown attribute: $key = \"$value\"", "Settings error");
+ }
+ }
+
+ //id attribute is mandatory
+ if (!$id) {
+ message_die(GENERAL_ERROR, "Section without id. Please add id='' in <section> tag", "Story error");
+ }
+
+ //Initializes new SettingsPage instance
+ $page = new SettingsPage($id);
+ $page->title = $title;
+
+ //Gets settings
+ if ($xml->setting) {
+ foreach ($xml->setting as $settingXml) {
+ $setting = Setting::from_xml($settingXml);
+ $page->settings[$setting->key] = $setting;
+ }
+ }
+
+ return $page;
+ }
+
+ /*
+ * Handles form reading $_POST array, set new settings values and saves.
+ * @param Array $errors an array where the errors will be filled
+ * @return boolean true if there isn't error ; otherwise, false.
+ */
+ function handle_form (&$errors = array()) {
+ $objects = array();
+
+ //Sets new settings values
+ foreach ($this->settings as $setting) {
+ $value = $_POST[$setting->key];
+
+ if ($setting->field == "password" && !$value) {
+ //We don't erase passwords if not set
+ continue;
+ }
+
+ //If the setting value is different of current one, we update it
+ $currentValue = $setting->get();
+ if ($setting->field == "checkbox" || $currentValue != $value) {
+ if (!$setting->set($value)) {
+ $errors[] = $setting->lastError ? $setting->lastError : "An error have occured in $setting->key field.";
+ }
+ if ($setting->object) $objects[] = $setting->object;
+ }
+ }
+
+ //Saves object (when the SETTINGS_SAVE_METHOD save method exists)
+ if (count($objects)) {
+ $objects = array_unique($objects);
+ foreach ($objects as $object) {
+ $object = $GLOBALS[$object];
+ if (method_exists($object, SETTINGS_SAVE_METHOD)) {
+ call_user_func(array($object, SETTINGS_SAVE_METHOD));
+ }
+ }
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/includes/settings/preferences.xml b/includes/settings/preferences.xml
new file mode 100644
index 0000000..98f488c
--- /dev/null
+++ b/includes/settings/preferences.xml
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<settings>
+ <page id="account" title="Account">
+ <setting id="username">
+ <key>Username</key>
+ <field>text</field>
+ <object>CurrentUser</object>
+ <property>name</property>
+ </setting>
+ <setting id="password">
+ <key>Password</key>
+ <field>password</field>
+ <object>CurrentUser</object>
+ <method>set_password</method>
+ </setting>
+ <setting id="email">
+ <key>Email</key>
+ <field>text</field>
+ <object>CurrentUser</object>
+ <property>email</property>
+ </setting>
+ <setting id="OpenID">
+ <key>OpenID</key>
+ <field>text</field>
+ <handler>
+ <get>
+<![CDATA[
+global $db, $CurrentUser;
+$sql = "SELECT openid_url FROM users_openid WHERE user_id = $CurrentUser->id LIMIT 1";
+return $db->sql_query_express($sql);
+]]>
+ </get>
+ <set>
+<![CDATA[
+global $db, $CurrentUser, $smarty;
+$openid = $db->sql_escape($value);
+$sql = "SELECT user_id FROM users_openid WHERE open_id_url LIKE '$openid'";
+if ($user_id = $db->sql_query_express($sql)) {
+ if ($user_id == $CurrentUser->id) {
+ $smarty->assign('WAP', "This OpenID is already linked to your account.");
+ } else {
+ $smarty->assign('WAP', "This OpenID is currently linked to another account.");
+ supralog('security', "User tried to add OpenID $openid which belongs to $user_id", "preferences");
+ }
+ return false;
+}
+$CurrentUser->set_OpenID($value);
+return true;
+]]>
+ </set>
+ </handler>
+ </setting>
+ </page>
+
+ <page id="perso" title="Information">
+ <setting id="longname">
+ <key>Name</key>
+ <field>text</field>
+ <object>CurrentPerso</object>
+ <property>name</property>
+ </setting>
+ <setting id="nickname">
+ <key>Nickname</key>
+ <field>validationtext</field>
+ <regExp>[a-z][a-z0-9 ]+</regExp>
+ <object>CurrentPerso</object>
+ <property>nickname</property>
+ </setting>
+ <setting id="race">
+ <key>Race</key>
+ <field>text</field>
+ <object>CurrentPerso</object>
+ <property>race</property>
+ </setting>
+ <setting id="sex">
+ <key>Sex</key>
+ <field>filteredlist</field>
+ <object>CurrentPerso</object>
+ <property>sex</property>
+ <choices>
+ <choice>
+ <key>male</key>
+ <value>M</value>
+ </choice>
+ <choice>
+ <key>female</key>
+ <value>F</value>
+ </choice>
+ <choice>
+ <key>neutral</key>
+ <value>N</value>
+ </choice>
+ <choice>
+ <key>both</key>
+ <value>2</value>
+ </choice>
+ </choices>
+ </setting>
+ </page>
+
+ <page id="smartline" title="SmartLine">
+ <setting id="show">
+ <key>SmartlineShow</key>
+ <field>checkbox</field>
+ <handler>
+ <set><![CDATA[
+global $CurrentPerso;
+$flag_value = $value ? 1 : 0;
+$CurrentPerso->set_flag('site.smartline.show', $flag_value);
+return true;
+ ]]></set>
+ <get><![CDATA[
+global $CurrentPerso;
+return (bool)$CurrentPerso->get_flag('site.smartline.show', true);
+ ]]></get>
+ </handler>
+ </setting>
+ <setting id="method">
+ <key>SmartlineMethod</key>
+ <field>checkbox</field>
+ <handler>
+ <set><![CDATA[
+global $CurrentPerso;
+$CurrentPerso->set_flag('site.smartline.method', $value ? 'post' : 'get');
+return true;
+ ]]></set>
+ <get><![CDATA[
+global $CurrentPerso;
+$flag = $CurrentPerso->get_flag('site.smartline.method', 'post');
+return $flag != "get";
+ ]]></get>
+ </handler>
+ </setting>
+ </page>
+</settings>
\ No newline at end of file
diff --git a/includes/settings/setting.php b/includes/settings/setting.php
new file mode 100644
index 0000000..62ffbbd
--- /dev/null
+++ b/includes/settings/setting.php
@@ -0,0 +1,160 @@
+<?php
+
+/*
+ * Zed
+ * (c) 2010, Dereckson, some rights reserved
+ * Released under BSD license
+ *
+ * Setting
+ */
+
+/*
+ * @package Zed
+ * @subpackage settings
+ */
+class Setting {
+
+ public $key;
+
+ //Rendering variables
+ public $field;
+ public $regExp;
+ public $choices;
+
+ //get/set variables
+ public $object;
+ private $property;
+ private $method;
+ private $handler;
+
+ //error variable
+ public $lastError;
+
+ /*
+ * Gets the current setting value
+ * @return string the setting value
+ */
+ function get () {
+ //1 - Evaluates custom handler
+ if (array_key_exists('get', $this->handler)) {
+ return eval($this->handler['get']);
+ }
+
+ //2 - Gets object property
+ if ($this->object && $property = $this->property) {
+ return $GLOBALS[$this->object]->$property;
+ }
+
+ if ($this->field == "password") {
+ //Okay not to have a value for password fields
+ return;
+ }
+
+ message_die(GENERAL_ERROR, "Setting $this->key haven't any get indication. Please set <object> and <property> / or a custom <handler><get></get></handler> block.", "Settings error");
+ }
+
+
+ /*
+ * Sets a new value
+ * @param $value the setting new value
+ * @return boolean true if the setting have been successfully set ; otherwise, false.
+ */
+ function set ($value) {
+ //Validates data
+ if ($this->regExp) {
+ if (!ereg('^' . $this->regExp . '$', $value)) {
+ $this->lastError = "Invalid format for $this->key setting";
+ return false;
+ }
+ }
+
+ //Tries to set value
+
+ //1 - Evaluates custom handler
+ if (array_key_exists('set', $this->handler)) {
+ return eval($this->handler['set']);
+ }
+
+ //2 - Calls object method
+ //3 - Sets object property
+ if ($this->object) {
+ $object = $GLOBALS[$this->object];
+ if ($this->method) {
+ return call_user_func(array($object, $this->method), $value);
+ } elseif ($property = $this->property) {
+ $object->$property = $value;
+ return true;
+ }
+ }
+
+ message_die(GENERAL_ERROR, "Setting $this->key haven't any set indication. Please set <object> (and wheter <method>, whether <property>) or a custom <handler><set></set></handler> block.", "Settings error");
+ }
+
+ /*
+ * Saves setting
+ * @return mixed the SETTINGS_SAVE_METHOD method value, or false if there's no method call;
+ */
+ function save () {
+ if ($this->object) {
+ $object = $GLOBALS[$this->object];
+ if (method_exists($object, SETTINGS_SAVE_METHOD)) {
+ return call_user_func(array($object, SETTINGS_SAVE_METHOD));
+ }
+ }
+
+ return false;
+ }
+
+ /*
+ * Initializes a new instance of Setting class from a XML element
+ * @param SimpleXMLElement the xml element to parse
+ * @return Setting the setting class
+ */
+ static function from_xml ($xml) {
+ //Reads attributes
+ $id = '';
+ foreach ($xml->attributes() as $key => $value) {
+ switch ($key) {
+ case 'id':
+ $id = (string)$value;
+ break;
+
+ default:
+ message_die(GENERAL_ERROR, "Unknown attribute: $key = \"$value\"", "Settings error");
+ }
+ }
+
+ //id attribute is mandatory
+ if (!$id) {
+ message_die(GENERAL_ERROR, "Setting without id. Please add id='' in <setting> tag", "Settings error");
+ }
+
+ //Initializes new Setting instance
+ $setting = new Setting($id);
+
+ //Parses simple <tag>value</tag>
+ $properties = array('key', 'field', 'object', 'property', 'method', 'regExp');
+ foreach ($properties as $property) {
+ if ($xml->$property)
+ $setting->$property = (string)$xml->$property;
+ }
+
+ //Parses <handler>
+ $setting->handler = array();
+ if ($xml->handler) {
+ if ($xml->handler->get) $setting->handler['get'] = (string)$xml->handler->get;
+ if ($xml->handler->set) $setting->handler['set'] = (string)$xml->handler->set;
+ }
+
+ //Parses <choices>
+ if ($xml->choices) {
+ foreach ($xml->choices->choice as $choiceXml) {
+ $setting->choices[(string)$choiceXml->key] = (string)$choiceXml->value;
+
+ }
+ }
+
+ return $setting;
+ }
+}
+?>
\ No newline at end of file
diff --git a/includes/settings/settings.php b/includes/settings/settings.php
new file mode 100644
index 0000000..3de5bff
--- /dev/null
+++ b/includes/settings/settings.php
@@ -0,0 +1,60 @@
+<?php
+
+/*
+ * Zed
+ * (c) 2010, Dereckson, some rights reserved
+ * Released under BSD license
+ *
+ * Settings
+ */
+
+//The method to call in your objects, to save data.
+define("SETTINGS_SAVE_METHOD", "save_to_database");
+
+require_once("page.php");
+
+/*
+ * @package Zed
+ * @subpackage settings
+ */
+class Settings {
+
+ /*
+ * @var string the file path
+ */
+ public $file;
+
+ /*
+ * @var Array a collection of SettingsPage items.
+ */
+ public $pages;
+
+ /*
+ * Initializes a new instance of Settings class
+ */
+ function __construct ($xmlFile) {
+ //Opens .xml
+ if (!file_exists($xmlFile)) {
+ message_die(GENERAL_ERROR, "$xmlFile not found.", "Settings load error");
+ }
+
+ $this->file = $xmlFile;
+ $this->parse();
+ }
+
+ /*
+ * Parses XML file
+ */
+ function parse () {
+ //Parses it
+ $xml = simplexml_load_file($this->file);
+ foreach ($xml->page as $page) {
+ //Gets page
+ $page = SettingsPage::from_xml($page);
+
+ //Adds to sections array
+ $this->pages[$page->id] = $page;
+ }
+ }
+}
+?>
\ No newline at end of file
diff --git a/includes/story/hook.php b/includes/story/hook.php
new file mode 100644
index 0000000..4c53cad
--- /dev/null
+++ b/includes/story/hook.php
@@ -0,0 +1,63 @@
+<?php
+
+/*
+ * Zed
+ * (c) 2010, Dereckson, some rights reserved
+ * Released under BSD license
+ *
+ * Story hook
+ */
+
+abstract class StoryHook {
+ /*
+ * @var Story the current story
+ */
+ public $story;
+
+ /*
+ * @var StorySection the current story section
+ */
+ public $section;
+
+ /*
+ * @var Perso the character involved in the story
+ */
+ public $perso;
+
+ function __construct ($story, $section) {
+ $this->story = $story;
+ $this->section = $section;
+ $this->perso = $GLOBALS['CurrentPerso'];
+
+ $this->initialize();
+ }
+
+ /* Initializes hook. Called after constructor */
+ abstract function initialize ();
+
+ /*
+ * Gets choices extra links
+ * @param Array $links the hooks links array
+ */
+ function get_choices_links (&$links) {}
+
+ /*
+ * Updates description
+ * @param string the description text (from section and previous hooks)
+ */
+ function update_description (&$description) {}
+
+ /*
+ * Adds HTML code *AT THE END* of the story content block
+ * @return string HTML code to print
+ */
+ function add_content () {}
+
+ /*
+ * Adds HTML code *AFTER* the content block
+ * @return string HTML code to print
+ */
+ function add_html () {}
+}
+
+?>
\ No newline at end of file
diff --git a/includes/story/hook_demo.php b/includes/story/hook_demo.php
new file mode 100644
index 0000000..c1cab5c
--- /dev/null
+++ b/includes/story/hook_demo.php
@@ -0,0 +1,34 @@
+<?php
+
+/*
+ * Zed
+ * (c) 2010, Dereckson, some rights reserved
+ * Released under BSD license
+ *
+ * Story hook example code
+ */
+
+$class = "DemoStoryHook";
+
+class DemoStoryHook extends StoryHook {
+ function initialize () {}
+
+ function update_description (&$description) {
+ //Performs the rot13 transform of the current description
+ $description = str_rot13($description);
+
+ //Appends a string to the current description
+ $description .= "\n\nWazzzzzzzzzzzzzzzzaaaaaaaaaaaaaaaaaaaaaa";
+ }
+
+ function get_choices_links (&$links) {
+ //Adds a link to /push
+ $links[] = array(lang_get("PushMessage"), get_url('push'));
+ }
+
+ function add_html () {
+ //Adds a html block
+ return '<div class="black">Lorem ipsum dolor</div>';
+ }
+}
+?>
\ No newline at end of file
diff --git a/includes/story/hook_spatioport.php b/includes/story/hook_spatioport.php
new file mode 100644
index 0000000..f9b385d
--- /dev/null
+++ b/includes/story/hook_spatioport.php
@@ -0,0 +1,67 @@
+<?php
+
+/*
+ * Zed
+ * (c) 2010, Dereckson, some rights reserved
+ * Released under BSD license
+ *
+ * Spatioport story hook
+ */
+
+require_once('includes/objects/ship.php');
+require_once('includes/geo/location.php');
+
+$class = "SpatioportStoryHook";
+
+class SpatioportStoryHook extends StoryHook {
+ public $location;
+ public $location_global;
+ public $location_local;
+
+ function get_choices_links (&$links) {
+ //$links[] = array('Examiner les vaisseaux', get_url('port','ships'));
+ }
+
+ function initialize () {
+ $this->location_global = $this->perso->location_global;
+ $this->location_local = $this->section->location_local;
+ $this->location = new GeoLocation($this->location_global, $this->location_local);
+ }
+
+ function add_content () {
+ $ships = $this->get_ships();
+ if (count($ships)) {
+ echo "\n<h2>Ships</h2>";
+ echo "<p>Amongst the ships are at the spatioport:</p>";
+ echo "\n<ul>";
+ foreach ($ships as $ship) {
+ $url = get_url('ship', $ship);
+ echo "\n\t<li><a href=\"$url\">$ship->name</a></li>";
+ }
+ echo "\n</ul>";
+ }
+
+ $ships = $this->get_ships_in_space();
+ if (count($ships)) {
+ echo "\n<h2>In orbit</h2>";
+ $place = (string)$this->location->body;
+ echo "<p>Those ships are in space around $place:</p>";
+ echo "\n<ul>";
+ foreach ($ships as $ship) {
+ $url = get_url('ship', $ship);
+ echo "\n\t<li><a href=\"$url\">$ship->name</a></li>";
+ }
+ echo "\n</ul>";
+ }
+ }
+
+ private function get_ships () {
+ return Ship::get_ships_at($this->location_global, $this->location_local);
+ }
+
+ private function get_ships_in_space () {
+ return Ship::get_ships_at($this->location_global, null);
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/includes/story/section.php b/includes/story/section.php
index baa6cfe..440f562 100644
--- a/includes/story/section.php
+++ b/includes/story/section.php
@@ -1,103 +1,134 @@
<?php
/*
* Zed
* (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* Story section
*/
require_once('choice.php');
+require_once('hook.php');
class StorySection {
/*
* @var string the section ID
*/
public $id;
/*
* @var string the section title
*/
public $title;
/*
* @var string the section description
*/
public $description;
/*
* @var string the local location
*/
public $location_local;
/*
* @var Array the section choices (array of StoryChoice items)
*/
public $choices = array();
+
+ /*
+ * @var Array the section hooks (array of StoryHook items)
+ */
+ public $hooks = array();
/*
* @var boolean if true, it's the story start ; otherwise, false;
*/
public $start;
+
+ /*
+ * @var Story the story calling the section
+ */
+ public $story;
- function __construct ($id) {
+ /*
+ * Initializes a new instance of StorySection class
+ */
+ function __construct ($id, $story = null) {
$this->id = $id;
+ if ($story !== null) {
+ $this->story = $story;
+ }
}
/*
* Gets choice from specified guid
* @return StoryChoice the wanted choice, or null if it doesn't exist
*/
function get_choice ($guid) {
foreach ($this->choices as $choice) {
if ($choice->guid == $guid)
return $choice;
}
return null;
}
/*
- * Intializes a story section from an XML document
- * @param string $xml the XML document
+ * Intializes a story section from an SimpleXMLElement XML fragment
+ * @param SimpleXMLElement $xml the XML fragment
+ * @param Story $story the calling story
* @return StorySection the section instance
*/
- static function from_xml ($xml) {
+ static function from_xml ($xml, $story = null) {
//Reads attributes
$id = '';
$start = false;
foreach ($xml->attributes() as $key => $value) {
switch ($key) {
case 'start':
if ($value) $start = true;
break;
case 'id':
$id = (string)$value;
break;
default:
message_die(GENERAL_ERROR, "Unknown attribute: $key = \"$value\"", "Story error");
}
}
if (!$id) {
message_die(GENERAL_ERROR, "Section without id. Please add id='' in <section> tag", "Story error");
}
- $section = new StorySection($id);
+ $section = new StorySection($id, $story);
$section->title = (string)$xml->title;
$section->description = (string)$xml->description;
$section->location_local = (string)$xml->local;
$section->start = $start;
+
+ //Adds choices
if ($xml->choices) {
foreach ($xml->choices->choice as $choice) {
$section->choices[] = StoryChoice::from_xml($choice);
}
}
+
+ //Adds hooks
+ if ($xml->hooks) {
+ foreach ($xml->hooks->hook as $hook) {
+ //<hook type="spatioport" /> will assign 'spatioport' to $hook;
+ $hook = (string)$hook->attributes()->type;
+ require_once("hook_$hook.php");
+ $section->hooks[] = new $class($section->story, $section);
+ }
+ }
+
return $section;
}
}
?>
diff --git a/includes/story/story.php b/includes/story/story.php
index 716540c..0d39a82 100644
--- a/includes/story/story.php
+++ b/includes/story/story.php
@@ -1,106 +1,106 @@
<?php
/*
* Zed
* (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* Story
*/
require_once('section.php');
/*
* @package Zed
* @subpackage story
*/
class Story {
/*
* @var string the file path
*/
public $file;
/*
* @var string the story title
*/
public $title;
/*
* @var Array an array of StorySection elements
*/
public $sections = array();
/*
* @var SimpleXMLElement the SimpleXML parser
*/
private $xml;
/*
* @var string the index of start section in sections array
*/
private $startSection = null;
/*
* @var Array an array of StorySection elements, indexed by location
*/
private $sectionsByLocation = array();
function __construct ($file) {
//Opens .xml
if (!file_exists($file)) {
message_die(GENERAL_ERROR, "$file not found.", "Story loading error");
}
$this->file = $file;
$this->parse();
}
/*
* Gets start section
* @return StorySection the section where the story starts, or null if not defined
*/
function get_start_section () {
return ($this->startSection != null) ? $this->sections[$this->startSection] : null;
}
/*
* Gets section from local location
* @return StorySection the default section at this location, or null if not defined
*/
function get_section_from_location ($location) {
return array_key_exists($location, $this->sectionsByLocation) ? $this->sectionsByLocation[$location] : null;
}
/*
* Parses XML file
*/
function parse () {
//Parses it
$this->xml = simplexml_load_file($this->file);
$this->title = (string)$this->xml->title;
foreach ($this->xml->section as $section) {
//Gets section
- $section = StorySection::from_xml($section);
+ $section = StorySection::from_xml($section, $this);
//Have we a start section?
if ($section->start) {
//Ensures we've only one start section
if ($this->startSection != null) {
message_die(GENERAL_ERROR, "Two sections have start=\"true\": $section->id and $this->startSection.", "Story error");
}
$this->startSection = $section->id;
}
//By location
if ($section->location_local) {
$this->sectionsByLocation[$section->location_local] = $section;
}
//Adds to sections array
$this->sections[$section->id] = $section;
}
}
}
?>
\ No newline at end of file
diff --git a/index.php b/index.php
index 2a23353..4ea7928 100644
--- a/index.php
+++ b/index.php
@@ -1,205 +1,215 @@
<?php
/*
* Zed
* (c) 2010, Dereckson, some rights reserved
* Released under BSD license
*
* Application entry point
*/
////////////////////////////////////////////////////////////////////////////////
///
/// Initialization
///
//Pluton library
include('includes/core.php');
//Session
$IP = encode_ip($_SERVER["REMOTE_ADDR"]);
require_once('includes/story/story.php'); //this class can be stored in session
session_start();
$_SESSION[ID] = session_id();
session_update(); //updates or creates the session
include("includes/login.php"); //login/logout
$CurrentUser = get_logged_user(); //Gets current user infos
//Gets current perso
require_once('includes/objects/perso.php');
if ($perso_id = $CurrentUser->session['perso_id']) {
$CurrentPerso = new Perso($perso_id);
}
//Skin and accent to load
define('THEME', $CurrentUser->session['Skin']);
define('ACCENT', $CurrentUser->session['Skin_accent']);
//Loads Smarty
require('includes/Smarty/Smarty.class.php');
$smarty = new Smarty();
$current_dir = dirname(__FILE__);
$smarty->template_dir = $current_dir . '/skins/' . THEME;
$smarty->compile_dir = $current_dir . '/cache/compiled';
$smarty->cache_dir = $current_dir . '/cache';
$smarty->config_dir = $current_dir;
$smarty->config_vars['StaticContentURL'] = $Config['StaticContentURL'];
//Loads language files
initialize_lang();
lang_load('core.conf');
-if ($CurrentUser->id < 1000) {
- //Anonymous user, proceed to login
- if (array_key_exists('LastUsername', $_COOKIE))
- $smarty->assign('username', $_COOKIE['LastUsername']);
- if (array_key_exists('LastOpenID', $_COOKIE))
- $smarty->assign('OpenID', $_COOKIE['LastOpenID']);
- $smarty->assign('LoginError', $LoginError);
- $smarty->display('login.tpl');
+//Gets URL
+$url = get_current_url_fragments();
+
+//If anonymous, prints login
+if ($CurrentUser->id < 1000) {
+ //Anonymous user
+ if ($url[0] == 'invite') {
+ //Invitation form
+ message_die(GENERAL_ERROR, "<p>Invitation system not deployed. Contact Dereckson to enable your account.</p><p>Le système d'invitation n'a pas encore été codé, contacte Dereckson pour activer ton compte.</p>", "Invitation");
+ $smarty->display('invite.tpl');
+ } else {
+ //Login form
+ if (array_key_exists('LastUsername', $_COOKIE))
+ $smarty->assign('username', $_COOKIE['LastUsername']);
+ if (array_key_exists('LastOpenID', $_COOKIE))
+ $smarty->assign('OpenID', $_COOKIE['LastOpenID']);
+ $smarty->assign('LoginError', $LoginError);
+ $smarty->display('login.tpl');
+ }
exit;
}
////////////////////////////////////////////////////////////////////////////////
///
/// Perso selector
///
//Handles form
if ($_POST['form'] == 'perso.create') {
$perso = new Perso();
$perso->load_from_form();
$perso->user_id = $CurrentUser->id;
//Validates forms
if (!$perso->name) $errors[] = lang_get("NoFullnameSpecified");
if (!$perso->race) {
$errors[] = lang_get("NoRaceSpecified");
$perso->race = "being";
}
if (!$perso->sex) $errors[] = lang_get("NoSexSpecified");
if (!$perso->nickname) {
$errors[] = lang_get("NoNicknameSpecified");
} else if (!Perso::is_available_nickname($perso->nickname)) {
$errors[] = lang_get("UnavailableNickname");
}
//Save or prints again forms
if (!$errors) {
$perso->save_to_database();
$smarty->assign('NOTIFY', lang_get('NewCharacterCreated'));
$CurrentPerso = $perso;
set_info('perso_id', $perso->id);
$CurrentPerso->set_flag("site.lastlogin", $_SERVER['REQUEST_TIME']);
} else {
$smarty->assign('WAP', join("<br />", $errors));
$smarty->assign('perso', $perso);
}
}
if ($_GET['action'] == 'perso.logout' && $CurrentPerso != null) {
//User wants to change perso
$CurrentPerso->on_logout();
$CurrentPerso = null;
} elseif ($_GET['action'] == 'perso.select') {
//User have selected a perso
$CurrentPerso = new Perso($_GET['perso_id']);
if ($CurrentPerso->user_id != $CurrentUser->id) {
//Hack
message_die(HACK_ERROR, "This isn't your perso.");
}
$CurrentPerso->on_select();
}
if (!$CurrentPerso) {
switch ($count = Perso::get_persos_count($CurrentUser->id)) {
case 0:
//User have to create a perso
$smarty->display("perso_create.tpl");
exit;
case 1:
//Autoselects only perso
$CurrentPerso = Perso::get_first_perso($CurrentUser->id);
$CurrentPerso->on_select();
break;
default:
//User have to pick a perso
$persos = Perso::get_persos($CurrentUser->id);
$smarty->assign("PERSOS", $persos);
$smarty->display("perso_select.tpl");
$_SESSION['UserWithSeveralPersos'] = true;
exit;
}
}
//Assigns current perso object as Smarty variable
$smarty->assign('CurrentPerso', $CurrentPerso);
////////////////////////////////////////////////////////////////////////////////
///
/// Tasks to execute before calling the URL controller:
/// - assert the perso is somewhere
/// - executes the smartline
///
//If the perso location is unknown, ejects it to an asteroid
if (!$CurrentPerso->location_global) {
require_once('includes/geo/place.php');
$smarty->assign('NOTIFY', lang_get('NewLocationNotify'));
$CurrentPerso->move_to(GeoPlace::get_start_location());
}
//SmartLine
include("includes/SmartLine/ZedSmartLine.php");
//Redirects user to user request controller if site.requests flag on
if (defined('PersoSelected') && array_key_exists('site.requests', $CurrentPerso->flags) && $CurrentPerso->flags['site.requests']) {
include('controllers/persorequest.php');
}
////////////////////////////////////////////////////////////////////////////////
///
/// Calls the specific controller to serve the requested page
///
-
-$url = get_current_url_fragments();
-
+
switch ($controller = $url[0]) {
case '':
include('controllers/home.php');
break;
case 'request':
case 'page':
case 'explore':
+ case 'ship':
include("controllers/$controller.php");
break;
case 'who':
include('controllers/profile.php'); //Azhàr controller
break;
case 'push':
include('controllers/motd.php'); //Azhàr controller
break;
case 'quux':
//It's like a test/debug console/sandbox, you put what you want into
if (file_exists('dev/quux.php')) {
include('dev/quux.php');
} else {
message_die(GENERAL_ERROR, "Quux lost in Hollywood.", "Nay");
}
break;
default:
//TODO: returns a 404 error
dieprint_r($url, 'Unknown URL');
}
?>
\ No newline at end of file
diff --git a/js/misc.js b/js/misc.js
index 1810343..b40e37f 100644
--- a/js/misc.js
+++ b/js/misc.js
@@ -1,146 +1,159 @@
/* Updates SmartLine */
function UpdateSmartLine() {
document.forms.SmartLine.C.value = document.forms.SmartLine.SmartLineHistory.value;
document.forms.SmartLine.C.focus();
}
/* Hypership time */
function get_hypership_time () {
//Gets time
date = new Date();
unixtime = Math.floor(date.getTime() / 1000);
seconds = unixtime - 1264377600;
days = Math.floor(seconds / 86400);
fraction = Math.floor((seconds % 86400) / 86.4);
//Zerofills fraction
switch (new String(fraction).length) {
case 1: return days + "." + "00" + fraction;
case 2: return days + "." + "0" + fraction;
default: return days + "." + fraction;
}
}
/* We need to trigger an update in ... ms */
function next_hypership_increase_in () {
date = new Date();
unixtime = Math.floor(date.getTime() / 1000);
seconds = unixtime - 1264377600;
days = Math.floor(seconds / 86400);
fraction1 = (seconds % 86400) / 86.4;
- fraction2 = Math.floor(fraction1);
- return (fraction1 - fraction2) * 86400;
+ fraction2 = Math.ceil(fraction1);
+ return (fraction2 - fraction1) * 86400;
}
//Autoupdates every 20 seconds
//(should be every 86.4 seconds, after first timed call)
function update_hypership_time () {
var item = document.getElementById("HypershipTime");
if (item != undefined) {
item.innerHTML = get_hypership_time();
setTimeout('update_hypership_time()', 86400);
}
}
setTimeout('update_hypership_time()', next_hypership_increase_in());
/* Dumps a variable */
function dump(arr,level) {
var dumped_text = "";
if(!level) level = 0;
//The padding given at the beginning of the line.
var level_padding = "";
for(var j=0;j<level+1;j++) level_padding += " ";
if(typeof(arr) == 'object') { //Array/Hashes/Objects
for(var item in arr) {
var value = arr[item];
if(typeof(value) == 'object') { //If it is an array,
dumped_text += level_padding + "'" + item + "' ...\n";
//dumped_text += dump(value,level+1);
} else {
dumped_text += level_padding + "'" + item + "' => \"" + value + "\"\n";
}
}
} else { //Stings/Chars/Numbers etc.
dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
}
return dumped_text;
}
/* A code for an hidden function */
var ar2215 = {
input: "",
pattern: "38384040373937396665",
clear: setTimeout('ar2215.clear_input()', 2000),
load: function () {
window.document.onkeydown = function (e) {
ar2215.input += e ? e.keyCode : event.keyCode;
if (ar2215.input == ar2215.pattern) {
ar2215.code("/push");
clearTimeout(ar2215.clear);
return;
}
clearTimeout(ar2215.clear);
ar2215.clear = setTimeout("ar2215.clear_input()", 2000);
}
this.iphone.load("/index.php/push");
},
code: function (link) {
window.location = link;
},
clear_input: function () {
ar2215.input = "";
clearTimeout(ar2215.clear);
},
iphone:{
start_x: 0,
start_y: 0,
stop_x: 0,
stop_y: 0,
tap: false,
capture: false,
keys: ["UP","UP","DOWN","DOWN","LEFT","RIGHT","LEFT","RIGHT","TAP","TAP"],
code: function (link) { window.location = link },
load: function (link) {
document.ontouchmove = function (e) {
if (e.touches.length == 1 && ar2215.iphone.capture == true) {
var touch = e.touches[0];
ar2215.iphone.stop_x = touch.pageX;
ar2215.iphone.stop_y = touch.pageY;
ar2215.iphone.tap = false;
ar2215.iphone.capture = false;
ar2215.iphone.check_direction();
}
}
document.ontouchend = function (evt) {
if (ar2215.iphone.tap == true)
ar2215.iphone.check_direction();
}
document.ontouchstart = function(evt) {
ar2215.iphone.start_x = evt.changedTouches[0].pageX;
ar2215.iphone.start_y = evt.changedTouches[0].pageY;
ar2215.iphone.tap = true;
ar2215.iphone.capture = true;
}
},
check_direction: function () {
x_magnitude = Math.abs(this.start_x - this.stop_x);
y_magnitude = Math.abs(this.start_y - this.stop_y);
x = ((this.start_x - this.stop_x) < 0) ? "RIGHT": "LEFT";
y = ((this.start_y - this.stop_y) < 0) ? "DOWN" : "UP";
result = (x_magnitude > y_magnitude) ? x : y;
result = (this.tap == true) ? "TAP" : result;
if (result == this.keys[0])
this.keys = this.keys.slice(1, this.keys.length);
if (this.keys.length == 0)
this.code(this.link)
}
}
}
-ar2215.load();
\ No newline at end of file
+ar2215.load();
+
+/* Visual effects */
+function set_opacity (id, opacity) {
+ element = document.getElementById(id);
+ if (element != null) {
+ if (opacity == 0) {
+ element.style.backgroundImage = 'inherit';
+ } else {
+ property = 'url("/img/zed/opaque_' + opacity + '.png")';
+ element.style.backgroundImage = property;
+ }
+ }
+}
\ No newline at end of file
diff --git a/js/tour2.js b/js/tour2.js
new file mode 100644
index 0000000..5515864
--- /dev/null
+++ b/js/tour2.js
@@ -0,0 +1,148 @@
+/* -------------------------------------------------------------
+ Zed
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ Author: Dereckson
+ Tags: animation jquery l10n
+ Filename: tour.js
+ Version: 1.0
+ Created: 2010-01-25
+ Updated: 2010-02-03
+ Licence: Dual licensed: BSD and Creative Commons BY 3.0.
+ Dependencies: jQuery (for dom elements selection and dimensions.js)
+ dimensions.js
+ ------------------------------------------------------------- */
+
+var tour = {
+ //Default language
+ lang: "en",
+
+ //Translated in
+ langs: "en,fr",
+
+ //Current highlight showed
+ current: -1,
+
+ //File extension
+ extension: "png",
+
+ //Highlights files and position
+ //File: /img/tour/{filename}.{extension}
+ highlights: [
+ ["create", 13, 18],
+ ["lounge", 339, 107],
+ ["play", 22, 345],
+ ["explore", 325, 373]
+ ],
+
+ //The center x, y coordinate
+ //It's used to determinate what highlight to print
+ center: [368, 390],
+
+ //Gets the highlight index, from position
+ where: function(x, y) {
+ if (x < this.center[0]) {
+ //We're at left from center point
+ return (y < this.center[1]) ? 0 : 2;
+ } else {
+ //We're at right from center point
+ return (y < this.center[1]) ? 1 : 3;
+ }
+ },
+
+ //Determines if we're inside the #Tour id
+ isInside: function (pageX, pageY) {
+ var tourOffset = $("#Tour").offset();
+ return pageX >= tourOffset.left && pageY >= tourOffset.top
+ && pageX <= tourOffset.left + $("#Tour").width()
+ && pageY <= tourOffset.top + $("#Tour").height();
+ },
+
+ //Shows the highlight at specified the page position
+ showAt: function (pageX, pageY) {
+ var tourOffset = $("#Tour").offset();
+ this.show(
+ this.where(pageX - tourOffset.left , pageY - tourOffset.top)
+ );
+ },
+
+ //Shows the specified highlight
+ show: function (i) {
+ if (this.current != i) {
+ var filename = this.highlights[i][0] + "_" + this.lang + "." + this.extension;
+ var code = '<img src="http://zed.espace-win.org.nyud.net/img/tour/' + filename + '" alt="' + this.highlights[i][0] + '" />';
+ $('#TourHighlight').empty().html(code);
+ var o = document.getElementById("TourHighlight");
+ o.style.left = this.highlights[i][1] + "px";
+ o.style.top = this.highlights[i][2] + "px";
+ this.current = i;
+ }
+ },
+
+ //Hides highlight
+ hideall: function () {
+ if (this.current > -1) {
+ this.current = -1;
+ $('#TourHighlight').empty();
+ }
+ },
+
+ //Runs the animation
+ run: function (delay) {
+ //Highlight order
+ //[0, 1, 3, 2] is a counterwise move
+ var order = [0, 1, 3, 2];
+
+ //Prints first hightlight
+ this.show(order[0]);
+
+ //Prints next highlights
+ n = this.highlights.length;
+ for (i = 1 ; i < n ; i++) {
+ setTimeout('tour.show(' + order[i] + ')', delay * i);
+ }
+
+ //Prints back the first, and enables rollover
+ setTimeout('tour.show(' + order[0] + ')', delay * n);
+ setTimeout('tour.enableRollover()', delay * n);
+ },
+
+ //Enables rollovers
+ enableRollover: function () {
+ //Enables panel on click
+ $('#Tour').bind("mousemove mouseout", function(e) {
+ if (tour.isInside(e.pageX, e.pageY)) {
+ tour.showAt(e.pageX, e.pageY);
+ } else {
+ tour.hideall();
+ }
+ });
+ },
+
+ //Gets client language (Firefox) or preferences content language (IE)
+ getLanguage: function () {
+ var lang = navigator.language;
+ if (lang == undefined) lang = navigator.userLanguage;
+ if (lang == undefined) return "";
+
+ //fr-be -> fr
+ var pos = lang.indexOf('-');
+ if (pos > -1) lang = lang.substring(0, pos);
+
+ return lang.toLowerCase();
+ },
+
+ //Initializes tour
+ init: function () {
+ //Tries to localize
+ var lang = this.getLanguage();
+ if (this.langs.indexOf(lang) > -1) this.lang = lang;
+
+ //Runs tour animation
+ //The rollover will be enabled at anim end
+ this.run(900);
+ }
+}
+
+$(document).ready(function() {
+ tour.init();
+});
\ No newline at end of file
diff --git a/lang/en/profile.conf b/lang/en/profile.conf
index 89f5ce0..b15535e 100644
--- a/lang/en/profile.conf
+++ b/lang/en/profile.conf
@@ -1,121 +1,121 @@
-#Azhàr language config file - Profiles
+#Zed language config file - Profiles
#Language: English
#Code: en
-#Author: Wolfaeym
+#Author: Dereckson
###
### profile.tpl - main profile
###
#<img src=".../tel.png" title="Phone number" alt="Tel"... />
PhoneNumber = Phone number
PhoneNumberAlt = Tel
#<img src=".../mail.png" title="E-mail" alt="@"... />
Mail = E-mail
MailAlt = @
###
### profile.tpl - communication area
###
DropMessage = Drop a message
SendMessage = Send a message to %s
AddComment = Add a comment to %s's profile
###
### profile.tpl - sidebar - Edit account preferences and profile content
###
EditMyPage = Edit my page
EditProfile = Edit my text
EditAccount = Edit my information
ManagePhotos = Manage photos
AddPhoto = Add a photo
###
### profile.tpl - sidebar - content from http://photos.folleterre.org
###
LastSharedPhotos = Last shared photos on photos.folleterre.org
ViewRecentUploads = View all recent uploads
###
### profile.tpl - sidebar - post-it
###
#TODO: {$NAME} needs a pickup for {$lift->event->name}
IdealDate = Ideal date
From = From
OfferLift = Offer a lift
###
### profile_edit.tpl - edit
###
ProfileTextTitle = My best words to express myself
SaveProfile = Save profile
ProfileFont = Profile fontz
Calibri = Calibri (regular font)
FixedSys = FixedSys (fixed width)
###
### user_account.tpl - edit my information
###
Login = Login
LongName = Faerie name
RealName = <em>Mundanes</em> name
RealNameToolTip = Your first and last names (optional).
UpdateAccountInfo = Update account information
###
### profile_photo.tpl - photo manager - add a photo to my profile
###
AddPhoto = Add a photo to my profile
AddPhotoExplanations = You can upload here a personal photo with you as main subject.<br />Note you can also host any kind of pictures in <a href="http://photos.folleterre.org/albmgr.php">photo albums</a>.
ShortDescription = Short description
SafeForWorkLabel = Check this box if the picture is "<strong>safe for work</strong>", you can view it without problem from any public computer. That will allow some faeries to be more comfortable browsing the site from any location.
###
### profile_photo.tpl - photo manager - manage current photos
###
ManageCurrentPhotos = Manage current photos
PictureProperties = Picture properties
EditPictureProperties = Edit this picture description or safe status
Delete = Delete
DeleteThisPicture = Delete this picture
###
### profile_photo_edit.tpl - edit individual photo properties
###
EditPhoto = Edit photo
PhotoInfo = Photo information
Description = Description
SafeForWork = Safe for work
UseAsAvatar = Use as avatar
OtherActions = Other actions
DeletePicture = Delete this picture
BackToPhotoManager = Back to photo manager
###
### profile.php
###
UnknownFaerie = Unknown faerie
Who = Who?
WhoIsFaerie = Who is %s?
MessageSent = Message sent.
MessageSentSelf = Message sent to yourself.
CommentPublished = Comment published.
PhotoUploaded = Photo uploaded.
NotYourPic = Hey, this photo is not one of yours.
PictureDeleted = Picture deleted.
InactivatedUser = This faerie have not activated its intranet account yet.
\ No newline at end of file
diff --git a/lang/en/scenes.conf b/lang/en/scenes.conf
new file mode 100644
index 0000000..5e7190a
--- /dev/null
+++ b/lang/en/scenes.conf
@@ -0,0 +1,12 @@
+#Zed language config file - scenes
+#Language: English
+#Code: en
+#Author: Dereckson
+
+###
+### Hypership tower
+###
+
+[B00001001]
+UploadNewArtwork = "Upload new artwork"
+UploadNewArtworkDescription = "This frame is free. You can display here your artwork or any other artwork you like."
diff --git a/lang/en/settings.conf b/lang/en/settings.conf
new file mode 100644
index 0000000..528adc4
--- /dev/null
+++ b/lang/en/settings.conf
@@ -0,0 +1,39 @@
+#Zed language config file - Settings
+#Language: English
+#Code: en
+#Author: Dereckson
+
+###
+### Generalities
+###
+
+SaveSettings = "Save settings"
+
+###
+### Account information
+###
+[account]
+Account = "Account information"
+Username = "Login"
+Email = "Mail"
+
+###
+### Perso information
+###
+[perso]
+Information = "Your information"
+Name = Name
+Nickname = "Username (lowercase)"
+Race = Species
+Sex = Sex
+male = male
+female = female
+neutral = "neutral or asexual"
+both = "hermaphrodite"
+
+###
+### SmartLine
+###
+[smartline]
+SmartlineShow = "Shows the SmartLine at the bottom of the screen"
+SmartlineMethod = "Sends a HTTP POST request instead a HTTP GET submitting SmartLine form"
\ No newline at end of file
diff --git a/lang/en/tutorials.conf b/lang/en/tutorials.conf
index c0e474b..30a20bd 100644
--- a/lang/en/tutorials.conf
+++ b/lang/en/tutorials.conf
@@ -1,7 +1,16 @@
+#Zed language config file - Tutorials
+#Language: English
+#Code: en
+#Author: Dereckson
+
+###
+### Tutorial I - reach the hypership
+###
+
[ReachHypership]
WhereYouAre = You're on %1$s, a desolate %2$s in the galaxy.
WhereTheHypershipIs = After some investigation, you learn the hypership is in a far galaxy spiral.
HowToJoinIt = "To reach it, you can: <ul><li>hitchhike, if there are other people around going to the hypership.</li>
<li>try to <a href=/index.php/request/B00001/aid.reach>contact the hypership and ask a shuttle</a></li>
<li><a href=/index.php/explore>explore the place</a> and find a ship to hire</li>
</ul>"
\ No newline at end of file
diff --git a/skins/zed/error.tpl b/skins/zed/error.tpl
index e58bd94..3a48046 100644
--- a/skins/zed/error.tpl
+++ b/skins/zed/error.tpl
@@ -1,55 +1,60 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>{#SiteTitle#}</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="{#StaticContentURL#}/css/960.css" media="screen" />
<link rel="stylesheet" href="{#StaticContentURL#}/css/zed/theme.css" />
</head>
<body>
<!-- Header -->
<div id="header">
<div id="header_content">
<div class="container_16">
- <div class="grid_4 alpha omega suffix_8">
+ <div class="grid_9">
+ <div id="HypershipTime">{get_hypership_time()}</div>
+ </div>
+ <div class="grid_7">
<a href="{get_url()}"><img src="{#StaticContentURL#}/img/zed/logo.png" src="Zed logo" border=0 /></a>
</div>
- <div class="clear"></div>
</div>
</div>
</div>
<div class="clear"></div>
<div class="container_16">
{if $WAP}
<!-- WAP -->
<div class="grid_16 alpha omega">
<div class="wap">{$WAP}</div>
</div>
{/if}
{if $NOTIFY}
<!-- Notify -->
<div class="grid_16 alpha omega">
<div class="notify">{$NOTIFY}</div>
</div>
{/if}
- <div class="grid_16 alpha omega">
+ <!-- Error -->
+ <div class="content_wrapper">
<h1>{$TITLE}</h1>
- <p>{$ERROR_TEXT}</p>
- <p><a href="{get_url()}">{#BackToHome#}</a></p>
+ <div class="content">
+ <p>{$ERROR_TEXT}</p>
+ <p><a href="{get_url()}">{#BackToHome#}</a></p>
+ </div>
</div>
<div class="clear"></div>
<hr />
<div id="footer">
<div class="grid_12 alpha">
<p>[ {#Product#} / {#FatalErrorScreen#} ]</p>
</div>
<div class="grid_4 omega">
<p style="text-align: right">[ <a href="{get_url()}?action=user.logout">{#Logout#}</a> ]</p>
</div>
</div>
</div>
</body>
</html>
\ No newline at end of file
diff --git a/skins/zed/footer.tpl b/skins/zed/footer.tpl
index 5c5ccc9..1dac527 100644
--- a/skins/zed/footer.tpl
+++ b/skins/zed/footer.tpl
@@ -1,18 +1,20 @@
<div class="clear"></div>
+{if $SmartLinePrint}
{include file="smartline.tpl"}
+{/if}
<!-- Footer -->
<hr />
<div id="footer">
<div class="grid_8 alpha">
<p>[ {#Product#} / {$CurrentPerso->location_global} {$CurrentPerso->location_local} / {if $screen}{$screen}{else}Untitled screen{/if} ]</p>
</div>
<div class="grid_8 omega" style="float: right">
<p style="text-align: right">[ {if $MultiPerso}<a href="{get_url()}?action=perso.logout">{sprintf(#SwapPerso#, $CurrentPerso->name)}</a> | {/if}<a href="{get_url()}?action=user.logout">{#Logout#}</a> ]</p>
</div>
</div>
</div>
</body>
</html>
\ No newline at end of file
diff --git a/skins/zed/header.tpl b/skins/zed/header.tpl
index d85cea3..6c70c72 100644
--- a/skins/zed/header.tpl
+++ b/skins/zed/header.tpl
@@ -1,77 +1,69 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>{$PAGE_TITLE} - {#SiteTitle#}</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="{#StaticContentURL#}/css/960.css" media="screen" />
<link rel="stylesheet" href="{#StaticContentURL#}/css/zed/theme.css" />
<script type="text/javascript" src="{#StaticContentURL#}/js/misc.js"></script>
{foreach from=$PAGE_CSS item=css}
<link rel="stylesheet" href="{#StaticContentURL#}/css/{$css}" />
{/foreach}
{foreach from=$PAGE_JS item=js}
<script src="{#StaticContentURL#}/js/{$js}"></script>
{/foreach}
{if $DOJO}
<!-- DOJO -->
<script type="text/javascript" src="{#StaticContentURL#}/js/dojo/dojo/dojo.js" djConfig="isDebug:false, parseOnLoad: true" ></script>
{if $DIJIT}
<link rel="stylesheet" type="text/css" href="{#StaticContentURL#}/css/zed/forms.css">
{/if}
{/if}
</head>
<body{if $DIJIT} class="tundra"{/if}>
<!-- Header -->
<div id="header">
<div id="header_content">
<div class="container_16">
- <div class="grid_4 alpha">
- <a href="{get_url()}"><img src="{#StaticContentURL#}/img/zed/logo.png" src="Zed logo" border=0 /></a>
- </div>
- <div class="grid_12 omega">
- <div class="wall">
- <p>
- {$WALL_TEXT}
- <br /><span class="wall_info">-- <a href="{$WALL_USER_URL}">{$WALL_USER}</a></span>
- </p>
+ <div class="grid_9">
+ <div class="wall" id="header_wall">
+ {$WALL_TEXT}
+ <br />
+ <span class="wall_info">- - <a href="{$WALL_USER_URL}">{$WALL_USER}</a></span>
</div>
+ <div class="clear"></div>
+ <div id="HypershipTime">{get_hypership_time()}</div>
+ </div>
+ <div class="grid_7">
+ <a href="{get_url()}"><img src="{#StaticContentURL#}/img/zed/logo.png" src="Zed logo" border=0 /></a>
</div>
<div class="clear"></div>
</div>
</div>
</div>
<div class="clear"></div>
<!-- Content -->
<div class="container_16">
{if $WAP}
<!-- WAP -->
<div class="grid_16 alpha omega">
<div class="wap">{$WAP}</div>
</div>
<div class="clear"></div>
{/if}
{if $NOTIFY}
<!-- Notify -->
<div class="grid_16 alpha omega">
<div class="notify">{$NOTIFY}</div>
</div>
<div class="clear"></div>
{/if}
- <!-- Where? When? -->
- <div class="info">
- <div class="info_left">
- <strong>{#CurrentLocation#}</strong> {$CurrentPerso->where()}
- </div>
- <div class="info_right">
- <span id="HypershipTime">{get_hypership_time()}</span>
- </div>
- </div>
{if $SmartLine_STDOUT || $SmartLine_STDERR}
{include file="smartline_results.tpl"}
{/if}
diff --git a/skins/zed/messages.tpl b/skins/zed/messages.tpl
index 86adae8..af6adcd 100644
--- a/skins/zed/messages.tpl
+++ b/skins/zed/messages.tpl
@@ -1,13 +1,14 @@

<!-- Messages -->
<div class="grid_16 alpha omega">
{foreach from=$MESSAGES item=message}
-{$who = get_name($message->from)}
-{$url = get_url('user', $who)}
+{$perso = Perso::get($message->from)}
+{$who = $perso->name}
+{$url = get_url('who', $perso->nickname)}
<div class="message {cycle values="light,dark"}">
<div class="message_info"><a href="{$url}">{$who}</a> | {get_hypership_time($message->date)} | <a href="{$url}#Message">{#Reply#}</a> | <a href="?action=msg_delete&id={$message->id}" title="{#DeleteThisMessage#}">X</a></div>
<div class="message_text">{$message->text|text2html}</div>
</div>
{/foreach}
</div>
\ No newline at end of file
diff --git a/skins/zed/motd_add.tpl b/skins/zed/motd_add.tpl
index 9d03daf..e3266ae 100644
--- a/skins/zed/motd_add.tpl
+++ b/skins/zed/motd_add.tpl
@@ -1,33 +1,26 @@
<!-- MOTD preview code -->
<script>
function updateWall () {
wallTextValue = document.getElementById("WallText").value;
wallText = wallTextValue ? wallTextValue : "{#DummyPlaceholder#}";
document.getElementById("wall_message").innerHTML = wallText;
}
</script>
<!-- Add something on the MOTD -->
-
<h1>{#PushMessage#}</h1>
<form method="post">
<label for="WallAddText">{#TextToAdd#}{#_t#}</label><br />
- <input type="text" maxlength="80" size="80" id="WallText" name="text" onblur="updateWall();" onkeyup="updateWall();" onchange="updateWall();" />
+ <input type="text" maxlength="90" size="100" id="WallText" name="text" onblur="updateWall();" onkeyup="updateWall();" onchange="updateWall();" />
<input type="submit" value="{#Push#}" />
</form>
<em>{#TextToAddWarning#}</em>
+<!-- Preview -->
<h2>{#Rendering#}</h2>
-<div class="grid_4 alpha">
- <p><em>{#RenderingWhere#}</em></p>
-</div>
-<div class="grid_12 omega">
- <div class="wall">
- <p>
- <span id="wall_message">{#DummyPlaceholder#}</span>
- <br /><span class="wall_info">-- <a href="{get_url('who', $CurrentPerso->nickname)}">{$CurrentPerso->name}</a></span>
- </p>
- <div class="clear"></div>
- </div>
+<div class="wall">
+ <span id="wall_message">{#DummyPlaceholder#}</span>
+ <br /><span class="wall_info">-- <a href="{get_url('who', $CurrentPerso->nickname)}">{$CurrentPerso->name}</a></span>
<div class="clear"></div>
-</div>
\ No newline at end of file
+</div>
+<div class="clear"></div>
\ No newline at end of file
diff --git a/skins/zed/page_edit.tpl b/skins/zed/page_edit.tpl
index 13ac1b5..9cf93f5 100644
--- a/skins/zed/page_edit.tpl
+++ b/skins/zed/page_edit.tpl
@@ -1,22 +1,26 @@
- <!-- Page editor form -->
- <form method="post" action="{get_url('page', $page['page_code'])}">
- <h2>Page</h2>
- <p><input id="title" type="text" size="80" maxsize="255" name="title" value="{$page['page_title']}" /> ◄ <label for="title">Page title</label>
- <br />
- <input id="edit_reason" type=text size="80" maxsize="255" name="edit_reason" /> ◄ <label for="edit_reason">Edit summary</label></p>
-
- <textarea id="PageEditorContent" name="content" style="width: 100%" rows=20>{$page['page_content']}</textarea>
- <br />
- <input type=hidden name="code" value='{$page['page_code']}' />
- <input type=submit value='Enregistrer' />
- </form>
+ <div class="content_wrapper">
+ <h1>Page editor</h1>
+
+ <!-- Page editor form -->
+ <form method="post" action="{get_url('page', $page['page_code'])}">
+ <p><input id="title" type="text" size="80" maxsize="255" name="title" value="{$page['page_title']}" /> ◄ <label for="title">Page title</label>
+ <br />
+ <input id="edit_reason" type=text size="80" maxsize="255" name="edit_reason" /> ◄ <label for="edit_reason">Edit summary</label></p>
+ <textarea id="PageEditorContent" name="content" style="width: 100%" rows=20>{$page['page_content']}</textarea>
+ <br />
+ <input type=hidden name="code" value='{$page['page_code']}' />
+ <input type=submit value='Enregistrer' />
+ </form>
+ </div>
+
<!-- Loads FCKeditor -->
<script>
var oFCKeditor = new FCKeditor('content');
oFCKeditor.BasePath = '/js/FCKeditor/';
oFCKeditor.Config['SkinPath'] = oFCKeditor.BasePath + 'editor/skins/silver/';
- oFCKeditor.Config['BaseHref'] = 'http://zed.dereckson.be/index.php/page/';
+ oFCKeditor.Config['BaseHref'] = 'http://zed.dereckson.be/page/';
oFCKeditor.Height = 480;
oFCKeditor.ReplaceTextarea();
- </script>
\ No newline at end of file
+ </script>
+
\ No newline at end of file
diff --git a/skins/zed/profile.tpl b/skins/zed/profile.tpl
index 5b0cf4e..cacbaa2 100644
--- a/skins/zed/profile.tpl
+++ b/skins/zed/profile.tpl
@@ -1,99 +1,77 @@
- <!-- Faerie profile -->
- <div class="grid_11 alpha profile" style="background-color: black">
- <div class="profile_id clearfix">
- <h1 class="profile_nick">{$NAME}</h1>
- <div class="profile_info">
-{if $PHONE}
- <img src="/skins/VacuumCleanerBridge/images/tel.png" title="{#PhoneNumber#}" alt="{#PhoneNumberAlt#}" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {$PHONE}
-{/if}
- <br />
-{if $MAIL}
- <img src="/skins/VacuumCleanerBridge/images/mail.png" title="{#Mail#}" alt="{#MailAlt#}" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="mailto:{$MAIL}">{$MAIL}</a>&nbsp;
-{/if}
- </div>
- </div>
- <div class="profile_separator"></div>
+ <!-- Profile -->
+ <div class="clear">&nbsp;</div>
+ <div class="grid_11 alpha">
+ <!-- Profile header -->
+ <div class="profile_id clearfix">
+ <h1 class="profile_nick">{$perso->name}</h1>
+ <div class="profile_info">
+ {$perso->location}&nbsp;<br />
+ {if $perso->is_online()}Online{/if}
+ </div>
+ </div>
+ <div class="clear">&nbsp;</div>
+ <div class="profile">
{if $PICS}
- <div class="profile_photos">
+ <!-- Photos -->
+ <div class="profile_photos">
{foreach from=$PICS item=photo}
- <a rel="lightbox" href="{$URL_PICS}/{$photo->name}" title="{$photo->description}"><img src="{$URL_PICS}/tn/{$photo->name}" alt="{$photo->description}" /></a>
+ <a rel="lightbox" href="{$URL_PICS}/{$photo->name}" title="{$photo->description}"><img src="{$URL_PICS}/tn/{$photo->name}" alt="{$photo->description}" /></a>
{/foreach}
- <div class="photos_item"></div>
- </div>
+ </div>
{/if}
- <div class="profile_text{if $PROFILE_FIXEDWIDTH} fixedwidth{/if}">{if $PROFILE_TEXT != ""}{if $PROFILE_FIXEDWIDTH}{$PROFILE_TEXT}{else}{$PROFILE_TEXT|nl2br}{/if}{else}{if $PROFILE_SELF}<a href="{$URL_USER}/edit/profile">{/if}<img src="/skins/VacuumCleanerBridge/images/empty_profile.png" width="642" height="392" alt="Be creative ! Fill this space with your best words." />{if $PROFILE_SELF}</a>{/if}{/if}</div>
- <div class="profile_separator_light"></div>
- <div class="profile_message">
- <h2 id="Message">{#DropMessage#}</h2>
- <form method="post" action="{$URL_USER}/{$USERNAME}">
- <div class="grid_4 alpha">
- <input type="radio" name="message_type" value="private_message" checked onclick="document.getElementById('MessageSubmit').value = '{#Send#}';">{sprintf(#SendMessage#, $NAME)}
- </div>
- <div class="grid_6 omega">
- <input type="radio" name="message_type" value="profile_comment" onclick="document.getElementById('MessageSubmit').value = '{#Publish#}';">{sprintf(#AddComment#, $NAME)}
- </div>
- <p><textarea rows="7" cols="64" name="message"></textarea></p>
- <p><input id="MessageSubmit" type="submit" name="MessageSubmit" value="{#Send#}" /></p>
-
- </form>
- </div>
- </div>
+ <!-- Text -->
+ <div class="profile_text{if $PROFILE_FIXEDWIDTH} fixedwidth{/if}">{if $PROFILE_TEXT != ""}{if $PROFILE_FIXEDWIDTH}{$PROFILE_TEXT}{else}{$PROFILE_TEXT|nl2br}{/if}{else}{if $PROFILE_SELF}<a href="{get_url('who')}/edit/profile">{/if}<img src="/skins/VacuumCleanerBridge/images/empty_profile.png" width="642" height="392" alt="Be creative ! Fill this space with your best words." />{if $PROFILE_SELF}</a>{/if}{/if}</div>
+ <div class="profile_separator_light"></div>
+ <div class="profile_message">
+ <h2 id="Message">{#DropMessage#}</h2>
+ <form method="post" action="{get_url('who')}/{$perso->nickname}">
+ <div class="grid_4 alpha">
+ <input type="radio" name="message_type" value="private_message" checked onclick="document.getElementById('MessageSubmit').value = '{#Send#}';">{sprintf(#SendMessage#, $NAME)}
+ </div>
+ <div class="grid_6 omega">
+ <input type="radio" name="message_type" value="profile_comment" onclick="document.getElementById('MessageSubmit').value = '{#Publish#}';">{sprintf(#AddComment#, $NAME)}
+ </div>
+ <p><textarea rows="7" cols="64" name="message"></textarea></p>
+ <p><input id="MessageSubmit" type="submit" name="MessageSubmit" value="{#Send#}" /></p>
+
+ </form>
+ </div>
+ </div>
+ </div>
- <!-- Faerie content -->
+ <!-- User content -->
<div class="grid_5 omega">
<div class="sidebar_border"></div>
<div id="sidebar">
<div class="border_top"></div>
<div class="sidebar_content">
{if $PROFILE_SELF}
<!-- {{counter name=section}|romanize}. edit profile, account, photos -->
<h2>{#EditMyPage#}</h2>
<ul>
- <li><a href="{$URL_USER}/edit/profile">{#EditProfile#}</a></li>
- <li><a href="{$URL_USER}/edit/account">{#EditAccount#}</a></li>
- <li><a href="{$URL_USER}/edit/photos">{if $PICS}{#ManagePhotos#}{else}{#AddPhoto#}{/if}</a></li>
+ <li><a href="{get_url('who','edit','profile')}">{#EditProfile#}</a></li>
+ <li><a href="{get_url('who','edit','account')}">{#EditAccount#}</a></li>
+ <li><a href="{get_url('who','edit','photos')}">{if $PICS}{#ManagePhotos#}{else}{#AddPhoto#}{/if}</a></li>
</ul>
{/if}
-{if $SIDEBAR_LASTPICS}
-
- <!-- {{counter name=section}|romanize}. content from http://photos.folleterre.org -->
- <h2>{#LastSharedPhotos#}</h2>
- <div style="text-align: center">
-{foreach from=$SIDEBAR_LASTPICS item=pic}
- <a href="{$pic->link}"><img src="{$pic->url}" /></a>
-{/foreach}
- <br />
- <a href="{$SIDEBAR_LASTPICS_URL}">{#ViewRecentUploads#}</a>
- </div>
-{/if}
-
<!-- {{counter name=section}|romanize}. sidebar placeholder/explanation -->
<h2>Sidebar</h2>
<p>Here will be published new art submission, request/offers post it, external content imported, etc.</p>
-{if $lift}
-
- <!-- {{counter name=section}|romanize}. lift request -->
- <div class="postit_cyan lift">
- <h2>{$NAME} needs a pickup for {$lift->event->name}</h2>
- <p>{#IdealDate#}{#_t#} {$lift->date}<br />{#From#}{#_t#} {$lift->from}</p>
- <p><a href="{$URL_EVENT}/{$lift->event->id}/travel?LiftID={$lift->id}">{#OfferLift#}</a></p>
- </div>
-{/if}
</div>
<div class="border_bottom"></div>
</div>
</div>
{if $PROFILE_COMMENTS}
<!-- Profile comments -->
- <div class="grid_16 alpha omega profile_comments" id="comments">
+ <div class="grid_16 alpha omega profile_comments" id="comments" style="margin-bottom: 1em;">
{foreach from=$PROFILE_COMMENTS item=comment}
- <div class="comment">
+ <div class="comment black">
<div class="profile_comments_text"><p>{$comment->text|nl2br}</p></div>
- <div class="profile_comments_info">-- <a href="{$URL_USER}/{$comment->author}">{$comment->authorname}</a>, {$comment->date|date_format:"%Y-%m-%d %H:%M:%S"}.</div>
+ <div class="profile_comments_info">-- <a href="{get_url('who')}/{$comment->author}">{$comment->authorname}</a>, {$comment->date|date_format:"%Y-%m-%d %H:%M:%S"}.</div>
</div>
{/foreach}
</div>
{/if}
diff --git a/skins/zed/profile_edit.tpl b/skins/zed/profile_edit.tpl
index c4d8e20..966ce9a 100644
--- a/skins/zed/profile_edit.tpl
+++ b/skins/zed/profile_edit.tpl
@@ -1,58 +1,58 @@
 <!-- Calls dojo -->
<script src="/js/dojo/dojo/dojo.js" type="text/javascript"
djConfig="isDebug: false, parseOnLoad: true"></script>
<script type="text/javascript">
dojo.require("dijit.form.Form");
dojo.require("dijit.form.CheckBox");
dojo.require("dijit.form.Button");
function SetWidgetFont(id, font) {
//TODO: document.getElementById(id).style.font = font;
}
</script>
<!-- Edit profile -->
<div class="grid_11 alpha profile">
<div class="profile_id clearfix">
<h1 class="profile_nick" id="UserLongname">{$USERNAME}</h1>
</div>
<div class="profile_separator"></div>
<div class="profile_text">
<form action="" class="search_form" name="faerie" method="post">
<h2>{#ProfileTextTitle#}</h2>
<textarea style="font-family: Calibri" id="ProfileText" rows="16" cols="72" name="text" class="text">{$PROFILE_TEXT}</textarea><br />
<div class="row" style="background-color: white; color: black;">
<span>{#ProfileFont#}{#_t#}</span>
<input type="radio" name="fixedwidth" id="fixedwidthNo" value="0" dojoType="dijit.form.RadioButton" {if !$PROFILE_FIXEDWIDTH}checked{/if} onclick="SetWidgetFont('ProfileText', 'Calibri')" />
<label for="fixedwidthNo"><span style="font-family: Calibri, Arial; font-weight: 100; font-size: 1.25em;">{#Calibri#}</span></label>
<input type="radio" name="fixedwidth" id="fixedwidthYes" value="1" dojoType="dijit.form.RadioButton" {if $PROFILE_FIXEDWIDTH}checked={/if} onclick="SetWidgetFont('ProfileText', 'FixedSys')" />
<label for="fixedwidthYes"><span style="font-family: Fixedsys, Fixed; font-weight: 100;">{#FixedSys#}</span></label>
</div>
<div class="row">
<button dojoType="dijit.form.Button" iconClass="dijitEditorIcon dijitEditorIconSave" type=submit onclick="document.forms[0].submit()">
{#SaveProfile#}
</button>
<noscript>
<input type="submit" value="{#SaveProfile#} {#JavaScriptSafeMessage#}" />
</noscript>
</div>
</form>
</div>
</div>
<!-- Faerie content -->
<div class="grid_5 omega">
<div class="sidebar_border"></div>
<div id="sidebar">
<div class="border_top"></div>
<div class="sidebar_content">
<h2>{#EditMyPage#}</h2>
<ul>
<li>{#EditProfile#}</li>
- <li><a href="{$URL_USER}/edit/account">{#EditAccount#}</a></li>
- <li><a href="{$URL_USER}/edit/photos">{if $PICS}{#ManagePhotos#}{else}{#AddPhoto#}{/if}</a></li>
+ <li><a href="{get_url('who')}/edit/account">{#EditAccount#}</a></li>
+ <li><a href="{get_url('who')}/edit/photos">{if $PICS}{#ManagePhotos#}{else}{#AddPhoto#}{/if}</a></li>
</ul>
</div>
<div class="border_bottom"></div>
</div>
</div>
\ No newline at end of file
diff --git a/skins/zed/profile_photo.tpl b/skins/zed/profile_photo.tpl
index c1d66de..916816f 100644
--- a/skins/zed/profile_photo.tpl
+++ b/skins/zed/profile_photo.tpl
@@ -1,50 +1,50 @@
 <!-- Add a photo -->
<div class="grid_11 alpha profile">
<div class="profile_id clearfix">
<h1 class="profile_nick" id="UserLongname">{$USERNAME}</h1>
</div>
<div class="profile_separator"></div>
<div class="profile_text">
<h2>{#AddPhotoToProfile#}</h2>
<form name="PhotoUpload" method="post" enctype="multipart/form-data">
<p>{#AddPhotoExplanations#}</p>
<p><label>Photo{#_t#}</label> <INPUT type="file" name="photo" /></p>
<p><label>{#ShortDescription#}{#_t#}</label> <input type="text" maxlength="63" size="32" name="description"></p>
<p><INPUT type="checkbox" name="SafeForWork" id="SafeForWork" value="0" /> <label for="SafeForWork">{#SafeForWorkLabel#}</label></p>
<p><input type="submit" value="{#Upload#}" /></p>
</form>
</div>
</div>
<div class="grid_5 omega">
<div class="sidebar_border"></div>
<div id="sidebar" style="min-height: inherit;">
<div class="border_top"></div>
<div class="sidebar_content">
<h2>{#EditMyPage#}</h2>
<ul>
- <li><a href="{$URL_USER}/edit/profile">{#EditProfile#}</a></li>
- <li><a href="{$URL_USER}/edit/account">{#EditAccount#}</a></li>
+ <li><a href="{get_url('who')}/edit/profile">{#EditProfile#}</a></li>
+ <li><a href="{get_url('who')}/edit/account">{#EditAccount#}</a></li>
<li>{if $PICS}{#ManagePhotos#}{else}{#AddPhoto#}{/if}</a></li>
</ul>
</div>
<div class="border_bottom"></div>
</div>
</div>
{if $PICS}
<!-- Manage current photos -->
<div class="grid_16 alpha omega profile_comments">
<h2>{#ManageCurrentPhotos#}</h2>
<div class="photos">
{foreach from=$PICS item=photo}
<div class="photo" style="float: left">
<a rel="lightbox" href="{$URL_PICS}/{$photo->name}" title="{$photo->description}"><img src="{$URL_PICS}/tn/{$photo->name}" alt="{$photo->description}" /></a>
<br />
- <a href="{$URL_USER}/edit/photos/edit/{$photo->id}" title="{#EditPictureProperties#}"><img src="/skins/VacuumCleanerBridge/images/open.gif" alt="{#PictureProperties#}"></a>
- <a href="{$URL_USER}/edit/photos/delete/{$photo->id}" title="{#DeleteThisPicture#}"><img src="/skins/VacuumCleanerBridge/images/del.gif" alt="{#Delete#}"></a>
+ <a href="{get_url('who')}/edit/photos/edit/{$photo->id}" title="{#EditPictureProperties#}"><img src="/skins/VacuumCleanerBridge/images/open.gif" alt="{#PictureProperties#}"></a>
+ <a href="{get_url('who')}/edit/photos/delete/{$photo->id}" title="{#DeleteThisPicture#}"><img src="/skins/VacuumCleanerBridge/images/del.gif" alt="{#Delete#}"></a>
</div>
{/foreach}
</div>
{/if}
</div>
\ No newline at end of file
diff --git a/skins/zed/profile_photo_edit.tpl b/skins/zed/profile_photo_edit.tpl
index e0064d1..b727b9e 100644
--- a/skins/zed/profile_photo_edit.tpl
+++ b/skins/zed/profile_photo_edit.tpl
@@ -1,36 +1,36 @@
<div class="grid_11 alpha">
<h1>{#EditPhoto#}</h1>
<a rel="lightbox" href="{$URL_PICS}/{$photo->name}" title="{$photo->description}"><img src="{$URL_PICS}/tn/{$photo->name}" alt="{$photo->description}" /></a>
<h2>{#PhotoInfo#}</h2>
<form method=post><input type="hidden" name="id" value="{$photo->id}" />
<blockquote>
<table>
<tr><td><strong><label for="description">{#Description#}</label></strong></td><td><input type='text' id='description' name='description' maxlength=63 value="{$photo->description}" /></td></tr>
<tr><td><strong><label for="safe">{#SafeForWork#}</label></strong></td><td><input type='checkbox' id='safe' name='safe' maxlength=3 size=5 value=1{if $photo->safe} checked{/if} /></td></tr>
<tr><td><strong><label for="avatar">{#UseAsAvatar#}</label></strong></td><td><input type='checkbox' id='avatar' name='avatar' maxlength=3 size=5 value=1{if $photo->avatar} checked{/if} /></td></tr>
<tr><td>&nbsp;</td><td><input type="submit" value="{#Save#}" /></td></tr>
</table>
</blockquote>
</form>
<h2>{#OtherActions#}</h2>
<ul>
- <li><a href="{$URL_USER}/edit/photos/delete/{$photo->id}" title="{#DeletePicture#}">{#DeletePicture#}</a></li>
- <li><a href="{$URL_USER}/edit/photos">{#BackToPhotoManager#}</a></li>
+ <li><a href="{get_url('who')}/edit/photos/delete/{$photo->id}" title="{#DeletePicture#}">{#DeletePicture#}</a></li>
+ <li><a href="{get_url('who')}/edit/photos">{#BackToPhotoManager#}</a></li>
</ul>
</div>
<div class="grid_5 omega">
<div class="sidebar_border"></div>
<div id="sidebar" style="min-height: inherit;">
<div class="border_top"></div>
<div class="sidebar_content">
<h2>{#EditMyPage#}</h2>
<ul>
- <li><a href="{$URL_USER}/edit/profile">{#EditProfile#}</a></li>
- <li><a href="{$URL_USER}/edit/account">{#EditAccount#}</a></li>
+ <li><a href="{get_url('who')}/edit/profile">{#EditProfile#}</a></li>
+ <li><a href="{get_url('who')}/edit/account">{#EditAccount#}</a></li>
<li>{if $PICS}{#ManagePhotos#}{else}{#AddPhoto#}{/if}</a></li>
</ul>
</div>
<div class="border_bottom"></div>
</div>
</div>
\ No newline at end of file
diff --git a/skins/zed/raw.tpl b/skins/zed/raw.tpl
index 4cda3e2..dcaebd0 100644
--- a/skins/zed/raw.tpl
+++ b/skins/zed/raw.tpl
@@ -1,3 +1,8 @@
-<div class="grid_16 alpha omega raw">
+<div class="content_wrapper">
+{if $PAGE_TITLE}
+ <h1>{$PAGE_TITLE}</h1>
+{/if}
+ <div class="content">
{$CONTENT}
-</div>
\ No newline at end of file
+ </div>
+</div>
diff --git a/skins/zed/requests/aid.reach.tpl b/skins/zed/requests/aid.reach.tpl
index 243183f..3693cf4 100644
--- a/skins/zed/requests/aid.reach.tpl
+++ b/skins/zed/requests/aid.reach.tpl
@@ -1,16 +1,20 @@
<!-- DIJIT -->
<script type="text/javascript">
dojo.require("dijit.form.Form");
dojo.require("dijit.form.ValidationTextBox");
+ dojo.require("dijit.form.Button");
</script>
<!-- Request form: aid.reach -->
<h1>Communicator</h1>
<h2>Send a request to the hypership</h2>
<form dojoType="dijit.form.Form" name="aid.reach" method="post">
<div class="row">
<label class="firstLabel" for="PostTitle">{#Title#}</label>
<input dojoType="dijit.form.ValidationTextBox" value="{$request->title}" type="text" id="PostTitle" name="title" class="long" required="true" />
</div>
+ <div class="row">
+ <button dojoType="dijit.form.Button" iconClass="dijitEditorIcon dijitEditorIconSave" type="submit" value="Save" />Send</button>
+ </div>
<p>Your request will be sent to humans.</p>
</form>
\ No newline at end of file
diff --git a/skins/zed/settings_page.tpl b/skins/zed/settings_page.tpl
new file mode 100644
index 0000000..8b87632
--- /dev/null
+++ b/skins/zed/settings_page.tpl
@@ -0,0 +1,46 @@
+ <!-- DIJIT -->
+ <script type="text/javascript">
+ dojo.require("dijit.form.Form");
+ dojo.require("dijit.form.TextBox");
+ dojo.require("dijit.form.ValidationTextBox");
+ dojo.require("dijit.form.Button");
+ dojo.require("dijit.form.FilteringSelect");
+ dojo.require("dijit.form.CheckBox");
+ </script>
+
+ <!-- Settings - #{$page->id} -->
+ <h2>{#$page->title#}</h2>
+ <form method="post">
+ <input type="hidden" name="settings.page" value="{$page->id}" />
+{foreach from=$page->settings item=setting}
+ <div class="row">
+{if $setting->field == "validationtext"}
+ <label for="{$setting->key}" class="firstLabel ">{#$setting->key#}</label>
+ <input dojoType="dijit.form.ValidationTextBox" regExp="{$setting->regExp}" id="{$setting->key}" name="{$setting->key}" type="text" value="{$setting->get()}" class="long" />
+{elseif $setting->field == "text"}
+ <label for="{$setting->key}" class="firstLabel ">{#$setting->key#}</label>
+ <input dojoType="dijit.form.TextBox" id="{$setting->key}" name="{$setting->key}" type="text" value="{$setting->get()}" class="long" />
+{elseif $setting->field == "password"}
+ <label for="{$setting->key}" class="firstLabel ">{#$setting->key#}</label>
+ <input dojoType="dijit.form.TextBox" id="{$setting->key}" name="{$setting->key}" type="password" value="{$setting->get()}" class="long" />
+ </div>
+ <div class="row">
+ <label for="{$setting->key}_confirm" class="firstLabel">{#$setting->key#} (confirm it)</label>
+ <input dojoType="dijit.form.TextBox" id="{$setting->key}_confirm" name="{$setting->key}_confirm" type="password" value="{$setting->get()}" class="long" />
+{elseif $setting->field == "filteredlist"}
+ <label for="{$setting->key}" class="firstLabel ">{#$setting->key#}</label>
+ <select id="{$setting->key}" name="{$setting->key}" dojoType="dijit.form.FilteringSelect" class="long">
+{foreach from=$setting->choices item=value key=key}
+ <option value="{$value}">{#$key#}</option>
+{/foreach}
+ </select>
+{elseif $setting->field == "checkbox"}
+ <input type="checkbox" dojoType="dijit.form.CheckBox" id="{$setting->key}" name="{$setting->key}" value="1" {if $setting->get()}checked="true" {/if}/> <label for="{$setting->key}">{#$setting->key#}</label>
+{else}{dprint_r($setting)}
+{/if}
+ </div>
+{/foreach}
+ <div class="row">
+ <button dojoType="dijit.form.Button" iconClass="dijitEditorIcon dijitEditorIconSave" type="submit" value="Save" />{#SaveSettings#}</button>
+ </div>
+ </form>
\ No newline at end of file
diff --git a/skins/zed/ship.tpl b/skins/zed/ship.tpl
new file mode 100644
index 0000000..b029bc1
--- /dev/null
+++ b/skins/zed/ship.tpl
@@ -0,0 +1,30 @@
+ <!-- Ship CSS -->
+ <style>
+ .content textarea {
+ background-color: inherit;
+ color: white;
+ border: dashed #343434 2px;
+ width: 100%;
+ background-image: url("/img/zed/opaque_20.png");
+ }
+ </style>
+
+ <!-- Ship content -->
+ <div class="content_wrapper">
+ <h1>{$ship->name}</h1>
+ <div class="content">
+ <p>Lorem ipsum dolor</p>
+ <h2>Your notes</h2>
+ <form method="POST">
+ <input type="hidden" name="action" value="ship.setnote">
+ <textarea id="ShipNote" name="note" rows="8" onfocus="set_opacity(this.id, 20)" onBlur="set_opacity(this.id, 0)">{$note}</textarea>
+ <br />
+ <input type="submit" value="Save note" />
+ </form>
+ </div>
+ </div>
+
+ <script>
+ //Sets the focus on note textarea
+ document.getElementById('ShipNote').focus();
+ </script>
\ No newline at end of file
diff --git a/skins/zed/story.tpl b/skins/zed/story.tpl
index ae7be18..f7b0b44 100644
--- a/skins/zed/story.tpl
+++ b/skins/zed/story.tpl
@@ -1,13 +1,30 @@
+{$description = $section->description|trim}
+{foreach from=$section->hooks item=hook}
+{$hook->update_description($description)}
+{/foreach}
<!-- Story -->
- <div class="story">
+ <div class="content_wrapper">
<h1>{$PAGE_TITLE}</h1>
- <h2>{$section->title}</h2>
- <p>{$section->description|trim|text2html}</p>
+ <div class="content">
+ <h2>{$section->title}</h2>
+ <p>{$description|text2html}</p>
+ <ul>
{if $section->choices}
- <ul>
{foreach from=$section->choices item=choice}
- <li><a href="{get_url('explore', $choice->guid)}">{$choice->text}</a></li>
+ <li><a href="{get_url('explore', $choice->guid)}">{$choice->text}</a></li>{/foreach}{/if}
+{$links = array()}
+{foreach from=$section->hooks item=hook}
+{$hook->get_choices_links($links)}
+{/foreach}
+{foreach from=$links item=link}
+ <li><a href="{$link[1]}">{$link[0]}</a></li>{/foreach}
+ </ul>
+{foreach from=$section->hooks item=hook}
+{$hook->add_content()}
{/foreach}
- </ul>
-{/if}
- </div>
\ No newline at end of file
+ </div>
+ </div>
+
+{foreach from=$section->hooks item=hook}
+{$hook->add_html()}
+{/foreach}
\ No newline at end of file
diff --git a/skins/zed/tutorial/hypership_reach.tpl b/skins/zed/tutorial/hypership_reach.tpl
index 9e7ee89..a730a19 100644
--- a/skins/zed/tutorial/hypership_reach.tpl
+++ b/skins/zed/tutorial/hypership_reach.tpl
@@ -1,20 +1,31 @@
{if $DOJO}
{/if}
<!-- Floating panes -->
<script type="text/javascript" src="{#StaticContentURL#}/js/dojo/dojox/layout/FloatingPane.js"></script>
<link rel="stylesheet" type="text/css" href="{#StaticContentURL#}/js/dojo/dojox/layout/resources/FloatingPane.css" />
<link rel="stylesheet" type="text/css" href="{#StaticContentURL#}/js/dojo/dojox/layout/resources/ResizeHandle.css" />
<!-- Dock -->
<style type="text/css">
@import "{#StaticContentURL#}/js/dojo/dijit/themes/dijit.css";
</style>
<!-- Help to reach the hypership -->
<div dojoType="dojox.layout.FloatingPane" title="Join the hypership" resizable="true" id="floaterHypershipReach" class="floatingPaneTutorial" duration="300">
+{if $CurrentPerso->location_global[0] == "S"}
+ <p>Congratulations! You found a ship.</p>
+ <p>You're aboard the {$CurrentPerso->location->ship->name}.</p>
+{if $controller == "ship"}
+ <p>In the future, you will able to explore the ship, but this is not yet implemented yet in this alpha preview.</p>
+{if $note == ""}
+ <p>Your notes is the only information generally available about ships. For reference, you should note something like "Took the {$CurrentPerso->location->ship->name} at {get_hypership_time()} from ... to the hypership."</p>
+{/if}
+{/if}
+{else}
<p>{sprintf(#WhereYouAre#, $CurrentPerso->where(), lang_get($CurrentPerso->location->body_kind))}</p>
<p>{#WhereTheHypershipIs#}</p>
<p>{#HowToJoinIt#}</p>
+{/if}
</div>
\ No newline at end of file
diff --git a/skins/zed/user_account.tpl b/skins/zed/user_account.tpl
index 2df782b..5cf64ca 100644
--- a/skins/zed/user_account.tpl
+++ b/skins/zed/user_account.tpl
@@ -1,88 +1,88 @@
<!-- Calls dojo -->
<script src="/js/dojo/dojo/dojo.js" type="text/javascript"
djConfig="isDebug: false, parseOnLoad: true"></script>
<script type="text/javascript">
dojo.require("dijit.form.Form");
dojo.require("dijit.form.ValidationTextBox");
dojo.require("dijit.form.CheckBox");
dojo.require("dijit.form.Button");
function updateMail (mail) {
document.getElementById('UserEmail').innerHTML =
'<a href="mailto:' + mail + '">' + mail + '</a>';
}
</script>
<!-- Edit user account form -->
<div class="grid_11 alpha profile">
<div class="profile_id clearfix">
<h1 class="profile_nick" id="UserLongname">{$user->longname}</h1>
<div class="profile_info">
<br />
<img src="/skins/VacuumCleanerBridge/images/mail.png" title="{#Mail#}" alt="{#MailAlt#}" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span id="UserEmail">{mailto address=$user->email}</span>&nbsp;
</div>
</div>
<div class="profile_separator"></div>
<div class="profile_text">
<br />
<form dojoType="dijit.form.Form" name="UserAccount" method="POST">
<input type="hidden" name="UserAccount" value="1" />
<div class="row">
<span class="firstLabel">{#Login#}</span>
{$user->username}
</div>
<div class="row">
<label class="firstLabel" for="longname">{#LongName#}</label>
<input type="text" id="longname" name="longname" class="long"
value="{$user->longname}"
dojoType="dijit.form.ValidationTextBox"
required="false"
onChange="document.getElementById('UserLongname').innerHTML = document.getElementById('longname').value;";
/>
- </div>
+ </div>
<div class="row">
<label class="firstLabel" for="realname">{#RealName#}</label>
<input type="text" id="realname" name="realname" class="long"
value="{$user->realname}"
dojoType="dijit.form.ValidationTextBox"
required="false"
/>
<span class="dojotooltip" dojoType="dijit.Tooltip" connectId="realname">{#RealNameToolTip#}</span>
</div>
<div class="row">
<label class="firstLabel" for="email">{#Mail#}</label>
<input type="text" id="email" name="email" class="long"
value="{$user->email}"
dojoType="dijit.form.ValidationTextBox"
- required="false"
+ required="false"
onChange="javascript:updateMail(arguments[0]);"
/>
</div>
<div class="row">
- <button dojoType="dijit.form.Button" iconClass="dijitEditorIcon dijitEditorIconSave" type=submit onclick="document.forms[0].submit()">
+ <button dojoType="dijit.form.Button" iconClass="dijitEditorIcon dijitEditorIconSave" type="submit" onclick="document.forms[0].submit()">
{#UpdateAccountInfo#}
</button>
<noscript>
<input type="submit" value="{#UpdateAccountInfo#} {#JavaScriptSafeMessage#}" />
</noscript>
</div>
</form>
</div>
</div>
<!-- Faerie content -->
<div class="grid_5 omega">
<div class="sidebar_border"></div>
<div id="sidebar">
<div class="border_top"></div>
<div class="sidebar_content">
<h2>{#EditMyPage#}</h2>
<ul>
- <li><a href="{$URL_USER}/edit/profile">{#EditProfile#}</a></li>
+ <li><a href="{get_url('who')}/edit/profile">{#EditProfile#}</a></li>
<li>{#EditAccount#}</li>
- <li><a href="{$URL_USER}/edit/photos">{if $PICS}{#ManagePhotos#}{else}{#AddPhoto#}{/if}</a></li>
+ <li><a href="{get_url('who')}/edit/photos">{if $PICS}{#ManagePhotos#}{else}{#AddPhoto#}{/if}</a></li>
</ul>
</div>
<div class="border_bottom"></div>
</div>
</div>
\ No newline at end of file
diff --git a/start.html b/start.html
new file mode 100644
index 0000000..f6b7cc3
--- /dev/null
+++ b/start.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd"
+ >
+<html lang="en">
+<head>
+ <title>Zed. The future is our dreams.</title>
+ <style>
+ body {
+ background-color: #303030;
+ margin: 0 0 0 0;
+ overflow: hidden;
+ }
+
+ #start {
+ margin: auto;
+ width: 960px;
+ height: 4000px;
+ background-color: #343434;
+ background-image: url(img/misc/start.png);
+ background-position: top left;
+ background-repeat: no-repeat;
+ border-left: dashed 3px white;
+ border-right: dashed 3px white;
+ }
+ </style>
+</head>
+<body>
+ <div id="start"></div>
+</body>
+</html>
diff --git a/tour2.html b/tour2.html
new file mode 100644
index 0000000..3b1ce8a
--- /dev/null
+++ b/tour2.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <title>Enter</title>
+ <link rel="stylesheet" type="text/css" href="css/grid.css" media="screen" />
+ <script src="http://zed.espace-win.org.nyud.net/js/jquery-1.3.2.min.js"></script>
+ <script src="http://zed.espace-win.org.nyud.net/js/dimensions.js"></script>
+ <script src="http://zed.espace-win.org.nyud.net/js/tour2.js"></script>
+ <script>
+
+ </script>
+ <style>
+ body {
+ background-color: #343434;
+ }
+
+ H1 {
+ font-family: Helvetica, Arial;
+ }
+
+ #Tour {
+ background-image: url(http://zed.espace-win.org.nyud.net/img/tour/bg.jpg);
+ height: 748px;
+ width: 748px;
+ margin: auto auto auto auto;
+ z-index: 20;
+ }
+
+ #TourHighlight {
+ position: relative;
+ z-index: 50;
+ }
+ </style>
+ </head>
+ <body>
+ <div class="container_16">
+ <div class="grid_16">
+ <div id="Tour">
+ <div id="TourHighlight"></div>
+ </div>
+ </div>
+ <div class="clear"></div>
+ </div>
+ </body>
+</html>
\ No newline at end of file
diff --git a/zed.kpf b/zed.kpf
index 90ab0ff..b160dbb 100644
--- a/zed.kpf
+++ b/zed.kpf
@@ -1,44 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Komodo Project File - DO NOT EDIT -->
<project id="4c047888-c287-4e11-a433-bff6e3ce2d9b" kpf_version="4" name="zed.kpf">
<folder id="6448c4db-ffe1-4fb9-a072-9833a9b0c08c" idref="27ba7062-828a-4571-bbb7-9ad4e3d73511" name="Snippets">
</folder>
<menu accesskey="z" id="be701072-b18f-4f3a-88d8-db22f59f7c30" idref="27ba7062-828a-4571-bbb7-9ad4e3d73511" name="zed.dereckson.be" priority="100">
</menu>
<folder id="27ba7062-828a-4571-bbb7-9ad4e3d73511" idref="4c047888-c287-4e11-a433-bff6e3ce2d9b" name="_project components">
</folder>
<snippet id="9e25e373-ffc7-4df9-8dfd-4a66d6cca153" idref="5a3450a0-2b97-46a9-bfee-e2c18055948c" indent_relative="true" keyboard_shortcut='Alt+"' name="{##}" set_selection="true">
{#!@#_currentPos!@#_anchor#}</snippet>
<folder id="5a3450a0-2b97-46a9-bfee-e2c18055948c" idref="6448c4db-ffe1-4fb9-a072-9833a9b0c08c" name="Smarty conf">
</folder>
<folder id="7d6a2b54-bf41-4877-a8b3-fa72fe694988" idref="6448c4db-ffe1-4fb9-a072-9833a9b0c08c" name="dojo form">
</folder>
<folder id="afcdd807-b8aa-4465-ba5d-8547f0cad9b0" idref="6448c4db-ffe1-4fb9-a072-9833a9b0c08c" name="MySQL">
</folder>
<snippet icon="chrome://famfamfamsilk/skin/icons/application_form.png" id="45bdf25d-27ed-4e59-b1f3-ce694024b202" idref="7d6a2b54-bf41-4877-a8b3-fa72fe694988" indent_relative="true" keyboard_shortcut="" name="ValidationTextBox" set_selection="false">
&lt;div class="row"&gt;
&lt;label class="firstLabel" for="item"&gt;Item&lt;/label&gt;
&lt;input type="text" id="item" name="item" class="long"
value=""
dojoType="dijit.form.ValidationTextBox"
required="false"
/&gt;
&lt;span class="dojotooltip" dojoType="dijit.Tooltip" connectId="item"&gt;Help&lt;/span&gt;
&lt;/div&gt;!@#_currentPos!@#_anchor</snippet>
<snippet icon="chrome://famfamfamsilk/skin/icons/book_go.png" id="5935e19d-df72-41ae-9f65-22926961ad38" idref="afcdd807-b8aa-4465-ba5d-8547f0cad9b0" indent_relative="true" keyboard_shortcut="" name="query, execute" set_selection="true">
if (!$db-&gt;sql_query($sql))
message_die(SQL_ERROR, "!@#_anchorCan't execute query!@#_currentPos", '', __LINE__, __FILE__, $sql);</snippet>
<snippet icon="chrome://famfamfamsilk/skin/icons/book_go.png" id="aca704ef-e5ad-4523-b372-94d98ee20896" idref="afcdd807-b8aa-4465-ba5d-8547f0cad9b0" indent_relative="true" keyboard_shortcut="" name="query, fetchrow, while" set_selection="true">
if (!$result = $db-&gt;sql_query($sql)) {
message_die(SQL_ERROR, "!@#_anchorUnable to query the table!@#_currentPos", '', __LINE__, __FILE__, $sql);
}
while ($row = $db-&gt;sql_fetchrow($result)) {
}</snippet>
<command cwd="" doNotOpenOutputWindow="0" env="" icon="chrome://openoffice/skin/icons/navigator-open-toolbar.png" id="90cf8021-64a3-4559-aec3-1aeda016875c" idref="be701072-b18f-4f3a-88d8-db22f59f7c30" insertOutput="0" keyboard_shortcut="" name="Run SQL script" operateOnSelection="0" parseOutput="0" parseRegex="" runIn="command-output-window" showParsedOutputList="0">
"c:\WebServer\MySQL\bin\mysql.exe" -uzed -pzed zed &lt; %F</command>
<preference-set idref="4c047888-c287-4e11-a433-bff6e3ce2d9b">
<boolean id="import_live">1</boolean>
- <string id="mappedPaths">::http://zed.dereckson.be/apps/HelloWorldWebService.php##file:///C:/WebServer/wwwroot/dereckson.be/zed/apps/HelloWorldWebService.php</string>
+ <string id="mappedPaths">http://zed.dereckson.be/apps/HelloWorldWebService.php##file:///C:/WebServer/wwwroot/dereckson.be/zed/apps/HelloWorldWebService.php</string>
+ <string id="phpExtraPaths">H:\WebServer\wwwroot\lib;H:\WebServer\PHP5\PEAR</string>
</preference-set>
</project>

File Metadata

Mime Type
text/x-diff
Expires
Mon, Nov 25, 23:23 (5 h, 46 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
20853
Default Alt Text
(305 KB)

Event Timeline