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.

Revisions

  1. wangbinyq revised this gist Oct 24, 2016. 1 changed file with 0 additions and 11 deletions.
    11 changes: 0 additions & 11 deletions mvvm.js
    Original file line number Diff line number Diff line change
    @@ -1,14 +1,3 @@
    // ==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'

  2. wangbinyq revised this gist Oct 24, 2016. 1 changed file with 55 additions and 43 deletions.
    98 changes: 55 additions & 43 deletions mvvm.js
    Original file line number Diff line number Diff line change
    @@ -1,48 +1,59 @@
    // ==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';
    'use strict'

    function defined(o) {
    return o !== undefined && o !== null;
    ;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;
    ;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.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);
    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;
    var fn = Binding.prototype
    fn.bind = function() {
    if(defined(this.binder.bind)) {
    this.binder.bind.call(this, this.el);
    this.binder.bind.call(this, this.el)
    }
    this.sync();
    };
    this.sync()
    }
    fn.unbind = function() {
    this.unwatch();
    this.unwatch()
    if(defined(this.binder.unbind)) {
    this.binder.unbind.call(this, this.el);
    this.binder.unbind.call(this, this.el)
    }
    };
    }
    fn.sync = function() {
    if(defined(this.binder.sync)) {
    this.binder.sync.call(this, this.el, this.value());
    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);
    var value = this.binder.value.call(this, this.el)
    this.value(value)
    })
    }
    fn.value = function(r) {
    @@ -54,22 +65,23 @@
    }


    function ViewModel(el, options) {
    ;function ViewModel(el, options) {
    this.init(el, options)
    }

    window.ViewModel = ViewModel

    fn = ViewModel.prototype;
    fn = ViewModel.prototype

    fn.init = function(el, options) {
    this.el = el;
    this.options = options;
    this.data = options.data || {};
    this.bindings = [];
    this.el = el
    this.options = options
    this.data = options.data || {}
    this.bindings = []

    this.compile(this.el);
    this.bind();
    };
    this.compile(this.el)
    this.bind()
    }

    fn.compile = function(el) {
    var block = false
    @@ -97,7 +109,7 @@
    this.compile(childEl)
    })
    }
    };
    }

    fn.bind = function() {
    this.bindings.sort((a, b) => {
    @@ -156,7 +168,7 @@
    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);
    this.vm.method[this.key].call(this.vm)
    }
    })
    }
    @@ -173,14 +185,14 @@
    }
    }

    function watch(obj, prop, callback) {
    ;function watch(obj, prop, callback) {
    if(!callback) {
    callback = prop;
    prop = obj;
    obj = this;
    callback = prop
    prop = obj
    obj = this
    }

    var value = obj[prop];
    var value = obj[prop]
    var callbacks = obj.$$callbacks = obj.$$callbacks || {}
    var propCallbacks = callbacks[prop] = callbacks[prop] || []

    @@ -204,9 +216,9 @@
    }

    return function() {
    var index = propCallbacks.indexOf(callback);
    propCallbacks.splice(index, 1);
    var index = propCallbacks.indexOf(callback)
    propCallbacks.splice(index, 1)
    }
    };
    }

    })();
    })()
  3. wangbinyq created this gist Oct 24, 2016.
    212 changes: 212 additions & 0 deletions mvvm.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,212 @@
    (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)
    }


    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);
    }
    };

    })();