Issues (1965)

html/user/kw_prefs.php (18 issues)

1
<?php
2
3
// This file is part of BOINC.
4
// http://boinc.berkeley.edu
5
// Copyright (C) 2019 University of California
6
//
7
// BOINC is free software; you can redistribute it and/or modify it
8
// under the terms of the GNU Lesser General Public License
9
// as published by the Free Software Foundation,
10
// either version 3 of the License, or (at your option) any later version.
11
//
12
// BOINC is distributed in the hope that it will be useful,
13
// but WITHOUT ANY WARRANTY; without even the implied warranty of
14
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
// See the GNU Lesser General Public License for more details.
16
//
17
// You should have received a copy of the GNU Lesser General Public License
18
// along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
19
20
require_once("../inc/util.inc");
21
require_once("../inc/keywords.inc");
22
require_once("../inc/kw_prefs.inc");
23
24
// Interactive page for editing keyword prefs
25
//
26
// The PHP generates rows for all keywords, and hides the appropriate ones.
27
// The Javascript hides and unhides rows as needed.
28
//
29
// element IDs for keyword K
30
//
31
// rowK: the <tr> row element
32
// textK: the plus or minus sign, or spaces
33
// radioK: the radio buttons
34
35
// for each kw K
36
// nprefs(K) = how many descendants of K have nonzero pref
37
// expanded(K): true if user chose to expand K
38
//      persists if ancestors are contracted;
39
//      doesn't persist if nprefs becomes nonzero
40
//
41
// actions:
42
// click on expand or contract: set or clear expanded(K)
43
// radio: recompute nprefs for all ancestors
44
//
45
// render:
46
//  for each terminal node K
47
//      if nprefs(parent)
48
//          unhide
49
//      else if all ancesters are either nprefs<>0 or expanded
50
//          unhide
51
//      else
52
//          hide
53
//
54
//  for each nonterminal node K
55
//      if nprefs(K)
56
//          expanded=true
57
//          unhide
58
//          button=none
59
//      else if nprefs(parent)
60
//          unhide
61
//          set button according to expanded
62
//      else if all ancestors are expanded
63
//          set button according to expanded
64
//      else
65
//          hide
66
67
// for each keyword K:
68
// - generate list of K's children
69
//
70
function keyword_setup($uprefs) {
71
    global $job_keywords;
72
    foreach ($job_keywords as $id=>$k) {
0 ignored issues
show
Expected 1 space before "=>"; 0 found
Loading history...
Expected 1 space after "=>"; 0 found
Loading history...
73
        $job_keywords[$id]->children = array();
74
        $job_keywords[$id]->expand = 0;
75
    }
76
    foreach ($job_keywords as $id=>$k) {
0 ignored issues
show
Expected 1 space before "=>"; 0 found
Loading history...
Expected 1 space after "=>"; 0 found
Loading history...
77
        if (!$k->parent) continue;
78
        $job_keywords[$k->parent]->children[] = $id;
79
    }
80
    foreach ($uprefs as $id=>$n) {
0 ignored issues
show
Expected 1 space before "=>"; 0 found
Loading history...
Expected 1 space after "=>"; 0 found
Loading history...
81
        while (1) {
82
            $id = $job_keywords[$id]->parent;
83
            if (!$id) break;
84
            $job_keywords[$id]->expand = true;
85
        }
86
    }
87
}
88
89
// output a keyword and (recursively) its descendants.
90
// If its parent is expanded, show it, else hide
91
//
92
function generate_html_kw($id, $uprefs) {
93
    global $job_keywords;
94
    $kw = $job_keywords[$id];
95
    $u = $uprefs[$id];
96
    $yes_checked = ($u == KW_YES)?"checked":"";
97
    $no_checked = ($u == KW_NO)?"checked":"";
98
    $maybe_checked = ($u == KW_MAYBE)?"checked":"";
99
100
    echo sprintf('<tr id="%s" hidden>%s', "row$id", "\n");
101
    echo sprintf('   <td width=50%% id="%s"></td>%s', "text$id", "\n");
102
    echo sprintf('   <td><input onclick="radio(%d, 1)" type="radio" name="%s" id="%s" value="%d" %s></td>%s',
103
        $id, "radio$id", "radio$id"."_0", KW_YES, $yes_checked, "\n"
104
    );
105
    echo sprintf('   <td><input onclick="radio(%d, 0)" type="radio" name="%s" id="%s" value="%d" %s></td>%s',
106
        $id, "radio$id", "radio$id"."_1", KW_MAYBE, $maybe_checked, "\n"
107
    );
108
    echo sprintf('   <td><input onclick="radio(%d, -1)" type="radio" name="%s" id="%s" value="%d" %s></td>%s',
109
        $id, "radio$id", "radio$id"."_2", KW_NO, $no_checked, "\n"
110
    );
111
    echo "</tr>\n";
112
113
    foreach ($kw->children as $k) {
114
        generate_html_kw($k, $uprefs);
115
    }
116
}
117
118
function generate_html_category($category, $uprefs) {
119
    global $job_keywords;
120
    row_heading_array(array(
121
        '',
122
        tra('Prefer'),
123
        tra('As needed'),
124
        tra('Never')),
0 ignored issues
show
There should be a trailing comma after the last value of an array declaration.
Loading history...
The closing parenthesis of an array declaration should be on a new line.
Loading history...
125
        null,
126
        'bg-default'
127
    );
128
    foreach ($job_keywords as $id=>$k) {
0 ignored issues
show
Expected 1 space before "=>"; 0 found
Loading history...
Expected 1 space after "=>"; 0 found
Loading history...
129
        if ($k->category != $category) continue;
130
        if ($k->parent) continue;
131
        generate_html_kw($id, $uprefs);
132
    }
133
}
134
135
function generate_javascript($uprefs) {
136
    global $job_keywords;
137
    echo "<script>
138
        var ids = new Array;
139
        var names = new Array;
140
        var levels = new Array;
141
        var parent = new Array;
142
        var radio_value = new Array;
143
";
144
    foreach ($job_keywords as $id=>$k) {
0 ignored issues
show
Expected 1 space before "=>"; 0 found
Loading history...
Expected 1 space after "=>"; 0 found
Loading history...
145
        $val = $uprefs[$id];
146
        echo "
147
            names[$id] = '$k->name';
148
            levels[$id] = $k->level;
149
            parent[$id] = $k->parent;
150
            radio_value[$id] = $val;
151
            ids.push($id);
152
        ";
153
    }
154
    echo sprintf("var nkws = %d;\n", count($job_keywords));
155
    echo <<<EOT
0 ignored issues
show
Use of heredoc and nowdoc syntax ("<<<") is not allowed; use standard strings or inline HTML instead
Loading history...
156
    var rows = new Array;
157
    var texts = new Array;
158
    var expanded = new Array;
159
    var terminal = new Array;
160
    var nprefs = new Array;
161
162
    // initialize stuff
163
164
    for (i=0; i<nkws; i++) {
165
        terminal[ids[i]] = true;
166
        nprefs[ids[i]] = 0;
167
    }
168
    for (i=0; i<nkws; i++) {
169
        var j = ids[i];
170
        var rowid = "row"+j;
171
        var textid = "text"+j;
172
        rows[j] = document.getElementById(rowid);
173
        texts[j] = document.getElementById(textid);
174
        if (parent[j]) {
175
            terminal[parent[j]] = false;
176
        }
177
        expanded[j] = false;
178
179
        if (radio_value[j]) {
180
            k = j;
181
            while (1) {
182
                k = parent[k];
183
                if (!k) break;
184
                nprefs[k]++;
185
            }
186
        }
187
    }
188
189
    // Firefox doesn't set radio buttons correctly.
190
    //
191
    for (i=0; i<nkws; i++) {
192
        var j = ids[i];
193
        if (!terminal[j]) continue;
194
        for (k=0; k<3; k++) {
195
            id = "radio"+j+"_"+k;
196
            r = document.getElementById(id);
197
            //console.log(id, r);
198
            r.checked= (k == 1-radio_value[j]);
199
        }
200
    }
201
202
    var font_size = [120, 108, 92, 80];
203
    var indent = [0, 1.3, 2.6, 3.9];
204
    var button_indent = 1.0;
205
206
    // -1: show "contract" button
207
    // 0: no button
208
    // 1: show "expand" button
209
    //
210
    function set_expand(k, val) {
211
        //console.log('set_expand ', k, val);
212
        var level = levels[k];
213
        var x = '<span style="font-size:'+font_size[level]+'%">';
214
        x += '<span style="padding-left:'+indent[level]+'em"/>';
215
        if (val < 0) {
216
            x += '<a onclick="expand_contract('+k+')" id="t'+k+'" href=#/>&boxminus;</a> ';
217
        } else if (val == 0) {
218
            x += '<span style="padding-left:'+button_indent+'em"/>';
219
        } else {
220
            x += '<a onclick="expand_contract('+k+')" id="t'+k+'" href=#/>&boxplus;</a> ';
221
        }
222
        x += names[k];
223
        texts[k].innerHTML = x;
224
    }
225
226
    function radio(k, val) {
227
        //console.log('radio ', k, val, parent[k]);
228
        old_val = radio_value[k];
229
        radio_value[k] = val;
230
        inc = 0;
231
        if (val && !old_val) inc = 1;
232
        if (!val && old_val) inc = -1;
233
        if (inc) {
234
            while (1) {
235
                k = parent[k];
236
                if (!k) break;
237
                nprefs[k] += inc;
238
            }
239
        }
240
        render();
241
    }
242
243
    // click on expand/contract link
244
    //
245
    function expand_contract(k) {
246
        expanded[k] = !expanded[k];
247
        set_expand(k, expanded[k]?-1:1);
248
        var h = expanded[k]?false:true;
249
        //console.log('expand_contract ', k, h);
250
        render();
251
        return false;
252
    }
253
254
    // return true if all ancestrors of i are expanded or nprefs>0
255
    //
256
    function ancestors_expanded(i) {
257
        while (1) {
258
            i = parent[i];
259
            if (!i) break;
260
            if (!nprefs[i] && !expanded[i]) return false;
261
        }
262
        return true;
263
    }
264
265
    function render() {
266
        for (i=0; i<nkws; i++) {
267
            j = ids[i];
268
            if (terminal[j]) {
269
                set_expand(j, 0);
270
                if (nprefs[parent[j]]>0 || ancestors_expanded(j)) {
271
                    rows[j].hidden = false;
272
                } else {
273
                    rows[j].hidden = true;
274
                }
275
            } else {
276
                //console.log("nprefs ", j, nprefs[j]);
277
                if (nprefs[j]) {
278
                    expanded[j] = true;
279
                    rows[j].hidden = false;
280
                    set_expand(j, 0);
281
                } else {
282
                    p = parent[j];
283
                    if (p) {
284
                        if (nprefs[parent[j]]>0 || ancestors_expanded(j)) {
285
                            rows[j].hidden = false;
286
                            set_expand(j, expanded[j]?-1:1);
287
                        } else {
288
                            rows[j].hidden = true;
289
                        }
290
                    } else {
291
                        rows[j].hidden = false;
292
                        set_expand(j, expanded[j]?-1:1);
293
                    }
294
                }
295
            }
296
        }
297
    }
298
299
    render();
300
301
EOT;
302
    echo "</script>\n";
303
}
304
305
function prefs_edit_form($user, $show_saved) {
306
    global $job_keywords;
307
308
    [$yes, $no] = read_kw_prefs($user);
309
310
    // convert user prefs to a map id=>-1/0/1
311
    //
312
    $uprefs = array();
313
    foreach ($job_keywords as $id=>$kw) {
0 ignored issues
show
Expected 1 space before "=>"; 0 found
Loading history...
Expected 1 space after "=>"; 0 found
Loading history...
314
        $uprefs[$id] = 0;
315
    }
316
    foreach ($no as $id) {
317
        $uprefs[$id] = KW_NO;
318
    }
319
    foreach ($yes as $id) {
320
        $uprefs[$id] = KW_YES;
321
    }
322
323
    keyword_setup($uprefs);
324
325
    page_head(tra("Science and location preferences"));
326
327
    if ($show_saved) {
328
        echo '<span class="text-success">'.tra("Preferences saved.").'</span><p><p>';
329
    }
330
331
    echo tra("Select science areas and locations you do or don't want to support.  Click %1 for more detail, %2 for less.  When done, click the Save button at the bottom.",
332
        "<a>&boxplus;</a>",
333
        "<a>&boxminus;</a>"
334
    );
335
    echo "
336
        <p>
337
    ";
338
    form_start("kw_prefs.php");
339
    form_input_hidden('action', 'submit');
340
    echo "<h3>".tra("Science areas")."</h3>\n";
341
    start_table("table-striped");
342
    generate_html_category(KW_CATEGORY_SCIENCE, $uprefs);
343
    end_table();
344
    echo "<h3>".tra("Locations")."</h3>\n";
345
    start_table("table-striped");
346
    generate_html_category(KW_CATEGORY_LOC, $uprefs);
347
    end_table();
348
    echo sprintf(
349
        '<button type="submit" %s class="btn">%s</button>',
350
        button_style(),
351
        tra("Save")
352
    );
353
    form_end();
354
    generate_javascript($uprefs);
355
    page_tail();
356
}
357
358
function prefs_edit_action($user) {
359
    global $job_keywords;
360
    $yes = [];
361
    $no = [];
362
    foreach ($job_keywords as $id=>$kw) {
0 ignored issues
show
Expected 1 space before "=>"; 0 found
Loading history...
Expected 1 space after "=>"; 0 found
Loading history...
363
        $name = "radio$id";
364
        $val = get_int($name, true);
365
        switch ($val) {
366
        case KW_NO:
367
            $no[] = $id;
368
            break;
369
        case KW_YES:
370
            $yes[] = $id;
371
            break;
372
        }
373
    }
374
    write_kw_prefs($user, $yes, $no);
375
}
376
377
$user = get_logged_in_user();
0 ignored issues
show
Are you sure the assignment to $user is correct as get_logged_in_user() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
378
$action = get_str('action', true);
379
380
if ($action == "submit") {
381
    prefs_edit_action($user);
382
    prefs_edit_form($user, true);
383
} else {
384
    prefs_edit_form($user, false);
385
}
386
387
?>
388