Permalink
Browse files

New feature: Multiple (homepage) URLs per Course

Users may now define multiple additional links for courses. This can be
used to deep-link contents such as lecture scripts along with the link
to the homepage.

The database's layout has changed! Use tools/migrate_course_url.php
for migration.
  • Loading branch information...
1 parent 2e4979b commit 0bca40beef09194d50083079e61e8a793f7cf6ec @phillipberndt committed Jun 12, 2011
Showing with 167 additions and 17 deletions.
  1. +36 −5 details.inc.php
  2. BIN images/application_form_edit.png
  3. +5 −3 main.inc.php
  4. +17 −4 style.css
  5. +4 −1 system.php
  6. +20 −0 tools/migrate_course_url.php
  7. +85 −4 uebungszettel.js
View
@@ -45,10 +45,38 @@
gotop("index.php?q=details&f=".$feed_id);
}
+ // Zusätzliche URLs
+ if($_GET['get'] == 'urls') {
+ ob_end_clean();
+ header('Content-Type: application/json');
+ $urls = array();
+ foreach($database->query('SELECT title, url FROM feed_links WHERE feed_id = ' . intval($feed_id)) as $urlset) {
+ $urls[$urlset['title']] = $urlset['url'];
+ }
+ die(json_encode($urls));
+ }
+
// Bearbeiten per AJAX
+ if($can_edit && isset($_POST['additional_urls'])) {
+ ob_end_clean();
+ $title = trim($_POST['title']);
+ if(!$title) die('0');
+ $url = trim($_POST['url']);
+ if(!$url) {
+ $database->prepare('DELETE FROM feed_links WHERE feed_id = ? AND title = ?')->execute(array($feed_id, $title));
+ die('1');
+ }
+ if($url && !preg_match('#^http://#i', $url)) {
+ die('0');
+ }
+ $database->prepare('REPLACE INTO feed_links (feed_id, title, url) VALUES (?, ?, ?)')->execute(array($feed_id, $title, $url));
+ die('1');
+ }
+
if($can_edit && isset($_POST['property'])) {
ob_end_clean();
$property = $_POST['property'];
+
$value = trim($_POST['value']);
if($value == "" || strlen($value) > 5000) die();
@@ -74,8 +102,8 @@
if(!preg_match('#^http://#i', $value)) {
die(htmlspecialchars($feed['course_url']));
}
- $stmt = $database->prepare('UPDATE feeds SET course_url = ? WHERE id = ?');
- $stmt->execute(array($value, $feed_id));
+ $stmt = $database->prepare('REPLACE INTO feed_links (feed_id, title, url) VALUES (?, "Homepage", ?)');
+ $stmt->execute(array($feed_id, $value));
}
if(array_search($property, array('url', 'search', 'exercise')) !== false) {
@@ -144,9 +172,12 @@
<dd><?=$feed['public'] ? 'Ja' : 'Nein'?></dd>
<dt>Kurs-Homepage</dt>
<dd class="editable url short" id="edit-course_url"><?
- if($feed['course_url']) {
- $link_title = parse_url($feed['course_url'], PHP_URL_HOST);
- echo '<a href="' . htmlspecialchars($feed['course_url']) . '">' . htmlspecialchars($link_title) . '</a>';
+ $course_url = $database->query('SELECT url FROM feed_links WHERE feed_id = ' .
+ intval($feed['id']) . ' AND title = "Homepage"')->fetchColumn();
+
+ if($course_url) {
+ $link_title = parse_url($course_url, PHP_URL_HOST);
+ echo '<a href="' . htmlspecialchars($course_url) . '">' . htmlspecialchars($link_title) . '</a>';
}
else {
echo 'Keine';
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
@@ -132,10 +132,12 @@
<h3>Links auf Deine Kurse</h3>
<ul>
<?php
- $course_urls = $database->query('SELECT id, course_url, short FROM feeds WHERE id IN (SELECT feed_id FROM user_feeds WHERE user_id = ' . user()->id . ')
- AND course_url NOT LIKE "" AND course_url IS NOT NULL');
+ $course_urls = $database->query('SELECT feed_id, title, url FROM feed_links WHERE feed_id IN
+ (SELECT feed_id FROM user_feeds WHERE user_id = ' . user()->id . ')');
foreach($course_urls as $course) {
- echo('<li><a href="' . htmlspecialchars($course['course_url']) . '">' . htmlspecialchars($course['short']) . '</a></li>');
+ echo('<li><a data-id="' . $course['feed_id'] . '" data-title="' . htmlspecialchars($course['title']) . '"
+ href="' . htmlspecialchars($course['url']) . '">' . htmlspecialchars($descs[$course['feed_id']]) . ': ' .
+ htmlspecialchars($course['title']) . '</a></li>');
}
?>
</ul>
View
@@ -29,9 +29,13 @@ div#error { display: block; width: 400px; margin-top: 200px; border: 1px solid #
div#content { margin: 0 20px; width: 80%; margin-bottom: 50px; }
-div#content table { width: 100%; border-collapse: collapse; }
-div#content th { text-align: left; background: #eef; }
-div#content td, div#content th { border: 1px solid #eee; padding: 3px; vertical-align: top;}
+div.dialog table, div#content table { width: 100%; border-collapse: collapse; }
+div.dialog th, div#content th { text-align: left; background: #eef; }
+div.dialog td, div.dialog th, div#content td, div#content th { border: 1px solid #eee; padding: 3px; vertical-align: top;}
+div.dialog th, div.dialog td { border: 1px solid #aaa; height: 1.5em; font-size: small; }
+div.dialog td input { margin: -1px; width: 100%; }
+div.dialog td:first-child { width: 200px; }
+div.dialog td { background: #fff; }
table#kurse td + td + td { width: 100px; }
table#kurse tr td:first-child { width: 20px; }
table#kurse-uebersicht td:first-child { width: 130px; }
@@ -91,7 +95,16 @@ div#content p.right a.selected { color: red ; }
div#ajax_info img { float: right; margin-top: -7px; }
div#ajax_info { position: fixed; width: 20%; border: 1px solid #488; top: 40%; left: 40%; padding: 10px; background: #eef; padding: 1em 10px 1em 10px; z-index: 5; }
div#exercise_info { position: fixed; width: 20%; border: 1px solid #488; right: 20px; bottom: 20px; padding: 10px; background: #eef; padding: 1em 10px 1em 10px; z-index: 5; font-size: small; }
-div#greyout { position: fixed; left: 0; top: 0; width: 100%; height: 100%; background: #000; opacity: 0.5; z-index: 4; }
+div#greyout { position: fixed; left: 0; top: 0; width: 100%; height: 100%; background: #eee; opacity: 0.8; z-index: 4; }
+div.dialog {
+ position: fixed; width: 70%; border: 1px solid #488; top: 10%; left: 10%; height: 500px; padding: 10px; background: #eef; padding: 1em 10px 1em 10px; z-index: 5; overflow: auto;
+}
+div.dialog h2 {
+ margin: -15px -10px 5px -10px;
+ padding: 3px;
+ background: #ddf;
+ font-size: small;
+}
a:visited {
color: #008;
View
@@ -54,7 +54,8 @@ function stripslashes_deep(&$value)
$database->exec('CREATE INDEX uauto ON user_autologin (id)');
$database->exec('CREATE INDEX user ON user_autologin (user_id)');
$database->exec('CREATE TABLE feeds (id INTEGER PRIMARY KEY AUTOINCREMENT, owner INT, desc VARCHAR(120), short VARCHAR(120),
- code LONGTEXT, public INT DEFAULT 0, update_timestamp INT, course_url VARCHAR(255));');
+ code LONGTEXT, public INT DEFAULT 0, update_timestamp INT);');
+ $database->query('CREATE TABLE feed_links (feed_id INTEGER, title VARCHAR(120), url TEXT, PRIMARY KEY (feed_id, title));');
$database->exec('CREATE TABLE data (id INTEGER PRIMARY KEY AUTOINCREMENT, feed_id INTEGER,
data MEDIUMTEXT, timestamp INT(11))');
$database->exec('CREATE INDEX fid ON data (feed_id);');
@@ -75,6 +76,8 @@ function stripslashes_deep(&$value)
$database->exec('CREATE TABLE feeds (id INTEGER PRIMARY KEY AUTO_INCREMENT, owner INTEGER, `desc` VARCHAR(120), short VARCHAR(120),
code LONGTEXT, public INTEGER DEFAULT 0, update_timestamp INT, course_url VARCHAR(255)
DEFAULT CHARSET=utf8;');
+ $database->query('CREATE TABLE feed_links (feed_id INTEGER, title VARCHAR(120), url TEXT, PRIMARY KEY (feed_id, title))
+ DEFAULT CHARSET=utf8;');
$database->exec('CREATE TABLE data (id INTEGER PRIMARY KEY AUTO_INCREMENT, feed_id INTEGER,
data MEDIUMTEXT, timestamp INT(11)) DEFAULT CHARSET=utf8');
$database->exec('CREATE INDEX fid ON data (feed_id);');
@@ -0,0 +1,20 @@
+<?php
+ chdir("..");
+ require("system.php");
+ header('Content-Type: text/plain');
+
+ $course_urls = $database->query('SELECT id, course_url FROM feeds WHERE course_url IS NOT NULL');
+ $database->query('CREATE TABLE feed_links (
+ feed_id INTEGER,
+ title VARCHAR(120),
+ url TEXT,
+ PRIMARY KEY (feed_id, title)
+ );');
+ $query = $database->prepare('INSERT INTO feed_links (feed_id, title, url) VALUES (?, "Homepage", ?)');
+ foreach($course_urls as $urlset) {
+ echo('Übernehme ' . $urlset['course_url'] . "\n");
+ $query->execute(array($urlset['id'], $urlset['course_url']));
+ }
+
+ # Not supported by Sqlite!
+ $database->query('ALTER TABLE feeds DROP course_url');
View
@@ -253,15 +253,20 @@ $(document).ready(function() {
}));
$("a.course-disp-only").each(function() {
var $this = $(this);
+ var f = $this.attr("href").match(/f=([0-9]+)/)[1];
+ var href = $this.attr("href");
+ var spanReplacement = $("<span>").css({"textDecoration": "underline", "cursor": "pointer"}).text($this.text());
+ $this.replaceWith(spanReplacement);
+ $this = spanReplacement;
+
var course_timeout;
var has_fired = false;
var menu = $("<ul class='hover_menu'>");
- var f = $this.attr("href").match(/f=([0-9]+)/)[1];
- $("<a>").attr("href", $this.attr("href")).text("Nur diesen Kurs anzeigen").appendTo(menu).wrap("<li>");
+ $("<a>").attr("href", href).text("Nur diesen Kurs anzeigen").appendTo(menu).wrap("<li>");
$("<a>").attr("href", "index.php?q=details&f=" + f).text("Informationen anzeigen").appendTo(menu).wrap("<li>");
$("#course_links a").each(function() {
- if($(this).text() == $this.text()) {
- $("<a>").attr("href", $(this).attr("href")).text("Zur Homepage").appendTo(menu).wrap("<li>");
+ if($(this).data("id") == f) {
+ $("<a>").attr("href", $(this).attr("href")).text($(this).data("title")).appendTo(menu).wrap("<li>");
}
});
@@ -296,6 +301,82 @@ $(document).ready(function() {
var feed_id = document.location.search.toString().match(/f=([0-9]+)/);
if(feed_id) {
feed_id = feed_id[1];
+
+ var edit_course_url = $("#edit-course_url");
+ if(edit_course_url.length > 0) {
+ var pos = edit_course_url.position();
+ $("<div><a title='Zusätzliche URLs editieren' href='#'><img src='images/application_form_edit.png'/></a></div>").css({
+ 'position': 'absolute',
+ 'left': pos.left + edit_course_url.width() - 16,
+ 'top': pos.top + 2
+ }).appendTo(document.body).find('img').css('border', 'none').end().find("a").click(function() {
+ $.get('index.php?q=details&f=' + feed_id + '&get=urls', function(urls) {
+ var edit_form = $("<div class='dialog' id='course_edit_form'>Lade..</div><div id='greyout'></div>").appendTo(document.body);
+ var inner_div = $("div#course_edit_form");
+ inner_div.css({"height": "300px"}).css({
+ left: ($(window).width() - inner_div.width()) / 2,
+ top: ($(window).height() - inner_div.height()) / 2
+ });
+ inner_div.html('<h2>Zusätzliche URLs</h2><table><tr><th>Titel</th><th>URL</th></tr></table>');
+ var table = inner_div.find("table");
+ var rows = 5;
+ function addRow(title, url) {
+ var row = $("<tr>");
+ var td_title = $("<td>").text(title).appendTo(row);
+ var td_url = $("<td>").text(url).appendTo(row);
+
+ td_title.click(function() {
+ var old_title = td_title.text().replace(/ $/, '');
+ var edit = $("<input>").val(td_title.text().replace(/ $/, "")).blur(function() {
+ var $this = $(this);
+ if(td_url.text() == "") {
+ td_title.text($this.val() + " ");
+ return;
+ }
+ $.post("index.php?q=details&f=" + feed_id, "additional_urls=1&title=" +
+ encodeURIComponent(old_title) + "&url=", function() {
+ $.post("index.php?q=details&f=" + feed_id, "additional_urls=1&title=" +
+ encodeURIComponent($this.val()) + "&url=" + encodeURIComponent(td_url.text()), function() {
+ td_title.text($this.val() + " ");
+ });
+ });
+ });
+ td_title.html(edit);
+ edit.focus();
+ });
+ td_url.click(function() {
+ var edit = $("<input>").val(td_url.text()).blur(function() {
+ var $this = $(this);
+ if(td_title.text() == " ") {
+ td_url.text($this.val() + " ");
+ return;
+ }
+ $.post("index.php?q=details&f=" + feed_id, "additional_urls=1&title=" +
+ encodeURIComponent(td_title.text().replace(/ $/, '')) +
+ "&url=" + encodeURIComponent($this.val()), function() {
+ td_url.text($this.val() + " ");
+ });
+ });
+ td_url.html(edit);
+ edit.focus();
+ });
+
+ row.appendTo(table);
+ }
+ for(title in urls) {
+ rows--;
+ addRow(title + " ", urls[title]);
+ }
+ while(rows-- > 0) {
+ addRow(" ", "");
+ }
+ $("<button>Zurück</button>").css({"display": "block", "marginTop": "5px", "float": "right"}).
+ appendTo(inner_div).click(function() { edit_form.remove(); return false; });
+ });
+ return false;
+ });
+ }
+
$(".editable").each(function() {
var $this = $(this);
var is_url = $this.hasClass("url");

0 comments on commit 0bca40b

Please sign in to comment.