2017年12月29日 星期五

GreenBackbone view 的 ajax(template | component)


--------------------------------------------------------------------------
// component的例子
<div>
    {{x}}
</div>
<script>
    // 把上面的 html內容傳進 fun
    function(template) {
        return Backbone.BForView.extend({
            templateContent: template
        });
    }
</script>
--------------------------------------------------------------------------
// template的例子
<div>
    {{x}}
</div>
<script>
    function(view) {
          // template mounted
    }
</script>
<script>
    function(view) {
          // template removed    }
</script>
 --------------------------------------------------------------------------
// template 改進
<div>
    {{x}}
</div>
<script>
  
    function() {
         return {
               mounted: fun(view),
               unmouted: fun(view)
              }
    }
</script>

 --------------------------------------------------------------------------

2017年12月23日 星期六

Backbone.Reactive 重要的例子

var d_1 = [{
            age: 12,
            selected: true
        }, {
            age: 1,
            selected: false
        }, {
            age: 2,
            selected: false
        }];
        var d_2 = Backbone.Reactive(d_1, {
            link: function(parent, child) {

                parent.listenTo(child, 'all', function(e, event, options) {
                    debugger;
                    var info = 'parent => ' + event + '|' + JSON.stringify(arguments);

                    for (var i = 0; i < this.value.length; i++) {
                        debugger;
                        var v = this.value[i];
                        var ob = v._bc_ob_;

                        if (v._bc_ob_.cid !== e.target.cid) {
                            ob.triggerOptions = {
                                exclude: [this] // 防止事件無窮回圈
                            }
                            v.selected = false;
                        }
                    }

                    $('#msg_1').html(JSON.stringify(this));
                })
            }
        });
        /*--------------------------*/

        d_2._bc_ob_.on('change', function() {
            var info = 'parent => ' + event + '|' + JSON.stringify(arguments);
            alert(info);
        });

        function set() {

            var index = Math.floor(Math.random() * d_2.length);
            index = (index >= d_2.length ? (d_2.length - 1) : index);
            d_2[index].selected = true;
        }

2017年12月22日 星期五

javascript Map

Properties   
    Map.prototype.size   

Methods
    Map.prototype.clear()

    Map.prototype.delete()

    Map.prototype.entries()

    Map.prototype.forEach()

    Map.prototype.get()

    Map.prototype.has()

    Map.prototype.keys()

    Map.prototype.set()

    Map.prototype.values()

    Map.prototype[@@iterator]()
-----------------------------------------------------------------

範例

區段

使用 Map 物件

區段

var myMap = new Map();

var keyString = 'a string',
    keyObj = {},
    keyFunc = function() {};

// setting the values
myMap.set(keyString, "value associated with 'a string'");
myMap.set(keyObj, 'value associated with keyObj');
myMap.set(keyFunc, 'value associated with keyFunc');

myMap.size; // 3

// getting the values
myMap.get(keyString);    // "value associated with 'a string'"
myMap.get(keyObj);       // "value associated with keyObj"
myMap.get(keyFunc);      // "value associated with keyFunc"

myMap.get('a string');   // "value associated with 'a string'"
                         // because keyString === 'a string'
myMap.get({});           // undefined, because keyObj !== {}
myMap.get(function() {}) // undefined, because keyFunc !== function () {}

使用 NaN 作為 Map 的鍵

區段

NaN can also be used as a key. Even though every NaN is not equal to itself (NaN !== NaN is true), the following example works because NaNs are indistinguishable from each other:
var myMap = new Map();
myMap.set(NaN, 'not a number');

myMap.get(NaN); // "not a number"

var otherNaN = Number('foo');
myMap.get(otherNaN); // "not a number"

透過 for..of 迭代 Maps

區段

Maps can be iterated using a for..of loop:
var myMap = new Map();
myMap.set(0, 'zero');
myMap.set(1, 'one');
for (var [key, value] of myMap) {
  console.log(key + ' = ' + value);
}
// 0 = zero
// 1 = one

for (var key of myMap.keys()) {
  console.log(key);
}
// 0
// 1

for (var value of myMap.values()) {
  console.log(value);
}
// zero
// one

for (var [key, value] of myMap.entries()) {
  console.log(key + ' = ' + value);
}
// 0 = zero
// 1 = one

透過 forEach() 迭代 Maps

區段

Maps can be iterated using the forEach() method:
myMap.forEach(function(value, key) {
  console.log(key + ' = ' + value);
});
// Will show 2 logs; first with "0 = zero" and second with "1 = one"

與 Array 物件關聯

區段

var kvArray = [['key1', 'value1'], ['key2', 'value2']];

// Use the regular Map constructor to transform a 2D key-value Array into a map
var myMap = new Map(kvArray);

myMap.get('key1'); // returns "value1"

// Use the Array.from function to transform a map into a 2D key-value Array
console.log(Array.from(myMap)); // Will show you exactly the same Array as kvArray

// Or use the keys or values iterators and convert them to an array
console.log(Array.from(myMap.keys())); // Will show ["key1", "key2"]

2017年12月11日 星期一

drupal 簡單 model_example

<?php

// $Id$

function gt_site_menu() {

    $items['site/%'] = array(
        'title' => 'test',
        'page callback' => 'goPage',
        'access callback' => true
    );

    return $items;
}

function goPage() {
    $res = theme('home', array());
    return $res;
}

function gt_site_theme() {
    // 取得 gt_site 該 model 的 path
    $path = drupal_get_path('module', 'gt_site');
    $path .= '/themes';

    return array(
        'home' => array(
            'template' => 'home',
            'path' => $path)
    );
}

/**
 * Implements hook_help().
 */

function gt_site_help($path, $arg) {

    $res = array();

    foreach ($_GET as $key => $value) {
        $res[] = sprintf('%s => %s', $key, $value);
    }
   
    $res[] = $path = drupal_get_path('module', 'gt_site');
   
    $res = implode(' | ', $res);

    return t($res);
}

2017年12月5日 星期二

js 筆記

let x = 1;

      y = (++x, ++x);
      console.log(y);

y=3
-----------------------------------------------------------------------------
js 基本類型

boolean, number, string, undefined
null is object
-----------------------------------------------------------------------------

js一些預設方法

 

string.slice(s, e), array.slice(s, e) => slice(切片) 

string.split(符號) 分割成 array => split (分裂)

array.splice(s, l, data_1, data_2)=>splice (拼接)



string.match() => //正則是否用/g差別很大,/g將不顯示捕獲組,但會將符合的化為 array
regular.exec()

以 proxy 為主的 react 只適用於 backbone

(function (Backbone) {
    var hasProto = ('__proto__' in {});
    /*========================================================================*/
    //    debugger;

    var arrayProto = Array.prototype;
    var arrayMethods = Object.create(arrayProto);

    var arrayMethodsNameList = [
        'push',
        'pop',
        'shift',
        'unshift',
        'splice',
        'sort',
        'reverse'
    ];

    (function () {
        arrayMethodsNameList.forEach(function (method) {

            // cache original method
            var original = arrayProto[method];

            def(arrayMethods, method, function mutator() {
                debugger;
                var ob = this._bc_ob_;

                ob.arrayMethod = method;

                var args = [];
                var len = arguments.length;
                var canTrigger = true;

                while (len--) {
                    args[len] = arguments[len];
                }
                // 遇到 [undefined].pop() 會出問題
                var result = original.apply(this, args);

                var add = [];
                var remove = [];

                debugger;

                switch (method) {
                    case 'push':
                    case 'unshift':
                        add = args;
                        break;
                    case 'pop':
                    case 'shift':
                        remove = result;
                        break;
                    case 'splice':
                        add = args.slice(2);
                        remove = result;
                        break;
                }

                if (!Array.isArray(add)) {
                    add = (add === undefined ? [] : [add]);
                }

                if (!Array.isArray(remove)) {
                    remove = (remove === undefined ? [] : [remove]);
                }
                // 為了 proxy 而設
                ob.arrayMethod = '';

                ob.notify_1([method], {
                    add: add,
                    remove: remove,
                    key: undefined
                });


                return result;
            });
        });
    })();

    var arrayKeys = Object.getOwnPropertyNames(arrayMethods);

    /*========================================================================*/
    // Define a property
    // 預設是不可枚舉
    function def(obj, key, val, enumerable) {
        Object.defineProperty(obj, key, {
            value: val,
            enumerable: !!enumerable,
            writable: true,
            configurable: true
        });
    };
    /*========================================================================*/
    function hasOwn(obj, key) {
        return Object.prototype.hasOwnProperty.call(obj, key);
    }
    /*========================================================================*/
    /**
     * Quick object check - this is primarily used to tell
     * Objects from primitive values when we know the value
     * is a JSON-compliant type.
     */
    function isObject(obj) {
        return (obj !== null && typeof obj === 'object');
    }
    /*========================================================================*/
    // Augment an target Object or Array by intercepting
    // the prototype chain using __proto__
    function protoAugment(target, src, keys) {
        /* eslint-disable no-proto */
        target.__proto__ = src;
        /* eslint-enable no-proto */
    };
    /*========================================================================*/
    // Augment an target Object or Array by defining
    // hidden properties.
    function copyAugment(target, src, keys) {
        debugger;
        for (var i = 0, l = keys.length; i < l; i++) {
            var key = keys[i];
            def(target, key, src[key]);
        }
    };
    /*========================================================================*/
    /**
     * Attempt to create an observer instance for a value,
     * returns the new observer if successfully observed,
     * or the existing observer if the value already has one.
     */
    function _observe(value, parent) {
        debugger;
        if (!isObject(value)) {
            return value;
        }
        var ob;
        if (hasOwn(value, '_bc_ob_') && value._bc_ob_ instanceof Backbone.Observer) {
            ob = value._bc_ob_;

        } else if ((Array.isArray(value) || _.isPlainObject(value)) && Object.isExtensible(value)) {
            value = Backbone.Reactive(value, parent.options);
            ob = value._bc_ob_;
        }

        ob.$link(parent);

        return value;
    }


    ////////////////////////////////////////////////////////////////////////////
    Backbone.$buildBackbone(factory);
    ////////////////////////////////////////////////////////////////////////////
    //
    // Backbone.Reactive
    //
    // 事件有(sort, update, remove(model發出), reset)
    //
    ////////////////////////////////////////////////////////////////////////////
    function factory(root, Backbone, _, $) {
        // here
        Backbone.Reactive = makeDataReactive;

        function makeDataReactive(value, options) {
            // debugger;


            if (value == null || (typeof value !== 'object')) {
                throw new Error('cant be observer');
            }
            /*--------------------------*/
            var observe = new Backbone.Observer(value, options);

            def(value, '_bc_ob_', observe);

            // debugger;
            /*--------------------------*/

            var proxy;
            if (Array.isArray(value)) {
                var augment = hasProto ? protoAugment : copyAugment;

                // 替換 [] 的原型方法
                augment(value, arrayMethods, arrayKeys);

                // 插入 proxy
                proxy = new Proxy(value, {
                    set: function (target, key, value, p) {
                        debugger;

                        var ob = target._bc_ob_;
                        var eventName = 'change';
                        var eventNameList = [];

                        var _value = _observe(value, ob);
                        /*====================================*/
                        if (key === 'length') {
                            eventName = 'reset';
                        }
                        /*====================================*/
                        target[key] = _value;

                        eventNameList.push(eventName);

                        if (ob.arrayMethod) {
                            eventNameList.push(ob.arrayMethod);
                        }
                        /*--------------------------*/
                        if (!ob.arrayMethod) {
                            ob.notify_2(key, eventNameList, {
                                key: key,
                                add: [],
                                remove: []
                            });
                        }

                        return true;
                    }
                });

                observe.proxy = proxy;
                observe.$walkArray(value);

            } else {
                proxy = new Proxy(value, {
                    set: function (t, k, v, p) {
                        debugger;

                        var ob = t._bc_ob_;
                        var prevValue = t[k];

                        var newValue = _observe(v, ob);
                        t[k] = newValue

                        ob.notify_2(t, ['change'], {
                            key: k
                        });

                        return true;
                    }
                });
                observe.proxy = proxy;
                observe.$walkPlainObject(value);
            }
            return proxy;
        }
        ////////////////////////////////////////////////////////////////////////
        (function (fn) {
            fn.del = function () {

            };
        })(makeDataReactive);
        ////////////////////////////////////////////////////////////////////////////
        //
        // 數據的背後觀察者
        // 放在數據的(_bc_ob_)裏,並且不可枚舉
        //
        // 要加入 controller 找數據底下的 _bc_ob_
        //
        ////////////////////////////////////////////////////////////////////////////
        Backbone.Observer = Observer;

        function Observer(value, options) {
            this.cid = _.uniqueId('observer');
            /*--------------------------*/
            this.triggerOptions = {};
            /*--------------------------*/
            this.$linkParent = new Map();
            /*--------------------------*/
            this.proxy;
            this.value; // 只能是 object
            this.prevValue;
            /*--------------------------*/
            this.keys = []; // 偵測 remove
            this.prevKeys = [];
            /*--------------------------*/
            this.$listenerList = [];
            this.arrayMethod = '';
            this.eventName; // 只有是 array 的方法才會用到
            this.options = {};
            /*--------------------------*/
            this.$prevChildList = [];
            (function () {
                // debugger;

                this.options = options || {};

                this.value = value;
                this.keys = Object.keys(this.value);

                this.$cloneValue();
            }).call(this);
        };

        _.extend(Observer.prototype, Backbone.Events);

        ////////////////////////////////////////////////////////////////////////

        (function () {

            // proxy
            this.$walkPlainObject = function (obj) {

                var observe = obj._bc_ob_;

                for (var key in obj) {
                    var child = obj[key];
                    var newValue = _observe(child, observe);
                    obj[key] = newValue
                }
            };
            /*====================================================================*/
            /**
             * Observer a list of Array items.
             */
            this.$walkArray = function observeArray(items) {
                var observe = items._bc_ob_;
                for (var i = 0, l = items.length; i < l; i++) {

                    var child = items[i];
                    var newValue = _observe(child, observe);
                    items[i] = newValue;
                }
            };
            /*================================================================*/


        }).call(Observer.prototype);


        (function () {
            this.$link = function (parent) {
                // debugger;

                if (!this.$linkParent.has(parent) && this.options.link) {
                    this.$linkParent.set(parent, true);
                    this.options.link.call(this, parent, this);
                }
            };

            /*====================================================================*/
            this.$cloneValue = function () {
                // debugger;
                if (Array.isArray(this.value)) {
                    this.prevValue = this.value.slice();
                } else {
                    this.prevValue = _.extend({}, this.value);
                }

                this.prevKeys = Object.keys(this.value);
            };
            /*====================================================================*/
            this.notify_1 = function (eventList, options) {

                this.keys = Object.keys(this.value);

                this._$notify_1(eventList, options);

                this.$cloneValue();

                this.reset();
            };
            /*====================================================================*/
            // call by item
            this.notify_2 = function (key, eventList, options) {
                this.keys = Object.keys(this.value);

                this._$notify_2(key, eventList, options);

                if (!this.arrayMethod) {
                    this.$cloneValue();
                }

                this.reset();
            }
            /*====================================================================*/
            // options =>(key, add, remove)

            this._$notify_1 = function (eventList, options) {
                debugger;

                options = options || {};
                options.eventList = eventList;

                var add = options.add || [];
                var remove = options.remove || [];
                var key = options.key;
                /*--------------------------*/
                var triggerEventName = '';

                // arrayMethod

                if ((eventList.indexOf('sort') >= 0) || (eventList.indexOf('reverse') >= 0)) {
                    // sort, reverse
                    triggerEventName = 'sort';
                } else {
                    triggerEventName = 'update';
                }
                /*--------------------------*/
                var changePosition = [];
                var wantTrigger = this.$compareAllValue(changePosition);

                /*--------------------------*/
                if (!wantTrigger) {
                    return;
                }
                /*--------------------------*/
                remove.forEach(function (value, key) {
                    debugger;

                    if (_.isPlainObject(value) && (typeof value._bc_ob_ !== 'undefined')) {
                        var ob = value._bc_ob_;
                        ob.remove(this.triggerOptions, options);
                    }
                }, this);
                /*--------------------------*/
                options.changePosition = changePosition;

                // 通知 controller
                this.$notifyListener(this.triggerOptions, triggerEventName, options);

                // 通知其他註冊者
                this.trigger(this.triggerOptions, triggerEventName, options);
            };
            /*====================================================================*/
            this._$notify_2 = function (key, eventList, options) {
                debugger;

                options = options || {};
                options.eventList = eventList;

                var add = options.add || [];
                var remove = options.remove || [];
                var key = options.key;
                var wantTrigger = true;
                /*--------------------------*/
                var triggerEventName = '';


                // item發起
                if (eventList.indexOf('change') >= 0) {

                    if ((eventList.indexOf('sort') >= 0) || (eventList.indexOf('reverse') >= 0)) {
                        wantTrigger = false;
                    } else {
                        triggerEventName = 'change';
                    }

                } else if (eventList.indexOf('reset') >= 0) {
                    triggerEventName = 'reset';
                    remove = remove.concat(this.prevValue);
                }
                /*--------------------------*/
                if (!wantTrigger) {
                    return;
                }

                if (this.arrayMethod) {
                    return;
                }

                var _remove = [];

                if (key === 'length') {
                    this.$compareAllValue(_remove);
                } else {
                    wantTrigger = this.$compareValue(key, _remove);
                }

                /*--------------------------*/
                if (!wantTrigger) {
                    return;
                }
                /*--------------------------*/
                _remove.forEach(function (_k, key) {
                    debugger;
                    var value = this.prevValue[_k];

                    if (_.isPlainObject(value) && (typeof value._bc_ob_ !== 'undefined')) {
                        var ob = value._bc_ob_;
                        ob.remove(this.triggerOptions, options);
                    }
                }, this);
                /*--------------------------*/
                options.changePosition = _remove;

                // 通知 controller
                this.$notifyListener(this.triggerOptions, triggerEventName, options);

                // 通知其他註冊者
                this.trigger(this.triggerOptions, triggerEventName, options);
            };

            /*====================================================================*/
            this.toJSON = function () {
                return this.proxy;
            };
            /*================================================================*/
            this.remove = function (e, options) {
                debugger;


                // 叫那些 controller
                this.$notifyListener(e, 'remove');
                this.$listenerList.length = 0;

                // 叫那些跟隨者
                this.trigger(e, 'remove', {});

                this.stopListening();
                this.off();
            };
            /*================================================================*/
            this.reset = function () {
                // debugger;

                if (!this.arrayMethod) {
                    this.triggerOptions = {};
                }
            };
            /*====================================================================*/
            this.$compareAllValue = function (remove) {
                // debugger;


                /*--------------------------*/
                var wantTriggerList = [];

                if (Array.isArray(this.value)) {

                    var length = ((this.prevValue.length - this.value.length > 0) ? this.prevValue.length : this.value.length);

                    for (var i = 0; i < length; i++) {
                        debugger;
                        var wantTrigger = this.$compareValue(i, remove);
                        if (wantTrigger) {
                            wantTriggerList.push(i);
                        }
                    }
                } else {
                    var keyLMap = {};

                    this.keys.forEach(function (k) {
                        keyLMap[k] = true;
                    });

                    this.prevKeys.forEach(function (k) {
                        keyLMap[k] = true;
                    });

                    for (var key in keyLMap) {
                        debugger;
                        var wantTrigger = this.$compareValue(key, remove);
                        if (wantTrigger) {
                            wantTriggerList.push(i);
                        }
                    }
                }
                /*--------------------------*/
                if (wantTriggerList.length || remove.length) {
                    return true;
                } else {
                    return false;
                }

            };
            /*====================================================================*/
            this.$compareValue = function (key, remove) {
                // debugger;

                var wantTrigger = false;

                var prev = this.prevValue[key];
                var current = this.value[key];


                if (typeof prev !== typeof current) {
                    wantTrigger = true;

                    remove.push(key);

                } else if ((prev == null && current == null) ||
                    (typeof prev._bc_ob_ === 'undefined' && typeof current._bc_ob_ === 'undefined')) {
                    // 都是簡單數據

                    if (!_.isEqual(prev, current)) {
                        wantTrigger = true;
                        remove.push(key);
                    }


                } else if (prev != null && current != null &&
                    typeof prev._bc_ob_ !== 'undefined' &&
                    typeof current._bc_ob_ !== 'undefined') {
                    // 都不是簡單數據

                    if (prev._bc_ob_.cid !== current._bc_ob_.cid) {
                        wantTrigger = true;
                        remove.push(key);
                    }

                } else {
                    wantTrigger = true;
                    remove.push(key);
                }
                return wantTrigger;
            };
            /*====================================================================*/

            this.$addListener = function (controller) {
                this.$listenerList.push(controller);
            };
            /*====================================================================*/
            this.$removeListener = function (controller) {
                if (controller == null) {
                    this.$listenerList.length = 0;
                    return;
                }

                var remain = [];

                for (var i = 0, c; c = this.$listenerList[i]; i++) {
                    if (c.cid === controller.cid) {
                        continue;
                    }
                    remain.push(c);
                }
                this.$listenerList = remain;
            };
            /*====================================================================*/
            this.$notifyListener = function (e, eventName, options) {
                this.$listenerList.forEach(function (c, index) {
                    c.update(e, eventName, options);
                }, this);
            };
        }).call(Observer.prototype);
    }

})(Backbone);