โŒˆโŒ‹ โŽ‡ branch:  freshcode


Check-in [92d96d21cf]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Introduce search/ function.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 92d96d21cf6ffb454234c39839c366515f37df54
User & Date: mario 2014-07-11 16:00:57
Context
2014-07-11
16:10
Adapt links from /tag/xy to /search?tag= and ?user= link now to /search. check-in: 0e277bc34e user: mario tags: trunk
16:00
Introduce search/ function. check-in: 92d96d21cf user: mario tags: trunk
12:52
Move JS functionality out of template/header, to prepare for tags-editing check-in: fcd926fc7e user: mario tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to aux.php.

208
209
210
211
212
213
214











215
216
217
218
219
220
221
    print "<p class=pagination-links> ยป";
    foreach (range($page_no-2, $page_no+9) as $n) if ($n > 0) {
        print " <a " . ($n==$page_no ? "class=current " : ""). "href=\"?n=$n\">$n</a> ";
    }
    print "ยซ </p>";
}













// CSRF token, only for logged-in users though
// Here they're mainly to prevent remotely initiated requests for other users here, not general form nonces
function csrf($probe=false) {

    // Tokens are stored in session, reusable, but only for an hour
    $store = & $_SESSION[__FUNCTION__];







>
>
>
>
>
>
>
>
>
>
>







208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
    print "<p class=pagination-links> ยป";
    foreach (range($page_no-2, $page_no+9) as $n) if ($n > 0) {
        print " <a " . ($n==$page_no ? "class=current " : ""). "href=\"?n=$n\">$n</a> ";
    }
    print "ยซ </p>";
}


// Output a list of select <option>s
function form_select_options($names, $value, $r="") {
    $map = is_string($names) ? array_combine($names = str_getcsv($names), $names) : $names;
    if ($value and !isset($map[$value])) { $map[$value] = $map[$value]; }
    foreach ($map as $id=>$title) {
        $r .= "<option" . ($id == $value ? " selected" : "") . " value=\"$id\" title=\"$title\">$id</option>";
    }
    return $r;
}


// CSRF token, only for logged-in users though
// Here they're mainly to prevent remotely initiated requests for other users here, not general form nonces
function csrf($probe=false) {

    // Tokens are stored in session, reusable, but only for an hour
    $store = & $_SESSION[__FUNCTION__];

Changes to freshcode.css.

1
2
3
4
5
6
7
8
9
10
11
12
13
...
312
313
314
315
316
317
318
























319
320
321
322
323
324
325
/**
 * api: css
 * type: stylesheet
 * title: freshcode.club layout+style
 * description: Simulates the late freecode.com layout and looks; well mostly.
 * version: 0.5.6
 *
 * Centered two-pane layout. The #main section is usually 33% of the screen width,
 * while the #sidebar floats at the right. They're repositioned only using padding:
 * to the outer html,body{}.
 *
 */

................................................................................
}
#main .project .trimmed div {
    box-shadow: inset 0 5pt 5pt 0px #ffeecc;
    height: 5.55em;
    overflow: hidden;
}

























/**
 * Variation for /projects/xyz detail view.
 */
#main .project .long-tags th {
    border: 1px solid #ddd;
    background: #eee;
    padding: 1pt 12pt;





|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
...
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
/**
 * api: css
 * type: stylesheet
 * title: freshcode.club layout+style
 * description: Simulates the late freecode.com layout and looks; well mostly.
 * version: 0.5.7
 *
 * Centered two-pane layout. The #main section is usually 33% of the screen width,
 * while the #sidebar floats at the right. They're repositioned only using padding:
 * to the outer html,body{}.
 *
 */

................................................................................
}
#main .project .trimmed div {
    box-shadow: inset 0 5pt 5pt 0px #ffeecc;
    height: 5.55em;
    overflow: hidden;
}


/**
 * Shortened view on search/
 *
 */
#main .project.search {
    clear: both;
    margin-bottom: 7pt;
}
#main .project.search h3 {
    display: inline;
    margin: 2pt;
    padding: 2pt;
    font-size: 95%;
}
#main .project.search img {
    border: 0;
    box-shadow: none;
    margin: 0 2pt 3pt 0;
}
#main .project.search small.description {
    line-height: 80%;
}

/**
 * Variation for /projects/xyz detail view.
 */
#main .project .long-tags th {
    border: 1px solid #ddd;
    background: #eee;
    padding: 1pt 12pt;

Changes to index.php.

1
2
3
4
5
6
7
8
9
10
11
12
13
..
21
22
23
24
25
26
27

28
29
30
31
32
33
34
<?php
/**
 * api: php
 * title: Freshcode.club
 * description: FLOSS software release tracking website
 * version: 0.4.5
 * author: mario
 * license: AGPL
 * 
 * Implements a freshmeat/freecode-like directory for open source
 * release publishing / tracking.
 *
 */
................................................................................
switch ($page = $_GET->id["page"]) {

    case "index":
    case "projects":
    case "feed":
    case "links":
    case "tags":

    case "login":
        include("page_$page.php");
        break;

    case "flag":
    case "submit":
        if ((LOGIN_REQUIRED or $page === "flag") and empty($_SESSION["openid"])) {





|







 







>







1
2
3
4
5
6
7
8
9
10
11
12
13
..
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php
/**
 * api: php
 * title: Freshcode.club
 * description: FLOSS software release tracking website
 * version: 0.4.7
 * author: mario
 * license: AGPL
 * 
 * Implements a freshmeat/freecode-like directory for open source
 * release publishing / tracking.
 *
 */
................................................................................
switch ($page = $_GET->id["page"]) {

    case "index":
    case "projects":
    case "feed":
    case "links":
    case "tags":
    case "search":
    case "login":
        include("page_$page.php");
        break;

    case "flag":
    case "submit":
        if ((LOGIN_REQUIRED or $page === "flag") and empty($_SESSION["openid"])) {

Added page_search.php.





















































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
<?php
/**
 * type: page
 * title: Search function
 * description: Scans packages for description, tags, license, user names
 * license: AGPL
 * version 0.1
 * 
 * Builds a search query from multiple input params:
 *   โ†’ ?user=
 *   โ†’ ?tags[]= or ?tag=
 *   โ†’ ?license=
 *   โ†’ ?q= for actual text search
 *
 */


// Bypass hybrid db() function to directly invoke $db{} wrapper with list of params
global $db;


include("template/header.php");
?> <section id=main> <?php


// Display form
if ($_GET->no("tag,tags,user,license,q")) {

    include("template/search_form.php");

}

// Actual search request
else {

    #-- Collect search terms
    $WHERE = "";
    $params = array();

    // List from ?tags[]= or single ?tag=
    if ($tags = array_filter(array_merge($_GET->array->words["tags"], $_GET->words->p_csv["tag"]))) {
        $WHERE .= " AND tags.tag IN (??)";
        $params[] = $tags;
    }
    // Select specific ?user=
    if ($user = $_GET->words["user"]) {
        $WHERE .= " AND submitter LIKE ?";
        $params[] = "$user%";
    }
    // Only ?license= results
    if ($license = $_GET->words["license"]) {
        $WHERE .= " AND license = ?";
        $params[] = $license;
    }
    // And finally the actual ?q= search string // Note switch to FTS
    if ($q = $_GET->text["q"]) {
        $WHERE .= " AND description LIKE ?";
        $params[] = "%$q%";
    }


    // Run SQL
    #db()->test = 1;
    $result = $db("
        SELECT release.name AS name, title, SUBSTR(description,1,500) AS description,
               version, image, homepage, download, submitter, release.tags AS tags,
               license, state, t_published, flag, hidden, deleted, MAX(t_changed)
          FROM release
     LEFT JOIN tags ON release.name = tags.name
         WHERE NOT deleted AND flag < 5
               $WHERE
      GROUP BY release.name
      ORDER BY t_published DESC, t_changed DESC
         LIMIT 100
    ", $params);



    // Show sidebar + long project description
    foreach ($result as $entry) {
        prepare_output($entry);
        include("template/search_entry.php");
    }

}


include("template/bottom.php");

?>

Changes to page_submit.php.

314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
}


include("template/bottom.php");



// Output a list of select <option>s
function form_select_options($names, $value, $r="") {
    $map = is_string($names) ? array_combine($names = str_getcsv($names), $names) : $names;
    if ($value and !isset($map[$value])) { $map[$value] = $map[$value]; }
    foreach ($map as $id=>$title) {
        $r .= "<option" . ($id == $value ? " selected" : "") . " value=\"$id\" title=\"$title\">$id</option>";
    }
    return $r;
}


?>







<
<
<
<
<
<
|
<
<
<
<

314
315
316
317
318
319
320






321




322
}


include("template/bottom.php");














?>

Added template/search_entry.php.

































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?php
/**
 * api: include
 * type: template
 * title: Search results
 * description: Display shortened project description
 *
 *
 */

if (!function_exists("smallify")) {
    function smallify($text, $r="") {
        $text = explode("\n", wordwrap(input::spaces($text), 20));
        foreach ($text as $i=>$line) {
            $q = 100 - $i;
            $h = $q * 0.5;
            $r .= "<span style=\"font: normal $q%/$h% Arial\">"
                . $line . "</span> ";
        }
        return $r;
    }
}


$_ = "trim";

print <<<PROJECT
      <article class="project search">

        <h3>
            <a href="projects/$entry[name]">
               $entry[title]
               <em class=version>$entry[version]</em>
            </a>
        </h3>

        <a href="$entry[homepage]">
           <img class=preview src="$entry[image]" align=left width=60 height=45>
        </a>

        <small class=description style="border:0">{$_(smallify($entry["description"]))}</small>

      </article>
      
PROJECT;


?>

Added template/search_form.php.



















































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php
/**
 * api: include
 * type: template
 * title: Search from
 * description: Show simple search <form>
 *
 *
 */

$select = "form_select_options";
$licenses = array_merge(array(""=>"*Any*"), $licenses);

?>

<h3>Search projects</h3>

<form action="/search" method=GET enctype="application/x-www-form-urlencode" accept-encoding=UTF-8>

    <label>
        Description
        <input name=q type=text size=50>
    </label>

    <label>
        Tags
        <input name=tag type=text size=50>
    </label>

    <label>
        License
        <select name=license>
            <?php print form_select_options($licenses, ""); ?>
        </select>
    </label>
    
    <label> 
       <input type=submit title=Search>
    </label>
    
</form>