Skip to content

Instantly share code, notes, and snippets.

@wangbinyq
Last active October 24, 2016 08:50
Show Gist options
  • Save wangbinyq/3515a6b8c643867915ae7b3fd3e9e104 to your computer and use it in GitHub Desktop.
Save wangbinyq/3515a6b8c643867915ae7b3fd3e9e104 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name autopager
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author wangbin
// @match http://*/*
// @include http*
// @grant none
// ==/UserScript==
(function() {
'use strict'
;function defined(o) {
return o !== undefined && o !== null
}
;function Binding(vm, el, key, binder) {
this.vm = vm
this.el = el
this.key = key
this.binder = binder
if(_.isFunction(binder)) {
this.binder.sync = binder
}
this.bind = this.bind.bind(this)
this.sync = this.sync.bind(this)
this.update = this.update.bind(this)
this.unwatch = watch(this.vm.data, this.key, this.sync)
}
var fn = Binding.prototype
fn.bind = function() {
if(defined(this.binder.bind)) {
this.binder.bind.call(this, this.el)
}
this.sync()
}
fn.unbind = function() {
this.unwatch()
if(defined(this.binder.unbind)) {
this.binder.unbind.call(this, this.el)
}
}
fn.sync = function() {
if(defined(this.binder.sync)) {
this.binder.sync.call(this, this.el, this.value())
})
}
fn.update = function() {
if(defined(this.binder.sync)) {
var value = this.binder.value.call(this, this.el)
this.value(value)
})
}
fn.value = function(r) {
if(r === undefined) {
return this.vm.data[this.key]
} else {
this.vm.data[this.key] = r
}
}
;function ViewModel(el, options) {
this.init(el, options)
}
window.ViewModel = ViewModel
fn = ViewModel.prototype
fn.init = function(el, options) {
this.el = el
this.options = options
this.data = options.data || {}
this.bindings = []
this.compile(this.el)
this.bind()
}
fn.compile = function(el) {
var block = false
if(el.nodeType !== 1) {
return
}
var dataset = el.dataset
for(var data in dataset) {
var binder = ViewModel.binders[data]
var key = dataset[data]
if(binder === undefined) {
binder = ViewModel.binders['*']
}
if(defined(binder)) {
this.bindings.push(new Binding(this, el, key, binder))
}
}
if(!block) {
el.childNodes.forEach((childEl) => {
this.compile(childEl)
})
}
}
fn.bind = function() {
this.bindings.sort((a, b) => {
var aPriority = defined(a.binder) ? (a.binder.priority || 0) : 0
var bPriority = defined(b.binder) ? (b.binder.priority || 0) : 0
return bPriority - aPriority
})
this.bindings.forEach(binding => {
binding.bind()
})
}
fn.unbind = function() {
this.bindins.forEach(binding => {
binding.unbind()
})
}
ViewModel.binders = {
value: {
bind(el) {
el.addEventListener('change', this.update)
},
sync(el, value) {
if(el.type === 'checkbox') {
el.checked = !!value
} else {
el.value = value
}
},
value(el) {
if(el.type === 'checkbox') {
return el.checked
} else {
return el.value
}
}
},
html: {
sync(el, value) {
el.innerHTML = value
}
},
show: {
priority: 2000,
sync(el, value) {
el.style.display = value ? '' : 'none'
}
},
on: {
bind(el) {
el.addEventListener(this.args[0], function() {
if(this.vm.method && this.vm.method[this.key]) {
this.vm.method[this.key].call(this.vm)
}
})
}
},
'*': {
sync(el, value) {
if(defined(value)) {
el.setAttribute(this.args[0], value)
} else {
el.removeAttribute(this.args[0])
}
}
}
}
;function watch(obj, prop, callback) {
if(!callback) {
callback = prop
prop = obj
obj = this
}
var value = obj[prop]
var callbacks = obj.$$callbacks = obj.$$callbacks || {}
var propCallbacks = callbacks[prop] = callbacks[prop] || []
Object.defineProperty(obj, prop, {
get: function(){
return value
},
set: function(newValue){
if(newValue !== value) {
value = newValue
propCallbacks.forEach(function(cb) {
cb()
})
}
}
})
if(propCallbacks.indexOf(callback) === -1) {
propCallbacks.push(callback)
}
return function() {
var index = propCallbacks.indexOf(callback)
propCallbacks.splice(index, 1)
}
}
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment