Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
## History

* to-release...
* Add warning on very long links that may require load via UI
* 2026/06/02 ver 3.2.4
* Cage mode in all grid types except cairo pentagonal
* Bug fixes and code improvement
Expand Down
4 changes: 2 additions & 2 deletions CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* Help icon made by <a href="https://www.flaticon.com/authors/roundicons" title="Roundicons">Roundicons</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a>
* Thanks to <a href="https://github.com/william42"> William42 </a> for SVG Screenshot code.
* Thanks to <a href="https://github.com/nmay231"> nmay231 </a> for contributions to puzz.link parser in Penpa+.
* Thanks to <a href="https://thegriddle.net"> davmillar </a> for contributions to redesign the GUI, language support and refactoring the code.
* Thanks to <a href="https://thegriddle.net"> David "Taco Dave" Millar </a> for contributions to redesign the GUI, language support and refactoring the code.
* Thanks to <a href="https://github.com/kieranclancy"> Kieran Clancy </a> for contributions to smart checking in Penpa+.
* Thanks to <a href="https://github.com/BenceJoful"> BenceJoful </a> for contributions to hexgrid and replay improvements in Penpa+.
* Thanks to <a href="https://github.com/marknn3"> Mark Langezaal </a> for contributions to improve Penpa+.
Expand All @@ -19,4 +19,4 @@
* Thanks to <a href="https://github.com/ReverM"> ReverM </a> for contributions to improvements in Penpa+.
* Thanks to <a href="https://github.com/dodomos"> dodomos </a> for contributions to improvements in Penpa+.
* Thanks to <a href="https://github.com/ZerolAcqua"> ZerolAcqua </a> for contributions to improvements in Penpa+.
* Thanks to <a href="https://github.com/T0nyX1ang"> T0nyX1ang </a> for contributions to improvements in Penpa+.
* Thanks to <a href="https://github.com/T0nyX1ang"> T0nyX1ang </a> for contributions to improvements in Penpa+.
16 changes: 15 additions & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@
"./js/class_uniform.js",
"./js/class_panel.js",
"./js/style.js",
"./js/io.js",
"./js/general.js",
"./js/customcolor.js",
"./js/translate.js"
Expand Down Expand Up @@ -1190,7 +1191,9 @@ <h5 class="modal-subheader" id="generate_lb">Generate URL</h5>
<input type="checkbox" name="save_undo" id="save_undo"><br/>
<label class="label_nb" for="auto_shorten_chk" id="auto_shorten_chk_lb">Automatically Shorten with
TinyURL</label>
<input type="checkbox" name="auto_shorten_chk" id="auto_shorten_chk"/>
<input type="checkbox" name="auto_shorten_chk" id="auto_shorten_chk"/><br/>
<label class="label_nb" for="warn_long_links_chk" id="warn_long_links_chk_lb">Warn on Very Long Links</label>
<input type="checkbox" name="warn_long_links_chk" id="warn_long_links_chk" checked />
</div>
<div class="nb_button">
<input type="button" id="address_edit" value="Editing URL"/>
Expand Down Expand Up @@ -1757,6 +1760,17 @@ <h4><label id="multitab_settings_lb">Solution Tab Setting:</label></h4>
</select>
</td>
</tr>
<tr>
<td>
<label id="lb_settings_warn_long_links">Warn on Very Long Links:</label>
</td>
<td>
<select id="warn_long_links_dropdown">
<option value="1" selected class="lb_generic_on">ON</option>
<option value="0" class="lb_generic_off">OFF</option>
</select>
</td>
</tr>
<!-- <tr>
<td>
<label>Draw on Edges/Corners:</label>
Expand Down
92 changes: 51 additions & 41 deletions docs/js/general.js
Original file line number Diff line number Diff line change
Expand Up @@ -1615,6 +1615,18 @@ async function request_shortlink(url) {

async function update_textarea(text) {
let newText = text;

if (
newText.length > PenpaIO.MAX_URI_LENGTH &&
UserSettings.warn_long_links
) {
Swal.fire({
html: PenpaText.get('long_link_warning'),
icon: 'info',
confirmButtonText: PenpaText.get('close'),
});
}

if (UserSettings.shorten_links) {
let shortened = await request_shortlink(newText);
if (shortened && pu.isReplay) {
Expand Down Expand Up @@ -1902,55 +1914,53 @@ function export_sudoku() {

async function import_url(urlstring) {
urlstring = urlstring || document.getElementById("urlstring").value;
if (urlstring !== "") {
if (urlstring.indexOf("/penpa-edit/") !== -1 || urlstring.match(/m=(?:edit|solve)/gi)) {

let param = urlstring.split('&');
let paramArray = [];
if (urlstring === "") {
return;
}

// Decompose address into elements
for (var i = 0; i < param.length; i++) {
let paramItem = param[i].split('=');
paramArray[paramItem[0]] = paramItem[1];
}
if (urlstring.indexOf("/penpa-edit/") !== -1 || urlstring.match(/m=(?:edit|solve)/gi)) {
let param = urlstring.split('&');
let paramArray = [];

const hash = PenpaProgress.getHash(paramArray.p);
// Decompose address into elements
for (var i = 0; i < param.length; i++) {
let paramItem = param[i].split('=');
paramArray[paramItem[0]] = paramItem[1];
}

// Decrypt puzzle data
let local_data = await PenpaProgress.tryLoad(hash);
const hash = PenpaProgress.getHash(paramArray.p);

if (local_data && local_data.includes('&p=')) {
// This is to account for old links and new links together
var url;
if (local_data.includes("#")) {
url = local_data.split('#')[1];
} else {
url = local_data.split('?')[1];
}
load(url, type = 'localstorage', origurl = paramArray.p);
} else {
if (urlstring.includes("#")) {
urlstring = urlstring.split("/penpa-edit/#")[1];
} else {
urlstring = urlstring.split("/penpa-edit/?")[1];
}
load(urlstring, 'local');
}
// Decrypt puzzle data
let local_data = await PenpaProgress.tryLoad(hash);

document.getElementById("modal-load").style.display = 'none';
if (UserSettings.tab_settings > 0) {
selectBox.setValue(UserSettings.tab_settings);
}
} else if (urlstring.match(/\/puzz.link\/p\?|pzprxs\.vercel\.app\/p\?|\/pzv\.jp\/p(\.html)?\?/)) {
decode_puzzlink(urlstring);
document.getElementById("modal-load").style.display = 'none';
if (local_data && local_data.includes('&p=')) {
// This is to account for old links and new links together
load(
PenpaIO.getPuzzleDataFromUrl(local_data),
'localstorage',
paramArray.p
);
} else {
Swal.fire({
html: PenpaText.get('invalid_url'),
icon: 'error',
confirmButtonText: PenpaText.get('close'),
});
load(
PenpaIO.getPuzzleDataFromUrl(urlstring),
'local'
);
}

document.getElementById("modal-load").style.display = 'none';
if (UserSettings.tab_settings > 0) {
selectBox.setValue(UserSettings.tab_settings);
}
} else if (urlstring.match(/\/puzz.link\/p\?|pzprxs\.vercel\.app\/p\?|\/pzv\.jp\/p(\.html)?\?/)) {
decode_puzzlink(urlstring);
document.getElementById("modal-load").style.display = 'none';
} else {
Swal.fire({
html: PenpaText.get('invalid_url'),
icon: 'error',
confirmButtonText: PenpaText.get('close'),
});
}
}

Expand Down
27 changes: 27 additions & 0 deletions docs/js/io.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class IO {
/**
* Estimated "URI too long" limit to use when checking for a URI's length after generating an
* export link.
*/
MAX_URI_LENGTH = 8000;

/**
* Attempts to get the puzzle data from the URL passed in.
*
* @param {string} loadUrl URL to attempt to parse for puzzle data.
*/
getPuzzleDataFromUrl = function (loadUrl) {
const urlAsUrl = new URL(loadUrl);
let puzzleData;

if (loadUrl.includes("#")) {
puzzleData = urlAsUrl.hash.split("#")[1];
} else {
puzzleData = urlAsUrl.search.split("?")[1];
}

return puzzleData;
};
};

const PenpaIO = new IO();
8 changes: 8 additions & 0 deletions docs/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -2282,6 +2282,14 @@ onload = function() {
UserSettings.shorten_links = this.checked;
}

// Warn on long links setting
document.getElementById("warn_long_links_dropdown").onchange = function() {
UserSettings.warn_long_links = String(this.value) === "1";
}
document.getElementById("warn_long_links_chk").onchange = function() {
UserSettings.warn_long_links = this.checked;
}

// Timer pause and unpause
document.getElementById("sw_pause").addEventListener("click", pauseTimer);
document.getElementById("sw_start").addEventListener("click", startTimer);
Expand Down
82 changes: 59 additions & 23 deletions docs/js/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,25 @@ function deleteCookie(name) {
setCookie(name, '', -1);
}

/**
* Helper that attempts to parse the value as a boolean flag (true/false) to make the settings
* code more concise.
*
* @param {any} value
*/
function parseBooleanish(value) {
if (!value) { return false; }

if (typeof value === 'string') {
if (value === "true" || value === "1") { return true; }
if (value === "false" || value === "0" || value == "") { return false; }
} else if (typeof value === "number") {
return value > 0;
}

return Boolean(value);
}

const UserSettings = {
// Cookie Expiry Constant
_expDate: 2147483647,
Expand Down Expand Up @@ -128,7 +147,7 @@ const UserSettings = {
// Check conflicts on pencil marks
_check_pencil_marks: false,
set check_pencil_marks(newValue) {
this._check_pencil_marks = newValue === "1" || newValue === "true" || newValue === true;
this._check_pencil_marks = parseBooleanish(newValue);
document.getElementById("check_pencil_marks_opt").value = this._check_pencil_marks ? "1" : "0";
if (window.pu)
pu.redraw();
Expand Down Expand Up @@ -194,7 +213,7 @@ const UserSettings = {

_outline_text: false,
set outline_text(newValue) {
this._outline_text = newValue === "1" || newValue === "true" || newValue === true;
this._outline_text = parseBooleanish(newValue);
document.getElementById("outline_text_opt").value = this._outline_text ? "1" : "0";
if (window.pu)
pu.redraw();
Expand Down Expand Up @@ -230,7 +249,7 @@ const UserSettings = {
// Setting to ignore all
_ignore_line_style: false,
set ignore_line_style(newValue) {
this._ignore_line_style = newValue === "1" || newValue === "true" || newValue === true;
this._ignore_line_style = parseBooleanish(newValue);
document.getElementById("ignore_line_style_opt").value = this._ignore_line_style ? "1" : "0";
this.attemptSave();
},
Expand Down Expand Up @@ -403,20 +422,33 @@ const UserSettings = {

_shorten_links: false,
set shorten_links(newValue) {
if (newValue === undefined) { newValue = false; }
// [ZW] Not sure how this is happening but a value of "false" can get stored in
// the settings which is interpreted as true
if (newValue === "false") { newValue = false; }
this._shorten_links = newValue;

document.getElementById("shorten_links_dropdown").value = newValue ? 1 : 0;
document.getElementById("auto_shorten_chk").checked = newValue ? 'checked' : null;
const parsedValue = parseBooleanish(newValue);
document.getElementById("shorten_links_dropdown").value = this._shorten_links ? 1 : 0;
document.getElementById("auto_shorten_chk").checked = this._shorten_links ? 'checked' : null;
this.attemptSave();
},
get shorten_links() {
return this._shorten_links;
},

/** @private Stored value for warn_long_links setting. */
_warn_long_links: true,
/**
* When enabled, warn the user that the generated link may be too long and cause "URI too long"
* error when attempting to visit as normal. Infrequent/new Penpa users may not know that this
* issue can happen and requires working around via the "Load" button.
*
* @param {boolean} newValue New value to set.
*/
set warn_long_links(newValue) {
this._warn_long_links = parseBooleanish(newValue);
document.getElementById("warn_long_links_dropdown").value = this._warn_long_links ? 1 : 0;
document.getElementById("warn_long_links_chk").checked = this._warn_long_links ? 'checked' : null;
},
get warn_long_links() {
return this._warn_long_links;
},

_panel_shown: false,
set panel_shown(newValue) {
if (newValue === undefined) { newValue = false; }
Expand Down Expand Up @@ -453,7 +485,7 @@ const UserSettings = {
get quick_panel_button() {
return this._quick_panel_btn;
},

_resize_whitespace: false,
set resize_whitespace(newValue) {
const button = document.getElementById("resize_whitespace_button");
Expand Down Expand Up @@ -483,18 +515,19 @@ const UserSettings = {
'starbattle_dots',
'sudoku_centre_size',
'sudoku_normal_size',
'timerbar_status'
'timerbar_status',
'warn_long_links'
],
gridtype_size: [
'gridtype',
'displaysize'
],

clearSettings: function() {
this.can_save.forEach(function(setting) {
clearSettings: function () {
this.can_save.forEach(function (setting) {
deleteCookie(setting);
});
this.gridtype_size.forEach(function(setting) {
this.gridtype_size.forEach(function (setting) {
deleteCookie(setting);
});
deleteCookie('tab_settings');
Expand All @@ -506,24 +539,24 @@ const UserSettings = {
_settingsLoaded: false,

// Handle saving settings if needed
attemptSave: function() {
attemptSave: function () {
if (!this._settingsLoaded) {
return;
}

this.can_save.forEach(function(setting) {
this.can_save.forEach(function (setting) {
setCookie(setting, UserSettings[setting], this._expDate);
});
this.gridtype_size.forEach(function(setting) {
this.gridtype_size.forEach(function (setting) {
setCookie(setting, UserSettings[setting], this._expDate);
});
setCookie("tab_settings", JSON.stringify(getValues('mode_choices')), this._expDate);
// setCookie("different_solution_tab", document.getElementById("multitab_settings_opt").value, this._expDate);
},

loadFromCookies: function(load = "others") {
loadFromCookies: function (load = "others") {
if (load === "others") {
this.can_save.forEach(function(setting) {
this.can_save.forEach(function (setting) {
let cookieQuery = getCookie(setting);
if (cookieQuery !== null) {
UserSettings[setting] = cookieQuery;
Expand All @@ -541,8 +574,11 @@ const UserSettings = {

this._settingsLoaded = true;
} else {
this.gridtype_size.forEach(function(setting) {
UserSettings[setting] = getCookie(setting);
this.gridtype_size.forEach(function (setting) {
let cookieValue = getCookie(setting);
if (cookieValue !== null) {
UserSettings[setting] = cookieValue;
}
});
}
}
Expand Down
Loading