Refactor more behaviors

This commit is contained in:
Rico Sta. Cruz 2017-10-01 02:04:51 +08:00
parent b837738adf
commit ede8f1c999
No known key found for this signature in database
GPG Key ID: CAAD38AE2962619A
12 changed files with 239 additions and 137 deletions

21
_js/behaviors/dismiss.js Normal file
View File

@ -0,0 +1,21 @@
import closest from 'dom101/closest'
import remove from 'dom101/remove'
import on from 'dom101/on'
import { getData } from '../helpers/data'
import onmount from 'onmount'
/**
* Dismiss button
*/
onmount('[data-js-dismiss]', function () {
const parent = closest(this, '[data-js-dismissable]')
const dismissable = getData(parent, 'js-dismissable')
const id = dismissable && dismissable.id || ''
on(this, 'click', e => {
Dismiss.setDismissed(id)
e.preventDefault()
if (parent) remove(parent)
})
})

View File

@ -0,0 +1,17 @@
import onmount from 'onmount'
import remove from 'dom101/remove'
import removeClass from 'dom101/remove-class'
import { getData } from '../helpers/data'
import { isDismissed } from '../helpers/dismiss'
import { isPreview } from '../helpers/preview'
onmount('[data-js-dismissable]', function () {
const id = getData(this, 'js-dismissable').id || ''
if (isPreview() || isDismissed(id)) {
remove(this)
} else {
removeClass(this, '-hide')
}
})

17
_js/behaviors/disqus.js Normal file
View File

@ -0,0 +1,17 @@
import onmount from 'onmount'
import injectDisqus from '../helpers/inject_disqus'
/**
* Injects Disqus onto the page.
*/
onmount('[data-js-disqus]', function () {
const data = JSON.parse(this.getAttribute('data-js-disqus'))
window.disqus_config = function () {
this.page.url = data.url
this.page.identifier = data.identifier
}
injectDisqus(data.host)
})

View File

@ -3,12 +3,14 @@ import ready from 'dom101/ready'
import remove from 'dom101/remove' import remove from 'dom101/remove'
import onmount from 'onmount' import onmount from 'onmount'
import { isPreview } from '../helpers/preview'
/* /*
* Behavior: Things to remove when preview mode is on * Behavior: Things to remove when preview mode is on
*/ */
onmount('[data-js-no-preview]', function (b) { onmount('[data-js-no-preview]', function (b) {
if (~window.location.search.indexOf('preview=1')) { if (isPreview()) {
remove(this) remove(this)
} }
}) })

View File

@ -0,0 +1,12 @@
import $ from 'jquery'
import onmount from 'onmount'
import permutate from '../helpers/permutate'
onmount('[data-js-searchable-item]', function () {
const $this = $(this)
const data = $this.data('js-searchable-item')
const words = permutate(data)
$this.attr('data-search-index', words.join(' '))
})

20
_js/helpers/data.js Normal file
View File

@ -0,0 +1,20 @@
/**
* Stores and retrieves data from an element. Works like jQuery.data().
*/
export function data (el, key, val) {
if (typeof val !== 'undefined') {
return getData(el, key)
} else {
return setData(el, key, val)
}
}
export function getData (el, key) {
const str = el.getAttribute('data-' + key)
return JSON.parse(str || '{}')
}
export function setData (el, key, val) {
el.setAttribute('data-' + key, JSON.stringify(val))
}

28
_js/helpers/dismiss.js Normal file
View File

@ -0,0 +1,28 @@
import * as Store from './store'
/**
* Dismisses an announcement.
*
* @example
* setDismissed('2017-09-02-happy-birthday')
*/
export function setDismissed (id) {
Store.update('dismissed', function (data) {
data[id] = true
return data
})
}
/**
* Checks if an announcement has been dismissed before.
*
* @example
* setDismissed('2017-09-02-happy-birthday')
* isDismissed('2017-09-02-happy-birthday') => true
*/
export function isDismissed (id) {
const data = Store.fetch('dismissed')
return data && data[id]
}

View File

@ -0,0 +1,14 @@
/**
* Injects disqus's scripts into the page.
*
* @example
* injectDisqus('devhints.disqus.com')
*/
export default function injectDisqus (host) {
var d = document, s = d.createElement('script')
s.src = 'https://' + host + '/embed.js'
s.setAttribute('data-timestamp', +new Date())
;(d.head || d.body).appendChild(s)
}

71
_js/helpers/permutate.js Normal file
View File

@ -0,0 +1,71 @@
/**
* Permutates a searcheable item.
*
* permutate({
* slug: 'hello-world',
* category: 'greetings'
* })
*/
export default function permutate (data) {
let words = []
if (data.slug) {
words = words.concat(permutateString(data.slug))
}
if (data.category) {
words = words.concat(permutateString(data.category))
}
return words
}
/*
* Permutates strings.
*
* @example
* permutateString('hi joe')
* => ['h', 'hi', 'j', 'jo', 'joe']
*/
export function permutateString (str) {
let words = []
let inputs = splitwords(str)
inputs.forEach(word => {
words = words.concat(permutateWord(word))
})
return words
}
/**
* Permutates a word.
*
* @example
* permutateWord('hello')
* => ['h', 'he', 'hel', 'hell', 'hello']
*/
export function permutateWord (str) {
let words = []
const len = str.length
for (var i = 1; i <= len; ++i) {
words.push(str.substr(0, i))
}
return words
}
/**
* Helper for splitting to words.
*
* @example
* splitWords('Hello, world!')
* => ['hello', 'world']
*/
export function splitwords (str) {
const words = str.toLowerCase()
.split(/[ \/\-_]/)
.filter(k => k && k.length !== 0)
return words
}

7
_js/helpers/preview.js Normal file
View File

@ -0,0 +1,7 @@
/**
* Checks if we're in preview mode (?preview=1).
*/
export function isPreview () {
return window.location.search.indexOf('preview=1') !== -1
}

29
_js/helpers/store.js Normal file
View File

@ -0,0 +1,29 @@
/**
* Updates a local storage key. If it doesn't exist, it defaults to an empty
* object.
*
* @example
* update('dismissed', (data) => {
* data.lol = true
* return data
* })
*/
export function update (key, fn) {
if (!window.localStorage) return
let data = JSON.parse(window.localStorage[key] || '{}')
data = fn(data)
window.localStorage[key] = JSON.stringify(data)
}
/**
* Fetches a local storage key.
*
* @example
* const data = fetch('dismissed')
*/
export function fetch (key) {
if (!window.localStorage) return
return JSON.parse(window.localStorage[key] || '{}')
}

View File

@ -3,14 +3,6 @@
*/ */
$(function () { $(function () {
$('[data-js-searchable-item]').each(function () {
const $this = $(this)
const data = $this.data('js-searchable-item')
const words = permutate(data)
$this.attr('data-search-index', words.join(' '))
})
// Propagate item search indices to headers // Propagate item search indices to headers
$('[data-js-searchable-header]').each(function () { $('[data-js-searchable-header]').each(function () {
const $this = $(this) const $this = $(this)
@ -65,100 +57,6 @@ $(function () {
}) })
}) })
/*
* Behavior: Disqus
*/
$(function () {
$('[data-js-disqus]').each(function () {
const $this = $(this)
const data = $this.data('js-disqus')
window.disqus_config = function () {
this.page.url = data.url
this.page.identifier = data.identifier
}
injectDisqus(data.host)
})
})
/*
* Behavior: dismiss button
*/
$(function () {
$('[data-js-dismiss]').each(function () {
var $button = $(this)
var $parent = $button.closest('[data-js-dismissable]')
var id = $parent.data('js-dismissable').id || ''
$button.on('click', function (e) {
Dismiss.setDismissed(id)
e.preventDefault()
$parent.remove()
})
})
$('[data-js-dismissable]').each(function () {
var $this = $(this)
var id = $this.data('js-dismissable').id || ''
const isDismissed = Dismiss.isDismissed(id)
if (isDismissed || window.location.search.indexOf('preview') !== -1) {
$this.remove()
} else {
$this.removeClass('-hide')
}
})
})
/*
* Helper: dismissed
*/
const Dismiss = {
setDismissed: function (id) {
Store.update('dismissed', function (data) {
data[id] = true
return data
})
},
isDismissed: function (id) {
const data = Store.fetch('dismissed')
return data && data[id]
}
}
/*
* Simple LocalStorage shim
*/
const Store = {
update: function (key, fn) {
if (!window.localStorage) return
let data = JSON.parse(window.localStorage[key] || '{}')
data = fn(data)
window.localStorage[key] = JSON.stringify(data)
},
fetch: function (key) {
if (!window.localStorage) return
return JSON.parse(window.localStorage[key] || '{}')
}
}
/*
* Helper: injects disqus
*/
function injectDisqus (host) {
var d = document, s = d.createElement('script')
s.src = 'https://' + host + '/embed.js'
s.setAttribute('data-timestamp', +new Date())
;(d.head || d.body).appendChild(s)
}
/* /*
* Helper for splitting to words * Helper for splitting to words
*/ */
@ -194,40 +92,6 @@ const Search = {
} }
} }
/*
* Permutator
*/
function permutate (data) {
let words = []
if (data.slug) {
words = words.concat(permutateString(data.slug))
}
if (data.category) {
words = words.concat(permutateString(data.category))
}
return words
}
function permutateString (str) {
let words = []
let inputs = splitwords(str)
inputs.forEach(word => {
words = words.concat(permutateWord(word))
})
return words
}
function permutateWord (str) {
let words = []
const len = str.length
for (var i = 1; i <= len; ++i) {
words.push(str.substr(0, i))
}
return words
}
/* /*
* Helper: minimal qs implementation * Helper: minimal qs implementation