]> git.wincent.com - hextrapolate.git/commitdiff
Update URL with "permalink" to current value
authorGreg Hurrell <greg@hurrell.net>
Tue, 4 Aug 2015 06:08:07 +0000 (23:08 -0700)
committerGreg Hurrell <greg@hurrell.net>
Tue, 4 Aug 2015 06:08:07 +0000 (23:08 -0700)
Use Base 62 for compactness. Note that this requires us to upgrade the
internals to handle bigger bases, even though we don't expose base > 36
elsewhere in the UI.

This fulfils the promise in the README that this feature exists.

src/App.js
src/DIGITS.js [new file with mode: 0644]
src/Field.react.js
src/getDigits.js
src/joinDigits.js

index f6678cf3dca632fdc26d0dbc2c40a45d909bd5ec..b3ff45d9530041ce26be2d449507ca973975449f 100644 (file)
@@ -7,25 +7,48 @@
 
 'use strict';
 
+import DIGITS from './DIGITS';
 import DynamicField from './DynamicField.react';
 import React from 'react';
 import type Value from './Field.react';
 import Field from './Field.react';
 import Label from './Label.react';
 import Size from './Size.react';
+import convert from './convert';
 
 import './App.css';
 
+const SERIALIZATION_BASE = DIGITS.length;
+
+function getInitialValue() {
+  // Extract value from URL fragment, if present.
+  const value = window.location.hash.replace(/^#/, '');
+  const validator = new RegExp(`^[${DIGITS}]+$`);
+  if (!validator.test(value)) {
+    return null;
+  } else {
+    return {
+      base: SERIALIZATION_BASE,
+      value,
+    };
+  }
+}
+
 export default class App extends React.Component {
   constructor(props) {
     super(props);
     this.state = {
-      value: null,
+      value: getInitialValue(),
     };
   }
 
   _onValueChange = (value: Value) => {
     this.setState({value});
+    window.history.replaceState(
+      {},
+      '',
+      '#' + convert(value.value, value.base, SERIALIZATION_BASE)
+    );
   }
 
   componentDidMount() {
diff --git a/src/DIGITS.js b/src/DIGITS.js
new file mode 100644 (file)
index 0000000..8929e89
--- /dev/null
@@ -0,0 +1,12 @@
+/**
+ * Copyright 2015-present Greg Hurrell. All rights reserved.
+ * Licensed under the terms of the MIT license.
+ *
+ * @flow
+ */
+
+'use strict';
+
+const DIGITS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+
+export default DIGITS;
index b5d201003869becd6729b1e840b428b7a93d427d..a2e39a839c610a1a33d8715db70558699131d511 100644 (file)
@@ -7,6 +7,7 @@
 
 'use strict';
 
+import DIGITS from './DIGITS';
 import React from 'react';
 import convert from './convert';
 import cx from 'classnames';
@@ -20,8 +21,6 @@ export const ValuePropType = React.PropTypes.shape({
   value: React.PropTypes.string,
 });
 
-const DIGITS = '0123456789abcdefghijklmnopqrstuvwxyz';
-
 /**
  * Convert from `value` to `base`.
  */
index fc8888da40fe64c3e8c0f7c202474400c8eac417..fed0aa38439900d23800214978795a6f8d90e7c5 100644 (file)
@@ -7,6 +7,8 @@
 
 'use strict';
 
+import DIGITS from './DIGITS';
+
 /**
  * Strips the leading prefix from `number` in `base` and returns the remaining
  * part of the string.
@@ -26,6 +28,15 @@ function stripPrefix(number: string, base: number): string {
   }
 }
 
+function parse(digit: string, base: number) {
+  if (base > 36 && base <= 62) {
+    const position = DIGITS.indexOf(digit);
+    return position !== -1 && position < base ? position + 1 : NaN;
+  } else {
+    return parseInt(digit, base);
+  }
+}
+
 /**
  * Breaks the string repsentation of `number` in `base` into an array of decimal
  * digits (from least significant to most significant) for easier manipulation.
@@ -35,7 +46,7 @@ function stripPrefix(number: string, base: number): string {
  */
 export default function getDigits(number: string, base: number): Array<number> {
   return stripPrefix(number, base).trim().split('').reverse().map(digit => {
-    const result = parseInt(digit, base);
+    const result = parse(digit, base);
     if (isNaN(result)) {
       throw new Error('Invalid digit `' + digit + '` for base `' + base + '`');
     }
index 3d6eae2f82fa7836697d50c364138c21dfe8e3f6..83d8d975a839f46a51b64a02d50f7736bfc0d765 100644 (file)
@@ -7,6 +7,16 @@
 
 'use strict';
 
+import DIGITS from './DIGITS';
+
+function encode(number: string, base: number) {
+  if (base > 36 && base <=62) {
+    return DIGITS[number - 1];
+  } else {
+    return number.toString(base);
+  }
+}
+
 /**
  * Turns an unpacked arbitrary-precision representation of a number, `digits`,
  * (as produced by `getDigits`) back into a string representation in `base`.
@@ -18,6 +28,6 @@ export default function joinDigits(
   return digits
     .slice()
     .reverse()
-    .map(number => number.toString(base))
+    .map(number => encode(number, base))
     .join('');
 }