[ home / rules / faq ] [ overboard / sfw / alt ] [ leftypol / siberia / hobby / tech / edu / games / anime / music ] [ meta / roulette ] [ cytube / git ] [ GET / ref / booru ]

/tech/ - Technology

"Technology reveals the active relation of man to nature"
Name
Email
Subject
Comment
Flag
File
Embed
Password (For file deletion.)

New Announcement: IRC<=>Matrix bridge #leftypol on Rizon
Please give feedback on proposals, new every Monday : /meta/
/edu/ want your help building a library! >>>/edu/7066
New /roulette/ topic: /draw/ - Original Art


File: 1612129656526.gif (2.28 MB, 224x240, 1608608621350.gif)

 No.6724[Last 50 Posts]

This thread is only for feedback related to technical issues (bug reports, suggestions). Otherwise use /meta/.
Public Repo:
https://git.leftypol.org/leftypol/leftypol
If you have any grievances you can make a PR.

Mobile Support:
https://github.com/PietroCarrara/Clover/releases/latest
Thread For Mobile Feedback: >>>/tech/6316

Onion Link:
76i2c3hn55fcj5nut3tqlboqqbbh23zvphv7lefk3vftpx6wketlanyd.onion

Cytube:
https://tv.leftypol.org

Matrix rooms:
https://matrix.to/#/#leftypolPublic:matrix.org

We are currently working on improvements to the site, subject to the need of the tech team to sleep and go to their day jobs. If you need more immediate feedback please join the matrix room[s] and ask around. Feel free to leave comments, concerns, and suggestions about the tech side of the site here and we will try to get to it as soon as possible

Archived thread:
>>>/leftypol_archive/903

 No.6727

File: 1612133034865.png (153.68 KB, 681x698, 2021-01-31.png)

Plug this hole.

 No.6730

>>6727
There was an issue with the previous fix.
It had to be rolled back, unfortunately.
The issue has been fixed and a new version is in PR.

 No.6731

>>6730
Okay thanks for letting me know it's progressing. I see the PR was made Jan 30, how long do you think it will take for the given admin(s) to enable the fix?
I'm so nagging about this because the warning and Google in general gives me anxiety.

p.s. nonmakina is based af

 No.6733

>>6731
nonmakina = antonious

 No.6744

File: 1612183832574.png (8.25 KB, 461x81, Untitled2.png)

To fix the bug of div#thread_stats not staying at the bottom of the reply list when auto-reload.js adds new replies, replace
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/b962f6a1283b33c6dc54c78cf4545adf92e21ce9/js/thread-stats.js#L18
.after('<div id="thread_stats"></div>');

To put the "Unique IPs" on the right with the thread stats dump the span style from the element
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/b962f6a1283b33c6dc54c78cf4545adf92e21ce9/templates/post_thread.html#L103
and add a rule to style.css:

[code]
#uniqueip > span {
display: block;
float: right;
margin: 0em 1em;
}
[/code]

The result is attached. Until a backend fix the following can be added to Options -> User JS:

[code]
(() => {
$('.clear').after($('#thread_stats'))
$('#uniqueip > span').attr('style', 'display: block; float: right; margin: 0em 1em;')
})()
[/code]

Options -> User JS quick reply spoiler fix >>>/leftypol_archive/1801
Options -> User JS catalog links in div.boardlist >>>/leftypol_archive/1803

 No.6749

>>6748
lmao do itdemocratic_socialismDemocratic Socialism

 No.6752

>404
It's not multi_image.js, it's multi-image.js.

 No.6753

To fix individual post hiding in Options -> User JS:

[code]
(() => {
const pcid2tid = (board, pcid) => {
const n = document.querySelector ('[data-board="' + board + '"].thread > div#' + pcid)
return n == null ? null : n.parentNode.getAttribute ('id').replace ('thread_', '')
}
const merge = (have, posts) => {
let changed = false
for (p of posts) {
if (!have.some (e => e.post === p.post)) {
have.push (p)
changed = true
}
}
return changed
}
const fixids = () => {
let lspf = JSON.parse (localStorage.postFilter)
let changed = false
for (const [board, threads] of Object.entries (lspf.postFilter)) {
for (const [id, posts] of Object.entries (threads)) {
if (!id.startsWith ('pc')) { continue; }
const tid = pcid2tid (board, id)
if (tid == null) { continue; }
if (tid in threads) {
const have = threads [tid]
if (merge (have, posts)) { changed = true; }
} else {
threads [tid] = posts
changed = true
}
delete threads [id]
}
}
if (changed) {
lspf = JSON.stringify (lspf)
localStorage.postFilter = lspf
$(document).trigger('filter_page')
}
}
fixids ()
$(document).on('filter_page', fixids)

// post-filter.js
const removepost = function (boardId, threadId, postId) {
const list = JSON.parse (localStorage.postFilter)
const filter = list.postFilter

// thread already pruned
if (typeof filter[boardId] == 'undefined' || typeof filter[boardId][threadId] == 'undefined') return;

for (var i=0; i<filter[boardId][threadId].length; i++) {
if (filter[boardId][threadId][i].post == postId) {
filter[boardId][threadId].splice(i, 1);
break;
}
}

if ($.isEmptyObject(filter[boardId][threadId])) {
delete filter[boardId][threadId];
delete list.nextPurge[boardId][threadId];

if ($.isEmptyObject(filter[boardId])) {
delete filter[boardId];
delete list.nextPurge[boardId];
}
}

localStorage.postFilter = JSON.stringify (list)
}

Menu.onclick(function (e, $buffer) {
var ele = e.target.parentElement.parentElement;
var $ele = $(ele);
var threadId = $ele.parents('.thread').attr('id').replace('thread_', '');
var boardId = $ele.parent().data('board');
var postId = $ele.find('.post_no').not('[id]').text();

if ($ele.data('hidden')) {
$buffer.find('#filter-menu-unhide').click(function () {
removepost(boardId, threadId, postId)
$(document).trigger('filter_page')
})
}
})
})()
[/code]

The price is that the page is filtered twice, once with the wrong pcN IDs from post-filter.js, then with the correct thread IDs. The backend fix >>>/leftypol_archive/1822 doesn't have this double filtering.

Options -> User JS quick reply spoiler fix >>>/leftypol_archive/1801
Options -> User JS catalog links in div.boardlist >>>/leftypol_archive/1803
Options -> User JS thread stats and Unique IPs >>6744

 No.6755

File: 1612309139952.txt (3.73 KB, userjs.txt)

A combined Options -> User JS with the four >>6753 fixes.

 No.6756

What might it take to setup a leftypol PeerTube instance?

 No.6763

>>6748
Due to their aggressive attitude, I request the first 'message' line be replaced with the second 'message' line. This will lower the change of them recognizing we're fucking with them personally.ak-47AK-47

 No.6764

File: 1612359900997.png (49.98 KB, 877x363, 1.png)

EASILY SOLVABLE
1. please order "OPTIONS -> [THEME SELECTION]" in ABC order.

2. please create a fuggen suboption menu for it. Currently, it's picrel, which is autistic. (picrel)
At the very least add some kind of "select look" or sg like that, lmao.

3. Please fix "Gentoo" outlook the following way:
how come the fucking hovering over message box is fucking semi-transparent? I can't see shit, because of the transparency effect. PLZ figgs!

 No.6765

>>6764
$('#style-select > select').css ({float: "none"}).before ('Select theme: ')

 No.6769

>>6764
Sorted, labeled style selector:

[code]
(() => {
$('#style-select > select').before ('Select theme: ')
const selected = $('div.styles > a.selected').attr ('id').replace ('style-select-', '')
const stylesSelect = $('<select></select>').css ({float: "none"})

Array.from (document.querySelectorAll ('div.styles > a')).map (a => [a.innerText.replace (/^\[(.+)\]$/, '$1'), a.getAttribute ('id').replace ('style-select-', '')]).sort ((a, b) => {
const au = a [0].toUpperCase ()
const bu = b [0].toUpperCase ()
if (au < bu) { return -1; }
if (au > bu) { return 1; }
return 0
}).forEach (([name, id]) => {
const opt = $('<option></option>').html(name).val(id)
if (id === selected) { opt.attr('selected', true); }
stylesSelect.append(opt)
})

$('#style-select > select').detach ()
stylesSelect.change(function() {
$('#style-select-' + $(this).val()).click()
})
$('#style-select').append (stylesSelect)
})()
[/code]

 No.6770

File: 1612411260062.txt (4.67 KB, userjs.txt)

A combined Options -> User JS with the five >>6753 >>6769 fixes.

 No.6771

>>6748
Rewriting to make it unambiguous.

I literally cannot make it any easier, devs. It takes ten seconds to find the file and five seconds to copy and paste and save. It will save the janitors a ton of effort over the next few years.

Append this to instance-config.php (if you actually added the version above, remove it first!)
//———————————————

$config['filters'][] = array(
'condition' => array(
// basic filter for copypasta anorectal spam
'OP' => true,
'subject' => '/Address rampant anorectal violence/' //checks subject only
),
'action' => 'reject',
'message' => 'Due to increased spam from /pol/, you must copy and paste the opening line of The Communist Manifesto into the email field in order to post.<br><br>Email [email protected] if you are unable to post.'
);

$config['filters'][] = array(
'condition' => array(
// special filter for anorectal spam
'OP' => true,
'custom' => function($post) {
// known filename
if ($post['has_file'] && preg_match("/TAKE ACTION v/", $post['files'][0]['filename']) ||
(preg_match("/Blatantly injurious/", $post['body'])) ||
(preg_match("/ustice.*paste/", $post['body'])) ){
sleep(10); # add a delay :^)
return true; # perform the action below
}
return false;
}
),
'action' => 'reject',
'message' => 'Due to increased spam from /pol/, you must copy and paste the opening line of The Communist Manifesto into the email field in order to post.<br><br>Email [email protected] if you are unable to post.'
);

 No.6772

>>6756
Not a dev but:
>a decision to do so
>an hour or so to properly set up (unless it fucks up)
>occasional maintenance if users can upload
I think it would be cool but why do you want it? What benefit would a leftypol instance have that other socialist instances don't offer?

 No.6773

Backend version of sorted, labeled style selector. >>6769

 No.6796

In addition to image.html hardcoding the initial loop parameter to 1 >>>/leftypol_archive/1535 in the non-JS case, with JS on expand-video.js also loops by default ignoring the loop=[01] in the player.php href.
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/b962f6a1283b33c6dc54c78cf4545adf92e21ce9/js/expand-video.js#L16
> var loop = true;
> loopControls[1].style.fontWeight = "bold";

In the JS case with expand-video.js the initial state can be switched to [play once] on all videos in a page with:

$('p.fileinfo > span').filter ((k, e) => e.innerText === '[play once]').each ((k, e) => e.click ())

Unfortunately the loopControls spans aren't tagged with a class.

 No.6798

File: 1612533367083.gif (772.08 KB, 228x170, ren-anxious.gif)

Is the leftypol_lainchan github maintainer okay? ~1 week has gone and they haven't updated for the fix to the Google leak.
>>6727
>>6730
https://github.com/towards-a-new-leftypol/leftypol_lainchan/pull/224

 No.6800


 No.6801

fix this already, pretty please

 No.6803

File: 1612568307155.png (76.05 KB, 444x216, Untitled.png)

>>6801
Your browser seems to be the one with the subpar handling of word-wrap:break-word, Képernyőkép dude. >>>/leftypol/69820 The break-word will not be removed, it's there for a reason. However what you can do is inspect that post, go up to div.body, locate the "div.post div.body" rules, uncheck word-wrap:break-word and post the resulting layout.

 No.6814

hiding individual posts doesn't seem to work, also, there's a lag when the hidden OPs show up in the catalog view like i can see it for half a second and then it disappears

 No.6816

Batch loop/once setting >>6796 for Options -> WebM, manual mode only for now.

Test thread: >>>/leftypol/32459

 No.6818

Batch loop/once setting >>6796 for Options -> WebM, with auto set on page load but not on new posts yet.

Test thread: >>>/leftypol/32459

 No.6819

Batch loop/once setting >>6796 >>>/leftypol_archive/1521 in Options -> WebM, with auto set on page load and on new posts. Test thread: >>>/leftypol/32459 The issue with new posts was that expand-video.js uses a MutationObserver instead of reacting to the 'new_post' event like everyone else, and the observer runs after the 'new_post' trigger.
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/b962f6a1283b33c6dc54c78cf4545adf92e21ce9/js/expand-video.js#L230

Options -> User JS quick reply spoiler fix >>>/leftypol_archive/1801
Options -> User JS catalog links in div.boardlist >>>/leftypol_archive/1803
Options -> User JS thread stats and Unique IPs fix >>6744
Options -> User JS individual post hiding >>6753
Options -> User JS sorted, labeled style selector >>6769

 No.6820

File: 1612660369892.txt (6.91 KB, userjs.txt)

A combined Options -> User JS with the six >>6819 fixes.

 No.6824

>>6814
HELLLO. JANNIES. WHY CANT I HIDE INDIVIDUAL POSTS? ONLY THE OP OF THREADS WHICH IS GREAT BUT I WANT TO HIDE INDIVIDUAL POSTS IN THREADS

 No.6835

Go to top/bottom navlinks in the top bar for Options -> User JS:

[code]
(() => {
const makea = (href, title, html) => {
const a = document.createElement ("a")
a.setAttribute ('href', href)
a.setAttribute ('title', title)
a.innerHTML = html
return a
}
if (document.querySelectorAll ('div.post.op').length == 1) {
const span = document.createElement ("span")
span.setAttribute ('id', 'topbottom-boardlist-navlinks')
span.setAttribute ('style', 'float:right;')
span.appendChild (makea ('#top', 'Go to top', '&#x25B2;'))
span.appendChild (makea ('#bottom', 'Go to bottom', '&#x25BC;'))
document.querySelector ('div.boardlist').appendChild (span)
}
})()
[/code]

 No.6837

File: 1612796305571.txt (7.56 KB, userjs.txt)

A combined Options -> User JS with the seven >>6819 >>6835 fixes.

 No.6841

1. Spoiler and deleted thumbs work in the catalog after >>>/leftypol_archive/1446 #124, but generic thumbs fail with e.g. src="/tech/thumb/file".
- spoiler: https://leftypol.org/meta/catalog.html spoiler OP test
- deleted: https://leftypol.org/meta/catalog.html Posting doesn't work for me
- generic: https://leftypol.org/tech/catalog.html Kickstarter workers unionize
The reason is that generateRecentPosts doesn't have any 'file' thumb handling:
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/b962f6a1283b33c6dc54c78cf4545adf92e21ce9/templates/themes/catalog/theme.php#L421
To add 'file' thumb handling, fix the fallback loop and add a missing 'else' branch:

[code]
if (isset($post['files']) && $post['files']) {
$files = json_decode($post['files']);

if (isset($files[0]) && $files[0]) {
$foundone = false;
foreach ($files as $file) {
if ($file->file != 'deleted') {
$post['file'] = $this->filepathForThumb($file->thumb, $file->file);
$foundone = true;
break;
}
}
if (!$foundone) {
$post['file'] = $this->filepathForThumb('deleted', null);
}
} else {
$post['file'] = $this->filepathForThumb('deleted', null);
}
} else {
$post['file'] = $this->filepathForThumb('deleted', null);
}
[/code]

Before or after generateRecentPosts:

[code]
private function filepathForThumb($thumb_or_special, $path_when_file) {
global $config;

if ($thumb_or_special === 'deleted') {
return $config['root'] . $config['image_deleted'];
} else if ($thumb_or_special === 'spoiler') {
return $config['root'] . $config['spoiler_image'];
} else if ($thumb_or_special === 'file') {
// see twig_extension_filter
$ext = mb_strtolower(mb_substr($path_when_file, mb_strrpos($path_when_file, '.') + 1));
$icons = $config['file_icons'];
// see templates/post/image.html
if (isset($icons[$ext])) {
return $config['root'] . sprintf($config['file_thumb'], $icons[$ext]);
} else {
return $config['root'] . sprintf($config['file_thumb'], $icons['default']);
}
} else {
return $config['uri_thumb'] . $thumb_or_special;
}
}
[/code]

2. There is what might be considered an UI bug, whereby the banner images cause a layout shift on nearly every page load. To fix it:
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/b962f6a1283b33c6dc54c78cf4545adf92e21ce9/inc/config.php#L937
> // Banner dimensions are also optional. As the banner loads after the rest of the page, everything may be
> // shifted down a few pixels when it does. Making the banner a fixed size will prevent this.
> // $config['banner_width'] = 300;
> // $config['banner_height'] = 100;
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/b962f6a1283b33c6dc54c78cf4545adf92e21ce9/inc/instance-config.php#L105

3. The "sticky bug in the overboard catalog view" #229 is caused by this line:
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/b962f6a1283b33c6dc54c78cf4545adf92e21ce9/js/catalog.js#L11
> $('#Grid').mixItUp('sort', (value == "random" ? value : "sticky:desc " + value));
To fix it change it to:
> $('#Grid').mixItUp('sort', (((value "random") || (board_name "overboard")) ? value : "sticky:desc " + value));
and update the test if the overboard ever moves from /overboard/.

4. For future reference, should a similar issue come up again, the clone_wrapped_with_exist_check fix to #225
https://github.com/towards-a-new-leftypol/leftypol_lainchan/commit/43a6a67844e2b806945e67cd34c593009f54c460
is almost the same as the @ error suppression from
>>>/leftypol_archive/1839 + >>>/leftypol/63272
and treats the symptoms. The explanation of the cause and of a few other problems with mod_move is still available in the archive.

+ catalog post form for non-JS users >>>/leftypol_archive/1833
+ thread stats and unique IPs fix >>6744
+ sorted, labeled style selector >>6773
in issues but not resolved yet:
+ track order #63 webm error 2 >>>/leftypol_archive/1337 [in PR]
+ arabic characters #125 >>>/leftypol_archive/1517
+ original file name downloads for non-JS users #128 >>>/leftypol_archive/1499
+ txt thumbnails #129 >>>/leftypol_archive/1593 >>>/leftypol_archive/1673
+ reply limit nobump markers in index and thread view #147 >>>/leftypol_archive/1775
+ UTF-8 troubles #193 >>>/leftypol_archive/1738 >>>/leftypol_archive/1744
+ posts below the line and related #207 >>>/leftypol_archive/1759
+ quick reply spoiler #213 >>>/leftypol_archive/1801
+ individual post hiding #215 >>>/leftypol_archive/1822
+ catalog links in div.boardlist #216 >>>/leftypol_archive/1807
+ zombie threads in catalog #219 >>>/leftypol_archive/1691
+ post quote ending an orange quote #220 >>>/leftypol_archive/1722
+ ICC profile error #221 >>>/leftypol_archive/1787

 No.6842

> $('#Grid').mixItUp('sort', (((value == "random") || (board_name == "overboard")) ? value : "sticky:desc " + value));

 No.6843

Client-side fix for generic file thumbs >>6841 in catalog:

Array.from (document.getElementsByTagName ('img')).filter (e => e.hasAttribute ('src')).map (e => [e, e.getAttribute ('src').match (/^\/([^\/]+)\/thumb\/file$/)]).filter (([e, m]) => m != null).forEach (([e, m]) => e.setAttribute ('src', '/static/file.png'))

 No.6847

I cannot post images via mobile. Is there any way around this?

 No.6848

>>6847
Post a screenshot of the error message in >>4951

 No.6849

Is the matrix server down for anyone else?

 No.6851

when do we get 24 hour unique IP calculation?

 No.6859

The "sticky bug in the overboard catalog view" #229 can also be fixed >>6842 manually on the client from the console after the page has finished loading.

[code]
(() => {
const sortby = (value) => { console.log (value); $('#Grid').mixItUp('sort', value); }
if ((active_page 'catalog') && (board_name "overboard")) {
$("#sort_by").change((e) => {
const v = e.target.value
if (v != "random") { sortby (v); }
})
if (localStorage && localStorage.catalog) {
const catalog = JSON.parse(localStorage.catalog)
const sb = catalog.sort_by
if (sb && (sb != "random")) { sortby (sb); }
}
}
})()
[/code]

This version won't work from Options -> User JS because both mixitup and catalog.js run after options/user-js.js.
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/b962f6a1283b33c6dc54c78cf4545adf92e21ce9/templates/themes/catalog/theme.php#L465

 No.6860

[code]
(() => {
const sortby = (value) => { console.log (value); $('#Grid').mixItUp('sort', value); }
if ((active_page == 'catalog') && (board_name == "overboard")) {
$("#sort_by").change((e) => {
const v = e.target.value
if (v != "random") { sortby (v); }
})
if (localStorage && localStorage.catalog) {
const catalog = JSON.parse(localStorage.catalog)
const sb = catalog.sort_by
if (sb && (sb != "random")) { sortby (sb); }
}
}
})()
[/code]

 No.6864

File: 1613008585135.txt (7.84 KB, userjs.txt)

A combined Options -> User JS with the eight >>6837 >>6843 fixes.

 No.6867

>>6727
>>6730
Why can't towards-a-new-leftypol just log in and merge this?

 No.6871

Options -> User JS fix for "sticky bug in the overboard catalog view" #229 using a mixEnd callback:
https://github.com/patrickkunka/mixitup/blob/v2/docs/events.md

[code]
(() => {
if ((active_page != 'catalog') || (board_name != "overboard")) { return; }
const state = { added: false }
$("#sort_by").change((e) => {
if (state.added) { return; }
state.added = true
$('#Grid').on('mixEnd', (ev, st) => {
as = st.activeSort
if ((typeof as === 'string') && as.startsWith ('sticky:desc ')) {
$('#Grid').mixItUp('sort', as.replace ('sticky:desc ', ""))
}
})
})
})()
[/code]

As with the individual post hiding #215 User JS fix >>6753 the price is double sorting, once with the sticky:desc forced in by catalog.js and again without. The backend fix >>6842 >>6841 doesn't have this double sorting.

 No.6878

> https://github.com/towards-a-new-leftypol/leftypol_lainchan/issues/231
> https://github.com/towards-a-new-leftypol/leftypol_lainchan/issues/230
Github mangled some code portions of the pasted comment.

> https://github.com/towards-a-new-leftypol/leftypol_lainchan/issues/229

The bugfix line in >>6841 point 3 has heading markup interference which ate the two pairs of ==.
The same line with the two pairs of == present is in >>6842.

 No.6880

File: 1613133932787.txt (8.29 KB, userjs.txt)

A combined Options -> User JS with the nine fixes.

① quick reply spoiler >>>/leftypol_archive/1801
② catalog links in div.boardlist >>>/leftypol_archive/1803
③ thread stats and Unique IPs >>6744
④ individual post hiding >>6753
⑤ sorted, labeled style selector >>6769
⑥ batch loop/once WebM setting >>6819
⑦ top/bottom navlinks in the top bar >>6835
⑧ generic file thumbs in catalog >>6843
⑨ sticky bug in the overboard catalog >>6871

 No.6881

Can mods confirm that they have heard from the maintainer (towards-a-new-leftypol) within the past two weeks to that they're ok?
Or have Biden's admin taken advantage of Trumps new anti-Antifa laws?

 No.6884

File: 1613212562675.png (21.22 KB, 491x258, 2021،02،13-13:31:42.png)

Using easy privacy list blocks cloudflare scripts that is required to pass the browser verification process. If the cloudflare check loops forever for you this might be the problem.ak-47AK-47

 No.6890

>>6881
Yes, they are alive and well.
Remember that anyone with an account can start a PR on github and also review PRs.
It also helps to attach patches (as .txt) so that they're easier to apply.

 No.6892

>>6890
>It also helps to attach patches (as .txt) so that they're easier to apply.

 No.6893

>>6890
Please tell them to log in and merge this which was pull-requested half a month ago:
https://github.com/towards-a-new-leftypol/leftypol_lainchan/pull/224

 No.6914

Put a link to the catalog at the top, as well. Right next to go to bottom so it looks like:

[ Return / Go to bottom ] [ Catalog ] [ Home ]

 No.6916

>>6914
Options -> User JS

[code]
(() => {
if (active_page !== "thread") { return; }
const added = ' [ <span class="threadlink"><a href="/' + board_name + '/catalog.html">Catalog</a></span> / <span class="threadlink"><a href="/">Home</a></span> ]'
document.querySelector ('div.threadlinks-noup').innerHTML += added
})()
[/code]

 No.6917

>>6893
Why is this not progressing / getting ignored?

 No.6923

>>6917
will checkin with tech team on this

 No.6928

File: 1613819005764.txt (8.71 KB, userjs.txt)

A combined Options -> User JS with the ten >>6880 >>6916 fixes. Added tooltips to div.boardlist catalog links.

 No.6933

To fix >>>/meta/3737
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/6885c1977834ec93b594494a963df4ef6c588c71/inc/functions.php#L2199

$code = "<pre class='code lang-$code_lang'>".str_replace(array("\n","\t"), array("&#10;","&#9;"), htmlspecialchars($code, ENT_COMPAT, "UTF-8", false))."</pre>";

https://www.php.net/manual/en/function.htmlspecialchars.php

 No.6934

Frontend workaround until the backend is fixed >>6933

Array.from (document.querySelectorAll ('pre.code')).forEach (e => { e.innerHTML = e.innerHTML.replace (/&amp;(amp|lt|gt);/g, '&$1;'); })

 No.6952

what happened to youtube embed thumbnails?

 No.6953


 No.6974

File: 1614632455671.txt (8.87 KB, userjs.txt)

A combined Options -> User JS with the eleven >>6928 >>6934 fixes.

 No.6988

Suggestion: load the [watchlist] element in the site navigation bar faster or earlier, or don't incorporate it in the centered container at all. Your use of Javascript to generate it is causing it to load much later than all the other elements. Alternatively, you could could delay the generation of the entire list until your slow-ass javashit is ready. Tired of misclicking a board I want to visit because the watchlist loads too late and shifts all the entries over!

 No.6991

when are u going to fix the youtube embeds already

 No.6992

>>6991
>>6952
They got disabled because the images were being loaded from youtube and causing a call to the site which impacted tor users especially. Someone could write code to download the images directly on the server from youtube.
Hop on the matrix chat if you're interested.

 No.7012

When you merge threads, moved posts still link back to the old thread that doesn't exist anymore.
This causes a 404 to occur if you click on a post-link in a post from the old thread

 No.7013


 No.7026

Some minor nitpicks/ideas about the onion:

On the index page for the news sections etc, leftypol.org links are not replaced with the onion.

Also with the index page and site in general, it might be worthwhile having a specific filter to replace links that have known onions for when accessing leftypol from its onion. Example would be marxists.org and archive.is both have onions, respectively: http://www.marxist7mbr3mbaj.onion http://archivecaslytosk.onion

Font Awesome and other icon fonts do not display in Tor Browser when its set at the safest security levels. SVGs are disabled as well

Continuing the idea of link replacements, might be good idea for reddit, twitter, and youtube links to be replaced on the fly to respective random instances for their privacy-oriented frontend alternatives: https://codeberg.org/teddit/teddit https://github.com/zedeus/nitter/wiki/Instances https://github.com/iv-org/documentation/blob/master/Invidious-Instances.md All three have onions listed.

 No.7050

>>7026
V2 onions are about to expire.

 No.7066

My suggestion is that we make it so it previews the flag you choose, so we lesson the chance we pick the wrong flag and it tells the new anons watch each flag looks like.

 No.7071

>>6890
> It also helps to attach patches (as .txt) so that they're easier to apply.
https://github.com/towards-a-new-leftypol/leftypol_lainchan/pull/238
> Commit the patch from issue 229 #238

Here's #125 >>>/leftypol_archive/1517

 No.7096

would it be complicated to add mathjax support? I want to start more technical thread and simply attaching latex rendered image seems unwieldy.

 No.7106

> Failed to resize image! Details: gm convert: iCCP: profile 'ICC Profile': 'RGB ': RGB color space not permitted on grayscale PNG (/tmp/phparr3Fy).
When posting this: https://files.catbox.moe/0mhv8x.png

 No.7107

The https://files.catbox.moe/0mhv8x.png >>7096 image is a type 0 grayscale png with an iCCP chunk holding 'RGB '.
$ identify rgb.png
rgb.png PNG 609x282 609x282+0+0 8-bit sRGB 256c 93.8KB 0.000u 0:00.020
identify-im6.q16: iCCP: profile 'ICC Profile': 'RGB ': RGB color space not permitted on grayscale PNG `rgb.png' @ warning/png.c/MagickPNGWarningHandler/1654.

Without the iCCP the image passes >>>/meta/3992. In IM this is only a warning which doesn't prevent thumbnailing.
$ convert rgb.png -thumbnail 200x200 rgbthumb.png
convert-im6.q16: iCCP: profile 'ICC Profile': 'RGB ': RGB color space not permitted on grayscale PNG `rgb.png' @ warning/png.c/MagickPNGWarningHandler/1654.
$ identify rgbthumb.png 
rgbthumb.png PNG 200x93 200x93+0+0 8-bit sRGB 15.2KB 0.000u 0:00.000

The entire >>>/leftypol_archive/1787 #221 applies with the additional exception string "'RGB ': RGB color space not permitted on grayscale PNG".

 No.7372

test

 No.7374

I wrote a small script to filter posts by flag. just posting it here for personal convenience so I can use it between devices. if you want to add or remove flags, just alter the "blocklist" and add or remove the strings that you see when you hover over the flags in question. might expand on it in the future to make it gui-based.
blocklist = ["Sandinista","Sabo-Tabby"]

x = document.getElementsByClassName("flag")
for(var i = 0; i &lt; x.length; i++) {
  flag = x[i]
  if (blocklist.find(element =&gt; element == flag.title)) {
    flag.parentNode.parentNode.parentNode.style.display = "none";
  }
}

 No.7375

>>7374
does the great-than symbol not work in code?
blocklist = ["Sandinista","Sabo-Tabby"]

x = document.getElementsByClassName("flag")
for(var i = 0; i &amp;lt; x.length; i++) {
  flag = x[i]
  if (blocklist.find(element =&gt; element == flag.title)) {
    flag.parentNode.parentNode.parentNode.style.display = "none";
  }
}

 No.7376

x = document.getElementsByClassName("flag")
for(var i = 0; i < x.length; i++) {
flag = x[i]
if (blocklist.find(element => element == flag.title)) {
flag.parentNode.parentNode.parentNode.style.display = "none";
}
}

 No.7382

>>7375
>does the great-than symbol not work in code?
see >>6933 >>6934

 No.7390

>Could we have one spoiler checkbox per file instead of it spoilering all files in a post?
>Could the Embed field be on the quick reply box too?

Also
>>>4015

 No.7391

>>7390

>>>/meta/4015

 No.7392


 No.7435

>>7390
>Could we have one spoiler checkbox per file instead of it spoilering all files in a post?
The storage model supports this with spoilers consisting of a per-file thumb value of 'spoiler'. >>>/anime/4442 The use of $_POST['spoiler'] in post.php for every file is relatively easy to upgrade.
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/1a6b26d2be19e430add273af00a0718fd41ef016/post.php#L1057
But after that every file with posting responsibilities would also have to be upgraded to allow for individual spoilers, among them multi-image.js, file-selector.js and quick-reply.js. This is only likely to be done by someone who needs that feature and regularly uploads multiple images, since multiple image upload is only available to begin with to those who regularly browse with remote code execution enabled.

 No.7464

File: 1617038832156.png (134.01 KB, 1002x674, "no".png)

Is this really necessary?
I doubt it.

 No.7465

Don't make a /mu/ board without fixing youtube embeds first

 No.7521

>>6727
This issue has recurred. It's leaking on catalog, but not in overboard or in-thread. Pretty sure it's still to do with embeds bugging out.

 No.7525

>>6824
>HELLLO. JANNIES. WHY CANT I HIDE INDIVIDUAL POSTS? ONLY THE OP OF THREADS WHICH IS GREAT BUT I WANT TO HIDE INDIVIDUAL POSTS IN THREADS
this still isn't fixed

 No.7526

comrades, jump on the matrix and help out contributing code.

>>7525
there's a [-] button to hide the entire thread.

 No.7528


 No.7632

>>7465
>>6727
<done I think

 No.7633

File: 1617493199624.png (Spoiler Image, 8.59 KB, 493x402, rl.png)

>>7632
Hey you
Yeah, you
I love you
<3

 No.7634

Bugged link found (radio link to .ogg as JS?)
>>>/music/1174

 No.7635

>>7634
Works ok for me, you realize it's a stream right?

 No.7637

>>7635
Yes I know it's a stream, I'm saying how it was added to the site caused a bug, similar to >>6727

 No.7641

(but obv has nothing to do with youtube this time)
maybe it's an underlying thing?

 No.7651

Requesting a peertube instance with increased maximum tag count to be used as a booru. The webm thread sucks for searching.
It will also be fun to see how long it takes to get blocked by 'safe space' socialist instances

 No.7683

>>7651
Does PeerTube even allow for more than 5 tags?

 No.7820


 No.7855

>>6724
Is there a way to go to the Cytube on the .onion domain? I just tried butchering the URL together with a tv. prefix and it didn't seem to work. Not really a big deal but it would be preferable to stay on the Tor network than to shoot out an exit node.piratePirate

 No.7857

>>7855
Well the cytube has embedded content, I don't think that will work over tor anyway, I'm not sure it can be supported.

 No.8225

https://github.com/towards-a-new-leftypol/leftypol_lainchan/issues/251
>Certain Posts with images do not stretch enough to fit the text #251
see >>6801 >>6803

 No.8386

I don't see the update button at bottom of threads anymore ?

 No.8406

>>8386
I do. What are you using?
Do you have any script blockers? Is your window larger than your screen?

 No.8425

test

 No.8631


 No.8772

>>8631
amogus

 No.9096

File: 1623357174519.png (4.97 KB, 194x60, pls-do-this.png)

(reminder)
Pls do this
Thnks

 No.9214

File: 1623700986087.png (74.49 KB, 1316x358, 000.png)

Please fix cytube config to allow direct streaming of videos, change picrel to true and avprobe respectively. Join https://cytu.be/r/ipfstest for an example of how it is supposed to work.

 No.9253

>>6756
PeerTube now supports livestreaming. Even if we don't have our own instance, can cytube support PeerTube streams?

 No.9265


 No.9478

File: 1624214509975.png (175.69 KB, 1291x637, ClipboardImage.png)

Very small thing but that I think would make a better user experience:
Put the title of the thread as the title of the page. It would make having multiple tab open much better.

 No.9481

>>9478
(() =&gt; {
  const ops = document.querySelectorAll ("div.thread &gt; div.op")
  if (ops.length !== 1) return
  const sub = ops [0].querySelector ("span.subject")
  if (!sub) return
  document.title = sub.innerText
})()


>>6933 >>6934

 No.9482

Also:
>// Show thread subject in page title.
>$config['thread_subject_in_title'] = false;
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/9acdacbb352f6f515f454f851bab581baef8fe3c/inc/config.php#L929

 No.9483

Update of catalog links in div.boardlist >>>/leftypol_archive/1803 for the new overboards:
Array.from (document.querySelectorAll ("div.boardlist a")).filter (a =&gt; a.hasAttribute ("href")).forEach (a =&gt; {
  const href = a.getAttribute ("href")
  const ma   = href.match (/^(\/[^\/]+\/)(index.html)?$/)
  let   cata = null
  if (ma != null) {
    cata = ma [1] + "catalog.html"
  }
  if (cata != null) {
    const e = document.createElement ("a")
    e.setAttribute ("href", cata)
    e.innerText = "+"
    if (a.hasAttribute ("title")) {
      e.setAttribute ("title", a.getAttribute ("title") + " - Catalog")
    }
    a.insertAdjacentElement ("afterend", e)
  }
})


>>6933 >>6934

 No.9485

Update of
https://github.com/towards-a-new-leftypol/leftypol_lainchan/issues/229
https://github.com/towards-a-new-leftypol/leftypol_lainchan/commit/237ad41fc02dded98ccde72c34ed3f87fb17186d
for the new overboards:
$('#Grid').mixItUp('sort', (((value == "random") || /^(overboard|sfw|alt)$/.test (board_name)) ? value : "sticky:desc " + value));

Or you might add a new JS var to signal an overboard.

 No.9565

>>9478
>>9482
Sorry for not seeing this earlier. Incidentally, I was thinking of doing the same thing yesterday for both user experience and SEO purposes.

 No.9567

>>9565
If, like the rest of us, you find it easy to miss things, see >>7071 for #125.

 No.9568

Maybe the wrong place, but is there a way to make the Kuroba app download the full non compressed image automatically?

 No.9570

>>9568>>4951

>This Thread Has Been Re-appropriated for leftypol.org Usage.

>General thread meant for the discussion of the mobile app for browsing leftypol.org, known as clover.

 No.9591

>>6849
I can't join matrix server

 No.9596

>>9591
Which link? In OP?
Try this one:
https://matrix.to/#/#Leftypol:matrix.org
Once you're in, find the /tech/ chat if you want.

 No.9796

File: 1625394656509.txt (7.44 KB, userjs.txt)

Updated Options -> User JS >>6974 for the recent backend changes.
① quick reply spoiler >>>/leftypol_archive/1801
② catalog links in div.boardlist >>9483
③ thread stats and Unique IPs >>6744
④ individual post hiding >>6753
⑤ batch loop/once WebM setting >>6819
⑥ top/bottom navlinks in the top bar >>6835
⑦ generic file thumbs in catalog >>6843
⑧ catalog link above OP >>6916
⑨ code double escaping >>6934

 No.9797

>>9796
One of the devs here, I've got a bit of spare time to solve some of these on the main site now that more critical changes are resolved.
Thanks for compiling and sharing these with everyone.

 No.9808

>>9797
>One of the devs here, I've got a bit of spare time to solve some of these on the main site now that more critical changes are resolved.
Thanks for all your hard work.

>Thanks for compiling and sharing these with everyone.

No problem. The last list for the backend is in >>6841. The backend-relevant updates since that list:
+ code double escaping >>6933
+ issue-125-patch.txt >>7071
+ more iCCP profiles >>7107
+ embed in quick reply >>7392
+ sticky overboard catalog sort >>9485

 No.9816

please pay attention to meeeeeeee

 No.9820

Is it just me or are all the new image thumbnails broken over the last day or so?

 No.9823

>>9820
Oh, I see what happened… Whose cocksucking idea was it to start making all thumbnails in Google's gay webp format?

 No.9824

>>9823
What browser are you using that can't handle them, mobile app?

 No.9825

>>9824
An older version of Palemoon. It's not easy for me to upgrade at the moment.

 No.9828

>>9825
Now I'm curious, you must be on a five+ year old version. Is there a breaking change? Increased requirements? Excessive customization?

 No.9829

>>9828
They adopted some new library versions a few months ago that aren't supported on *buntu 16.04. The PPA maintainer seems to have given up supporting that version and it doesn't seem like this will be easy to fix without a full system upgrade (a much more complicated problem for me).

 No.9830

File: 1625436363651.png (15.78 KB, 729x90, ooboontoo.png)

>>9829
>a few
I wouldn't call over 260 months a few, v26 introduced support. 16.04 LTS is EOL, so I suspect an OS upgrade is increasingly inevitable when things start breaking. Have you tried a live USB on the newer LTS versions?

 No.9831

>>9830
lol typo with the months, meant 60

 No.9836

To fix >>>/meta/7789 stripped file sizes for the current strip_exif+use_exiftool case:
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/e0ff3ea33ba2c81acdeb6bbc1b72ecd15a734be2/post.php#L1094
if($error = shell_exec_error('exiftool -overwrite_original -ignoreMinorErrors -q -q -all= ' .
    escapeshellarg($file['tmp_name']))) {
    error(_('Could not strip EXIF metadata!'), null, $error);
} else {
    clearstatcache(true, $file['tmp_name']);
    if (($newfilesize = filesize($file['tmp_name'])) !== false)
        $file['size'] = $newfilesize;
}

More generally, operations that modify an uploaded file should reread its size.

https://www.php.net/manual/en/function.filesize.php
https://www.php.net/manual/en/function.clearstatcache.php

 No.9851

>>9830
>v26 introduced support
Oh? I'm on v28.15 and webp rendering is broken.

 No.9854

Maybe add some escaping >>>/leftypol_archive/1499 to #289 for >>>/meta/7808.

 No.9874

File: 1625529717281.png (476.67 KB, 1234x705, ClipboardImage.png)

>>9851
Huh, that's weird then, my mistake. There have been no WebP fixes since 28.15 in updates, and support was introduced in 26.
I downloaded the 29.2.1 binary for 16.04 *ubuntu and it works, but I realize that is different.
Do either of these work?
https://developers.google.com/speed/webp/gallery1
https://developers.google.com/speed/webp/gallery2
(If you don't want to touch Google, you can search for some in https://commons.wikimedia.org/w/index.php?search=webp instead)

 No.9891

>>9874
If you don't want to or can't fix the webp thumbnails, go to Options (top right) and add this script to User JS to replace the thumbnails with the source image.

ext = ["png","jpg", "jpeg"];
$('.file').each(function(file){
   children = this.childNodes;
   if (this.tagName == 'DIV'){
   link=this.childNodes[1].href;
   if (ext.includes(link.split('.').pop())){
      this.getElementsByClassName('post-image')[0].src = link;
   }}
});


(If someone wants to critique this skiddie hack, please do.)

 No.9952

saving as original filename suddenly doesn't work
tried two browsers on both desktop and mobile

 No.9960

Any chance kuroba can work with Orbot?

 No.9965

>>9952
Thanks for reporting.
We did a change last week that deferred JS loading, which broke a few features (hopefully fixed this weekend).
At the same time, I replaced the download with filename funciton with one that didn't need Javascript, but the way I did it was flawed and lead to a security issue so we quickly removed it.
So we're currently running the deferred one that appears to be broken until enough devs are online to push the new changes.

 No.10011

New update. [code­] tags double-encoding should be fixed.

<test> && "test"

 No.10013

Javascript is fucked, backlinks don't work, the autoupdate and the [Watch Thread] appear twice.

 No.10014

>>10013
The dev team is aware and a fix should be deployed soon.

 No.10015

>>10014
Also whatever the fuck is going on here

 No.10016

>>10015
Yeah, that was trippy. On the dev env I got a quad one once.
Issue should now be resolved.

 No.10018

>>9891
Here's a better version:
[code]
$('div.file a').each(function(index){
let ext = ["png","jpg", "jpeg"];
let file = $(this);
let fullSize = file.prop("href");
if (ext.includes(fullSize.split('.').pop())){
file.find('img').prop("src", fullSize);
}
});
[\code]
the indentation is fucked.

 No.10079

>>10016
Still happens if you open the thread to reply, like using this link: https://leftypol.org/tech/res/6724.html#q10016

 No.10082

>>9986
wtf it does work, nvm

 No.10101

File: 1626170899444.txt (6.83 KB, userjs.txt)

Trimmed Options -> User JS >>9796 for the recent backend changes.
① catalog links in div.boardlist >>9483
② thread stats and Unique IPs >>6744
③ individual post hiding >>6753
④ batch loop/once WebM setting >>6819
⑤ top/bottom navlinks in the top bar >>6835
⑥ generic file thumbs in catalog >>6843
⑦ catalog link above OP >>6916

 No.10104


 No.10109

const callonce_factory = target => {
  let   called = false
  const once   = (...args) => {
    if (!called) {
      called = true
      return target (...args)
    }
  }
  return once
}

const init_file_selector_once = callonce_factory (init_file_selector)

This way init_file_selector_once can be harmlessly and cheaply called any number of times, such as at $(document).ready and before show_quick_reply → clone, without losing any defer-like benefits for the most common case where there's no q fragment.

 No.10226

>>6724
is there a way to automatically decline all legitimate interests cookies from all websites using firefoxak-47AK-47

 No.10247

When the reply count drops and a recent version of the thread is available, the ids can be diffed:
>> Array.from (document.querySelectorAll ("div.post.reply")).map (e => e.getAttribute ('id').replace (/^reply_/, '')).join (' ')
"6727 ..."

$ diffids () { diff <(echo "$1" | tr ' ' '\n') <(echo "$2" | tr ' ' '\n'); }
$ diffids "6727 ..." "6727 ..."
140d139
< 9986
151a151
> 10226

In this case the logs https://leftypol.org/log.php?board=tech suggest 9986 was probably in "Deleted all posts by IP address".

 No.10389

Duplicate scripts:
>> console.log (Object.entries (Array.from (document.getElementsByTagName ("script")).filter (e => e.hasAttribute ("src")).map (e => e.getAttribute ("src")).reduce ((acc, name, idx) => {
  if (name in acc) {
    acc [name].push (idx)
  } else {
    acc [name] = [idx]
  }
  return acc
}, {})).filter (([name, indices]) => indices.length > 1).sort ((a, b) => a [1] [0] - b [1] [0]).map (([name, indices]) => name + ' ' + indices.toString ()).join ('\n'))

/js/jquery.min.js 1,3
/js/inline-expanding.js 2,5

The source of the problem is this duplication:
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/5faa622303f7a3d9568a7c89728c3095a664b5c7/inc/config.php#L1039
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/5faa622303f7a3d9568a7c89728c3095a664b5c7/inc/instance-config.php#L375

While two jquery.min only slow page loads, the two inline-expanding cause double registration of listeners and duplicate options gui spans.

 No.10393

https://github.com/towards-a-new-leftypol/leftypol_lainchan/issues/326
> Multiple features in the Options dialog appear to be broken #326
> The first three options appear to have no effect and do not store a value when activated.
> Show relative time

After the page has loaded with scripts enabled the inspector can be used to verify that '#show-relative-time>input' has no listener. The listener is added in:
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/5faa622303f7a3d9568a7c89728c3095a664b5c7/js/local-time.js#L91
> $('#show-relative-time>input').on('change', function() {

Setting a breakpoint on that line shows that $('#show-relative-time>input') is empty, so the listener is added to nothing. One way to fix this is to retrieve the input from the options tab instead of the document:
< Options.get_tab ('general').content.find ('#show-relative-time>input').on('change', function() {

I don't know whether this is the only fix needed for js/local-time.js, that needs to be retested after the listener is in place. A similar consideration applies to every script that has been moved from onready to $(document).ready and attempts to retrieve options gui elements after an Options.extend_tab or equivalent call.

https://github.com/towards-a-new-leftypol/leftypol_lainchan/commit/88f6088a429fb73d12805377b43c6b567d03a5db
> fix Relative Time and Image Throttler
> Author: marktaiwan <[email protected]>
> Date: Fri Jan 23 00:03:37 2015 +0800
> marktaiwan authored and czaks committed May 5, 2016

 No.10407

The reason $('#show-relative-time>input') is empty >>10393 is that js/options.js adds its gui to the document at $(document).ready
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/5faa622303f7a3d9568a7c89728c3095a664b5c7/js/options.js#L105
but it's placed after some scripts that add options in $config['additional_javascript']
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/5faa622303f7a3d9568a7c89728c3095a664b5c7/inc/instance-config.php#L393

The only reason js/local-time.js and its friends even find a general tab is that js/options/general.js adds it at the time of head:
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/5faa622303f7a3d9568a7c89728c3095a664b5c7/js/options/general.js#L15

 No.10414

https://github.com/towards-a-new-leftypol/leftypol_lainchan/issues/326
> Number of simultaneous image downloads (0 to disable):

Besides being run >>10389 twice, js/inline-expanding.js has the same no listener issue >>10393 because $('#inline-expand-max input') is empty.
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/5faa622303f7a3d9568a7c89728c3095a664b5c7/js/inline-expanding.js#L196

One fix is:
< Options.get_tab ('general').content.find ('#inline-expand-max input')

 No.10419


 No.10420

When testing with scripts enabled, cloudflare's injected malware can be avoided by blocking leftypol URLs that contain "/cdn-cgi/".

 No.10421

Thanks for all your help with this, I'm going to start making pull requests over the next few days.

>>10109
Would you consider this an ideal solution for us to implement, or a simple and effective bandaid for our short-sighted $(document).ready changes? Is it sane for us to be in this situation where it is called multiple times?

 No.10429

>>10421
That is certainly only a quickfix, but a very cheap one because after the first call it will immediately return on a boolean test. A more pleasing long-term solution would be for the rememberStuff chain not to trigger 'cite' that early and instead cause a delayed 'cite' to fire at the time of $(document).ready, but this way great care must be taken with the order in which things run.

Also, I see that PR #330 has been approved and its commit merged but the duplicate scripts are still being served as I'm writing this.

 No.10430

>>10429
>>10429
We're testing bb. One sec.

 No.10432

File: 1627126740264.png (9.16 KB, 454x122, ClipboardImage.png)

>>10429
>Also, I see that PR #330 has been approved and its commit merged but the duplicate scripts are still being served as I'm writing this.
Yep, merge happens before final testing, before they go live.
I can confirm it removes the duplication in the Option form.

>That is certainly only a quickfix [snip]

I'm happy with adding that, it's safe and effective. I might aim for the better solution once we've finished fixing the fallout from our speed-improvement changes and downstreaming the years of vichan changes that lainchan ignored.

 No.10441

https://github.com/towards-a-new-leftypol/leftypol_lainchan/issues/318
> Syncronize spoiler button state on quick reply and main post form #318

While looking into this the synchronization section of js/quick-reply.js turns out to be quite peculiar.
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/dcf92dfef5f5ab900dc879d7dc4c3f04fab0aed8/js/quick-reply.js#L296
Every time the quick reply form is manually closed and reopened, new listeners are installed on the forms and the window, but the old listeners are never cleared in the .close-btn click handler.
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/dcf92dfef5f5ab900dc879d7dc4c3f04fab0aed8/js/quick-reply.js#L348

The effect can be observed on elements of the top form, such as the textarea, for which the inspector shows an ever increasing number of listeners. These keep the closed quick reply forms reachable and therefore uncollectable, leaking memory. They also transfer the top form text to each closed quick reply form, and after a sufficient number typing becomes sluggish. The .close-btn click handler should deregister all listeners that only served the closed quick reply form.

Keeping in mind that the current way of doing things leaks memory with abandon, the spoiler checkboxes can be synced by extending the synchronization section:
const cbsync = (form1, form2, name) => {
  const sel = 'input[type="checkbox"][name="' + name + '"]'
  const cb1 = form1.find (sel)
  const cb2 = form2.find (sel)
  cb1.on ('change', () => {
    cb2.prop ('checked', cb1.prop ('checked'))
  })
  cb2.on ('change', () => {
    cb1.prop ('checked', cb2.prop ('checked'))
  })
}

cbsync ($origPostForm, $postForm, 'spoiler')

 No.10444

>>10441
>Every time the quick reply form is manually closed and reopened, new listeners are installed on the forms and the window, but the old listeners are never cleared in the .close-btn click handler.
It looks adding these two .off() lines fixes it correctly:
		$postForm.find('th .close-btn').click(function() {
			// Remove origPostForm listeners
			$origPostForm.find('textarea[name="body"]').off('change input propertychange focus');
			$origPostForm.find('input[type="text"],select').off('change input propertychange');

 No.10455

>>10444
That removes every listener for those events from those elements, not just those added by js/quick-reply.js. Currently there are no others, but in the future that might remove some other script's listeners. To avoid this the events can be namespaced with something like .quickreply in both on and off calls.
https://api.jquery.com/on/#event-names

> > new listeners are installed on the forms and the window >>10441

This scroll handler on the window
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/dcf92dfef5f5ab900dc879d7dc4c3f04fab0aed8/js/quick-reply.js#L363
needs to be deregistered as well on .close-btn click because it keeps the old $postForm reachable and therefore uncollectable.

This stylesheet handler on the window
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/dcf92dfef5f5ab900dc879d7dc4c3f04fab0aed8/js/quick-reply.js#L375
needs the same treatment. Alternatively it could be added exactly once >>10109, since it doesn't depend on the $postForm, but in that case it must be moved out of show_quick_reply.

This 'quick-reply' handler on the window
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/dcf92dfef5f5ab900dc879d7dc4c3f04fab0aed8/js/quick-reply.js#L414
is added anew on every floating_link call, which occurs on every .close-btn click. It needs to be added at most once. >>10109

 No.10478

Here's a cleanup_jquery_listeners utility function:
const cleanup_jquery_listeners = cleanupspec => {
  // cleanupspec is a list of triples of
  // [jquery sets, selector or null, event string]
  // example: [
  //   [[$origPostForm, $postForm], 'input[type="text"],select', '.quickreply'],
  //   [[$(window)], null, 'scroll.quickreply']
  // ]
  for (const [sets, sel, events] of cleanupspec) {
    for (let oneset of sets) {
      if (sel != null) {
        oneset = oneset.find (sel)
      }
      oneset.off (events)
    }
  }
}

Then in .close-btn click:
const spec = [
  [[$origPostForm, $postForm], 'textarea[name="body"]', '.quickreply'],
  [[$origPostForm, $postForm], 'input[type="text"],select', '.quickreply'],
  [[$(window)], null, 'scroll.quickreply'],
  [[$postForm], 'th .close-btn', 'click.quickreply'],
]

cleanup_jquery_listeners (spec)

The $postForm is cleaned up for completeness. When spoilers are synced >>10441 they can be added to the spec list in the obvious way. All on calls need .quickreply on their events. The click, focus and scroll calls become .on('click.quickreply', …) and equivalent. The exceptions are the last two listeners of >>10455 which can be dealt with using callonce_factory >>10109.

 No.10486

>>10109
Should the callonce factory be placed in main.js?

 No.10487

For the last two listeners of >>10455, inside the outermost function of js/quick-reply.js:
const stylesheet_handler_once = callonce_factory (() => {
  $(window).on('stylesheet', function() {
    do_css();
    if ($('link#stylesheet').attr('href')) {
      $('link#stylesheet')[0].onload = do_css;
    }
  });
})

const qr_handler_once = callonce_factory (() => {
  $(window).on('quick-reply', function() {
    $('.quick-reply-btn').remove();
  });
})

Then replace
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/dcf92dfef5f5ab900dc879d7dc4c3f04fab0aed8/js/quick-reply.js#L375
with
< stylesheet_handler_once ()
and replace
https://github.com/towards-a-new-leftypol/leftypol_lainchan/blob/dcf92dfef5f5ab900dc879d7dc4c3f04fab0aed8/js/quick-reply.js#L414
with
< qr_handler_once ()

>>10486
Either templates/main.js or a new js/functools.js, entirely at the techs' option.

 No.10493

Temporary fix for spoiler sync #318 in Options -> User JS until the backend is fixed >>10441.
(() => {
  const cbsync = (form1, form2, name) => {
    const sel = 'input[type="checkbox"][name="' + name + '"]'
    const cb1 = form1.find (sel)
    const cb2 = form2.find (sel)
    cb1.on ('change', () => {
      cb2.prop ('checked', cb1.prop ('checked'))
    })
    cb2.on ('change', () => {
      cb1.prop ('checked', cb2.prop ('checked'))
    })
  }
  const spoilersync = () => {
    const ftop   = $('form[name="post"]:first')
    const fquick = $('#quick-reply')
    if ((ftop.length != 1) || (fquick.length != 1)) { return; }
    if (fquick.attr ('data-userjs-spoilersync') == 'spoilersync') { return; }
    cbsync (ftop, fquick, 'spoiler')
    fquick.attr ('data-userjs-spoilersync', 'spoilersync')
  }
  spoilersync ()
  $(window).on('quick-reply', spoilersync)
})()

 No.10494

Temporary fix for >>10079 in Options -> User JS until the backend is fixed >>10104 >>10109.
$('#quick-reply input[name="file"]').remove ()

 No.10495

File: 1627344936998.txt (7.71 KB, userjs.txt)

Updated Options -> User JS >>10101 with the current fixes.
① catalog links in div.boardlist >>9483
② thread stats and Unique IPs >>6744
③ individual post hiding >>6753
④ batch loop/once WebM setting >>6819
⑤ top/bottom navlinks in the top bar >>6835
⑥ generic file thumbs in catalog >>6843
⑦ catalog link above OP >>6916
⑧ quick reply spoiler sync >>10493
⑨ quick reply before init_file_selector >>10494

 No.10656

links like https://leftychan.net/leftypol don't work anymore

 No.10664

>extremely basic pull requests in queue for weeks
>one of three devs remaining
._.

 No.10703

Threads are having the old issue where posts don't immediately show up when you update.

 No.10705

>>10703
Now that we have more active devs and most of the basic necessities are set up, I'll request to the dev team that this become a priority fix.

btw filename download should now be fixed.

 No.10716

>>10419
auto-update.js is no longer deferred or tardy. This appears to have fixed the reliability issues with that script in normal use.
Thank you, once again.

 No.10723

>> console.log ((lines => lines.join ('\n') + '\nentries: ' + lines.length) (Object.entries (Array.from (document.getElementsByTagName ("script")).filter (e => e.hasAttribute ("src")).map (e => e.getAttribute ("src")).reduce ((acc, name, idx) => {
  if (name in acc) {
    acc [name].push (idx)
  } else {
    acc [name] = [idx]
  }
  return acc
}, {})).filter (([name, indices]) => indices.length > 1).sort ((a, b) => a [1] [0] - b [1] [0]).map (([name, indices]) => name + ' ' + indices.toString ())))

entries: 0


👍 >>10389 👍

 No.10724

I see that your post transfer method replaced some deleted file entries with generic file entries, so users will get legitimate but probably unexpected 404s.

>>>/meta/979

 No.10725

>>10724
That is strange, I'm not exactly sure what caused that.
The transfer method was a very rushed effort (for another example, flags were mistakenly added to 'body' instead of 'body_nomarkup').

>>10716
Update: this appears to be false, only part of the problem has been fixed. Work on this is continuing.

 No.10727

The post transfer method seems to have assigned the virtual thumbnail's dimensions to each spoiler image, leading to stretched spoilers like >>>/anime/8489 >>>/anime/8560. To remove the dimensions from such spoilers and show them at their natural size:
Array.from (document.querySelectorAll ("div.files > div.file img.post-image")).filter (e => e.hasAttribute ("src") && /^\/static\/.*spoiler/i.test (e.getAttribute ("src")) && e.hasAttribute ("style") && /^width:[0-9]*px;height:[0-9]*px;?$/i.test (e.getAttribute ("style").replace (/\s+/g, ''))).forEach (e => { e.removeAttribute ("style"); })

 No.10728

I believe I have found the true cause of the auto-update issue after making a new post, a regression caused by an absolute hack of a commit from January.

 No.10738

>>10728
thanks devanon.

 No.10743

We're in a shortage of SEA communist flags (only Kampuchea, Vietnam). No Thai, no Pathet Lao, no Malay Communists, not even PKI is in the list currently.
Can you mods add those?

 No.10745

>>10414
>>10419
You mention $('#inline-expand-max-input') and $('#autoScroll') as being empty and I've seen this issue in a few other cases (leading to things like a broken filter tab). Do you know what could cause them not to be found despite being generated immediately earlier? It feels like there must be something we messed up that causes them all not to work any more.
Otherwise I can patch the issue per-case with that 'find' fix you suggested.

 No.10747

>>10745
>Do you know what could cause them not to be found despite being generated immediately earlier?
This is explained in >>10407. The options gui elements are only added to the global document in the $(document).ready of js/options.js. Prior to that they cannot be retrieved from the global document because they are only in the tabs, which go into options_div, which goes into options_handler, which is not yet in the global document. Js/options.js is effectively an undeclared order dependency of js/local-time.js >>10393 js/inline-expanding.js >>10414 js/auto-scroll.js >>10419 and their friends, but it's placed too late in $config['additional_javascript'] >>10407.

>Otherwise I can patch the issue per-case with that 'find' fix you suggested.

The main advantage of retrieving the options gui elements from the tabs instead of the document is to remove the undeclared order dependence on js/options.js, which if preserved may come back to bite you in the future.

 No.10749

This question is probably better asked here than /meta/, where should leftypol.org create its Git version management?
I'm sure we can all agree on 'fuck GitHub'. Personally I would prefer a site that has no external connections/trackers and allows use without enabling JavaScript.
What would be the pros and cons of various platforms?

Current suggestions:
>self-hosted - Gitea instance on leftypol.org
>0xacab.org (GitLab, explicitly leftist, has onion, requires JS)
>disroot.org (Gitea instance, explicitly leftist, no onion)
>codeberg.org (popular, no onion)

 No.10751

Scripts usually declare their optional dependencies with //.
$ head -n 14 js/local-time.js
/*
 * local-time.js
 * https://github.com/savetheinternet/Tinyboard/blob/master/js/local-time.js
 *
 * Released under the MIT license
 * Copyright (c) 2012 Michael Save <[email protected]>
 * Copyright (c) 2013-2014 Marcin Łabanowski <[email protected]>
 *
 * Usage:
 *   // $config['additional_javascript'][] = 'js/jquery.min.js';
 *   // $config['additional_javascript'][] = 'js/strftime.min.js';
 *   $config['additional_javascript'][] = 'js/local-time.js';
 *
 */

But jquery-ui.custom in quick-reply uses verbiage instead.
$ grep -F -ne "\$config['additional_javascript'][]" -r js | grep -e ';.\+'
js/quick-reply.js:11: *   $config['additional_javascript'][] = 'js/jquery-ui.custom.min.js'; // Optional; if you want the form to be draggable.
js/show-backlinks.js:11: *   // $config['additional_javascript'][] = 'js/post-hover'; (optional; must come first)

It should be switched to // for consistency and automation.

>>10749
The sources can be seen from anywhere by cloning and pulling, but if the site requires JS then I won't be able to see ancillary features like issues and PRs. Currently GitHub has the best feature set available without JS, so by this specific criterion it's the best option, regardless of our feelings about Microsoft.

 No.10752

Here's an alpha version of a tool that checks the consistency of the ordering restrictions declared by individual scripts against the order in instance-config.php's $config['additional_javascript']. Ideally individual scripts would declare complete and correct ordering restrictions, but this doesn't hold >>10747 in practice, so this tool can only provide a hint. It currently checks for:
- duplicates in $config['additional_javascript']
- unsatisfied dependencies that are not marked optional with // >>10751
- order reversals in individual scripts versus $config['additional_javascript']
- satisfiability of the full ordering restriction graph if all scripts were to be included
Here's a wrapper that sets up the grep calls:
$ cat addjs.sh
#!/bin/sh
SRC="$1"

grep -F -ne "\$config['additional_javascript'][]" -r "$SRC"/js > scripts.txt
grep -F -ne "\$config['additional_javascript'][]" "$SRC"/inc/instance-config.php > config.txt
python3 addjs.py scripts.txt config.txt

Sample invocation:
$ sh addjs.sh ~/Documents/leftypol_lainchan
js/forced-anon.js has js/[email protected] js/options/[email protected] but config has js/[email protected] js/options/[email protected]
js/toggle-images.js has js/[email protected] js/options/[email protected] but config has js/[email protected] js/options/[email protected]
js/no-animated-gif.js has js/[email protected] js/options/[email protected] but config has js/[email protected] js/options/[email protected]
js/toggle-locked-threads.js has js/[email protected] js/options/[email protected] but config has js/[email protected] js/options/[email protected]
js/options/general.js has js/[email protected] js/options/[email protected] but config has js/[email protected] js/options/[email protected]
problems: 5

Currently, on the public sources, the only problem is style-select versus options/general, which is declared five times in the opposite order from $config['additional_javascript']. But this is the only declared >>10747 ordering problem. The style selector has been moved around recently, piggybacking on its sorted fix, but its placement in $config['additional_javascript'] and its attempted transfer at the end of options/general haven't been kept consistent. This can be fixed in either direction once the long-term placement of the style selector is decided.

 No.10753

the sample invocation without clownflare interference

 No.10831

Iqdb links but only for thumbnails supported by iqdb.org, so no webps and no full images.
Array.from (document.querySelectorAll ("div.files > div.file")).map (e => [e.querySelector ("img.post-image"), e.querySelector ("span.details")]).filter (([img, details]) => img.hasAttribute ("src") && /^\/[^\/]+\/thumb\/[^\/.]+[.](jpe?g|png|gif)$/i.test (img.getAttribute ("src"))).forEach (([img, details]) => {
  const span = document.createElement ("span")
  span.setAttribute ("class", "iqdb")
  span.innerHTML = ' <a href="https://iqdb.org/?url=https://leftypol.org' + img.getAttribute ("src") + '" target="_blank">iqdb</a>'
  details.appendChild (span)
})

 No.10838

>>10831
Why not full images? They seem to support them.

 No.10845

>>10838
>Why not full images? They seem to support them.
The first thing iqdb.org and friends do is shrink the image, so transferring full images is a waste of bandwidth on both ends when thumbnails are available. Unfortunately, not creating a retrievable thumbnail at all for spoilered images is a problem that goes all the way back to Tinyboard:
https://github.com/savetheinternet/Tinyboard/blob/master/post.php#L572
Using the full images when either a thumbnail is not available or is a webp will be in a future version of >>10831.

 No.10888

Upgrade of >>10831 to use the full images when either thumbnails are not available or in an unsupported format. A failed iqdb search will provide a saucenao link using a thumbnail generated by iqdb. This hasn't been tested with image hiders, expanders and similar scripts that mutate the div.file subtree.
((getthumb, getfull, getdest, getthumb2, getfull2, realthumb, formatok, speclist, showft) => Array.from (document.querySelectorAll ("div.files > div.file")).map (e => [getthumb (e), getfull (e), getdest (e)]).map (([ethumb, efull, edest]) => [ethumb ? getthumb2 (ethumb) : null, efull ? getfull2 (efull) : null, edest]).map (([thumb, full, edest]) => [thumb, full, edest, thumb && realthumb (thumb) && formatok (thumb), full && formatok (full)]).filter (([thumb, full, edest, thumbok, fullok]) => thumbok || fullok).forEach (([thumb, full, edest, thumbok, fullok]) => {
  const url  = "https://leftypol.org" + (thumbok ? thumb : full)
  const span = document.createElement ("span")
  span.setAttribute ("class", "iqdb")
  span.innerHTML = ' ' + (showft ? ((thumbok ? 'T' : 'F') + ':') : "") + speclist.map (([label, urlfun]) => '<a href="' + urlfun (url) + '" target="_blank">' + label + '</a>').join (' ')
  edest.appendChild (span)
})) (
  e => e.querySelector ("img.post-image"),
  e => e.querySelector ('p.fileinfo a[target="_blank"][href*="/src/"]'),
  e => e.querySelector ("span.details"),
  e => e.getAttribute ("src"),
  e => e.getAttribute ("href"),
  s => /^\/[^\/]+\/thumb\//.test (s),
  s => /[.](jpe?g|png|gif)$/i.test (s),
  [
    ["iqdb", s => "https://iqdb.org/?url=" + s],
 // ["nao",  s => "https://saucenao.com/search.php?db=999&dbmaski=32768&url=" + s]
  ],
  false
)

 No.10935

Multiupload with the site's scripts disabled but JS enabled in the dev tools console:
(count => {
  const dest = document.querySelector ("tr#upload > td.upload-area")
  if (dest == null) { return; }
  const have = dest.querySelectorAll ('input[type="file"]').length
  if (have >= count) { return; }
  const make = n => '<br class="file_separator"/><input type="file" name="file' + n + '" id="upload_file' + n + '">'
  const add  = []
  for (let k = 2; k <= count; k++) {
    add.push (make (k))
  }
  dest.innerHTML += add.join ("")
}) (5)

test: >>>/meta/10945

 No.10948

Some harmless fun with the original filenames. If the filename looks like a timestamp from a board download >>6724 the UTC date is provided. If it looks like an md5 hash >>6841 an md5 search link is provided to r34. Other matchers might be added later. This is merely a demo, not anything serious.
((getfilesbody, getorig, decorate, providers) => getfilesbody ().forEach (([files, body]) => {
  const infolist = Array.from (files.querySelectorAll ("div.file")).map ((f, index) => [getorig (f), index + 1]).filter (p => p [0] != null).map (([name, index]) => providers.map (p => p (name, index)).filter (s => s != null)).flat (1)
  if (infolist.length > 0) {
    decorate (body, infolist)
  }
})) (
  () => Array.from (document.querySelectorAll ("div.thread > div.files")).map (f => [f, f.parentNode.querySelector ("div.post.op > div.body")]).concat (Array.from (document.querySelectorAll ("div.post.reply")).map (r => [r.querySelector ("div.files"), r.querySelector ("div.body")]).filter (p => p [0] != null)),
  f => {
    const a = f.querySelector ('span.details > a[download][title^="Save as original filename"]')
    return a == null ? null : a.getAttribute ("download")
  },
  (body, infolist) => {
    const p = document.createElement ("p")
    p.setAttribute ("class", "miscfilesbodyinfo")
    p.innerHTML = infolist.join ("<br/>")
    if (body.firstChild) {
       body.insertBefore (p, body.firstChild)
       const hr = document.createElement ("hr")
       hr.setAttribute ("style", "clear: none;")
       body.insertBefore (hr, p.nextSibling)
    } else {
       body.appendChild (p)
    }
  },
  [
 // (name, index) => "file " + index + " name " + name,
    (name, index) => {
      const m = name.match (/^([0-9a-fA-F]{32})[.]/)
      if (m == null) { return null; }
      const hash = m [1]
      return "file " + index + " md5 " + hash + ' search <a href="https://rule34.xxx/index.php?page=post&s=list&tags=md5%3a' + hash + '" target="_blank">r34</a>'
    },
    (name, index) => {
      const m = name.match (/^([0-9]{13})[.]/)
      if (m == null) { return null; }
      const time = parseInt (m [1], 10)
      return "file " + index + " timestamp " + time + " date " + new Date (time).toUTCString ()
    }
  ]
)

 No.10970

Let me get rid of this, I keep clicking it instead of the reply button

 No.10981

>>10970
Include enough context around it to show which one you mean.

 No.10982

File: 1630662239183.png (140.99 KB, 1086x450, ClipboardImage.png)

>>10981
Oh also I had another niche feature idea that I think would actually be used quite a bit but sounds silly. A "greentext/quote all text" button so you can copy and paste an article without having to manually add > to every line and inevitably miss a break in the middle of a paragraph due to the site it being copied from having weird formatting.

 No.10983

>>10982
If you want that button gone right now without waiting for anything fancy you can go to Options → User CSS and enter:
div.post.op > p.intro > a.watchThread { display: none; }

Adding a button to quote every line in the comment field can be done from User JS, I'll post that tomorrow. Recovering missing line breaks from another site can only be done after you specify precise and complete rules for doing so.

 No.10984

>>10983
>Recovering missing line breaks from another site can only be done after you specify precise and complete rules for doing so.
No I mean it will avoid quoting text like

>Oh also I had another niche feature idea that I think would actually

be used quite a bit but sounds silly.
>A "greentext/quote all text" button so you can copy and paste an article without
having to manually add > to every line and inevitably miss a break in the middle of a paragraph due to the site it being copied from having weird formatting.

Because line breaks aren't always visible when adding the quotes manually, it will just keep it all green
>div.post.op > p.intro > a.watchThread { display: none; }
Based, thanks

 No.11029

>>10984
Here's some Options → User JS code to add a quote link to the post forms that quotes the lines of the comment field. To change the link's text modify the value of the a.innerText assignment. Empty lines and lines that look like post links are exempt from quoting. To modify the exemptions adjust the untouched function.
(() => {
  const empty     = s => /^\s*$/.test (s)
  const untouched = s => /^\s*>>(\d+|>\/\w+\/\d*)\s*$/.test (s)
  const prefix    = "> "
  const oneline   = s => (empty (s) || untouched (s)) ? s : (prefix + s)
  const edit      = s => s.split ("\n").map (oneline).join ("\n")
  const perform   = area => {
    const vold = area.value
    const vnew = edit (vold)
    if (vold != vnew) {
      area.focus ()
      area.setRangeText (vnew, 0, vold.length, "end")
    }
  }
  const install   = form => {
    const dest = form.querySelector ("div.banner")
    const have = dest.querySelector ("a.quotecommentlines")
    const area = form.querySelector ('textarea[name="body"]')
    if (have == null) {
      const a = document.createElement ("a")
      a.setAttribute ("class", "quotecommentlines")
      a.setAttribute ("href",  "javascript:void(0)")
      a.setAttribute ("title", "quote comment lines")
      a.innerText = "> "
      a.addEventListener ('click', event => {
        perform (area)
      })
      dest.insertBefore (a, dest.firstChild)
    } else if (form.getAttribute ("id") == "quick-reply") {
      have.addEventListener ('click', event => {
        perform (area)
      })
    }
  }
  const setup     = () => {
    const form    = document.querySelector ('form[name="post"]')
    if (form == null) { return; }
    install (form)
    const doquick = () => {
      const q = document.querySelector ('form#quick-reply')
      if (q != null) { install (q); }
    }
    doquick ()
    $(window).on ('quick-reply', doquick)
  }

  setup ()
}) ()

 No.11046

There's no div.banner in the post form in index pages so >>11029 only works in thread pages. Here's the fix to the install function to make it work in both thread pages and index pages.
(() => {
  const empty     = s => /^\s*$/.test (s)
  const untouched = s => /^\s*>>(\d+|>\/\w+\/\d*)\s*$/.test (s)
  const prefix    = "> "
  const oneline   = s => (empty (s) || untouched (s)) ? s : (prefix + s)
  const edit      = s => s.split ("\n").map (oneline).join ("\n")
  const perform   = area => {
    const vold = area.value
    const vnew = edit (vold)
    if (vold != vnew) {
      area.focus ()
      area.setRangeText (vnew, 0, vold.length, "end")
    }
  }
  const install   = form => {
    const area   = form.querySelector ('textarea[name="body"]')
    const listen = e => {
      e.addEventListener ('click', event => {
        perform (area)
      })
    }
    const quick  = form.getAttribute ("id") == "quick-reply"
    const build  = () => {
      const a = document.createElement ("a")
      a.setAttribute ("class", "quotecommentlines")
      a.setAttribute ("href",  "javascript:void(0)")
      a.setAttribute ("title", "quote comment lines")
      a.innerText = "> "
      return a
    }
    const have   = form.querySelector ("a.quotecommentlines")
    const insert = e => {
      if (quick) {
        const dest = form.querySelector ("div.banner")
        if (dest == null) { return; }
        dest.insertBefore (e, dest.firstChild)
      } else {
        const dest = area.parentNode.previousSibling
        if (dest == null) { return; }
        dest.insertBefore (document.createElement ("br"), dest.firstChild)
        dest.insertBefore (e, dest.firstChild)
      }
    }

    if (have == null) {
      const e = build ()
      insert (e)
      listen (e)
    } else if (quick) {
      insert (have)
      listen (have)
    }
  }
  const setup     = () => {
    const form    = document.querySelector ('form[name="post"]')
    if (form == null) { return; }
    install (form)
    const doquick = () => {
      const q = document.querySelector ('form#quick-reply')
      if (q != null) { install (q); }
    }
    doquick ()
    $(window).on ('quick-reply', doquick)
  }

  setup ()
}) ()

 No.11066

File: 1630855709885.png (3.05 KB, 449x67, ClipboardImage.png)

m8 who tf extended the already annoying as fuck FLOOD DETECTED box to two minutes? Can we have something slightly more sophisticated like kicking in on the third post so I don't have to sit like a retard pressing New Reply to correct a mistake in the previous post?

 No.11074

Upgrade of >>10948 to unify handling of the two sites. It'll work on some other vichan-based boards as well if their URLs are added.
(regexlisttest => ((sitespec, providers) => {
  const site = sitespec.find (spec => spec ["test"] ())
  if (!site) { return; }
  const postfiles = site ["postfiles"]
  const original  = site ["original" ]
  const decorate  = site ["decorate" ]
  site ["filesbody"] ().forEach (([files, body]) => {
    const infolist = postfiles (files).map ((f, index) => [original (f), index + 1]).filter (p => p [0] != null).map (([name, index]) => providers.map (p => p (name, index)).filter (s => s != null)).flat (1)
    if (infolist.length > 0) {
      decorate (body, infolist)
    }
  })
}) (
  [
    {
      test:      regexlisttest ([
     // /^https?:\/\//,
        /^https?:\/\/leftychan\.net\//,
        /^https?:\/\/leftypol\.org\//,
      ]),
      filesbody: () => Array.from (document.querySelectorAll ("div.thread > div.files")).map (f => [f, f.parentNode.querySelector ("div.post.op > div.body")]).concat (Array.from (document.querySelectorAll ("div.post.reply")).map (r => [r.querySelector ("div.files"), r.querySelector ("div.body")]).filter (p => p [0] != null)),
      postfiles: files => Array.from (files.querySelectorAll ("div.file")),
      original:  f => {
        let e = f.querySelector ('span.postfilename')
        if (e != null) { return e.hasAttribute ("title") ? e.getAttribute ("title") : e.innerText; }
        e = f.querySelector ('span.details > a[download][title*="original filename"]')
        if (e != null) { return e.getAttribute ("download"); }
        return null
      },
      decorate:  (body, infolist) => {
        const p = document.createElement ("p")
        p.setAttribute ("class", "miscfilesbodyinfo")
        p.innerHTML = infolist.join ("<br/>")
        if (body.firstChild) {
          body.insertBefore (p, body.firstChild)
          const hr = document.createElement ("hr")
          hr.setAttribute ("style", "clear: none;")
          body.insertBefore (hr, p.nextSibling)
        } else {
          body.appendChild (p)
        }
      }
    }
  ], [
 // (name, index) => "file " + index + " name " + name,
    ((link, speclist) => (name, index) => {
      const m = name.match (/^([0-9a-fA-F]{32})[.]/)
      if (m == null) { return null; }
      const hash = m [1]
      return "file " + index + " md5 " + hash + ' search ' + speclist.map (e => link (e ["href"] (hash), e ["name"])).join (" ")
    }) (
      (h, t) => '<a href="' + h + '" target="_blank">' + t + '</a>',
      [
        {
          name: "r3",
          href: s => "https://rule34.xxx/index.php?page=post&s=list&tags=md5%3a" + s,
        }
      ]
    ),
    (name, index) => {
      const m = name.match (/^([0-9]{13})[-.]/)
      if (m == null) { return null; }
      const time = parseInt (m [1], 10)
      return "file " + index + " timestamp " + time + " date " + new Date (time).toUTCString ()
    }
  ]
)) (
  regexlist => () => (url => regexlist.some (rx => rx.test (url))) (document.location.href)
)

 No.11079

>>11066
Two minutes? Which board is this? It shouldn't ever be that high unless you're on a shared IP during high traffic (such as the Tor node) or making new threads (different message).
I can look into making a more lenient filter, we're currently just using the default basic one.

 No.11081

>>11079
Lainchan was a mistake.

Turns out the long-tern post filtering bug (cannot hide/filter individual posts in threads) was due to them adding a postcontainer div, apparently just so that they could add '>>' to the left of each reply. Since they don't use bloat many of the additional Javascripts, they didn't realize it broke some.

As a side affect, I believe reverting that change fixed the issue where short posts are occasionally stacked to the right instead of below.

Filters appear to work fine now which opens up a lot of opportunities. Shout out if anything seems to have broken.

 No.11091

>>11079
/leftypol/, non-shared private IP. The time between the two posts was 2 minutes when it finally allowed me to post. Sometimes it feels like pressing it resets the count.

 No.11093

>>11081
>adding a postcontainer div
The alternative solution with keeping postcontainer is in >>>/leftypol_archive/1822 2021-01-29.

 No.11094

>>11093
I'm happy to implement either solution, which do you think is better? It looked to me as if the postcontainer didn't offer anything and broke scripts.

 No.11097

>>11094
>which do you think is better?
I have no opinion to offer on the costs/benefits of keeping versus removing div.postcontainer, so I trust your judgement that "the postcontainer didn't offer anything and broke scripts" and should therefore be removed. Regardless of the fate of postcontainer I also recommend the change >>>/leftypol_archive/1822 from .parent() to .parents('.thread') simply because it makes the id retrieval more resilient by causing it to work both in the presence and absence of postcontainer.

 No.11107

Upgrade of >>11074 to add support for lynx-based boards.
((regexlisttest, prefixhr) => ((sitespec, providers) => {
  const site = sitespec.find (spec => spec ["test"] ())
  if (!site) { return; }
  const postfiles = site ["postfiles"]
  const original  = site ["original" ]
  const decorate  = site ["decorate" ]
  site ["filesbody"] ().forEach (([files, body]) => {
    const infolist = postfiles (files).map ((f, index) => [original (f), index + 1]).filter (p => p [0] != null).map (([name, index]) => providers.map (p => p (name, index)).filter (s => s != null)).flat (1)
    if (infolist.length > 0) {
      decorate (body, infolist)
    }
  })
}) (
  [
    {
      test:      regexlisttest ([
        /^https?:\/\/someoldchan\.live\//,
      ]),
      filesbody: () => Array.from (document.querySelectorAll ("div.innerOP, div.innerPost")).map (i => [i.querySelector ("div.panelUploads"), i.querySelector ("div.divMessage")]).filter (p => p [0] != null),
      postfiles: files => Array.from (files.querySelectorAll ("figure.uploadCell")),
      original:  f => {
        const e = f.querySelector ('a.originalNameLink[download]')
        return e == null ? null : e.getAttribute ("download")
      },
      decorate:  prefixhr ({join: '<br style="display: initial;"/>'})
    }, {
      test:      regexlisttest ([
     // /^https?:\/\//,
        /^https?:\/\/leftychan\.net\//,
        /^https?:\/\/leftypol\.org\//,
      ]),
      filesbody: () => Array.from (document.querySelectorAll ("div.thread > div.files")).map (f => [f, f.parentNode.querySelector ("div.post.op > div.body")]).concat (Array.from (document.querySelectorAll ("div.post.reply")).map (r => [r.querySelector ("div.files"), r.querySelector ("div.body")]).filter (p => p [0] != null)),
      postfiles: files => Array.from (files.querySelectorAll ("div.file")),
      original:  f => {
        let e = f.querySelector ('span.postfilename')
        if (e != null) { return e.hasAttribute ("title") ? e.getAttribute ("title") : e.innerText; }
        e = f.querySelector ('span.details > a[download][title*="original filename"]')
        if (e != null) { return e.getAttribute ("download"); }
        return null
      },
      decorate:  prefixhr ({join: "<br/>"})
    }
  ], [
 // (name, index) => "file " + index + " name " + name,
    ((link, speclist) => (name, index) => {
      const m = name.match (/^([0-9a-fA-F]{32})[.]/)
      if (m == null) { return null; }
      const hash = m [1]
      return "file " + index + " md5 " + hash + ' search ' + speclist.map (e => link (e ["href"] (hash), e ["name"])).join (" ")
    }) (
      (h, t) => '<a href="' + h + '" target="_blank">' + t + '</a>',
      [
        {
          name: "r3",
          href: s => "https://rule34.xxx/index.php?page=post&s=list&tags=md5%3a" + s,
        }
      ]
    ),
    (name, index) => {
      const m = name.match (/^([0-9]{13})[-.]/)
      if (m == null) { return null; }
      const time = parseInt (m [1], 10)
      return "file " + index + " timestamp " + time + " date " + new Date (time).toUTCString ()
    }
  ]
)) (
  regexlist => () => (url => regexlist.some (rx => rx.test (url))) (document.location.href),
  config => (body, infolist) => {
    const p = document.createElement ("p")
    p.setAttribute ("class", "miscfilesbodyinfo")
    p.innerHTML = infolist.join (config ["join"])
    if (body.firstChild) {
      body.insertBefore (p, body.firstChild)
      const hr = document.createElement ("hr")
      hr.setAttribute ("style", "clear: none;")
      body.insertBefore (hr, p.nextSibling)
    } else {
      body.appendChild (p)
    }
  }
)

 No.11115

File: 1631011636594.png (232.27 KB, 707x615, ClipboardImage.png)

Why did the date format on the posts change from a beautiful ISO8601 to a horrible and confusing burger date format?

 No.11124

>>11115
Are those posts still like that? Can you link them?
All the posts look like ISO8601 to me. The one I'm replying to is fine.

 No.11137

>>11124
Sorry it's just 4chanX messing up with the format.

 No.11141

Okay lads I have a feature suggestion I have never seen on any imageboard, I am quite pleased to say it is a genius idea and quite simple.
In the reply box, when you start a line with > or <, it will greentext or orangetext the line as it would appear in the reply.

 No.11147

>>11141
>In the reply box
Textarea is a plain text element without subrange styling.
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea
The comment line quoter which avoids >>10984 is in >>11046.

 No.11561

i might be the only affected person but i can't upload images via tor browser on android

 No.11636

File: 1632148454808.png (83.52 KB, 972x609, ClipboardImage.png)

There's now a dark solarized theme.

 No.11641

>>11561
It's not just you, I usually don't post images via mobile but I tried and they wouldn't attach (both with and without JS). I'm not sure how it would be fixed.

 No.11642

YouTube now blocks every Tor exit node. Can you change the URLs of YouTube videos so instead of YouTube links, it gives you Invidious links like this? That way we can all watch easily.

https://iteroni.com/watch?v=r65hqtFSoBY

 No.11643

>>11641
that makes two of us

 No.11644

>>11642
i type in watch?v= all the time. making it automatic would probably require an add-on? which is unadvisable with tor borwser

 No.11646

The best part about leftychan is that they reverted your shitty fucking webp thumbnail bullshit and suddenly the site became 10x more usable again because I can actually see post thumbnails on a fucking image board. Do the same here and maybe I'll think about posting again. The mods have otherwise done next to nothing constructive to end the split.

 No.11649

>>11642
Array.from (document.querySelectorAll ('a[href^="https://youtu.be/"]')).map (e => [e, e.getAttribute ("href").match (/^https:\/\/youtu\.be\/(watch\?v=)?([^?\/]+)$/)]).filter (p => p [1] != null).forEach (([e, m]) => { e.setAttribute ("href", "https://iteroni.com/watch?v=" + m [2]); })


>>11644
Array.from (document.querySelectorAll ('a[href^="https://youtu.be/"]')).map (e => [e, e.getAttribute ("href").match (/^https:\/\/youtu\.be\/([^?\/]+)$/)]).filter (p => p [1] != null).forEach (([e, m]) => { e.setAttribute ("href", "https://youtu.be/watch?v=" + m [1]); })


>>11641
If you can upload on other sites with the same procedure look at a var_dump of $_FILES early in post.php:handle_post.

 No.11650

>>11642
How about having a separate button for embedding with a mirror?
Eg:
[Embed] [Mirror]
?
Ive had issues with some invidious instances. How can we choose a reliable one?

 No.11651

>>11650
That would be cool, They could probably allow us to enter a custom instance in the options menu, so long as the default is a sane choice that proxies.

>>11646
If your computer can't show .webp in a browser by now, I think you should look into fixing it.

 No.11652

>>11651
Do you know of a good proxy?

 No.11654

File: 1632225263176.png (358.88 KB, 950x681, ClipboardImage.png)

>>11652
I never really looked into it properly, but I have confirmed https://incogtube.com proxies the videos instead of direct linking, and they also have Tor, I2P and Yggdrasil services.
aka. http://tuberyps2pn6dor6h47brof3w2asmauahhk4ei42krugybzzzo55klad.onion/feed/trending

 No.11658


 No.11660

>>11654
>….onion
This works well. Ok, I'll put it in the backlog.

Maybe if you're on tor, it embeds the .onion, if you're on clearnet, it embeds the clearnet site. That makes the most sense, right? Or is clearnet preferred for both situations?

 No.11664

>>11650
>Ive had issues with some invidious instances. How can we choose a reliable one?
How about the [Mirror] button links to https://redirect.invidious.io/watch?v={youtube_video_id}?

 No.11666

>>11660
It's not just Tor users that want to use invidious instead of YouTube, so I'd rather link both Youtube and an invidious instance on clearnet as well.

Here's a radical idea though: how about we embed an invidious instance by default and provide the original Youtube link as secondary? Like this: [Embed] [YouTube]

 No.11669


 No.11723

>>11660
If it's not difficult, Tor->Tor makes sense.

>>11666
I support this.

 No.11856

>>11643
>>11561
Can you find any websites where Tor android upload does work? I tried on a generic upload site and it failed the same way.

 No.11882

> https://git.leftypol.org/leftypol/leftypol/commit/1e690333a8b91e852fa81d2e5f458d64050c3e53
> Remove instance configuration
Removing instance-config.php from git will make issues harder to diagnose.

 No.11883

>>11882
Yeah but maybe the `salt' and `secure_trip_salt' shouldn't be public lmao

 No.11888

>>11883
> https://git.leftypol.org/leftypol/leftypol/commit/1e690333a8b91e852fa81d2e5f458d64050c3e53
> $config['db']['password'] = '';
Perhaps you could replace sensitive strings with the empty string, as is already done with $config['db']['password'], and restore the rest of instance-config.php, which is a great help in debugging.

 No.11889

>>11888
(NTA) I guess the issue is:
- adding the instance-config so that it has convenient version control
- preventing sensitive information from being added
I wonder if using an 'include' at the bottom of the instance-config to store sensitive values in another config file is an appropriate solution.

 No.11894

>>11889
Whatever system is already in use for wiping $config['db']['password'] can be used for the salts.

 No.11896

Sorry for the unreasonable delays on many of these old issues. Hopefully we can get through them quicker now that we have more active devs with code access and a stable set-up.

File-thumbing on catalogs should now be fixed. Tested it on file uploads and deleting the first image of two in an OP.
Catalog posting without javascript now works, added an inline "list-style: none" to remove the drop-down triangle.
Fixed a few of the themes and added Midnight from >>>/leftypol_archive/1541

Let us know about any outstanding issues that aren't in the Gitea tracker.

 No.11898

>>11888
>>11894
I doubt they replace the password. It is much more likely that they don't actually use one.

 No.11905

>>11898 >>11883
>I doubt they replace the password. It is much more likely that they don't actually use one.
I have no way of knowing that, but we know a password was formerly in use:
> https://git.leftypol.org/leftypol/leftypol/commit/80dc724738310b5c86ff43a7b3c6977ccd74e965
> lots of print statements
> - $config['db']['password'] = 'oijrljqqwjr242kjn';
> + $config['db']['password'] = '';

Here's a generator for >>11883 an instance-config-nosecrets.php:
$ cat instance-config-nosecrets.sh
#!/bin/sh
set -e

keylist ()
{
   #  in: cookies salt
   # out: \['cookies'\]\['salt'\]
   echo "$1" | sed -r -e 's/([^ ]+)( +|$)/\\['"'"'\1'"'"'\\]/g'
}

wipeone ()
{
   #  in: cookies salt
   # out: s/^(\$config\['cookies'\]\['salt'\] *= *')[^']+('.+)$/\1\2/
   env echo 's/^(\$config'"$(keylist "$1") *= *')[^']+('.+)\$/\1\2/"
}

nosecrets ()
{
   sed -r \
       -e "$(wipeone 'cookies salt')" \
       -e "$(wipeone secure_trip_salt)" \
       "$1" > "$2"
}

main ()
{
   nosecrets inc/instance-config.php inc/instance-config-nosecrets.php
}

main

It can be rerun whenever instance-config.php is modified, and instance-config-nosecrets.php can be put into git. To verify:
$ diff inc/instance-config.php inc/instance-config-nosecrets.php

 No.11906

>>11896
>File-thumbing on catalogs should now be fixed. Tested it on file uploads and deleting the first image of two in an OP.
>Catalog posting without javascript now works, added an inline "list-style: none" to remove the drop-down triangle.
👍

>Let us know about any outstanding issues that aren't in the Gitea tracker.

I'll make a list, but it takes a bit.

 No.11907

File: 1633098081688.txt (4.85 KB, userjs.txt)

Trimmed Options → User JS >>10495 for the new backend fixes.
① catalog links in div.boardlist >>9483
② thread stats and Unique IPs >>6744
③ batch loop/once WebM setting >>6819
④ top/bottom navlinks in the top bar >>6835
⑤ catalog link above OP >>6916
⑥ quick reply spoiler sync >>10493
⑦ quick reply before init_file_selector >>10494

 No.11914

File: 1633120548099.jpg (797.3 KB, 720x1080, 1630180285468.jpg)

> outstanding issues that aren't in the Gitea tracker >>11896
+ Unique IPs on the right | requested by >>>/leftypol_archive/1601 >>>/leftypol_archive/1624 >>>/leftypol_archive/1756 | fix >>6744
+ batch loop/once WebM setting | requested by >>>/leftypol_archive/1521 | frontend-only hack >>6819
+ update of old #229 sticky catalog for the new overboards | fix >>9485
+ catalog links in boardlist; as phrased #22 is distinct | requested by >>>/leftypol_archive/1449 | fix >>>/leftypol_archive/1807
+ up/down buttons floating | requested by >>>/leftypol_archive/1832 | frontend-only hack >>6835
+ per-file spoiler | requested by >>7390 | see this thread on the other site #10799 #10800
+ leftover memory leaks from quick-reply sync >>10441 >>10455 >>10478 >>10487
+ restore instance-config.php to git without salts >>11883 >>11905

 No.11923

>>11914
Thank you very much for this.
Also, we might revert the deferring code, at least for things like the file-selector.js where it should be loaded timely to avoid complication.

 No.11926

>>11923
>we might revert the deferring code, at least for things like the file-selector.js where it should be loaded timely to avoid complication
That's for you to decide. On the same theme: >>10104 >>10109 >>10421 >>10429 >>10432.

 No.11927

File: 1633176083089.png (25.16 KB, 625x205, ClipboardImage.png)

please add .jfif as an acceptable file extension

 No.11929

>>11927
and djvu

 No.11930

A backend version of >>6835 >>11914.

The thread view's top/bottom targets are #top and #bottom:
https://git.leftypol.org/leftypol/leftypol/src/commit/2d16e747a18ba900ec220a4303249402c19dcd37/templates/thread.html#L61
> <span class="threadlink"><a href="#bottom" style="padding-left: 10px"> {% trans %}Go to bottom{% endtrans %}</a> ]</span>
https://git.leftypol.org/leftypol/leftypol/src/commit/2d16e747a18ba900ec220a4303249402c19dcd37/templates/thread.html#L73
> <a id="thread-top" href="#top">[{% trans %}Go to top{% endtrans %}]</a>

The corresponding anchors are placed just after the boardlist and just before the end of the body:
https://git.leftypol.org/leftypol/leftypol/src/commit/2d16e747a18ba900ec220a4303249402c19dcd37/templates/thread.html#L32
> <a name="top"></a>
https://git.leftypol.org/leftypol/leftypol/src/commit/2d16e747a18ba900ec220a4303249402c19dcd37/templates/thread.html#L116
> <a href="#" id="bottom"></a>

The boardlist assembly:
https://git.leftypol.org/leftypol/leftypol/src/commit/2d16e747a18ba900ec220a4303249402c19dcd37/inc/display.php#L80
> 'top' => '<div class="boardlist">' . $body . '</div>' . $top,
This could host a span with two links with titles, some classes and some default styling such as floating in style.css. Inclusion could be controlled by a new optional boolean passed to createBoardlist that defaults to false.
// after trim
if ($topbottomlinks) {
    $body .= ' <span class="topbottomlinks"><a href="#top" title="' . _('Go to top') . '">&#x25B2;</a> <a href="#bottom" title="' . _('Go to bottom') . '">&#x25BC;</a></span>';
}

// in style.css
.topbottomlinks {
    ... style to taste ...
}
.topbottomlinks a {
    ... style to taste ...
}


The createBoardlist invocations that would need the new boolean set to true:
https://git.leftypol.org/leftypol/leftypol/src/commit/2d16e747a18ba900ec220a4303249402c19dcd37/inc/functions.php#L1405
https://git.leftypol.org/leftypol/leftypol/src/commit/2d16e747a18ba900ec220a4303249402c19dcd37/inc/functions.php#L2331
https://git.leftypol.org/leftypol/leftypol/src/commit/2d16e747a18ba900ec220a4303249402c19dcd37/inc/functions.php#L2434
https://git.leftypol.org/leftypol/leftypol/src/commit/2d16e747a18ba900ec220a4303249402c19dcd37/templates/themes/catalog/theme.php#L486
https://git.leftypol.org/leftypol/leftypol/src/commit/2d16e747a18ba900ec220a4303249402c19dcd37/templates/themes/overboards/theme.php#L216

Plenty of views have boardlists, most of them lacking top/bottom anchors:
$ grep -e '{{ *boardlist\.top *}}' -r .
Out of those the ones that matter and need top/bottom anchors are:
templates/index.html
templates/themes/catalog/catalog.html

The unicode arrows used above:
▲=&#x25B2;
▼=&#x25BC;

 No.11931

File: 1633218508777.png (33.66 KB, 447x420, 1630800257046.png)

Since the sources can now be referenced, here are the per-file spoiler >>11914 posts.


To move towards per-file spoilers >>7390 >>7435 exemptions for spoiler1 through spoiler9 should be added to $config['spam']['valid_inputs'], to allow per-file booleans to pass through the post form. Their number is simply for consistency with the existing file_url9.
https://git.leftypol.org/leftypol/leftypol/src/commit/2d16e747a18ba900ec220a4303249402c19dcd37/inc/config.php#L279

The names of the file fields of the post form are file, file2, file3 and so on.
https://git.leftypol.org/leftypol/leftypol/src/commit/2d16e747a18ba900ec220a4303249402c19dcd37/js/file-selector.js#L73

Those names can be used to select corresponding booleans sent by checkboxes, and are available as $_FILES keys when processing uploads. The $key can be temporarily stored in $file, for example as $file['formparametername'].
https://git.leftypol.org/leftypol/leftypol/src/commit/2d16e747a18ba900ec220a4303249402c19dcd37/post.php#L793
https://www.php.net/manual/en/features.file-upload.post-method.php

The spoiler test
https://git.leftypol.org/leftypol/leftypol/src/commit/2d16e747a18ba900ec220a4303249402c19dcd37/post.php#L1064
can then be modified to check per-file booleans:
< if ($config['spoiler_images'] && isset($_POST[str_replace('file', 'spoiler', $file['formparametername'])])) {


For per-file spoilers for the non-JS case the way to have multiple file controls can be found in multi-image.js:
https://git.leftypol.org/leftypol/leftypol/src/commit/2d16e747a18ba900ec220a4303249402c19dcd37/js/multi-image.js#L21
> var new_file = '<br class="file_separator"/><input type="file" name="file'+(images_len+1)+'" id="upload_file'+(images_len+1)+'">';

The original spoiler checkbox is in post_form.html:
https://git.leftypol.org/leftypol/leftypol/src/commit/2d16e747a18ba900ec220a4303249402c19dcd37/templates/post_form.html#L51
> {% if config.spoiler_images %}<div id="spoilercontainer"> <input id="spoiler" name="spoiler" type="checkbox"> <label for="spoiler">{% trans %}Spoiler Image{% endtrans %}</label></div>{% endif %}

as is the file input:
https://git.leftypol.org/leftypol/leftypol/src/commit/2d16e747a18ba900ec220a4303249402c19dcd37/templates/post_form.html#L149
> <input type="file" name="file" id="upload_file">

The div#spoilercontainer can be dropped and the file input replaced with:
{% for counter in 1..config.max_images %}
    {% if counter > 1 %}<br class="file_separator"/>{% endif %}
    {% set countersuffix = counter == 1 ? '' : counter %}
    {% if config.spoiler_images %}<span class="spoilercontainer"><input id="spoiler{{ countersuffix }}" name="spoiler{{ countersuffix }}" type="checkbox"><label for="spoiler{{ countersuffix }}">S{{ counter }}</label></span>{% endif %}
    <input type="file" name="file{{ countersuffix }}" id="upload_file{{ countersuffix }}">
{% endfor %}


A sample result is attached. This will enable per-file spoilers for the non-JS case. I'll leave the necessary frontend changes for the JS case to those who regularly browse with remote code execution enabled.

 No.11988

>>11642
>YouTube now blocks every Tor exit node.
When you browse via tor, embeds now use an invidious hidden service by default.
In an ideal world, the embed would choose a random proxy from a list of good proxies >>7026 (https://github.com/iv-org/documentation/blob/master/Invidious-Instances.md ).

My wish is something that helps with twitter links to automatically link to a random nitter instance. I absolutely detest the twitter front end. So much so that I avoid clicking twitter links.

Maybe it could look like this:
www.twitter.com/something/something [nitter]
Where [nitter] is a button that takes you to the same link, but on nitter.

>>11927
>>11929
Done. Please test and report.

 No.11998

https://git.leftypol.org/leftypol/leftypol/commit/af8b645b2395cf0d3ac0e6202d2fe1793f74e140
> Adds bar | to unique IP counter
If you want a vertical bar but place it there, you'll get a dangling bar on the right in the non-JS case. By contrast, if you want a vertical bar but place it on the left in
https://git.leftypol.org/leftypol/leftypol/src/commit/2a506d8dec5b9cb10686c8509ec73f112069bd07/js/thread-stats.js#L25
you'll get essentially the same effect but without dangling bars.

 No.12046

File: 1633862319695.jpg (253.81 KB, 566x800, aqua thumbs up.jpg)

>>11988
>Done. Please test and report.
djvu works

 No.12054

File: 1633954114029.png (126.28 KB, 1059x719, lpimage.png)

Here's a graph of relative PPD for the last 30 days for thread views.
((pagetest, install, getdata, draw) => {
  const back   = 'rgba(  0,   0,  60, 1)'
  const bars   = 'rgba(  0,   0, 255, 1)'
  const grid   = 'rgba(128, 128, 128, 1)'
  const count  = 30, step = 15
  const width  = count * step
  const height = 100

  if (!pagetest ()) { return; }
  context = install ({
    width:  width,
    height: height,
  })
  if (!context.ok) { return; }

  context.back   = back
  context.bars   = bars
  context.grid   = grid
  context.count  = count
  context.step   = step
  context.width  = width
  context.height = height
  context.data   = getdata (count)
  draw (context)
}) (
  () => (document.getElementById ('uniqueip') != null) && (document.querySelectorAll ('div.post.op').length == 1),
  config => {
    const holder = document.createElement ("div")
    holder.innerHTML = '<div style="text-align: center;"><canvas id="canvasid" width="' + config.width + '" height="' + config.height + '" style="border: 1px solid; z-index: 100; position: relative;">canvas</canvas></div>'
    const target = document.getElementById ('thread-interactions')
    if (target == null) { return { ok: false }; }
    target.parentNode.insertBefore (holder, target)
    const canvas = document.getElementById ('canvasid')

    if (canvas.getContext) {
      const ctx = canvas.getContext ('2d')
      return {
        ok:      true,
        holder:  holder,
        canvas:  canvas,
        context: ctx,
      }
    } else {
      holder.remove ()
      return { ok: false }
    }
  },
  count => {
    const all = Array.from (document.querySelectorAll ('p.intro time')).map (e => e.innerText.match (/^\d{4}-\d{2}-\d{2}/)).filter (m => m != null).reduce ((acc, m) => {
      const key = m [0]
      if (key in acc) {
        acc [key] += 1
      } else {
        acc [key]  = 1
      }
      return acc
    }, {})
    const now = new Date ()
    const key = k => {
      const when = new Date (now)
      when.setUTCDate (now.getUTCDate () - k)
      return when.getUTCFullYear ().toString ().padStart (4, '0') + '-' + (when.getUTCMonth () + 1).toString ().padStart (2, '0') + '-' + when.getUTCDate ().toString ().padStart (2, '0')
    }
    const ret = Array.from ({length: count}, (x, k) => all [key (k)] ?? 0)
    return ret
  },
  context => {
    const ctx   = context.context
    const data  = context.data
    const max   = data.reduce ((a, b) => Math.max (a, b), 0) || 1
    const w     = context.width
    const h     = context.height
    const count = context.count
    const step  = context.step

    ctx.fillStyle = context.back
    ctx.fillRect (0, 0, w, h)

    ctx.strokeStyle = context.grid
    for (let k = 0; k < count; k++) {
      ctx.beginPath ()
      ctx.moveTo (step * k, 0)
      ctx.lineTo (step * k, h)
      ctx.stroke ()
    }

    ctx.fillStyle = context.bars
    for (let k = 0; k < count; k++) {
      const y = data [k] * h / max
      ctx.fillRect (w - step - k * step, h - y, step, y)
    }
  }
)

Just a demo.

 No.12074

Would it be possible to hide threads from the catalog?

 No.12077

>>12074
It should be. Threads hidden in the normal index page view are hidden in the catalog.

 No.12103

File: 1634121334334.png (244.59 KB, 3177x800, lpimage.png)

Here's a plot for catalog views that shows the relative age of threads, growing to the right, the relative reply counts, growing to the top, and the relative bump freshness, active in red, dormant in blue. The sample images are for /tech/, /leftypol/ and /siberia/.
(tools => ((install, sitespec) => {
  const site   = sitespec.find (spec => spec.pagetest ())
  if (!site) { return; }
  const config = site.getconfig ()
  if (!config.ok) { return; }
  install (config)
  if (!config.ok) { return; }
  site.getdata (config)
  if (!config.ok) {
    config.holder.remove ()
    return
  }
  site.draw (config)
}) (
  config => {
    // > width height insertmode inserttarget
    // < holder canvas context
    const modes = {
      after:  (holder, target) => { target.parentNode.insertBefore (holder, target.nextSibling); },
      before: (holder, target) => { target.parentNode.insertBefore (holder, target); },
      first:  (holder, target) => { target.insertBefore (holder, target.firstChild); },
      last:   (holder, target) => { target.appendChild (holder); },
    }

    const holder = document.createElement ("div")
    holder.innerHTML = '<div style="text-align: center;"><canvas id="canvasid" width="' + config.width + '" height="' + config.height + '" style="border: 1px solid; z-index: 100; position: relative;">canvas</canvas></div>'
    modes [config.insertmode] (holder, config.inserttarget)
    const canvas = document.getElementById ('canvasid')

    if (canvas.getContext) {
      config.holder  = holder
      config.canvas  = canvas
      config.context = canvas.getContext ('2d')
    } else {
      holder.remove ()
      config.ok = false
    }
  }, [{
    pagetest:  () => /^https?:\/\/(leftypol\.org|leftychan\.net)\//.test (document.location.href) && (document.getElementById ('uniqueip') != null) && (document.querySelectorAll ('div.post.op').length == 1),
    getconfig: () => {
      const target = document.getElementById ('thread-interactions')
      if (target == null) { return { ok: false }; }
      const count  = 60, step = 10

      return {
        ok:     true,
        width:  count * step,
        height: 100,
        count:  count,
        step:   step,
        back:   'rgba(  0,   0,  60, 1)',
        bars:   'rgba(  0,   0, 255, 1)',
        grid:   'rgba(128, 128, 128, 1)',
        insertmode:   'before',
        inserttarget: target,
      }
    },
    getdata: config => {
      const dates = Array.from (document.querySelectorAll ('p.intro time')).map (e => e.innerText.match (/^\d{4}-\d{2}-\d{2}/)).filter (m => m != null).map (m => m [0])
      tools.getdatadatecount (config, dates)
    },
    draw: tools.drawrelative
  }, {
    pagetest:  () => /^https?:\/\/(leftypol\.org|leftychan\.net)\//.test (document.location.href) && (document.getElementById ('Grid') != null),
    getconfig: () => {
      const target = document.getElementById ('Grid')
      if (target == null) { return { ok: false }; }

      return {
        ok:     true,
        width:  400,
        height: 400,
        radius: 8,
        insertmode:   'after',
        inserttarget: target,
      }
    },
    getdata: config => {
      const now  = Date.now () / 1000
      const data = Array.from (document.querySelectorAll ('div.mix[data-bump][data-reply][data-time]')).map (e => ["data-bump", "data-reply", "data-time"].map (s => parseInt (e.getAttribute (s), 10))).map (([b, r, t]) => [now - b, r, now - t])
      config.data = data
    },
    draw: config => {
      const ctx    = config.context
      const w      = config.width
      const h      = config.height
      const radius = config.radius
      const data   = config.data
      const [maxb, maxr, maxt] = Array.from ({length: 3}, (x, k) => data.reduce ((a, b) => Math.max (a, b [k]), 0) || 1)

      data.reverse ()
      for (const [b, r, t] of data) {
        const x = t * w / maxt
        const y = h - r * h / maxr
        const c = Math.floor (b * 255 / maxb)
        const f = 'rgba(' + (255 - c) + ', 0, ' + c + ', 1)'

        ctx.fillStyle = f
        ctx.beginPath ()
        ctx.arc (x, y, radius, 0, 2 * Math.PI, true)
        ctx.fill ()
      }
    }
  }]
)) ({
  drawrelative: config => {
    const ctx   = config.context
    const data  = config.data
    const max   = data.reduce ((a, b) => Math.max (a, b), 0) || 1
    const w     = config.width
    const h     = config.height
    const count = config.count
    const step  = config.step

    ctx.fillStyle = config.back
    ctx.fillRect (0, 0, w, h)

    ctx.strokeStyle = config.grid
    for (let k = 0; k < count; k++) {
      ctx.beginPath ()
      ctx.moveTo (step * k, 0)
      ctx.lineTo (step * k, h)
      ctx.stroke ()
    }

    ctx.fillStyle = config.bars
    for (let k = 0; k < count; k++) {
      const y = data [k] * h / max
      ctx.fillRect (w - step - k * step, h - y, step, y)
    }
  },
  getdatadatecount: (config, datestrings) => {
    // YYYY-MM-DD
    const all = datestrings.reduce ((acc, key) => {
      if (key in acc) {
        acc [key] += 1
      } else {
        acc [key]  = 1
      }
      return acc
    }, {})
    const now = new Date ()
    const key = k => {
      const when = new Date (now)
      when.setUTCDate (now.getUTCDate () - k)
      return when.getUTCFullYear ().toString ().padStart (4, '0') + '-' + (when.getUTCMonth () + 1).toString ().padStart (2, '0') + '-' + when.getUTCDate ().toString ().padStart (2, '0')
    }
    const ret = Array.from ({length: config.count}, (x, k) => all [key (k)] ?? 0)
    config.data = ret
  }
})

Just a demo.

 No.12112

Just noticed that we can now hide replies! Based tech team!

 No.12113

>>12112
You're welcome! (Filters also work now.)

 No.12117

File: 1634352869762.jpg (48.94 KB, 426x639, 1628313217874.jpg)

From the meta thread:

How hard would it be to put a cool-down timer on posts? I'm probably the only mfer who would benefit from it but anyone who dumps anything on this site would appreciate it.

 No.12122

>>12117
I'm not sure if it would be too hard, but it's low-priority compared to other outstanding issues.


Unique IPs: 21 |

[Return][Go to top] [Catalog] | [Home][Post a Reply]
Delete Post [ ]
[ home / rules / faq ] [ overboard / sfw / alt ] [ leftypol / siberia / hobby / tech / edu / games / anime / music ] [ meta / roulette ] [ cytube / git ] [ GET / ref / booru ]