felixhao28/JSCPP

demo page - load/save state from/to url fragment ID / hash string

milahu opened this issue · 1 comments

please include this feature on the demo page, so we can link to demo code

sample implementation:

Main = React.createClass({
  // ....
  saveToUrl: function(e) {
    if (e != null) {
      e.preventDefault();
    }
    return setFragmentFromState(this.state);
  },
  loadFromUrl: function(e) {
    if (e != null) {
      e.preventDefault();
    }
    return this.setState(
      getStateDiffFromFragment()
    );
  },
var parseQueryString = function(input) {
  // similar to PHP $_GET[key]
  // return array of values if key is repeated in query string
  let queryObject = {};
  const re = /([^?&=]+)(?:=([^&]+))?/g;
  let match;
  while (match = re.exec(input)) {
    const [k, v] = [
      decodeURIComponent(match[1]),
      // empty value = true
      (decodeURIComponent(match[2]) || true)
    ];
    if (k in queryObject) {
      if (Array.isArray(queryObject[k])) {
        queryObject[k].push(v);
      } else {
        queryObject[k] = [queryObject[k], v];
    }} else {
      queryObject[k] = v;
    }
  }
  return queryObject;
};

// keys shared between state and fragment query string
// key "code" is always shared
const fragmentKeys = ["input"];

var getStateDiffFromFragment = function() {
  // fragment string format: key=val&key2=val2/codeString
  // val, val2, ... must be encoded with encodeURIComponent
  // codeString can be encoded with encodeURI
  // which is more compact than encodeURIComponent
  const idxCode = document.location.hash.indexOf("/");
  const query = parseQueryString(
    document.location.hash.substring(1, idxCode));
  let stateDiff = Object.keys(query).reduce((acc, key) => {
    if (fragmentKeys.includes(key)) {
      acc[key] = query[key];
    }
    return acc;
  }, {});
  const code = decodeURI(document.location.hash.substring(idxCode + 1));
  if (code) {
    stateDiff.code = code;
  }
  return stateDiff;
};

var setFragmentFromState = function(state) {
  document.location.hash = fragmentKeys.reduce((acc, key) => {
    if (state[key]) {
      acc.push(`${key}=${encodeURIComponent(state[key])}`)
    }
    return acc;
  }, []).join("&") + "/" + encodeURI(state.code);
};

javascript says document.location.hash, the official name is fragment identifier

limitation: old browsers limit URL length

license is creative-commons-zero, so feel free to steal my code

ps: can you make /gh-pages public? (including jsx files)

gh-pages is already public at https://github.com/felixhao28/JSCPP/tree/gh-pages. Feel free to send a PR. : )