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


Check-in [c4755c01bd]

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

Overview
Comment:Using diff now for /admin pages and /rc
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: c4755c01bdc43df63a36ef5c716e93113e540c54
User & Date: mario 2014-08-08 17:37:53
Context
2014-08-08
17:38
Make `$version` replacement work on complete text input (RegExp/g) check-in: 6afb9901a5 user: mario tags: trunk
17:37
Using diff now for /admin pages and /rc check-in: c4755c01bd user: mario tags: trunk
2014-08-06
11:01
Reordered gallery, added Fossies.org check-in: 92ebd481e3 user: mario tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to freshcode.css.

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
 * api: css
 * type: stylesheet
 * title: freshcode.club layout+style
 * description: Simulates the late freecode.com layout and looks; well mostly.
 * version: 0.6.3.1
 *
 * 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{}.
 *
 */






|







1
2
3
4
5
6
7
8
9
10
11
12
13
/**
 * api: css
 * type: stylesheet
 * title: freshcode.club layout+style
 * description: Simulates the late freecode.com layout and looks; well mostly.
 * version: 0.6.4.1
 *
 * 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{}.
 *
 */

96
97
98
99
100
101
102
103
104
105
106
107
108
109
110

111
112
113
114
115
116
117

/**
 * Main action link box, hovering halfway over header box.
 *
 */
#tools {
    margin: 0 150pt;
    padding: 4pt;
    border: 1.75pt solid #bbb;
    border-top: 1pt solid #ccc;
    border-radius: 5pt;
    background: #e5e7e9;
    background: linear-gradient(to bottom, #ffffff, #fdfefe, #f5f7f9, #eaecee, #e5e7e9, #e1e3e5, #d0d1d2);
    position: relative;
    top: -15pt;

}
.absolute {
    position: absolute;
}
#tools a {
    color: #777;
    margin: 0 1pt;







|






|
>







96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118

/**
 * Main action link box, hovering halfway over header box.
 *
 */
#tools {
    margin: 0 150pt;
    padding: 3pt 5pt 2pt 5pt;
    border: 1.75pt solid #bbb;
    border-top: 1pt solid #ccc;
    border-radius: 5pt;
    background: #e5e7e9;
    background: linear-gradient(to bottom, #ffffff, #fdfefe, #f5f7f9, #eaecee, #e5e7e9, #e1e3e5, #d0d1d2);
    position: relative;
    top: -14pt;
    font-size: 95%;
}
.absolute {
    position: absolute;
}
#tools a {
    color: #777;
    margin: 0 1pt;
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
    font-weight: 900;
    display: block;
}
#trove_tags span > span.option:hover, #trove_tags span.optgroup > b:hover {
    background: #ccf;
}
#trove_tags .option.selected, #tag_cloud a.selected {
    background: #fba;
}

#trove_tags .optgroup[data-tag='topic']   { background: #f3f4f7; }
#trove_tags .optgroup[data-tag='topic'] * { background: #f7f7f9; }
#trove_tags .optgroup[data-tag='programming-language']   { background: #d7dcf0; }
#trove_tags .optgroup[data-tag='programming-language'] * { background: #ecf0fa; }
#trove_tags .optgroup[data-tag='environment']   { background: #f3f0e0; }







|







569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
    font-weight: 900;
    display: block;
}
#trove_tags span > span.option:hover, #trove_tags span.optgroup > b:hover {
    background: #ccf;
}
#trove_tags .option.selected, #tag_cloud a.selected {
    background: #fba !important;
}

#trove_tags .optgroup[data-tag='topic']   { background: #f3f4f7; }
#trove_tags .optgroup[data-tag='topic'] * { background: #f7f7f9; }
#trove_tags .optgroup[data-tag='programming-language']   { background: #d7dcf0; }
#trove_tags .optgroup[data-tag='programming-language'] * { background: #ecf0fa; }
#trove_tags .optgroup[data-tag='environment']   { background: #f3f0e0; }
626
627
628
629
630
631
632









633
634
635
636
637
638
639
   border-bottom: 1px dashed green;
   background: #efe;
}
.rc del {
   color: #521;
   background: #fee;
}









.rc .funcs {
   float: right;
}
.rc .funcs a {
   font-size: 60%;
   color: #99b;
   background: #e3e3e3;







>
>
>
>
>
>
>
>
>







627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
   border-bottom: 1px dashed green;
   background: #efe;
}
.rc del {
   color: #521;
   background: #fee;
}
.rc.admin ins {
   border: none;
   background: #f1fff3;
}
.rc.admin del {
   color: #210;
   background: #fff5f3;
   text-decoration: none;
}
.rc .funcs {
   float: right;
}
.rc .funcs a {
   font-size: 60%;
   color: #99b;
   background: #e3e3e3;

Added lib/diff.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
<?php
/*
    Paul's Simple Diff Algorithm v 0.1
    (C) Paul Butler 2007 <http://www.paulbutler.org/>
    May be used and distributed under the zlib/libpng license.
    
    This code is intended for learning purposes; it was written with short
    code taking priority over performance. It could be used in a practical
    application, but there are a few ways it could be optimized.
    
    Given two arrays, the function diff will return an array of the changes.
    I won't describe the format of the array, but it will be obvious
    if you use print_r() on the result of a diff on some test data.
    
    htmlDiff is a wrapper for the diff command, it takes two strings and
    returns the differences in HTML. The tags used are <ins> and <del>,
    which can easily be styled with CSS.  
*/

class pdiff {

    // 
    static function diff($old, $new){
        $matrix = array();
        $maxlen = 0;
        foreach($old as $oindex => $ovalue){
            $nkeys = array_keys($new, $ovalue);
            foreach($nkeys as $nindex){
                $matrix[$oindex][$nindex] = isset($matrix[$oindex - 1][$nindex - 1]) ?
                    $matrix[$oindex - 1][$nindex - 1] + 1 : 1;
                if($matrix[$oindex][$nindex] > $maxlen){
                    $maxlen = $matrix[$oindex][$nindex];
                    $omax = $oindex + 1 - $maxlen;
                    $nmax = $nindex + 1 - $maxlen;
                }
            }   
        }
        if($maxlen == 0) return array(array('d'=>$old, 'i'=>$new));
        return array_merge(
            pdiff::diff(array_slice($old, 0, $omax), array_slice($new, 0, $nmax)),
            array_slice($new, $nmax, $maxlen),
            pdiff::diff(array_slice($old, $omax + $maxlen), array_slice($new, $nmax + $maxlen)));
    }

    // markup <ins> and <del> between old and new text blob
    static function htmlDiff($old, $new){
        $ret = '';
        $diff = pdiff::diff(preg_split("/[\s]+/", $old), preg_split("/[\s]+/", $new));
        foreach($diff as $k){
            if(is_array($k))
                $ret .=
                    (!empty($k['d']) ? "<del>" . input::html(implode(' ',$k['d'])) . "</del> " : '').
                    (!empty($k['i']) ? "<ins>" . input::html(implode(' ',$k['i'])) . "</ins> " : '');
            else $ret .= $k . ' ';
        }
        return $ret;
    }

    // Just compare word-wise without between three revisions, without honoring order
    static function triDiff($prev, $curr, $next){
        $ret = '';
        $prev = preg_split("/[\s]+/", $prev);
        $curr = preg_split("/[\s]+/", $curr);
        $next = preg_split("/[\s]+/", $next);
        foreach($curr as $word){
            if (!in_array($word, $prev)) {
               $ret .= "<ins>$word</ins> ";
            }
            elseif (!in_array($word, $next)) {
               $ret .= "<del>$word</del> ";
            }
            else {
               $ret .= "$word ";
            }
        }
        return $ret;
    }

}
?>

Added page_admin.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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
<?php
/**
 * api: freshcode
 * type: page
 * title: admin interface
 * description: Showcase user flags and allow to delete or hide project entries/revisions.
 * version: 0.1
 * depends: db
 *
 * User flags are collected in a separate `flags` table. Yet each project
 * entry contains a `flags` counter column as well (this is used by front-end
 * code to automatically hide too frequently flagged submissions)..
 *
 * CREATE TABLE flags
 *     (name TEXT, reason TEXT, note TEXT, submitter_openid TEXT, submitter_ip TEXT);
 *
 * The admin page lists from the flags table. Then allows to "delete" certain
 * revisions, or just mark them as hidden.
 *
 */



// Moderator authorization already handled by dispatcher (index.php)
include("template/header.php");
?>
  <section id=main>
<?php
$name = $_REQUEST->proj_name["name"];


// Just list flags+projects
if (empty($name)) {
    print "<h3>Flagged entries</h3> <dl>";

    // query flags table, but associate data from last release
    $flags = db("SELECT * FROM flags
                 LEFT JOIN release_versions ON flags.name=release_versions.name");
   
    // just output admin/PROJID links
    while ($row = $flags->fetch()) {
        $row = array_map("input::html", $row);
        print <<<HTML
           <dt><a href="admin/$row[name]">$row[name]</a> (<em>$row[flag]</em> flags on #$row[t_published])</dt>
           <dd><b>$row[reason]</b>
               $row[note]
           </dd>
HTML;
    }
    
}

// Show entry + respond to actions
else {


    /**
     * Apply actions
     *
     *   โ†’ Actions in `action[field][]=name and action[value][]=value`
     *   โ†’ Revisions are  lists of `select[t_published][] = t_changed`
     *
     */
    if ($_POST->has("action")) {
    
        // Merge action keys and values
        $action = $_POST->raw["action"];
        $action = array_combine(
            array_intersect_key($action["field"], $action["value"]),
            array_intersect_key($action["value"], $action["field"])
        );
        var_dump($action);

        // Run trough actions
        foreach ($action as $field=>$value) if (strlen($field)) {
            // Update DB for each revision in select[][]
            foreach ($_POST->raw["select"] as $t_published => $t_changed) {
                db("UPDATE release
                    SET :? = ?
                    WHERE name=? AND t_published=? AND t_changed IN (??)",
                    array($field), $value,
                    $name, $t_published, $t_changed
                );
            }
        }
        
        // Manually empty `flags` table
        if ($action["flag"] === 0) {
            db("DELETE FROM flags WHERE name=?", $name);
        }
    }



    /**
     * Get all revisions and flags for project name
     *
     *
     */
    $entries = db("SELECT * FROM release WHERE name=? ORDER BY t_published ASC, t_changed ASC", $name)->fetchAll();
    $flags = db("SELECT * FROM flags WHERE name=?", $name)->fetchAll();


    // Start <form>
    print "<h3>Edit '$name' revisions</h3>  Oldest to newest.
           <form action='admin/$name' method=POST>         
          ";

    // Show all flagging notes
    foreach ($flags as $row) {
        $row = array_map("input::html", $row);
        print "<li>Flag: <b>$row[reason]</b><br>Note: <em>$row[note]</em><br>By: <u>$row[submitter_openid]</u></li><br>";
    }

    
    // Print each revision;
    foreach ($entries as $rev=>$row) {
    
        // current, last, and next row
        $row = array_map("input::html", $row);
        $last = isset($entries[$rev-1]) ? array_map("input::html", $entries[$rev-1]) : $row;
        $next = isset($entries[$rev+1]) ? array_map("input::html", $entries[$rev+1]) : $row;

        // Version header
        $date = strftime("%Y-%m-%d %T", $row["t_changed"]);
        print "
        <br>
        <table class='rc admin'>
        <tr>
          <th>
             <input type=checkbox name='select[$row[t_published]][]' value='$row[t_changed]'>
             rev=$rev
          </th>
          <th>
             pub=$row[t_published]
             chg=$row[t_changed] <small>($date)</small>
          </th>
        </tr>";
        
        // Fields
        foreach ($row as $f=>$v) {
            $v = pdiff::tridiff($last[$f], $v, $next[$f]);
            if (in_array($f, ["t_published", "t_changed"])) {
                $v .= " <small>(" . strftime("%Y-%m-%d %T", $row[$f]) . ")</small>";
            }
            if (in_array($f, ["hidden","flag","deleted","name","t_changed","version"])) {
                $f = "<em>$f</em>";
            }
            print "<tr><td>$f</td><td>$v</td>";
        }
        print "</table>";
    }

    
    /**
     * Print `action` form fields
     *
     *  โ†’ Assocciatively as `action[field][] = dbfield`
     *                  and `action[value][] = vakue`
     *  โ†’ Applying depends an the field being non-empty
     *    (for unchecked checkboxes they are).
     *
     */
    print <<<HTML
    <h4>Actions</h4>
    <table class=rc>
    <tr>
      <td><label>
        <input type=checkbox name="action[field][0]" value="hidden">
        <input type=hidden name="action[value][0]" value="1">
        <b>Set hidden</b>
      </label></td>
      <td>so the revision will no longer show up on the frontpage. </td>
    </tr>
    <tr>
      <td><label>
        <input type=checkbox name="action[field][1]" value="deleted">
        <input type=hidden name="action[value][1]" value="1">
        <b>Mark deleted</b>
      </label></td>
      <td> to terminate a project revision line </td>
    </tr>
    <tr>
      <td><label>
        <input type=checkbox name="action[field][2]" value="flag" checked>
        <input type=hidden name="action[value][2]" value="0">
        <b>Unset flags</b>
      </label></td>
      <td> to clear flagging history when finished. </td>
    </tr>
    <tr><th>Update field</th><th>with value</th></tr>
    <tr>
      <td> <input type=text name="action[field][3]" value=""> </td>
      <td> <input type=text name="action[value][3]" value="" size=40> </td>
    </tr>
    <tr>
      <td> <input type=text name="action[field][4]" value=""> </td>
      <td> <input type=text name="action[value][4]" value="" size=40> </td>
    </tr>
    </table>
    <br>
    <input type=submit value=Apply>
    <br>
    <br>
HTML;
}



?>

Changes to page_rc.php.

87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
    #-- Table
    print "\n\n<table class=rc><tr><th><a href=/projects/$name>$name</a></th><th>$date <small>ยค$time_diff</small> <span class=funcs><a href=/submit/$name>edit</a> <a href=/admin/$name>admin</a></span></th></tr>\n";
    foreach ($fields as $fn ) {

        // Diff only if there are differences, obviously
        if ($entry["prev_$fn"] !== $entry["crnt_$fn"]) {
        
            $diff = htmlDiff($entry["prev_$fn"], $entry["crnt_$fn"]);
            print "<tr><td>$fn</td><td class=trimmed>$diff</td></tr>\n";
        }
    }
    print "</table>\n";
}


// page footer
include("template/bottom.php");


?><?php
/*
    Paul's Simple Diff Algorithm v 0.1
    (C) Paul Butler 2007 <http://www.paulbutler.org/>
    May be used and distributed under the zlib/libpng license.
    
    This code is intended for learning purposes; it was written with short
    code taking priority over performance. It could be used in a practical
    application, but there are a few ways it could be optimized.
    
    Given two arrays, the function diff will return an array of the changes.
    I won't describe the format of the array, but it will be obvious
    if you use print_r() on the result of a diff on some test data.
    
    htmlDiff is a wrapper for the diff command, it takes two strings and
    returns the differences in HTML. The tags used are <ins> and <del>,
    which can easily be styled with CSS.  
*/

function diff($old, $new){
    $matrix = array();
    $maxlen = 0;
    foreach($old as $oindex => $ovalue){
        $nkeys = array_keys($new, $ovalue);
        foreach($nkeys as $nindex){
            $matrix[$oindex][$nindex] = isset($matrix[$oindex - 1][$nindex - 1]) ?
                $matrix[$oindex - 1][$nindex - 1] + 1 : 1;
            if($matrix[$oindex][$nindex] > $maxlen){
                $maxlen = $matrix[$oindex][$nindex];
                $omax = $oindex + 1 - $maxlen;
                $nmax = $nindex + 1 - $maxlen;
            }
        }   
    }
    if($maxlen == 0) return array(array('d'=>$old, 'i'=>$new));
    return array_merge(
        diff(array_slice($old, 0, $omax), array_slice($new, 0, $nmax)),
        array_slice($new, $nmax, $maxlen),
        diff(array_slice($old, $omax + $maxlen), array_slice($new, $nmax + $maxlen)));
}

function htmlDiff($old, $new){
    $ret = '';
    $diff = diff(preg_split("/[\s]+/", $old), preg_split("/[\s]+/", $new));
    foreach($diff as $k){
        if(is_array($k))
            $ret .=
                (!empty($k['d']) ? "<del>" . input::html(implode(' ',$k['d'])) . "</del> " : '').
                (!empty($k['i']) ? "<ins>" . input::html(implode(' ',$k['i'])) . "</ins> " : '');
        else $ret .= $k . ' ';
    }
    return $ret;
}


?>







|











<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105























































106
    #-- Table
    print "\n\n<table class=rc><tr><th><a href=/projects/$name>$name</a></th><th>$date <small>ยค$time_diff</small> <span class=funcs><a href=/submit/$name>edit</a> <a href=/admin/$name>admin</a></span></th></tr>\n";
    foreach ($fields as $fn ) {

        // Diff only if there are differences, obviously
        if ($entry["prev_$fn"] !== $entry["crnt_$fn"]) {
        
            $diff = pdiff::htmlDiff($entry["prev_$fn"], $entry["crnt_$fn"]);
            print "<tr><td>$fn</td><td class=trimmed>$diff</td></tr>\n";
        }
    }
    print "</table>\n";
}


// page footer
include("template/bottom.php");

























































?>