PPPHP

Client‑Side Utility Library – pp Object

The pp global object provides modern, lightweight utilities that work everywhere in the framework — AJAX requests, dialog boxes, form helpers, and common functions like debounce and deep clone. It is loaded automatically on every project SPA page.

Dependencies: SweetAlert2 (must be loaded before pp.js).

Contents

pp.ajax – HTTP Requests

Thin wrappers around the Fetch API with built‑in JSON handling and a loading spinner helper.

GET request

const users = await pp.ajax.get('/api/users');

POST request (JSON)

const result = await pp.ajax.post('/api/save', {
    name: 'Alice',
    email: 'alice@example.com'
});
console.log(result.success); // true/false

File upload with progress

const formData = new FormData();
formData.append('file', fileInput.files[0]);

const response = await pp.ajax.upload('/api/upload', formData, (percent) => {
    console.log(`Uploading: ${percent}%`);
});

GET with automatic loading spinner

const data = await pp.ajax.load('/api/slow-endpoint', 'Fetching records…');
// Shows a SweetAlert2 spinner while loading, then auto‑closes

Adding custom headers

const data = await pp.ajax.get('/api/secure', {
    headers: { 'X-CSRF-Token': csrfToken }
});

pp.dialog – User Dialogs

Unified SweetAlert2 shortcuts that keep every module's UI consistent.

Toast notification

pp.dialog.toast('success', 'Record saved!');
pp.dialog.toast('error', 'Something went wrong.');
pp.dialog.toast('warning', 'Please check your input.');
pp.dialog.toast('info', '3 new notifications.');

Confirmation dialog

const confirmed = await pp.dialog.confirm(
    'Delete this record?',
    'This action cannot be undone.'
);
if (confirmed) {
    // proceed with deletion
}

Custom confirmation buttons

const yes = await pp.dialog.confirm('Archive?', 'Move to archive.', {
    confirmText: 'Archive',
    cancelText: 'Keep',
    confirmColor: '#0d6efd'
});

Text prompt

const folderName = await pp.dialog.prompt('New folder', 'Enter folder name');
if (folderName) {
    // create folder
}

Simple alert

await pp.dialog.alert('Done', 'All files processed.', 'success');

pp.form – Form Utilities

Quick value access and simple validation without heavyweight plugins.

Get / Set a form value

const email = pp.form.getValue('#email');
pp.form.setValue('#name', 'John Doe');

Checkbox and radio

const active = pp.form.getValue('#activeCheckbox');  // true/false
pp.form.setValue('#activeCheckbox', true);

const plan = pp.form.getValue('input[name="plan"]');  // 'basic'
pp.form.setValue('input[name="plan"]', 'premium');

Validate a field

const { valid, message } = pp.form.validate('#email', {
    required: true,
    email: true,
    requiredMessage: 'Email is required.'
});
if (!valid) {
    pp.dialog.toast('error', message);
}

Validate with minlength and pattern

const check = pp.form.validate('#username', {
    required: true,
    minlength: 3,
    pattern: /^[a-zA-Z0-9_]+$/,
    patternMessage: 'Only letters, numbers, and underscores allowed.'
});

Serialise a form to an object

const data = pp.form.toObject('#myForm');
// { name: "Alice", email: "alice@example.com", subscribe: "on" }
await pp.ajax.post('/api/submit', data);

pp.util – General Helpers

Debounce (search input)

const doSearch = pp.util.debounce((query) => {
    fetch(`/api/search?q=${query}`).then(res => res.json()).then(renderResults);
}, 400);

document.getElementById('searchBox').addEventListener('input', (e) => {
    doSearch(e.target.value);
});

Throttle (scroll handler)

window.addEventListener('scroll', pp.util.throttle(() => {
    console.log('User is scrolling...');
}, 200));

Format a date

pp.util.formatDate('2025-06-15');                      // "Jun 15, 2025, 12:00 am"
pp.util.formatDate('2025-06-15', 'F j, Y');            // "June 15, 2025"
pp.util.formatDate('2025-06-15 14:30:00', 'H:i');       // "14:30"

Deep clone an object

const original = { a: 1, b: { c: 2 } };
const copy = pp.util.deepClone(original);
copy.b.c = 99;
console.log(original.b.c);  // 2  (unchanged)

Generate a UUID

const id = pp.util.uuid();  // "c9b5a2e4-1234-4abc-5678-def012345678"

Escape HTML

const safe = pp.util.escapeHtml('<script>alert("xss")</script>');
// "&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;"

Real‑World Examples

Example 1 – Save form with loading spinner

async function saveRecord() {
    const data = pp.form.toObject('#recordForm');
    const result = await pp.ajax.load('/api/save', 'Saving…', {
        method: 'POST',
        body: JSON.stringify(data)
    });
    if (result.success) {
        pp.dialog.toast('success', 'Record saved!');
    } else {
        pp.dialog.toast('error', result.message);
    }
}

Example 2 – Delete with confirmation

async function deleteRecord(id) {
    const ok = await pp.dialog.confirm('Delete?', 'Record #' + id + ' will be permanently removed.');
    if (!ok) return;

    const result = await pp.ajax.post('/api/delete', { id });
    if (result.success) {
        pp.dialog.toast('success', 'Deleted.');
    }
}

Example 3 – Live search with debounce

const search = pp.util.debounce(async (query) => {
    const results = await pp.ajax.get(`/api/search?q=${encodeURIComponent(query)}`);
    renderResults(results);
}, 300);

document.getElementById('searchInput').addEventListener('input', e => search(e.target.value));

Example 4 – Form validation before submit

document.getElementById('saveBtn').addEventListener('click', async () => {
    const emailCheck = pp.form.validate('#email', { required: true, email: true });
    const nameCheck  = pp.form.validate('#name', { required: true, minlength: 2 });

    if (!emailCheck.valid) return pp.dialog.toast('error', emailCheck.message);
    if (!nameCheck.valid)  return pp.dialog.toast('error', nameCheck.message);

    // All good – submit
    await pp.ajax.post('/api/save', pp.form.toObject('#myForm'));
    pp.dialog.toast('success', 'Saved!');
});

🔗 Related Help Topics

Database API Security API Search API