<commit_before>import Animate from '../mixin/animate';
import Class from '../mixin/class';
import {$$, addClass, after, assign, append, attr, before, clamp, css, getEventPos, height, includes, index, isEmpty, isInput, offset, off, on, pointerDown, pointerMove, pointerUp, remove, removeClass, scrollTop, toggleClass, toNodes, trigger, within} from 'uikit-util';

export default {

    mixins: [Class, Animate],

    props: {
        group: String,
        threshold: Number,
        clsItem: String,
        clsPlaceholder: String,
        clsDrag: String,
        clsDragState: String,
        clsBase: String,
        clsNoDrag: String,
        clsEmpty: String,
        clsCustom: String,
        handle: String
    },

    data: {
        group: false,
        threshold: 5,
        clsItem: 'uk-sortable-item',
        clsPlaceholder: 'uk-sortable-placeholder',
        clsDrag: 'uk-sortable-drag',
        clsDragState: 'uk-drag',
        clsBase: 'uk-sortable',
        clsNoDrag: 'uk-sortable-nodrag',
        clsEmpty: 'uk-sortable-empty',
        clsCustom: '',
        handle: false
    },

    created() {
        ['init', 'start', 'move', 'end'].forEach(key => {
            const fn = this[key];
            this[key] = e => {
                this.scrollY = window.pageYOffset;
                const {x, y} = getEventPos(e, 'page');
                this.pos = {x, y};

                fn(e);
            };
        });
    },

    events: {

        name: pointerDown,
        passive: false,
        handler: 'init'

    },

    update: {

        write() {

            if (this.clsEmpty) {
                toggleClass(this.$el, this.clsEmpty, isEmpty(this.$el.children));
            }

            css(this.handle ? $$(this.handle, this.$el) : this.$el.children, {touchAction: 'none', userSelect: 'none'});

            if (this.drag) {

                // clamp to viewport
                const {right, bottom} = offset(window);
                offset(this.drag, {
                    top: clamp(this.pos.y + this.origin.top, 0, bottom - this.drag.offsetHeight),
                    left: clamp(this.pos.x + this.origin.left, 0, right - this.drag.offsetWidth)
                });

                trackScroll(this.pos);

            }

        }

    },

    methods: {

        init(e) {

            const {target, button, defaultPrevented} = e;
            const [placeholder] = toNodes(this.$el.children).filter(el => within(target, el));

            if (!placeholder
                || defaultPrevented
                || button > 0
                || isInput(target)
                || within(target, `.${this.clsNoDrag}`)
                || this.handle && !within(target, this.handle)
            ) {
                return;
            }

            e.preventDefault();

            this.touched = [this];
            this.placeholder = placeholder;
            this.origin = assign({target, index: index(placeholder)}, this.pos);

            on(document, pointerMove, this.move);
            on(document, pointerUp, this.end);
            on(window, 'scroll', this.scroll);

            if (!this.threshold) {
                this.start(e);
            }

        },

        start(e) {

            this.drag = append(this.$container, this.placeholder.outerHTML.replace(/^<li/i, '<div').replace(/li>$/i, 'div>'));

            css(this.drag, assign({
                boxSizing: 'border-box',
                width: this.placeholder.offsetWidth,
                height: this.placeholder.offsetHeight,
                overflow: 'hidden'
            }, css(this.placeholder, ['paddingLeft', 'paddingRight', 'paddingTop', 'paddingBottom'])));
            attr(this.drag, 'uk-no-boot', '');
            addClass(this.drag, this.clsDrag, this.clsCustom);

            height(this.drag.firstElementChild, height(this.placeholder.firstElementChild));

            const {left, top} = offset(this.placeholder);
            assign(this.origin, {left: left - this.pos.x, top: top - this.pos.y});

            addClass(this.placeholder, this.clsPlaceholder);
            addClass(this.$el.children, this.clsItem);
            addClass(document.documentElement, this.clsDragState);

            trigger(this.$el, 'start', [this, this.placeholder]);

            this.move(e);
        },

        move(e) {

            if (!this.drag) {

                if (Math.abs(this.pos.x - this.origin.x) > this.threshold || Math.abs(this.pos.y - this.origin.y) > this.threshold) {
                    this.start(e);
                }

                return;
            }

            this.$emit();

            let target = e.type === 'mousemove' ? e.target : document.elementFromPoint(this.pos.x - window.pageXOffset, this.pos.y - window.pageYOffset);

            const sortable = this.getSortable(target);
            const previous = this.getSortable(this.placeholder);
            const move = sortable !== previous;

            if (!sortable || within(target, this.placeholder) || move && (!sortable.group || sortable.group !== previous.group)) {
                return;
            }

            target = sortable.$el === target.parentNode && target || toNodes(sortable.$el.children).filter(element => within(target, element))[0];

            if (move) {
                previous.remove(this.placeholder);
            } else if (!target) {
                return;
            }

            sortable.insert(this.placeholder, target);

            if (!includes(this.touched, sortable)) {
                this.touched.push(sortable);
            }

        },

        end(e) {

            off(document, pointerMove, this.move);
            off(document, pointerUp, this.end);
            off(window, 'scroll', this.scroll);

            if (!this.drag) {
                if (e.type === 'touchend') {
                    e.target.click();
                }

                return;
            }

            untrackScroll();

            const sortable = this.getSortable(this.placeholder);

            if (this === sortable) {
                if (this.origin.index !== index(this.placeholder)) {
                    trigger(this.$el, 'moved', [this, this.placeholder]);
                }
            } else {
                trigger(sortable.$el, 'added', [sortable, this.placeholder]);
                trigger(this.$el, 'removed', [this, this.placeholder]);
            }

            trigger(this.$el, 'stop', [this, this.placeholder]);

            remove(this.drag);
            this.drag = null;

            const classes = this.touched.map(sortable => `${sortable.clsPlaceholder} ${sortable.clsItem}`).join(' ');
            this.touched.forEach(sortable => removeClass(sortable.$el.children, classes));

            removeClass(document.documentElement, this.clsDragState);

        },

        scroll() {
            const scroll = window.pageYOffset;
            if (scroll !== this.scrollY) {
                this.pos.y += scroll - this.scrollY;
                this.scrollY = scroll;
                this.$emit();
            }
        },

        insert(element, target) {

            addClass(this.$el.children, this.clsItem);

            const insert = () => {

                if (target) {

                    if (!within(element, this.$el) || isPredecessor(element, target)) {
                        before(target, element);
                    } else {
                        after(target, element);
                    }

                } else {
                    append(this.$el, element);
                }

            };

            if (this.animation) {
                this.animate(insert);
            } else {
                insert();
            }

        },

        remove(element) {

            if (!within(element, this.$el)) {
                return;
            }

            css(this.handle ? $$(this.handle, element) : element, {touchAction: '', userSelect: ''});

            if (this.animation) {
                this.animate(() => remove(element));
            } else {
                remove(element);
            }

        },

        getSortable(element) {
            return element && (this.$getComponent(element, 'sortable') || this.getSortable(element.parentNode));
        }

    }

};

function isPredecessor(element, target) {
    return element.parentNode === target.parentNode && index(element) > index(target);
}

let trackTimer;
function trackScroll({x, y}) {

    clearTimeout(trackTimer);

    scrollParents(document.elementFromPoint(x - window.pageXOffset, y - window.pageYOffset)).some(scrollEl => {

        let {scrollTop: scroll, scrollHeight} = scrollEl;

        if (getScrollingElement() === scrollEl) {
            scrollEl = window;
            scrollHeight -= window.innerHeight;
        }

        const {top, bottom} = offset(scrollEl);

        if (top < y && top + 30 > y) {
            scroll -= 5;
        } else if (bottom > y && bottom - 20 < y) {
            scroll += 5;
        }

        if (scroll > 0 && scroll < scrollHeight) {
            return trackTimer = setTimeout(() => {
                scrollTop(scrollEl, scroll);
                trackScroll({x, y});
            }, 10);
        }

    });

}

function untrackScroll() {
    clearTimeout(trackTimer);
}

const overflowRe = /(auto|scroll)/;

function scrollParents(element) {
    const scrollEl = getScrollingElement();
    return parents(element, parent => parent === scrollEl || overflowRe.test(css(parent, 'overflow')));
}

function parents(element, fn) {
    const parents = [];
    do {
        if (fn(element)) {
            parents.unshift(element);
        }
    } while (element && (element = element.parentElement));
    return parents;
}

function getScrollingElement() {
    return document.scrollingElement || document.documentElement;
}
<commit_msg>cleanup<commit_after>import Animate from '../mixin/animate';
import Class from '../mixin/class';
import {$$, addClass, after, assign, append, attr, before, clamp, css, getEventPos, height, includes, index, isEmpty, isInput, offset, off, on, pointerDown, pointerMove, pointerUp, remove, removeClass, scrollTop, toggleClass, toNodes, trigger, within} from 'uikit-util';

export default {

    mixins: [Class, Animate],

    props: {
        group: String,
        threshold: Number,
        clsItem: String,
        clsPlaceholder: String,
        clsDrag: String,
        clsDragState: String,
        clsBase: String,
        clsNoDrag: String,
        clsEmpty: String,
        clsCustom: String,
        handle: String
    },

    data: {
        group: false,
        threshold: 5,
        clsItem: 'uk-sortable-item',
        clsPlaceholder: 'uk-sortable-placeholder',
        clsDrag: 'uk-sortable-drag',
        clsDragState: 'uk-drag',
        clsBase: 'uk-sortable',
        clsNoDrag: 'uk-sortable-nodrag',
        clsEmpty: 'uk-sortable-empty',
        clsCustom: '',
        handle: false
    },

    created() {
        ['init', 'start', 'move', 'end'].forEach(key => {
            const fn = this[key];
            this[key] = e => {
                this.scrollY = window.pageYOffset;
                const {x, y} = getEventPos(e, 'page');
                this.pos = {x, y};

                fn(e);
            };
        });
    },

    events: {

        name: pointerDown,
        passive: false,
        handler: 'init'

    },

    update: {

        write() {

            if (this.clsEmpty) {
                toggleClass(this.$el, this.clsEmpty, isEmpty(this.$el.children));
            }

            css(this.handle ? $$(this.handle, this.$el) : this.$el.children, {touchAction: 'none', userSelect: 'none'});

            if (this.drag) {

                // clamp to viewport
                const {right, bottom} = offset(window);
                offset(this.drag, {
                    top: clamp(this.pos.y + this.origin.top, 0, bottom - this.drag.offsetHeight),
                    left: clamp(this.pos.x + this.origin.left, 0, right - this.drag.offsetWidth)
                });

                trackScroll(this.pos);

            }

        }

    },

    methods: {

        init(e) {

            const {target, button, defaultPrevented} = e;
            const [placeholder] = toNodes(this.$el.children).filter(el => within(target, el));

            if (!placeholder
                || defaultPrevented
                || button > 0
                || isInput(target)
                || within(target, `.${this.clsNoDrag}`)
                || this.handle && !within(target, this.handle)
            ) {
                return;
            }

            e.preventDefault();

            this.touched = [this];
            this.placeholder = placeholder;
            this.origin = assign({target, index: index(placeholder)}, this.pos);

            on(document, pointerMove, this.move);
            on(document, pointerUp, this.end);
            on(window, 'scroll', this.scroll);

            if (!this.threshold) {
                this.start(e);
            }

        },

        start(e) {

            this.drag = append(this.$container, this.placeholder.outerHTML.replace(/^<li/i, '<div').replace(/li>$/i, 'div>'));

            css(this.drag, assign({
                boxSizing: 'border-box',
                width: this.placeholder.offsetWidth,
                height: this.placeholder.offsetHeight,
                overflow: 'hidden'
            }, css(this.placeholder, ['paddingLeft', 'paddingRight', 'paddingTop', 'paddingBottom'])));
            attr(this.drag, 'uk-no-boot', '');
            addClass(this.drag, this.clsDrag, this.clsCustom);

            height(this.drag.firstElementChild, height(this.placeholder.firstElementChild));

            const {left, top} = offset(this.placeholder);
            assign(this.origin, {left: left - this.pos.x, top: top - this.pos.y});

            addClass(this.placeholder, this.clsPlaceholder);
            addClass(this.$el.children, this.clsItem);
            addClass(document.documentElement, this.clsDragState);

            trigger(this.$el, 'start', [this, this.placeholder]);

            this.move(e);
        },

        move(e) {

            if (!this.drag) {

                if (Math.abs(this.pos.x - this.origin.x) > this.threshold || Math.abs(this.pos.y - this.origin.y) > this.threshold) {
                    this.start(e);
                }

                return;
            }

            this.$emit();

            let target = e.type === 'mousemove' ? e.target : document.elementFromPoint(this.pos.x - window.pageXOffset, this.pos.y - window.pageYOffset);

            const sortable = this.getSortable(target);
            const previous = this.getSortable(this.placeholder);
            const move = sortable !== previous;

            if (!sortable || within(target, this.placeholder) || move && (!sortable.group || sortable.group !== previous.group)) {
                return;
            }

            target = sortable.$el === target.parentNode && target || toNodes(sortable.$el.children).filter(element => within(target, element))[0];

            if (move) {
                previous.remove(this.placeholder);
            } else if (!target) {
                return;
            }

            sortable.insert(this.placeholder, target);

            if (!includes(this.touched, sortable)) {
                this.touched.push(sortable);
            }

        },

        end(e) {

            off(document, pointerMove, this.move);
            off(document, pointerUp, this.end);
            off(window, 'scroll', this.scroll);

            if (!this.drag) {
                if (e.type === 'touchend') {
                    e.target.click();
                }

                return;
            }

            untrackScroll();

            const sortable = this.getSortable(this.placeholder);

            if (this === sortable) {
                if (this.origin.index !== index(this.placeholder)) {
                    trigger(this.$el, 'moved', [this, this.placeholder]);
                }
            } else {
                trigger(sortable.$el, 'added', [sortable, this.placeholder]);
                trigger(this.$el, 'removed', [this, this.placeholder]);
            }

            trigger(this.$el, 'stop', [this, this.placeholder]);

            remove(this.drag);
            this.drag = null;

            const classes = this.touched.map(sortable => `${sortable.clsPlaceholder} ${sortable.clsItem}`).join(' ');
            this.touched.forEach(sortable => removeClass(sortable.$el.children, classes));

            removeClass(document.documentElement, this.clsDragState);

        },

        scroll() {
            const scroll = window.pageYOffset;
            if (scroll !== this.scrollY) {
                this.pos.y += scroll - this.scrollY;
                this.scrollY = scroll;
                this.$emit();
            }
        },

        insert(element, target) {

            addClass(this.$el.children, this.clsItem);

            const insert = () => {

                if (target) {

                    if (!within(element, this.$el) || isPredecessor(element, target)) {
                        before(target, element);
                    } else {
                        after(target, element);
                    }

                } else {
                    append(this.$el, element);
                }

            };

            if (this.animation) {
                this.animate(insert);
            } else {
                insert();
            }

        },

        remove(element) {

            if (!within(element, this.$el)) {
                return;
            }

            css(this.handle ? $$(this.handle, element) : element, {touchAction: '', userSelect: ''});

            if (this.animation) {
                this.animate(() => remove(element));
            } else {
                remove(element);
            }

        },

        getSortable(element) {
            return element && (this.$getComponent(element, 'sortable') || this.getSortable(element.parentNode));
        }

    }

};

function isPredecessor(element, target) {
    return element.parentNode === target.parentNode && index(element) > index(target);
}

let trackTimer;
function trackScroll({x, y}) {

    clearTimeout(trackTimer);

    scrollParents(document.elementFromPoint(x - window.pageXOffset, y - window.pageYOffset)).some(scrollEl => {

        let {scrollTop: scroll, scrollHeight} = scrollEl;

        if (getScrollingElement() === scrollEl) {
            scrollEl = window;
            scrollHeight -= window.innerHeight;
        }

        const {top, bottom} = offset(scrollEl);

        if (top < y && top + 30 > y) {
            scroll -= 5;
        } else if (bottom > y && bottom - 20 < y) {
            scroll += 5;
        }

        if (scroll > 0 && scroll < scrollHeight) {
            return trackTimer = setTimeout(() => {
                scrollTop(scrollEl, scroll);
                trackScroll({x, y});
            }, 10);
        }

    });

}

function untrackScroll() {
    clearTimeout(trackTimer);
}

const overflowRe = /auto|scroll/;

function scrollParents(element) {
    const scrollEl = getScrollingElement();
    return parents(element, parent => parent === scrollEl || overflowRe.test(css(parent, 'overflow')));
}

function parents(element, fn) {
    const parents = [];
    do {
        if (fn(element)) {
            parents.unshift(element);
        }
    } while (element && (element = element.parentElement));
    return parents;
}

function getScrollingElement() {
    return document.scrollingElement || document.documentElement;
}
<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc function
 * @name Pear2Pear.controller:SessionCtrl
 * @description
 * # SessionCtrl
 * Controller of the Pear2Pear
 */
angular.module('Pear2Pear')
  .config(['$routeProvider', function($routeProvider) {
    $routeProvider.
      when('/session/new', {
        templateUrl: 'session/new.html',
        controller:'SessionCtrl'
      })
    .when('/session/userdata',{
      templateUrl: 'session/userdata.html',
      controller:'SessionCtrl'
    });
  }])

  .controller('SessionCtrl', [
    '$scope', '$location', '$route', 'pear', '$timeout',
    function($scope, $location, $route, pear, $timeout) {
    $scope.session = {};

    $scope.loginRegexp = new RegExp('^[a-zA-Z0-9\.]+$');

    $scope.user = {
      nick : ""
    };

    $scope.login = function() {
      var startSession = function(){
        // TODO change password when register is available
        console.log(name);
        pear.startSession(
          $scope.user.nick, pear.users.password,
          function(){
            $timeout(function(){
              if ($route.current.params.redirect) {
                var params = $route.current.params;
                var redirect = $route.current.params.redirect;
                // redirects are of the form /community/:communityId/project/projectId
                var communityId = redirect.split('/')[2];
                pear.communities.setCurrent(communityId);
                delete params.redirect;
                $route.updateParams(params);
                $location.path(redirect);
              }
              else {
                $location.path('/communities');
              }
            });
          },
          function(error){
            console.log(error);
          }
        );
      };
      pear.registerUser($scope.user.nick, '$password$', startSession, startSession);
    };

    // Check for stored session information
    if (pear.users.current() !== null) {
      if (pear.communities.current()){
        $location.path('/communities/' + pear.communities.current() + '/projects');
      } else {
        $location.path('/communities');
      }
    }

    $scope.userData = function () {
      _paq.push(['appendToTrackingUrl', 'new_visit=1']);
      _paq.push(["deleteCookies"]);
      _paq.push(['setCustomVariable', 1, 'gender', $scope.user.gender, 'visit']);
      _paq.push(['setCustomVariable', 2, 'age', $scope.user.age, 'visit']);
      _paq.push(['setCustomVariable', 3, 'role', $scope.user.role, 'visit']);
      _paq.push(['setCustomVariable', 4, 'tech', $scope.user.tech, 'visit']);
      _paq.push(['setCustomVariable', 5, 'community', $scope.user.community, 'visit']);

      // tracker.storeCustomVariablesInCookie();
      _paq.push(['trackEvent', 'UserQuestionaire', 'answer']);
      _paq.push(['trackPageView']);
      if ($route.current.params['redirect']) {
         var redirect = $route.current.params['redirect'];
        $location.path(redirect);
      }
      else if ($route.current.params['predirect']) {
        window.location.href =  $route.current.params['predirect'];
      }
      else {
        $location.path('/timeline');
      }
    };
  }]);
<commit_msg>fix redirect when logged in users<commit_after>'use strict';

/**
 * @ngdoc function
 * @name Pear2Pear.controller:SessionCtrl
 * @description
 * # SessionCtrl
 * Controller of the Pear2Pear
 */
angular.module('Pear2Pear')
  .config(['$routeProvider', function($routeProvider) {
    $routeProvider.
      when('/session/new', {
        templateUrl: 'session/new.html',
        controller:'SessionCtrl'
      })
    .when('/session/userdata',{
      templateUrl: 'session/userdata.html',
      controller:'SessionCtrl'
    });
  }])

  .controller('SessionCtrl', [
    '$scope', '$location', '$route', 'pear', '$timeout',
    function($scope, $location, $route, pear, $timeout) {
    $scope.session = {};

    $scope.loginRegexp = new RegExp('^[a-zA-Z0-9\.]+$');

    $scope.user = {
      nick : ""
    };

    $scope.login = function() {
      var startSession = function(){
        // TODO change password when register is available
        pear.startSession(
          $scope.user.nick, pear.users.password,
          function(){
            $timeout(function(){
              if ($route.current.params.redirect) {
                var params = $route.current.params;
                var redirect = $route.current.params.redirect;
                // redirects are of the form /community/:communityId/project/projectId
                var communityId = redirect.split('/')[2];
                pear.communities.setCurrent(communityId);
                delete params.redirect;
                $route.updateParams(params);
                $location.path(redirect);
              }
              else {
                $location.path('/communities');
              }
            });
          },
          function(error){
            console.log(error);
          }
        );
      };
      pear.registerUser($scope.user.nick, '$password$', startSession, startSession);
    };

    // Check for stored session information
    if (pear.users.current() !== null) {
      if (pear.communities.current() && !$route.current.params.redirect){
        $location.path('/communities/' + pear.communities.current() + '/projects');
      } else {
        $location.path('/communities');
      }
    }

    $scope.userData = function () {
      _paq.push(['appendToTrackingUrl', 'new_visit=1']);
      _paq.push(["deleteCookies"]);
      _paq.push(['setCustomVariable', 1, 'gender', $scope.user.gender, 'visit']);
      _paq.push(['setCustomVariable', 2, 'age', $scope.user.age, 'visit']);
      _paq.push(['setCustomVariable', 3, 'role', $scope.user.role, 'visit']);
      _paq.push(['setCustomVariable', 4, 'tech', $scope.user.tech, 'visit']);
      _paq.push(['setCustomVariable', 5, 'community', $scope.user.community, 'visit']);

      // tracker.storeCustomVariablesInCookie();
      _paq.push(['trackEvent', 'UserQuestionaire', 'answer']);
      _paq.push(['trackPageView']);
      if ($route.current.params['redirect']) {
         var redirect = $route.current.params['redirect'];
        $location.path(redirect);
      }
      else if ($route.current.params['predirect']) {
        window.location.href =  $route.current.params['predirect'];
      }
      else {
        $location.path('/timeline');
      }
    };
  }]);
<|endoftext|>


<commit_before>/* @flow */

const LIFECYCLE_HOOKS = [
  // App
  'onLaunch',
  'onShow',
  'onHide',
  'onUniNViewMessage',
  'onError',
  // Page
  'onLoad',
  // 'onShow',
  'onReady',
  // 'onHide',
  'onUnload',
  'onPullDownRefresh',
  'onReachBottom',
  'onTabItemTap',
  'onShareAppMessage',
  'onResize',
  'onPageScroll',
  'onNavigationBarButtonTap',
  'onBackPress',
  'onNavigationBarSearchInputChanged',
  'onNavigationBarSearchInputConfirmed',
  'onNavigationBarSearchInputClicked',
  'onNavigationBarSearchInputFocusChanged',
  // Component
  // 'onReady', // 兼容旧版本，应该移除该事件
  'onPageShow',
  'onPageHide',
  'onPageResize',
  // 小程序的 created,attached 生命周期(需要在 service 层的 Vue 内核 mounted 时触发,因小程序 created 可以使用 selectComponent)
  'onServiceCreated',
  'onServiceAttached'
]

const KEYS = ['data', 'properties', 'options', 'relations']

function mergeObject (ret, fromVal, key) {
  if (fromVal[key]) {
    Object.assign((ret[key] || (ret[key] = {})), fromVal[key])
  }
}

function mergeArray (toArray, fromArray) {
  toArray.push(...fromArray)
}

function mergeOptions (ret, toVal) {
  KEYS.forEach(key => {
    mergeObject(ret, toVal, key)
  })
  if (toVal.externalClasses) {
    mergeArray((ret.externalClasses || (ret.externalClasses = [])), toVal.externalClasses)
  }
  if (toVal.path) {
    ret.path = toVal.path
  }
}

export function lifecycleMixin (Vue) {
  // fixed vue-class-component
  const oldExtend = Vue.extend
  Vue.extend = function (extendOptions) {
    extendOptions = extendOptions || {}

    const methods = extendOptions.methods
    if (methods) {
      Object.keys(methods).forEach(methodName => {
        if (LIFECYCLE_HOOKS.indexOf(methodName) !== -1) {
          extendOptions[methodName] = methods[methodName]
          delete methods[methodName]
        }
      })
    }

    return oldExtend.call(this, extendOptions)
  }

  const strategies = Vue.config.optionMergeStrategies
  const mergeHook = strategies.created
  LIFECYCLE_HOOKS.forEach(hook => {
    strategies[hook] = mergeHook
  })

  // mp runtime
  strategies.mpOptions = function (toVal, fromVal) {
    // data,properties,options,externalClasses,relations,path
    if (!toVal) {
      return fromVal
    }
    const ret = Object.create(null)
    mergeOptions(ret, toVal)
    if (fromVal) {
      mergeOptions(ret, fromVal)
    }
    return ret
  }
}
<commit_msg>fix(h5): onPageNotFound #1743<commit_after>/* @flow */

const LIFECYCLE_HOOKS = [
  // App
  'onLaunch',
  'onShow',
  'onHide',
  'onUniNViewMessage',
  'onPageNotFound',
  'onError',
  // Page
  'onLoad',
  // 'onShow',
  'onReady',
  // 'onHide',
  'onUnload',
  'onPullDownRefresh',
  'onReachBottom',
  'onTabItemTap',
  'onShareAppMessage',
  'onResize',
  'onPageScroll',
  'onNavigationBarButtonTap',
  'onBackPress',
  'onNavigationBarSearchInputChanged',
  'onNavigationBarSearchInputConfirmed',
  'onNavigationBarSearchInputClicked',
  'onNavigationBarSearchInputFocusChanged',
  // Component
  // 'onReady', // 兼容旧版本，应该移除该事件
  'onPageShow',
  'onPageHide',
  'onPageResize',
  // 小程序的 created,attached 生命周期(需要在 service 层的 Vue 内核 mounted 时触发,因小程序 created 可以使用 selectComponent)
  'onServiceCreated',
  'onServiceAttached'
]

const KEYS = ['data', 'properties', 'options', 'relations']

function mergeObject (ret, fromVal, key) {
  if (fromVal[key]) {
    Object.assign((ret[key] || (ret[key] = {})), fromVal[key])
  }
}

function mergeArray (toArray, fromArray) {
  toArray.push(...fromArray)
}

function mergeOptions (ret, toVal) {
  KEYS.forEach(key => {
    mergeObject(ret, toVal, key)
  })
  if (toVal.externalClasses) {
    mergeArray((ret.externalClasses || (ret.externalClasses = [])), toVal.externalClasses)
  }
  if (toVal.path) {
    ret.path = toVal.path
  }
}

export function lifecycleMixin (Vue) {
  // fixed vue-class-component
  const oldExtend = Vue.extend
  Vue.extend = function (extendOptions) {
    extendOptions = extendOptions || {}

    const methods = extendOptions.methods
    if (methods) {
      Object.keys(methods).forEach(methodName => {
        if (LIFECYCLE_HOOKS.indexOf(methodName) !== -1) {
          extendOptions[methodName] = methods[methodName]
          delete methods[methodName]
        }
      })
    }

    return oldExtend.call(this, extendOptions)
  }

  const strategies = Vue.config.optionMergeStrategies
  const mergeHook = strategies.created
  LIFECYCLE_HOOKS.forEach(hook => {
    strategies[hook] = mergeHook
  })

  // mp runtime
  strategies.mpOptions = function (toVal, fromVal) {
    // data,properties,options,externalClasses,relations,path
    if (!toVal) {
      return fromVal
    }
    const ret = Object.create(null)
    mergeOptions(ret, toVal)
    if (fromVal) {
      mergeOptions(ret, fromVal)
    }
    return ret
  }
}
<|endoftext|>


<commit_before>/**
 * This namespace holds different utilities.
 * @namespace Cocoon.Utils
 */
Cocoon.define("Cocoon.Utils", function (extension) {
    "use strict";

    /**
    * Prints in the console the memory usage of the currently alive textures.
    * @function logMemoryInfo
    * @memberOf Cocoon.Utils
    * @example
    * Cocoon.Utils.logMemoryInfo();
    */
    extension.logMemoryInfo = function () {
        if (Cocoon.nativeAvailable() && navigator.isCocoonJS) {
            return Cocoon.callNative("IDTK_APP", "logMemoryInfo", arguments);
        }
    };

    /**
    * Sets the texture reduction options. The texture reduction is a process that allows big images to be reduced/scaled down when they are loaded.
    * Although the quality of the images may decrease, it can be very useful in low end devices or those with limited amount of memory.
    * The function sets the threshold on image size (width or height) that will be used in order to know if an image should be reduced or not.
    * It also allows to specify a list of strings to identify in which images file paths should be applied (when they meet the size threshold requirement)
    * The developer will still think that the image is of the original size. Cocoon handles all of the internals to be able to show the image correctly.
    * IMPORTANT NOTE: This function should be called when the application is initialized before any image is set to be loaded for obvious reasons ;).
    * and in which sould be forbid (even if they meet the threshold requirement).
    * @function setTextureReduction
    * @memberOf Cocoon.Utils
    * @param {number} sizeThreshold This parameter specifies the minimun size (either width or height) that an image should have in order to be reduced.
    * @param {string|array} applyTo This parameter can either be a string or an array of strings. It's purpose is to specify one (the string) or more (the array) substring(s)
    * that will be compared against the file path of an image to be loaded in order to know if the reduction should be applied or not. If the image meets the
    * threshold size requirement and it's file path contains this string (or strings), it will be reduced. This parameter can also be null.
    * @param {string|array} forbidFor This parameter can either be a string or an array of strings. It's purpose is to specify one (the string) or more (the array) substring(s)
    * that will be compared against the file path of an image to be loaded in order to know if the reduction should be applied or not. If the image meets the
    * threshold size requirement and it's file path contains this string (or strings), it won't be reduced. This parameter should be used in order to mantain the
    * quality of some images even they meet the size threshold requirement.
    * @example
    * Cocoon.Utils.textureReduction(64);
    */
    extension.textureReduction = function (sizeThreshold, applyTo, forbidFor) {
        if (Cocoon.nativeAvailable() && navigator.isCocoonJS) {
            return Cocoon.callNative("IDTK_APP", "setDefaultTextureReducerThreshold", arguments);
        }
    };

    /**
    * Marks a audio file to be used as music by the system. Cocoon, internally, differentiates among music files and sound files.
    * Music files are usually bigger in size and longer in duration that sound files. There can only be just one music file
    * playing at a specific given time. The developer can mark as many files as he/she wants to be treated as music. When the corresponding
    * HTML5 audio object is used, the system will automatically know how to treat the audio resource as music or as sound.
    * Note that it is not mandatory to use this function. The system automatically tries to identify if a file is suitable to be treated as music
    * or as sound by checking file size and duration thresholds. It is recommended, though, that the developer specifies him/herself what he/she considers
    * to be music.
    * @function markAsMusic
    * @param {string} filePath File path to be marked as music
    * @memberOf Cocoon.Utils
    * @example
    * Cocoon.Utils.markAsMusic("path/to/file.mp3");
    */
    extension.markAsMusic = function (audioFilePath) {
        if (Cocoon.nativeAvailable()) {
            return Cocoon.callNative("IDTK_APP", "addForceMusic", arguments);
        }
    };

    /**
     * Captures a image of the screen synchronously and saves it to a file. Sync mode allows to capture the screen in the middle of a frame rendering.
     * @function captureScreen
     * @memberof Cocoon.Utils
     * @param {string} fileName Desired file name and format (png or jpg). If no value is passed, "capture.png" value is used by default
     * @param {Cocoon.App.StorageType} storageType The developer can specify the storage where it is stored. If no value is passed, the {@link Cocoon.Utils.StorageType.TMP_STORAGE} value is used by default.
     * @param {Cocoon.Utils.CaptureType} captureType Optional value to choose capture type. See {@link Cocoon.Utils.CaptureType}.
     * - 0: Captures everything.
     * - 1: Only captures cocoon surface.
     * - 2: Only captures system views.
     * @param {boolean} saveToGallery Optional value to specify if the capture image should be stored in the device image gallery or not.
     * @throws exception if the image fails to be stored or there is another error.
     * @return The URL of the saved file.
     * @example
     * Cocoon.Utils.captureScreen("myScreenshot.png");
     */
    extension.captureScreen = function (fileName, storageType, captureType, saveToGallery) {
        if (Cocoon.nativeAvailable()) {
            return Cocoon.callNative("IDTK_APP", "captureScreen", arguments);
        }
    };

    /**
    * Captures a image of the screen asynchronously and saves it to a file.
    * Async mode captures a final frame as soon as possible.
    * @function captureScreenAsync
    * @memberof Cocoon.Utils
    * @param {string} fileName Desired file name and format (png or jpg). If no value is passed, "capture.png" value is used by default
    * @param {Cocoon.App.StorageType} storageType The developer can specify the storage where it is stored. If no value is passed, the {@see Cocoon.Utils.StorageType.TMP_STORAGE} value is used by default.
    * @param {Cocoon.Utils.CaptureType} captureType Optional value to choose capture type. See {@link Cocoon.Utils.CaptureType}.
    * - 0: Captures everything.
    * - 1: Only captures cocoon surface.
    * - 2: Only captures system views.
    * @param {boolean} saveToGallery Optional value to specify if the capture image should be stored in the device image gallery or not.
    * @param {function} callback Response callback, check the error property to monitor errors. Check the 'url' property to get the URL of the saved Image
    * @example
    * Cocoon.Utils.captureScreenAsync("myScreenshot.png", Cocoon.Utils.StorageType.TMP_STORAGE, false, Cocoon.Utils.CaptureType.EVERYTHING, function(url, error){
    * ...
    * });
    */
    extension.captureScreenAsync = function (fileName, storageType, captureType, saveToGallery, callback) {
        if (Cocoon.nativeAvailable()) {
            Cocoon.callNative("IDTK_APP", "captureScreen", arguments, true);
        }
    };

    /**
    * Activates or deactivates the antialas functionality from the Cocoon rendering.
    * @function setAntialias
    * @memberOf Cocoon.Utils
    * @param {boolean} enable A boolean value to enable (true) or disable (false) antialias.
    * @example
    * Cocoon.Utils.setAntialias(true);
    */
    extension.setAntialias = function (enable) {
        if (Cocoon.nativeAvailable() && navigator.isCocoonJS) {
            return Cocoon.callNative("IDTK_APP", "setDefaultAntialias", arguments);
        }
    };

    /**
    * Activates or deactivates the webgl functionality from the Cocoon Canvas+ rendering.
    * @function setWebGLEnabled
    * @memberOf Cocoon.Utils
    * @param {boolean} enabled A boolean value to enable (true) or disable (false) webgl in Canvas+.
    * @example
    * Cocoon.Utils.setWebGLEnabled(true);
    */
    extension.setWebGLEnabled = function (enabled) {
        if (Cocoon.nativeAvailable()) {
            return Cocoon.callNative("IDTK_APP", "setWebGLEnabled", arguments, false);
        }
    };

    /**
    * Checks if WebGL is enabled in Canvas+
    * @function isWebGLEnabled
    * @example
    * var enabled = Cocoon.Utils.isWebGLEnabled();
    */
    extension.isWebGLEnabled = function () {
        if (Cocoon.nativeAvailable()) {
            return Cocoon.callNative("IDTK_APP", "isWebGLEnabled", arguments, false);
        }
    };

    /**
     * Enables NPOT (not power of two) textures in Canvas+.
     * Canvas+ uses POT (power of two) textures by default. Enabling NPOT improves memory usage but may affect performance on old GPUs.
     * @function setNPOTEnabled
     * @memberof Cocoon.Utils
     * @param {boolean} enabled true to enable NPOT Textures
     * @example
     * Cocoon.Utils.setNPOTEnabled(true);
     */
    extension.setNPOTEnabled = function (enabled) {
        if (Cocoon.nativeAvailable() && navigator.isCocoonJS) {
            return window.ext.IDTK_APP.makeCall("setNPOTEnabled", enabled);
        }
    };

    /**
     * Sets a max memory threshold in Canvas+ for canvas2D contexts.
     * If the maxMemory is enabled, Cocoon checks the total amount of texture sizes (images and canvases).
     * When the memory size reaches the max memory threshold Cocoon disposes least recently used textures until the memory fits the threshold.
     * It disposes textures used for JS Image objects (which can be reloaded later if needed).
     * It doesn't dispose canvas objects because they cannot be reconstructed if they are used again in a render operation.
     * @function setMaxMemory
     * @memberof Cocoon.Utils
     * @param {number} memoryInMBs max memory in megabytes
     * @example
     * Cocoon.Utils.setMaxMemory(75);
     */
    extension.setMaxMemory = function (memoryInMBs) {
        if (Cocoon.nativeAvailable() && navigator.isCocoonJS) {
            return window.ext.IDTK_APP.makeCall("setMaxMemory", memoryInMBs);
        }
    };

    /**
    *
    * @memberof Cocoon.Utils
    * @name Cocoon.Utils.CaptureType
    * @property {string} Cocoon.Utils.CaptureType - The base object
    * @property {string} Cocoon.Utils.CaptureType.EVERYTHING - Captures everything, both the Cocoon GL hardware accelerated surface and the system views (like the WebView).
    * @property {string} Cocoon.Utils.CaptureType.COCOONJS_GL_SURFACE - Captures just the Cocoon GL hardware accelerated surface.
    * @property {string} Cocoon.Utils.CaptureType.JUST_SYSTEM_VIEWS - Captures just the sustem views (like the webview)
    */
    extension.CaptureType = {
        EVERYTHING: 0,
        COCOONJS_GL_SURFACE: 1,
        JUST_SYSTEM_VIEWS: 2
    };

    /**
    * Queries if a file exists in the specified path and storage type. If none or unknown storage type is specified, the TEMPORARY_STORAGE is used as default.
    * @function existsPath
    * @memberof Cocoon.Utils
    * @param {string} path The relative path to look for inside the storage of the underlying system.
    * @param {Cocoon.App.StorageType} storageType The storage type where to look for the specified path inside the system.
    * @example
    * console.log(Cocoon.Utils.existsPath("file.txt"));
    */
    extension.existsPath = function (path, storageType) {
        if (Cocoon.nativeAvailable()) {
            return Cocoon.callNative("IDTK_APP", "existsPath", arguments);
        }
        return false;
    };

    /**
    * Setups the internal text texture cache size.
    * In order to improve the performance of fill and stroke operations, a text texture cache is used internally. Once a text is drawn
    * a texture is stored that matches that text and that text configuration. If the same text is called to
    * be drawn, this cached texture would be used.
    * This function allows to set the size of the cache. A value of 0 would mean that no cache
    * will be used.
    * @function setTextCacheSize
    * @memberof Cocoon.Utils
    * @param size {number} The size of the text cache.
    * @example
    * Cocoon.Utils.setTextCacheSize(32);
    */
    extension.setTextCacheSize = function (size) {
        if (Cocoon.nativeAvailable() && navigator.isCocoonJS) {
            return Cocoon.callNative("IDTK_APP", "setTextCacheSize", arguments);
        }
    };

    return extension;

});<commit_msg>Fixed isWebGLEnabled docs<commit_after>/**
 * This namespace holds different utilities.
 * @namespace Cocoon.Utils
 */
Cocoon.define("Cocoon.Utils", function (extension) {
    "use strict";

    /**
    * Prints in the console the memory usage of the currently alive textures.
    * @function logMemoryInfo
    * @memberOf Cocoon.Utils
    * @example
    * Cocoon.Utils.logMemoryInfo();
    */
    extension.logMemoryInfo = function () {
        if (Cocoon.nativeAvailable() && navigator.isCocoonJS) {
            return Cocoon.callNative("IDTK_APP", "logMemoryInfo", arguments);
        }
    };

    /**
    * Sets the texture reduction options. The texture reduction is a process that allows big images to be reduced/scaled down when they are loaded.
    * Although the quality of the images may decrease, it can be very useful in low end devices or those with limited amount of memory.
    * The function sets the threshold on image size (width or height) that will be used in order to know if an image should be reduced or not.
    * It also allows to specify a list of strings to identify in which images file paths should be applied (when they meet the size threshold requirement)
    * The developer will still think that the image is of the original size. Cocoon handles all of the internals to be able to show the image correctly.
    * IMPORTANT NOTE: This function should be called when the application is initialized before any image is set to be loaded for obvious reasons ;).
    * and in which sould be forbid (even if they meet the threshold requirement).
    * @function setTextureReduction
    * @memberOf Cocoon.Utils
    * @param {number} sizeThreshold This parameter specifies the minimun size (either width or height) that an image should have in order to be reduced.
    * @param {string|array} applyTo This parameter can either be a string or an array of strings. It's purpose is to specify one (the string) or more (the array) substring(s)
    * that will be compared against the file path of an image to be loaded in order to know if the reduction should be applied or not. If the image meets the
    * threshold size requirement and it's file path contains this string (or strings), it will be reduced. This parameter can also be null.
    * @param {string|array} forbidFor This parameter can either be a string or an array of strings. It's purpose is to specify one (the string) or more (the array) substring(s)
    * that will be compared against the file path of an image to be loaded in order to know if the reduction should be applied or not. If the image meets the
    * threshold size requirement and it's file path contains this string (or strings), it won't be reduced. This parameter should be used in order to mantain the
    * quality of some images even they meet the size threshold requirement.
    * @example
    * Cocoon.Utils.textureReduction(64);
    */
    extension.textureReduction = function (sizeThreshold, applyTo, forbidFor) {
        if (Cocoon.nativeAvailable() && navigator.isCocoonJS) {
            return Cocoon.callNative("IDTK_APP", "setDefaultTextureReducerThreshold", arguments);
        }
    };

    /**
    * Marks a audio file to be used as music by the system. Cocoon, internally, differentiates among music files and sound files.
    * Music files are usually bigger in size and longer in duration that sound files. There can only be just one music file
    * playing at a specific given time. The developer can mark as many files as he/she wants to be treated as music. When the corresponding
    * HTML5 audio object is used, the system will automatically know how to treat the audio resource as music or as sound.
    * Note that it is not mandatory to use this function. The system automatically tries to identify if a file is suitable to be treated as music
    * or as sound by checking file size and duration thresholds. It is recommended, though, that the developer specifies him/herself what he/she considers
    * to be music.
    * @function markAsMusic
    * @param {string} filePath File path to be marked as music
    * @memberOf Cocoon.Utils
    * @example
    * Cocoon.Utils.markAsMusic("path/to/file.mp3");
    */
    extension.markAsMusic = function (audioFilePath) {
        if (Cocoon.nativeAvailable()) {
            return Cocoon.callNative("IDTK_APP", "addForceMusic", arguments);
        }
    };

    /**
     * Captures a image of the screen synchronously and saves it to a file. Sync mode allows to capture the screen in the middle of a frame rendering.
     * @function captureScreen
     * @memberof Cocoon.Utils
     * @param {string} fileName Desired file name and format (png or jpg). If no value is passed, "capture.png" value is used by default
     * @param {Cocoon.App.StorageType} storageType The developer can specify the storage where it is stored. If no value is passed, the {@link Cocoon.Utils.StorageType.TMP_STORAGE} value is used by default.
     * @param {Cocoon.Utils.CaptureType} captureType Optional value to choose capture type. See {@link Cocoon.Utils.CaptureType}.
     * - 0: Captures everything.
     * - 1: Only captures cocoon surface.
     * - 2: Only captures system views.
     * @param {boolean} saveToGallery Optional value to specify if the capture image should be stored in the device image gallery or not.
     * @throws exception if the image fails to be stored or there is another error.
     * @return The URL of the saved file.
     * @example
     * Cocoon.Utils.captureScreen("myScreenshot.png");
     */
    extension.captureScreen = function (fileName, storageType, captureType, saveToGallery) {
        if (Cocoon.nativeAvailable()) {
            return Cocoon.callNative("IDTK_APP", "captureScreen", arguments);
        }
    };

    /**
    * Captures a image of the screen asynchronously and saves it to a file.
    * Async mode captures a final frame as soon as possible.
    * @function captureScreenAsync
    * @memberof Cocoon.Utils
    * @param {string} fileName Desired file name and format (png or jpg). If no value is passed, "capture.png" value is used by default
    * @param {Cocoon.App.StorageType} storageType The developer can specify the storage where it is stored. If no value is passed, the {@see Cocoon.Utils.StorageType.TMP_STORAGE} value is used by default.
    * @param {Cocoon.Utils.CaptureType} captureType Optional value to choose capture type. See {@link Cocoon.Utils.CaptureType}.
    * - 0: Captures everything.
    * - 1: Only captures cocoon surface.
    * - 2: Only captures system views.
    * @param {boolean} saveToGallery Optional value to specify if the capture image should be stored in the device image gallery or not.
    * @param {function} callback Response callback, check the error property to monitor errors. Check the 'url' property to get the URL of the saved Image
    * @example
    * Cocoon.Utils.captureScreenAsync("myScreenshot.png", Cocoon.Utils.StorageType.TMP_STORAGE, false, Cocoon.Utils.CaptureType.EVERYTHING, function(url, error){
    * ...
    * });
    */
    extension.captureScreenAsync = function (fileName, storageType, captureType, saveToGallery, callback) {
        if (Cocoon.nativeAvailable()) {
            Cocoon.callNative("IDTK_APP", "captureScreen", arguments, true);
        }
    };

    /**
    * Activates or deactivates the antialas functionality from the Cocoon rendering.
    * @function setAntialias
    * @memberOf Cocoon.Utils
    * @param {boolean} enable A boolean value to enable (true) or disable (false) antialias.
    * @example
    * Cocoon.Utils.setAntialias(true);
    */
    extension.setAntialias = function (enable) {
        if (Cocoon.nativeAvailable() && navigator.isCocoonJS) {
            return Cocoon.callNative("IDTK_APP", "setDefaultAntialias", arguments);
        }
    };

    /**
    * Activates or deactivates the webgl functionality from the Cocoon Canvas+ rendering.
    * @function setWebGLEnabled
    * @memberOf Cocoon.Utils
    * @param {boolean} enabled A boolean value to enable (true) or disable (false) webgl in Canvas+.
    * @example
    * Cocoon.Utils.setWebGLEnabled(true);
    */
    extension.setWebGLEnabled = function (enabled) {
        if (Cocoon.nativeAvailable()) {
            return Cocoon.callNative("IDTK_APP", "setWebGLEnabled", arguments, false);
        }
    };

    /**
    * Checks if WebGL is enabled in Canvas+.
    * @function isWebGLEnabled
    * @memberOf Cocoon.Utils
    * @example
    * var enabled = Cocoon.Utils.isWebGLEnabled();
    */
    extension.isWebGLEnabled = function () {
        if (Cocoon.nativeAvailable()) {
            return Cocoon.callNative("IDTK_APP", "isWebGLEnabled", arguments, false);
        }
    };

    /**
     * Enables NPOT (not power of two) textures in Canvas+.
     * Canvas+ uses POT (power of two) textures by default. Enabling NPOT improves memory usage but may affect performance on old GPUs.
     * @function setNPOTEnabled
     * @memberof Cocoon.Utils
     * @param {boolean} enabled true to enable NPOT Textures
     * @example
     * Cocoon.Utils.setNPOTEnabled(true);
     */
    extension.setNPOTEnabled = function (enabled) {
        if (Cocoon.nativeAvailable() && navigator.isCocoonJS) {
            return window.ext.IDTK_APP.makeCall("setNPOTEnabled", enabled);
        }
    };

    /**
     * Sets a max memory threshold in Canvas+ for canvas2D contexts.
     * If the maxMemory is enabled, Cocoon checks the total amount of texture sizes (images and canvases).
     * When the memory size reaches the max memory threshold Cocoon disposes least recently used textures until the memory fits the threshold.
     * It disposes textures used for JS Image objects (which can be reloaded later if needed).
     * It doesn't dispose canvas objects because they cannot be reconstructed if they are used again in a render operation.
     * @function setMaxMemory
     * @memberof Cocoon.Utils
     * @param {number} memoryInMBs max memory in megabytes
     * @example
     * Cocoon.Utils.setMaxMemory(75);
     */
    extension.setMaxMemory = function (memoryInMBs) {
        if (Cocoon.nativeAvailable() && navigator.isCocoonJS) {
            return window.ext.IDTK_APP.makeCall("setMaxMemory", memoryInMBs);
        }
    };

    /**
    *
    * @memberof Cocoon.Utils
    * @name Cocoon.Utils.CaptureType
    * @property {string} Cocoon.Utils.CaptureType - The base object
    * @property {string} Cocoon.Utils.CaptureType.EVERYTHING - Captures everything, both the Cocoon GL hardware accelerated surface and the system views (like the WebView).
    * @property {string} Cocoon.Utils.CaptureType.COCOONJS_GL_SURFACE - Captures just the Cocoon GL hardware accelerated surface.
    * @property {string} Cocoon.Utils.CaptureType.JUST_SYSTEM_VIEWS - Captures just the sustem views (like the webview)
    */
    extension.CaptureType = {
        EVERYTHING: 0,
        COCOONJS_GL_SURFACE: 1,
        JUST_SYSTEM_VIEWS: 2
    };

    /**
    * Queries if a file exists in the specified path and storage type. If none or unknown storage type is specified, the TEMPORARY_STORAGE is used as default.
    * @function existsPath
    * @memberof Cocoon.Utils
    * @param {string} path The relative path to look for inside the storage of the underlying system.
    * @param {Cocoon.App.StorageType} storageType The storage type where to look for the specified path inside the system.
    * @example
    * console.log(Cocoon.Utils.existsPath("file.txt"));
    */
    extension.existsPath = function (path, storageType) {
        if (Cocoon.nativeAvailable()) {
            return Cocoon.callNative("IDTK_APP", "existsPath", arguments);
        }
        return false;
    };

    /**
    * Setups the internal text texture cache size.
    * In order to improve the performance of fill and stroke operations, a text texture cache is used internally. Once a text is drawn
    * a texture is stored that matches that text and that text configuration. If the same text is called to
    * be drawn, this cached texture would be used.
    * This function allows to set the size of the cache. A value of 0 would mean that no cache
    * will be used.
    * @function setTextCacheSize
    * @memberof Cocoon.Utils
    * @param size {number} The size of the text cache.
    * @example
    * Cocoon.Utils.setTextCacheSize(32);
    */
    extension.setTextCacheSize = function (size) {
        if (Cocoon.nativeAvailable() && navigator.isCocoonJS) {
            return Cocoon.callNative("IDTK_APP", "setTextCacheSize", arguments);
        }
    };

    return extension;

});<|endoftext|>


<commit_before>/**
 * Created by theon on 11/28/2016.
 */

var Twitter = require('twitter');

var client = new Twitter({
    consumer_key: process.env.CONSUMERKEY,
    consumer_secret: process.env.CONSUMERSECRET,
    access_token_key: process.env.ACCESSTOKEN,
    access_token_secret: process.env.ACCESSTOKENSECRET
});

var params = {"q": 'spectacles snapchat',
"result_type": 'recent', "count": 100};
console.log(client);
client.get('/search/tweets', params, function(error, tweets, response) {
    var options = ["retweet","favorite"];

    if (!error) {
        console.log("No error")
    } else {
        console.log(error)
    }
    var temptweets = tweets;
    console.log(temptweets);
    for(var i =0; i < 10; i++) {
        var index = Math.floor(Math.random() * temptweets.statuses.length);
        var selectedtweet = temptweets.statuses[index];
        var option = options[Math.floor(Math.random() * options.length)];
        console.log("tweet length", temptweets.statuses.length, index);
        if (option == "favorite") {
        client.post('favorites/create',{id: selectedtweet.id_str}, function (error,tweets,response){console.log(error + " Favorited");});
        // client.post('favorites/create',{id: selectedtweet.id}, function (error,tweets,response){console.log(error+ ", Favorited "+ selectedtweet.id);});
        } else {
        // client.post('statuses/retweet',{id: selectedtweet.id}, function (error,tweets,response){console.log(error+ ", Retweeted "+ selectedtweet.id);});
        client.post('statuses/retweet',{id: selectedtweet.id_str}, function (error,tweets,response){console.log(error + " Retweeted");});
        }
        temptweets.statuses.splice(index, 1);

    }

    client.post('friendships/create',{screen_name: selectedtweet.user.screen_name, user_id: selectedtweet.user.id_str},function (error,tweets,response){console.log(error + "Friended "+ selectedtweet.user.screen_name);});

});

// console.log("NEW TASK WAS RUN!");
// setTimeout(function(){
//     console.log("DONE");
// }, 20000);
// var client = new Twitter({
//     consumer_key: process.env.TWITTER_PURRCH_KEY, // should be url encoded. skipping for now
//     consumer_secret: process.env.TWITTER_SECRET,
//     access_token_key: usermodel.token,
//     access_token_secret: usermodel.tokenSecret
// });
<commit_msg>deploy: capitalize environment variables<commit_after>/**
 * Created by theon on 11/28/2016.
 */

var Twitter = require('twitter');

var client = new Twitter({
    consumer_key: process.env.CONSUMERKEY,
    consumer_secret: process.env.CONSUMERSECRET,
    access_token_key: process.env.ACCESSTOKEN,
    access_token_secret: process.env.ACCESSTOKENSECRET
});

var params = {"q": 'spectacles snapchat',
"result_type": 'recent', "count": 100};
console.log(client);

setTimeout(
client.get('/search/tweets', params, function(error, tweets, response) {
    var options = ["retweet","favorite"];

    if (!error) {
        console.log("No error")
    } else {
        console.log(error)
    }
    var temptweets = tweets;
    console.log(temptweets);
    for(var i =0; i < 10; i++) {
        var index = Math.floor(Math.random() * temptweets.statuses.length);
        var selectedtweet = temptweets.statuses[index];
        var option = options[Math.floor(Math.random() * options.length)];
        console.log("tweet length", temptweets.statuses.length, index);
        if (option == "favorite") {
        client.post('favorites/create',{id: selectedtweet.id_str}, function (error,tweets,response){console.log(error + " Favorited");});
        // client.post('favorites/create',{id: selectedtweet.id}, function (error,tweets,response){console.log(error+ ", Favorited "+ selectedtweet.id);});
        } else {
        // client.post('statuses/retweet',{id: selectedtweet.id}, function (error,tweets,response){console.log(error+ ", Retweeted "+ selectedtweet.id);});
        client.post('statuses/retweet',{id: selectedtweet.id_str}, function (error,tweets,response){console.log(error + " Retweeted");});
        }
        temptweets.statuses.splice(index, 1);

    }

    client.post('friendships/create',{screen_name: selectedtweet.user.screen_name, user_id: selectedtweet.user.id_str},function (error,tweets,response){console.log(error + "Friended "+ selectedtweet.user.screen_name);});

}),2000);

// console.log("NEW TASK WAS RUN!");
// setTimeout(function(){
//     console.log("DONE");
// }, 20000);
// var client = new Twitter({
//     consumer_key: process.env.TWITTER_PURRCH_KEY, // should be url encoded. skipping for now
//     consumer_secret: process.env.TWITTER_SECRET,
//     access_token_key: usermodel.token,
//     access_token_secret: usermodel.tokenSecret
// });
<|endoftext|>


<commit_before>var Download = function(table){
	this.table = table; //hold Tabulator object
	this.fields = {}; //hold filed multi dimension arrays
};

//trigger file download
Download.prototype.download = function(type, filename, options){
	var self = this,
	downloadFunc = false;

	function buildLink(data, mime){
		self.triggerDownload(data, mime, type, filename);
	}

	if(typeof type == "function"){
		downloadFunc = type;
	}else{
		if(self.downloaders[type]){
			downloadFunc = self.downloaders[type];
		}else{
			console.warn("Download Error - No such download type found: ", type);
		}
	}

	if(downloadFunc){
		downloadFunc.call(this, self.processDefinitions(), self.processData() , options, buildLink);
	}
};

Download.prototype.processDefinitions = function(){
	var self = this,
	definitions = self.table.columnManager.getDefinitions(),
	processedDefinitions = [];

	self.fields = {};

	definitions.forEach(function(column){
		if(column.field){
			self.fields[column.field] = column.field.split(".");

			if(column.download !== false){
				//isolate definiton from defintion object
				var def = {};

				for(var key in column){
					def[key] = column[key];
				}

				if(typeof column.downloadTitle != "undefined"){
					def.title = column.downloadTitle;
				}

				processedDefinitions.push(def);
			}
		}
	});

	return  processedDefinitions;
};

Download.prototype.processData = function(){
	var self = this,
	data = self.table.rowManager.getData(true);

	//add user data processing step;
	if(typeof self.table.options.downloadDataMutator == "function"){
		data = self.table.options.downloadDataMutator(data);
	}

	return data;
};

Download.prototype.triggerDownload = function(data, mime, type, filename){
	var element = document.createElement('a'),
	blob = new Blob([data],{type:mime}),
	filename = filename || "Tabulator." + (typeof type === "function" ? "txt" : type);

	blob = this.table.options.downloadReady(data, blob);

	console.log("blob", blob)

	if(blob){

		if(navigator.msSaveOrOpenBlob){
			navigator.msSaveOrOpenBlob(blob, filename);
		}else{
			element.setAttribute('href', window.URL.createObjectURL(blob));

			//set file title
			element.setAttribute('download', filename);

			//trigger download
			element.style.display = 'none';
			document.body.appendChild(element);
			element.click();

			//remove temporary link element
			document.body.removeChild(element);
		}

		if(this.table.options.downloadComplete){
			this.table.options.downloadComplete();
		}
	}

};

//nested field lookup
Download.prototype.getFieldValue = function(field, data){
	var dataObj = data,
	structure = this.fields[field],
	length = structure.length,
	output;

	for(let i = 0; i < length; i++){

		dataObj = dataObj[structure[i]];

		output = dataObj;

		if(!dataObj){
			break;
		}
	}

	return output;
};

//downloaders
Download.prototype.downloaders = {
	csv:function(columns, data, options, setFileContents){
		var self = this,
		titles = [],
		fields = [],
		delimiter = options && options.delimiter ? options.delimiter : ",",
		fileContents;

		//get field lists
		columns.forEach(function(column){
			if(column.field){
				titles.push('"' + String(column.title).split('"').join('""') + '"');
				fields.push(column.field);
			}
		})

		//generate header row
		fileContents = [titles.join(delimiter)];

		//generate each row of the table
		data.forEach(function(row){
			var rowData = [];

			fields.forEach(function(field){
				var value = self.getFieldValue(field, row);

				switch(typeof value){
					case "object":
					value = JSON.stringify(value);
					break;

					case "undefined":
					case "null":
					value = "";
					break;

					default:
					value = value;
				}

				//escape uotation marks
				rowData.push('"' + String(value).split('"').join('""') + '"');
			})

			fileContents.push(rowData.join(delimiter));
		});

		setFileContents(fileContents.join("\n"), "text/csv");
	},

	json:function(columns, data, options, setFileContents){
		var fileContents = JSON.stringify(data, null, '\t');

		setFileContents(fileContents, "application/json");
	},

	xlsx:function(columns, data, options, setFileContents){
		var self = this,
		titles = [],
		fields = [],
		rows = [],
		workbook = { SheetNames:["Sheet1"], Sheets:{} },
		worksheet, output;

		//convert rows to worksheet
		function rowsToSheet(){
			var sheet = {};
			var range = {s: {c:0, r:0}, e: {c:fields.length, r:rows.length }};

			rows.forEach(function(row, i){
				row.forEach(function(value, j){
					var cell = {v: typeof value == "undefined" || value === null ? "" : value};

					if(cell != null){
						switch(typeof cell.v){
							case "number":
							cell.t = 'n';
							break;
							case "boolean":
							cell.t = 'b';
							break;
							default:
							cell.t = 's';
							break;
						}

						sheet[XLSX.utils.encode_cell({c:j,r:i})] = cell
					}
				});
			});

			sheet['!ref'] = XLSX.utils.encode_range(range);

			return sheet;
		}

		//convert workbook to binary array
		function s2ab(s) {
			var buf = new ArrayBuffer(s.length);
			var view = new Uint8Array(buf);
			for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
				return buf;
		}

		//get field lists
		columns.forEach(function(column){
			if(column.field){
				titles.push(column.title);
				fields.push(column.field);
			}
		});

		rows.push(titles);

		//generate each row of the table
		data.forEach(function(row){
			var rowData = [];

			fields.forEach(function(field){
				rowData.push(self.getFieldValue(field, row));
			});

			rows.push(rowData);
		});

		worksheet = rowsToSheet();
		workbook.Sheets["Sheet1"] = worksheet;

		output = XLSX.write(workbook, {bookType:'xlsx', bookSST:true, type: 'binary'});

		setFileContents(s2ab(output), "application/octet-stream");
	}
};

Tabulator.registerExtension("download", Download);<commit_msg>remove unneeded console.log<commit_after>var Download = function(table){
	this.table = table; //hold Tabulator object
	this.fields = {}; //hold filed multi dimension arrays
};

//trigger file download
Download.prototype.download = function(type, filename, options){
	var self = this,
	downloadFunc = false;

	function buildLink(data, mime){
		self.triggerDownload(data, mime, type, filename);
	}

	if(typeof type == "function"){
		downloadFunc = type;
	}else{
		if(self.downloaders[type]){
			downloadFunc = self.downloaders[type];
		}else{
			console.warn("Download Error - No such download type found: ", type);
		}
	}

	if(downloadFunc){
		downloadFunc.call(this, self.processDefinitions(), self.processData() , options, buildLink);
	}
};

Download.prototype.processDefinitions = function(){
	var self = this,
	definitions = self.table.columnManager.getDefinitions(),
	processedDefinitions = [];

	self.fields = {};

	definitions.forEach(function(column){
		if(column.field){
			self.fields[column.field] = column.field.split(".");

			if(column.download !== false){
				//isolate definiton from defintion object
				var def = {};

				for(var key in column){
					def[key] = column[key];
				}

				if(typeof column.downloadTitle != "undefined"){
					def.title = column.downloadTitle;
				}

				processedDefinitions.push(def);
			}
		}
	});

	return  processedDefinitions;
};

Download.prototype.processData = function(){
	var self = this,
	data = self.table.rowManager.getData(true);

	//add user data processing step;
	if(typeof self.table.options.downloadDataMutator == "function"){
		data = self.table.options.downloadDataMutator(data);
	}

	return data;
};

Download.prototype.triggerDownload = function(data, mime, type, filename){
	var element = document.createElement('a'),
	blob = new Blob([data],{type:mime}),
	filename = filename || "Tabulator." + (typeof type === "function" ? "txt" : type);

	blob = this.table.options.downloadReady(data, blob);

	if(blob){

		if(navigator.msSaveOrOpenBlob){
			navigator.msSaveOrOpenBlob(blob, filename);
		}else{
			element.setAttribute('href', window.URL.createObjectURL(blob));

			//set file title
			element.setAttribute('download', filename);

			//trigger download
			element.style.display = 'none';
			document.body.appendChild(element);
			element.click();

			//remove temporary link element
			document.body.removeChild(element);
		}

		if(this.table.options.downloadComplete){
			this.table.options.downloadComplete();
		}
	}

};

//nested field lookup
Download.prototype.getFieldValue = function(field, data){
	var dataObj = data,
	structure = this.fields[field],
	length = structure.length,
	output;

	for(let i = 0; i < length; i++){

		dataObj = dataObj[structure[i]];

		output = dataObj;

		if(!dataObj){
			break;
		}
	}

	return output;
};

//downloaders
Download.prototype.downloaders = {
	csv:function(columns, data, options, setFileContents){
		var self = this,
		titles = [],
		fields = [],
		delimiter = options && options.delimiter ? options.delimiter : ",",
		fileContents;

		//get field lists
		columns.forEach(function(column){
			if(column.field){
				titles.push('"' + String(column.title).split('"').join('""') + '"');
				fields.push(column.field);
			}
		})

		//generate header row
		fileContents = [titles.join(delimiter)];

		//generate each row of the table
		data.forEach(function(row){
			var rowData = [];

			fields.forEach(function(field){
				var value = self.getFieldValue(field, row);

				switch(typeof value){
					case "object":
					value = JSON.stringify(value);
					break;

					case "undefined":
					case "null":
					value = "";
					break;

					default:
					value = value;
				}

				//escape uotation marks
				rowData.push('"' + String(value).split('"').join('""') + '"');
			})

			fileContents.push(rowData.join(delimiter));
		});

		setFileContents(fileContents.join("\n"), "text/csv");
	},

	json:function(columns, data, options, setFileContents){
		var fileContents = JSON.stringify(data, null, '\t');

		setFileContents(fileContents, "application/json");
	},

	xlsx:function(columns, data, options, setFileContents){
		var self = this,
		titles = [],
		fields = [],
		rows = [],
		workbook = { SheetNames:["Sheet1"], Sheets:{} },
		worksheet, output;

		//convert rows to worksheet
		function rowsToSheet(){
			var sheet = {};
			var range = {s: {c:0, r:0}, e: {c:fields.length, r:rows.length }};

			rows.forEach(function(row, i){
				row.forEach(function(value, j){
					var cell = {v: typeof value == "undefined" || value === null ? "" : value};

					if(cell != null){
						switch(typeof cell.v){
							case "number":
							cell.t = 'n';
							break;
							case "boolean":
							cell.t = 'b';
							break;
							default:
							cell.t = 's';
							break;
						}

						sheet[XLSX.utils.encode_cell({c:j,r:i})] = cell
					}
				});
			});

			sheet['!ref'] = XLSX.utils.encode_range(range);

			return sheet;
		}

		//convert workbook to binary array
		function s2ab(s) {
			var buf = new ArrayBuffer(s.length);
			var view = new Uint8Array(buf);
			for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
				return buf;
		}

		//get field lists
		columns.forEach(function(column){
			if(column.field){
				titles.push(column.title);
				fields.push(column.field);
			}
		});

		rows.push(titles);

		//generate each row of the table
		data.forEach(function(row){
			var rowData = [];

			fields.forEach(function(field){
				rowData.push(self.getFieldValue(field, row));
			});

			rows.push(rowData);
		});

		worksheet = rowsToSheet();
		workbook.Sheets["Sheet1"] = worksheet;

		output = XLSX.write(workbook, {bookType:'xlsx', bookSST:true, type: 'binary'});

		setFileContents(s2ab(output), "application/octet-stream");
	}
};

Tabulator.registerExtension("download", Download);<|endoftext|>


<commit_before>//
// Set up the database for the backend of the site for grpres.
//
// If any other set up or initialization is needed, this should handle that as
// well.
//
//
// Options:
// node grpres.js init <group>
// node grpres.js addusers <group> <user1> <user2> ...
//

var fs = require('fs');
var sqlite3 = require('sqlite3');

var cmd = process.argv[2];

var group, users, db, dbname, stmt;

switch ( cmd )
{
    case "init":
        group = process.argv[3];
        dbname = group + ".db";

        if ( fs.existsSync( dbname ) )
        {
            console.log( '*** Error:  database already exists for this group:  ' + dbname );
            process.exit( -1 );
        }

        db = new sqlite3.Database( dbname );
        db.serialize( function() {
            db.run("CREATE TABLE posts ( "     +
                    "id INTEGER PRIMARY KEY, " +
                    "time TEXT, "              +
                    "submitter TEXT, "         +
                    "type TEXT, "              +
                    "title TEXT, "             +
                    "summary TEXT, "           +
                    "body TEXT, "              +
                    "filename TEXT "           +
                ");");
            db.run("CREATE TABLE submitters ( "  +
                    "id INTEGER PRIMARY KEY, "   +
                    "name TEXT "                 +
                    ");");});
        console.log( "Initialized database for group: " + group );
        break;

    case "addusers":
        dbname = process.argv[3] + ".db";
        db = new sqlite3.Database( dbname, sqlite3.OPEN_READWRITE );
        users = process.argv.slice(4);
        db.serialize();
        stmt = db.prepare( "INSERT INTO submitters (name) VALUES (?);" );
        for ( var i = 0; i < users.length; i++ )  {
            stmt.run( users[i] );
        }
        stmt.finalize();
        db.parallelize();
        console.log("Inserted " + users.length + " users.");
        break;

    default:
        console.log("*** Error: unknown command.  Use: init or addusers.");
        break;
}

<commit_msg>add TODO<commit_after>//
// Set up the database for the backend of the site for grpres.
//
// If any other set up or initialization is needed, this should handle that as
// well.
//
//
// Options:
// $ node grpres.js init <group>
// $ node grpres.js addusers <group> <user1> <user2> ...
//

var fs = require('fs');
var sqlite3 = require('sqlite3');

var cmd = process.argv[2];

var group, users, db, dbname, stmt;

switch ( cmd )
{
    case "init":
        // TODO: init should allow for setting the group password.
        // $ node grpres.js init <group> <password>
        group = process.argv[3];
        dbname = group + ".db";

        if ( fs.existsSync( dbname ) )
        {
            console.log( '*** Error:  database already exists for this group:  ' + dbname );
            process.exit( -1 );
        }

        db = new sqlite3.Database( dbname );
        db.serialize( function() {
            db.run("CREATE TABLE posts ( "     +
                    "id INTEGER PRIMARY KEY, " +
                    "time TEXT, "              +
                    "submitter TEXT, "         +
                    "type TEXT, "              +
                    "title TEXT, "             +
                    "summary TEXT, "           +
                    "body TEXT, "              +
                    "filename TEXT "           +
                ");");
            db.run("CREATE TABLE submitters ( "  +
                    "id INTEGER PRIMARY KEY, "   +
                    "name TEXT "                 +
                    ");");});
        console.log( "Initialized database for group: " + group );
        break;

    case "addusers":
        dbname = process.argv[3] + ".db";
        db = new sqlite3.Database( dbname, sqlite3.OPEN_READWRITE );
        users = process.argv.slice(4);
        db.serialize();
        stmt = db.prepare( "INSERT INTO submitters (name) VALUES (?);" );
        for ( var i = 0; i < users.length; i++ )  {
            stmt.run( users[i] );
        }
        stmt.finalize();
        db.parallelize();
        console.log("Inserted " + users.length + " users.");
        break;

    default:
        console.log("*** Error: unknown command.  Use: init or addusers.");
        break;
}

<|endoftext|>


<commit_before>var fs = require('fs');

require('browsernizr/test/css/animations');
var Modernizr = require('browsernizr');

module.exports = Backbone.View.extend({
    tagName: "div",
    className: "game",
    events: {
        "click .answer": "tryAnswer",
    },

    template: _.template(fs.readFileSync(__dirname + '/../../templates/question.html', 'utf8')),

    initialize: function(){
        this.listenTo(this.model, 'change', this.render);
    },
    render: function(){
        this.$el.html(this.template(this.model.toJSON()));
        return this;
    },
    transitionIn: function(callback){
        var view = this;

        var animateIn = function(){
            function success(){
                if(_.isFunction(callback)){
                    callback();
                }
            }

            if(Modernizr.cssanimations){
                view.$el.one('webkitAnimationEnd animationend', success);
            }
            else{
                _.delay(success, 1000);
            }

            view.$el.addClass('is-visible');
        }

        _.delay(animateIn, 20);
    },
    transitionOut: function(callback){
        callback();
    },
    tryAnswer: function(event){
        var view = this;
        var button = $(event.target);
        var choice = parseInt(button.data('choice'));

        var isCorrect = this.model.isCorrect(choice);

        if(isCorrect){
            this.$('.answer').addClass('invisible');

            button.removeClass('invisible');
            button.addClass('correct');

            $('#correct').removeClass('hidden');

            window.setTimeout(function(){ view.nextQuestion(); }, 1000);
        }
        else{
            this.$('.question').removeClass('wrong');
            _.delay(function(){ view.$('.question').addClass('wrong'); }, 20);

            button.prop('disabled', true);
        }

        event.preventDefault();
        event.stopPropagation();
    },

    nextQuestion: function(){
        this.model.nextQuestion();
    }
});
<commit_msg>Removes unnecessary event propagation preventions<commit_after>var fs = require('fs');

require('browsernizr/test/css/animations');
var Modernizr = require('browsernizr');

module.exports = Backbone.View.extend({
    tagName: "div",
    className: "game",
    events: {
        "click .answer": "tryAnswer",
    },

    template: _.template(fs.readFileSync(__dirname + '/../../templates/question.html', 'utf8')),

    initialize: function(){
        this.listenTo(this.model, 'change', this.render);
    },
    render: function(){
        this.$el.html(this.template(this.model.toJSON()));
        return this;
    },
    transitionIn: function(callback){
        var view = this;

        var animateIn = function(){
            function success(){
                if(_.isFunction(callback)){
                    callback();
                }
            }

            if(Modernizr.cssanimations){
                view.$el.one('webkitAnimationEnd animationend', success);
            }
            else{
                _.delay(success, 1000);
            }

            view.$el.addClass('is-visible');
        }

        _.delay(animateIn, 20);
    },
    transitionOut: function(callback){
        callback();
    },
    tryAnswer: function(event){
        var view = this;
        var button = $(event.target);
        var choice = parseInt(button.data('choice'));

        var isCorrect = this.model.isCorrect(choice);

        if(isCorrect){
            this.$('.answer').addClass('invisible');

            button.removeClass('invisible');
            button.addClass('correct');

            $('#correct').removeClass('hidden');

            window.setTimeout(function(){ view.nextQuestion(); }, 1000);
        }
        else{
            this.$('.question').removeClass('wrong');
            _.delay(function(){ view.$('.question').addClass('wrong'); }, 20);

            button.prop('disabled', true);
        }
    },

    nextQuestion: function(){
        this.model.nextQuestion();
    }
});
<|endoftext|>