Dup Ver Goto 📝

minimum-viable

PT2/webdev/php/ajax does not exist
To
208 lines, 513 words, 5153 chars Page 'minimum-viable' does not exist.

The idea here is to make the minimum viable AJAX backend. Rather than via the URI, the page is requested via a JSON message. So we need to take JSON via POST, and decode it, find the file

Backend

<?php

require_once("Parsedown.php");

define('PageNotFound','PageNotFound'); # page to return if the page does not exist
define('PagesDir','pages');
define('PageExt','ptmd');

if( $_SERVER['REQUEST_METHOD'] !== "POST" ) {
  echo '{ "error": "Must POST", "source": "", "path": "" }';
  exit;
}
function the_json() {
  global $input;
  $input = file_get_contents('php://input');
  return $input;
}
function the_data() {
  global $json;
  $json = the_json();
  return json_decode(the_json(),true);
}
function fpath_for_path($path) {
  return PagesDir."/".$path.".".PageExt;
}
function send_as_json($data) {
  echo json_encode($data);
  exit;
}


$data = the_data();
if( !isset($data['path']) ) {
  $path = PageNotFound;
} else {
  $path = $data['path'];
  if( !file_exists(fpath_for_path($path)) ) {
    $path = PageNotFound;
  }
}
$fpath = fpath_for_path($path);
$source = file_get_contents($fpath);
$reply = [
  "path" => $path,
  "source" => $source,
  "input" => $data,
  "json" => $json
];

$ptmd = new Parsedown();
$pinput = preg_replace('/\[\[([^\]]+)\]\]/','[\1](\1)',$source);
$reply["pinput"] = $pinput;
$html = $ptmd->text($pinput);
$reply["html"] = $html;
$reply["nhtml"] = "";

send_as_json($reply);

Frontend

app.js

class Ajax {
  constructor(backend) {
    this.backend = backend
  }
  getPage(path,callback) {
    const request = { path }
    return this.dispatch(request,callback)
  }
  putPage(path,source,callback) {
    const request = { "type": "put", path, source }
    return this.dispatch(request,callback)
  }
  dispatch(request,callback) {
    console.log(request)
    $.ajax({
      type: "POST",
      data: JSON.stringify(request),
      url: this.backend,
      success: callback,
      dataType: "json" 
    }).fail(error => {
      const { responseText } = error
      console.log({responseText,error})
      const errorData = {
        pagename: "ERROR",
        navbar: `Failed to load page ${url}`,
        tags: [],
        body: responseText.replace(/&/g,"&amp;").replace(/>/g,"&gt;").replace(/</g,"&lt;")
      }
      window.error = error
      window.responseText = responseText
      window.errorData = errorData
    })
  }
}
class ViewBase {
  constructor() {
    this.data = null
    console.log(10)
  }
  setData(data) {
    this.data = data
  }
  render() {
    if( !this.data ) return
  }
}
class ViewHtml extends ViewBase {
  constructor(target) {
    super()
    this.target = target
  }
  render() {
    this.target.innerHTML = this.data.html
  }
}
class ViewSource extends ViewBase {
  constructor(target) {
    super()
    this.target = target
  }
  render() {
    this.target.innerText = this.data.source
  }
}
class EditSource extends ViewBase {
  constructor(target) {
    super()
    this.target = target
    this.textarea = target.querySelector("textarea")
  }
  render() {
    this.textarea.value = this.data.source
  }
}
export { Ajax, ViewBase, ViewSource, ViewHtml, EditSource }

the rest

Note that we use JQuery to handle the Ajax requests.

  <script>
    window.q = (x,y=document) => y.querySelector(x)
    window.qq = (x,y=document) => Array.from(y.querySelectorAll(x)) 
  </script>
  <script type="module">
    import { Ajax, ViewHtml, ViewSource, EditSource } from './app.js'
    const ajax = new Ajax("http://t420b/a/backend.php")
    console.log(1)
    window.addEventListener("load", _ => {
      console.log(2)
      const viewhtml = document.createElement("div")
      viewhtml.classList.add("view")
      viewhtml.classList.add("view-html")
      const viewsource = document.createElement("div")
      viewsource.classList.add("view")
      viewsource.classList.add("view-source")
      const editsource = document.createElement("div")
      editsource.classList.add("view")
      editsource.classList.add("edit-source")
      const textarea = document.createElement("textarea")
      editsource.append(textarea)
      const body = document.body
      body.append(viewhtml)
      body.append(viewsource)
      body.append(editsource)
      const view_html = new ViewHtml(viewhtml)
      const view_source = new ViewSource(viewsource)
      const edit_source = new EditSource(editsource)

      const success = x => {
        console.log("this",x)
        view_html.setData(x)
        view_source.setData(x)
        edit_source.setData(x)
        view_html.render()
        view_source.render()
        edit_source.render()
      }

      ajax.getPage("0",success)
      window.loadPage = x => ajax.getPage(x,success)
    })
  </script>
  <script>
    window.addEventListener("load", _ => {
      const input = q("input")
      input.addEventListener("keydown", e => {
        if( e.key == "Enter" ) {
          e.preventDefault()
          const p = input.value
          input.value = ""
          input.focus()
          return window.loadPage(p)
        }
      })
      input.focus()
    })
  </script>